QPixmap QDeclarativeTextPrivate::wrappedTextImage(bool drawStyle) { //do layout QSize size = cachedLayoutSize; int x = 0; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); if (hAlign == QDeclarativeText::AlignLeft) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = size.width() - (int)line.naturalTextWidth(); } else if (hAlign == QDeclarativeText::AlignHCenter) { x = (size.width() - (int)line.naturalTextWidth()) / 2; } line.setPosition(QPoint(x, (int)line.y())); } //paint text QPixmap img(size); if (!size.isEmpty()) { img.fill(Qt::transparent); QPainter p(&img); drawWrappedText(&p, QPointF(0,0), drawStyle); } return img; }
void TextLabel::drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect) { if (rect.width() < 1 || rect.height() < 1) { return; } QPixmap pixmap(rect.size()); pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.setPen(painter->pen()); // Create the alpha gradient for the fade out effect QLinearGradient alphaGradient(0, 0, 1, 0); alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode); if (layout.textOption().textDirection() == Qt::LeftToRight) { alphaGradient.setColorAt(0, QColor(0, 0, 0, 255)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 0)); } else { alphaGradient.setColorAt(0, QColor(0, 0, 0, 0)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 255)); } QFontMetrics fm(layout.font()); int textHeight = layout.lineCount() * fm.lineSpacing(); QPointF position(0, (rect.height() - textHeight) / 2); QList<QRect> fadeRects; int fadeWidth = 30; // Draw each line in the layout for (int i = 0; i < layout.lineCount(); i++) { QTextLine line = layout.lineAt(i); line.draw(&p, position); // Add a fade out rect to the list if the line is too long if (line.naturalTextWidth() > rect.width()) { int x = int(qMin(line.naturalTextWidth(), (qreal)pixmap.width())) - fadeWidth; int y = int(line.position().y() + position.y()); QRect r = QStyle::visualRect(layout.textOption().textDirection(), pixmap.rect(), QRect(x, y, fadeWidth, int(line.height()))); fadeRects.append(r); } } // Reduce the alpha in each fade out rect using the alpha gradient if (!fadeRects.isEmpty()) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); foreach (const QRect &rect, fadeRects) { p.fillRect(rect, alphaGradient); }
void TextLabel::layoutText(QTextLayout &layout, const QString &text, const QSize &constraints) { QFontMetrics metrics(layout.font()); int leading = metrics.leading(); int height = 0; int maxWidth = constraints.width(); int widthUsed = 0; int lineSpacing = metrics.lineSpacing(); QTextLine line; layout.setText(text); layout.beginLayout(); while ((line = layout.createLine()).isValid()) { height += leading; // Make the last line that will fit infinitely long. // drawTextLayout() will handle this by fading the line out // if it won't fit in the constraints. if (height + 2 * lineSpacing > constraints.height()) { line.setPosition(QPoint(0, height)); break; } line.setLineWidth(maxWidth); line.setPosition(QPoint(0, height)); height += int(line.height()); widthUsed = int(qMax(qreal(widthUsed), line.naturalTextWidth())); } layout.endLayout(); }
void setContent(const ToolTipContent &data) { QString html; if (!data.mainText().isEmpty()) { html.append("<div><b>" + data.mainText() + "</b></div>"); } html.append(data.subText()); m_anchor.clear(); m_document->clear(); data.registerResources(m_document); if (!html.isEmpty()) { m_document->setHtml("<p>" + html + "</p>"); } m_document->adjustSize(); m_haloRects.clear(); QTextLayout *layout = m_document->begin().layout(); //layout->setPosition(QPointF(textRect.x(), textBoundingRect->y())); QTextLine line; for (int i = 0; i < layout->lineCount(); ++i) { line = layout->lineAt(i); // Add halo rect only when a non empty line is found if (line.naturalTextWidth()) { m_haloRects.append(line.naturalTextRect().translated(layout->position().toPoint()).toRect().translated(m_margin, m_margin)); } } update(); }
void KTextDocumentLayout::Private::adjustSize() { if (parent->resizeMethod() == KTextDocument::NoResize) return; if (parent->shapes().isEmpty()) return; // Limit auto-resizing to the first shape only (there won't be more // with auto-resizing turned on, unless specifically set) KShape *shape = parent->shapes().first(); // Determine the maximum width of all text lines qreal width = 0; for (QTextBlock block = parent->document()->begin(); block.isValid(); block = block.next()) { // The block layout's wrap mode must be QTextOption::NoWrap, thus the line count // of a valid block must be 1 (otherwise this resizing scheme wouldn't work) Q_ASSERT(block.layout()->lineCount() == 1); QTextLine line = block.layout()->lineAt(0); width = qMax(width, line.naturalTextWidth()); } // Use position and height of last text line to calculate height QTextLine line = parent->document()->lastBlock().layout()->lineAt(0); qreal height = line.position().y() + line.height(); shape->setSize(QSizeF(width, height)); }
int JobItem::descriptionHeight(const QStyleOptionViewItem & option) { int textTotalWidth = 0; int lineWidth = option.rect.width() - 2 * m_itemPadding; QString description = m_job->description().simplified(); QTextLayout descriptionLayout(description, m_descriptionFont, m_paintDevice); descriptionLayout.beginLayout(); for (int i = 0; i < m_descriptionLineCount - 1; ++i) { QTextLine line = descriptionLayout.createLine(); if (!line.isValid()) { // There is no text left to be inserted into the layout. break; } line.setLineWidth(lineWidth); textTotalWidth += line.naturalTextWidth(); } descriptionLayout.endLayout(); // Add space for last visible line. textTotalWidth += lineWidth; m_descriptionText = m_descriptionFontMetrics.elidedText(description, Qt::ElideRight, textTotalWidth); m_descriptionRect = m_descriptionFontMetrics.boundingRect(0, 0, option.rect.width() - 2 * m_itemPadding, 0, descriptionFlags(), m_descriptionText); return m_descriptionRect.height(); }
void paint_QTextLayout(QPainter &p, bool useCache) { static bool first = true; static QTextLayout *textLayout[lines]; if (first) { for (int i = 0; i < lines; ++i) { textLayout[i] = new QTextLayout(strings[i]); int leading = p.fontMetrics().leading(); qreal height = 0; qreal widthUsed = 0; textLayout[i]->setCacheEnabled(useCache); textLayout[i]->beginLayout(); while (1) { QTextLine line = textLayout[i]->createLine(); if (!line.isValid()) break; line.setLineWidth(lineWidth); height += leading; line.setPosition(QPointF(0, height)); height += line.height(); widthUsed = qMax(widthUsed, line.naturalTextWidth()); } textLayout[i]->endLayout(); } first = false; } for (int i = 0; i < count; ++i) { for (int j = 0; j < lines; ++j) { textLayout[j]->draw(&p, QPoint(0, j*spacing)); } } }
QSize QDeclarativeTextPrivate::setupTextLayout(QTextLayout *layout) { Q_Q(QDeclarativeText); layout->setCacheEnabled(true); int height = 0; qreal widthUsed = 0; qreal lineWidth = 0; //set manual width if ((wrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) lineWidth = q->width(); layout->beginLayout(); while (1) { QTextLine line = layout->createLine(); if (!line.isValid()) break; if ((wrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) line.setLineWidth(lineWidth); } layout->endLayout(); int x = 0; for (int i = 0; i < layout->lineCount(); ++i) { QTextLine line = layout->lineAt(i); widthUsed = qMax(widthUsed, line.naturalTextWidth()); line.setPosition(QPointF(0, height)); height += int(line.height()); if (!cache) { if (hAlign == QDeclarativeText::AlignLeft) { x = 0; } else if (hAlign == QDeclarativeText::AlignRight) { x = q->width() - (int)line.naturalTextWidth(); } else if (hAlign == QDeclarativeText::AlignHCenter) { x = (q->width() - (int)line.naturalTextWidth()) / 2; } line.setPosition(QPoint(x, (int)line.y())); } } return QSize(qCeil(widthUsed), height); }
qreal TextDocumentLayout::blockWidth(const QTextBlock &block) { QTextLayout *layout = block.layout(); if (!layout->lineCount()) return 0; // only for layouted blocks qreal blockWidth = 0; for (int i = 0; i < layout->lineCount(); ++i) { QTextLine line = layout->lineAt(i); blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth); } return blockWidth; }
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const { if (!run.length()) return 0; const QString string = fixSpacing(qstring(run)); QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); int w = int(line.naturalTextWidth()); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) if (treatAsSpace(run[0])) w -= m_wordSpacing; return w + run.padding(); }
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) { int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; if (style.padding()) flags |= Qt::TextJustificationForced; layout->setFlags(flags); layout->beginLayout(); QTextLine line = layout->createLine(); line.setLineWidth(INT_MAX/256); if (style.padding()) line.setLineWidth(line.naturalTextWidth() + style.padding()); layout->endLayout(); return line; }
// Origin: Qt static void viewItemTextLayout ( QTextLayout &textLayout, int lineWidth, qreal &height, qreal &widthUsed ) { height = 0; widthUsed = 0; textLayout.beginLayout(); while ( true ) { QTextLine line = textLayout.createLine(); if ( !line.isValid() ) break; line.setLineWidth ( lineWidth ); line.setPosition ( QPointF ( 0, height ) ); height += line.height(); widthUsed = qMax ( widthUsed, line.naturalTextWidth() ); } textLayout.endLayout(); }
// copied from QItemDelegate for drawDisplay QSizeF doTextLayout(QTextLayout *textLayout, int lineWidth) { qreal height = 0; qreal widthUsed = 0; textLayout->beginLayout(); while (true) { QTextLine line = textLayout->createLine(); if (!line.isValid()) break; line.setLineWidth(lineWidth); line.setPosition(QPointF(0, height)); height += line.height(); widthUsed = qMax(widthUsed, line.naturalTextWidth()); } textLayout->endLayout(); return QSizeF(widthUsed, height); }
void CodeEditor::paintEvent(QPaintEvent* event) { QPlainTextEdit::paintEvent(event); QPainter painter(viewport()); painter.setPen(Qt::darkGray); QTextBlock block = firstVisibleBlock(); QRectF rect; do { if (!block.isVisible()) continue; rect = blockBoundingGeometry(block).translated(contentOffset()); QTextLine line = block.layout()->lineAt(0); if (config->whitespaces) { QString txt = block.text(); for (int i = 0; i < txt.length(); i++) { // rect.x() <- учитывая горизонтальный скролинг QPoint point(rect.x() + line.cursorToX(i), rect.y() + line.ascent()); if (txt[i] == ' ') painter.drawText(point, QChar(0x00b7)); else if (txt[i] == '\t') painter.drawText(point, QChar(0x21b9)); } } int state = block.userState(); if (!(state & Error) && state & Folded) { QRect collapseRect(rect.x() + line.rect().x() + line.naturalTextWidth() + FONTWIDTH * 2, rect.y() + 2, FONTWIDTH * 6, line.height() - 4); painter.drawText(collapseRect, Qt::AlignCenter, state & Comment ? "...;" : "...)"); painter.drawRoundedRect(collapseRect, 4, 6); } } while ((block = block.next()).isValid() && rect.y() < viewport()->height()); }
static int layoutText(QTextLayout *layout, int maxWidth) { qreal height = 0; int textWidth = 0; layout->beginLayout(); while (true) { QTextLine line = layout->createLine(); if (!line.isValid()) { break; } line.setLineWidth(maxWidth); line.setPosition(QPointF(0, height)); height += line.height(); textWidth = qMax(textWidth, qRound(line.naturalTextWidth() + 0.5)); } layout->endLayout(); return textWidth; }
QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const { qreal height = 0; qreal widthUsed = 0; textLayout.beginLayout(); while (true) { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(lineWidth); line.setPosition(QPointF(0, height)); height += line.height(); widthUsed = qMax(widthUsed, line.naturalTextWidth()); } textLayout.endLayout(); return QSizeF(widthUsed, height); }
void CodeEditor::mouseMoveEvent(QMouseEvent* event) { QTextBlock block = findBlockByY(event->pos().y()); QRect collapseRect; if (block.isValid()) { QRectF rect = blockBoundingGeometry(block).translated(contentOffset()); QTextLine line = block.layout()->lineAt(0); collapseRect = QRect(rect.x() + line.rect().x() + line.naturalTextWidth() + FONTWIDTH * 2, rect.y() + 2, FONTWIDTH * 6, line.height() - 4); } int state = block.userState(); if (!(state & Error) && state & Folded && collapseRect.contains(event->pos())) { pointedBlock = block; viewport()->setCursor(Qt::PointingHandCursor); QString str; while ((block = block.next()).isValid() && !block.isVisible()) { if (str.count() > 1) str += "\n"; if (block.blockNumber() - pointedBlock.blockNumber() > 50) { str += "..."; // "\n..."; break; } str += block.text(); } QToolTip::showText(event->globalPos(), str, this); } else { pointedBlock = QTextBlock(); viewport()->setCursor(Qt::IBeamCursor); } QPlainTextEdit::mouseMoveEvent(event); }
qreal QmlConsoleItemDelegate::layoutText(QTextLayout &tl, int width, bool *showFileLineInfo) const { qreal height = 0; tl.beginLayout(); while (true) { QTextLine line = tl.createLine(); if (!line.isValid()) break; line.setLeadingIncluded(true); line.setLineWidth(width); if (width < line.naturalTextWidth() && showFileLineInfo) *showFileLineInfo = false; line.setPosition(QPoint(0, height)); height += line.height(); } tl.endLayout(); return height; }
void ElidedLabel::paintEvent( QPaintEvent* event ) { QFrame::paintEvent( event ); QPainter p( this ); QRect r = contentsRect(); r.adjust( m_margin, m_margin, -m_margin, -m_margin ); if ( m_multiLine ) { QTextLayout textLayout( m_text ); textLayout.setFont( p.font() ); int widthUsed = 0; int lineCount = 0; int lineLimit = r.height() / fontMetrics().height(); textLayout.beginLayout(); while ( ++lineCount < lineLimit ) { QTextLine line = textLayout.createLine(); if ( !line.isValid() ) break; line.setLineWidth( r.width() ); widthUsed += line.naturalTextWidth(); } textLayout.endLayout(); widthUsed += r.width(); const QString elidedText = fontMetrics().elidedText( m_text, Qt::ElideRight, widthUsed ); p.drawText( r, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, elidedText ); } else { const QString elidedText = fontMetrics().elidedText( m_text, m_mode, r.width() ); p.drawText( r, m_align, elidedText ); } }
void FadingMultilineLabel::positionLayouts() { QFontMetricsF fm = fontMetrics(); qreal lineHeight = fm.height(); delete textLayout_; textLayout_ = 0; textLayout_ = new QTextLayout(text_, font()); textLayout_->setTextOption(textOption_); // textLayout_->setAdditionalFormats(formats[p]); textLayout_->beginLayout(); qreal x = 0.0; qreal y = 0.0; qreal ymax = 0.0; fadeOuts_.clear(); QTextLine line = textLayout_->createLine(); while (line.isValid()) { line.setPosition(QPointF(x, y)); line.setLineWidth(width()); if (line.naturalTextWidth() > width()) { fadeOuts_ << QRect(x, y, width(), lineHeight); } y += line.height(); line = textLayout_->createLine(); } textLayout_->endLayout(); sizeHint_ = QSize(width(), y); updateGeometry(); }
void Msg::ShowMsg(const QString str) { mUpdateRect = boundingRect(); mLay->setText(str); int leading = -3; qreal h = 0; qreal maxw = 0; qreal maxh = 0; mLay->beginLayout(); while (1) { QTextLine line = mLay->createLine(); if (!line.isValid()) { break; } line.setLineWidth(280); h += leading; line.setPosition(QPointF(0, h)); h += line.height(); maxw = qMax(maxw, line.naturalTextWidth()); } mLay->endLayout(); float ypos = 4 + (70 - mLay->boundingRect().height()) / 2; maxw = qMax(mUpdateRect.width(), mLay->boundingRect().width()); maxh = qMax(mUpdateRect.height(), mLay->boundingRect().height() + ypos); mUpdateRect = QRectF(0, 0, maxw, maxh + ypos); update(boundingRect()); }
int main(int argc, char* argv[]) { #if defined(_MSC_VER) && defined(_DEBUG) // Enable leak detection for MSVC debug builds. { // Check for a debugger and prompt if one is not attached. while (!IsDebuggerPresent() && IDYES == MessageBox(0, "You are starting debug mudlet without a debugger attached. If you wish to attach one and verify that it worked, click yes. To continue without a debugger, click no.", "Mudlet Debug", MB_ICONINFORMATION | MB_YESNO | MB_DEFBUTTON2)) ; // _CRTDBG_ALLOC_MEM_DF: Enable heap debugging. // _CRTDBG_LEAK_CHECK_DF: Check for leaks at program exit. _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // Create a log file for writing leaks. HANDLE hLogFile = CreateFile("stderr.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, hLogFile); // Set this to break on the allocation number shown in the debug output above. // _crtBreakAlloc = 0; pcre_malloc = pcre_malloc_dbg; pcre_free = pcre_free_dbg; pcre_stack_malloc = pcre_malloc_dbg; pcre_stack_free = pcre_free_dbg; } #endif // _MSC_VER && _DEBUG spDebugConsole = 0; unsigned int startupAction = 0; Q_INIT_RESOURCE(mudlet_alpha); QScopedPointer<QCoreApplication> initApp(createApplication(argc, argv, startupAction)); QApplication* app = qobject_cast<QApplication*>(initApp.data()); // Non-GUI actions --help and --version as suggested by GNU coding standards, // section 4.7: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces if (app == 0) { if (startupAction & 2) { // Do "version" action - wording and format is quite tightly specified by the coding standards std::cout << APP_TARGET << " " << APP_VERSION << APP_BUILD << std::endl; std::cout << "Qt libraries " << QT_VERSION_STR << "(compilation) " << qVersion() << "(runtime)" << std::endl; std::cout << "Copyright (C) 2008-" << std::string(__DATE__).substr(7, 4) << " Mudlet devs." << std::endl; std::cout << "Licence GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>" << std::endl; std::cout << "This is free software: you are free to change and redistribute it." << std::endl; std::cout << "There is NO WARRANTY, to the extent permitted by law." << std::endl; } if (startupAction & 1) { // Do "help" action - std::cout << "Usage: " << std::string(APP_TARGET) << "[OPTION...]" << std::endl; #if defined(Q_OS_WIN32) std::cout << " /h, /help displays this message." << std::endl; std::cout << " /v, /version displays version information." << std::endl; std::cout << " /q, /quiet no splash screen on startup." << std::endl; #define OPT_PREFIX '/' #else std::cout << " -h, --help displays this message." << std::endl; std::cout << " -v, --version displays version information." << std::endl; std::cout << " -q, --quiet no splash screen on startup." << std::endl; #define OPT_PREFIX '-' #endif std::cout << "There are other inherited options that arise from the Qt Libraries which" << std::endl; std::cout << "are not likely to be useful for normal use of this application:" << std::endl; // From documentation and from http://qt-project.org/doc/qt-5/qapplication.html: std::cout << " " << OPT_PREFIX << "dograb ignore any implicit or explicit -nograb." << std::endl; std::cout << " " << OPT_PREFIX << "dograb wins over " << OPT_PREFIX << "nograb even when" << std::endl; std::cout << " " << OPT_PREFIX << "nograb is last on the command line." << std::endl; std::cout << " " << OPT_PREFIX << "nograb the application should never grab the mouse or the" << std::endl; #if defined(Q_OS_LINUX) std::cout << " keyboard. This option is set by default when Mudlet is" << std::endl; std::cout << " running in the gdb debugger under Linux." << std::endl; #else std::cout << " keyboard." << std::endl; #endif std::cout << " " << OPT_PREFIX << "reverse sets the application's layout direction to" << std::endl; std::cout << " right to left." << std::endl; std::cout << " " << OPT_PREFIX << "style= style sets the application GUI style. Possible values depend" << std::endl; std::cout << " on your system configuration. If Qt was compiled with" << std::endl; std::cout << " additional styles or has additional styles as plugins" << std::endl; std::cout << " these will be available to the -style command line" << std::endl; std::cout << " option. You can also set the style for all Qt" << std::endl; std::cout << " applications by setting the QT_STYLE_OVERRIDE environment" << std::endl; std::cout << " variable." << std::endl; std::cout << " " << OPT_PREFIX << "style style is the same as listed above." << std::endl; std::cout << " " << OPT_PREFIX << "stylesheet= stylesheet" << std::endl; std::cout << " sets the application styleSheet." << std::endl; std::cout << " The value must be a path to a file that contains the" << std::endl; std::cout << " Style Sheet. Note: Relative URLs in the Style Sheet" << std::endl; std::cout << " file are relative to the Style Sheet file's path." << std::endl; std::cout << " " << OPT_PREFIX << "stylesheet stylesheet" << std::endl; std::cout << " is the same as listed above." << std::endl; #if defined(Q_OS_UNIX) std::cout << " " << OPT_PREFIX << "sync runs Mudlet in X synchronous mode. Synchronous mode" << std::endl; std::cout << " forces the X server to perform each X client request" << std::endl; std::cout << " immediately and not use buffer optimization. It makes" << std::endl; std::cout << " the program easier to debug and often much slower. The" << std::endl; std::cout << " -sync option is only valid for the X11 version of Qt." << std::endl; #endif std::cout << " " << OPT_PREFIX << "widgetcount prints debug message at the end about number of widgets" << std::endl; std::cout << " left undestroyed and maximum number of widgets existing" << std::endl; std::cout << " at the same time." << std::endl; std::cout << " " << OPT_PREFIX << "qmljsdebugger=1234[,block]" << std::endl; std::cout << " activates the QML/JS debugger with a specified port." << std::endl; std::cout << " The number is the port value and block is optional" << std::endl; std::cout << " and will make the application wait until a debugger" << std::endl; std::cout << " connects to it." << std::endl; std::cout << std::endl; std::cout << "Report bugs to: <https://github.com/Mudlet/Mudlet/issues>" << std::endl; std::cout << "pkg home page: <http://www.mudlet.org/>" << std::endl; } return 0; } // Turn the cursor into the waiting one during startup, so something shows // activity even if the quiet, no splashscreen startup has been used app->setOverrideCursor(QCursor(Qt::WaitCursor)); app->setOrganizationName("Mudlet"); app->setApplicationName("Mudlet"); app->setApplicationVersion(APP_VERSION); bool show_splash = !(startupAction & 4); // Not --quiet. QImage splashImage(":/Mudlet_splashscreen_main.png"); if (show_splash) { QPainter painter(&splashImage); unsigned fontSize = 16; QString sourceVersionText = QString("Version: " APP_VERSION APP_BUILD); bool isWithinSpace = false; while (!isWithinSpace) { QFont font("DejaVu Serif", fontSize, QFont::Bold | QFont::Serif | QFont::PreferMatch | QFont::PreferAntialias); QTextLayout versionTextLayout(sourceVersionText, font, painter.device()); versionTextLayout.beginLayout(); // Start work in this text item QTextLine versionTextline = versionTextLayout.createLine(); // First draw (one line from) the text we have put in on the layout to // see how wide it is..., assuming accutally that it will only take one // line of text versionTextline.setLineWidth(280); //Splashscreen bitmap is (now) 320x360 - hopefully entire line will all fit into 280 versionTextline.setPosition(QPointF(0, 0)); // Only pretend, so we can see how much space it will take QTextLine dummy = versionTextLayout.createLine(); if (!dummy.isValid()) { // No second line so have got all text in first so can do it isWithinSpace = true; qreal versionTextWidth = versionTextline.naturalTextWidth(); // This is the ACTUAL width of the created text versionTextline.setPosition(QPointF((320 - versionTextWidth) / 2.0, 270)); // And now we can place it centred horizontally versionTextLayout.endLayout(); // end the layout process and paint it out painter.setPen(QColor(176, 64, 0, 255)); // #b04000 versionTextLayout.draw(&painter, QPointF(0, 0)); } else { // Too big - text has spilled over onto a second line - so try again fontSize--; versionTextLayout.clearLayout(); versionTextLayout.endLayout(); } } // Repeat for other text, but we know it will fit at given size QString sourceCopyrightText = QChar(169) % QString(" Mudlet makers 2008-") % QString(__DATE__).mid(7); QFont font("DejaVu Serif", 16, QFont::Bold | QFont::Serif | QFont::PreferMatch | QFont::PreferAntialias); QTextLayout copyrightTextLayout(sourceCopyrightText, font, painter.device()); copyrightTextLayout.beginLayout(); QTextLine copyrightTextline = copyrightTextLayout.createLine(); copyrightTextline.setLineWidth(280); copyrightTextline.setPosition(QPointF(1, 1)); qreal copyrightTextWidth = copyrightTextline.naturalTextWidth(); copyrightTextline.setPosition(QPointF((320 - copyrightTextWidth) / 2.0, 340)); copyrightTextLayout.endLayout(); painter.setPen(QColor(112, 16, 0, 255)); // #701000 copyrightTextLayout.draw(&painter, QPointF(0, 0)); } QPixmap pixmap = QPixmap::fromImage(splashImage); QSplashScreen splash(pixmap); if (show_splash) { splash.show(); } app->processEvents(); QString splash_message; if (show_splash) { splash_message.append("\n\nMudlet comes with\n" "ABSOLUTELY NO WARRANTY!\n" "This is free software, and you are\n" "welcome to redistribute it under\n" "certain conditions; select the\n" "'About' item for details.\n\n"); splash_message.append("Locating profiles... "); splash.showMessage(splash_message, Qt::AlignHCenter | Qt::AlignTop); app->processEvents(); } QString directory = QDir::homePath() + "/.config/mudlet"; QDir dir; if (!dir.exists(directory)) { dir.mkpath(directory); } if (show_splash) { splash_message.append("Done.\n\nLoading font files... "); splash.showMessage(splash_message, Qt::AlignHCenter | Qt::AlignTop); app->processEvents(); } if (!QFile::exists(directory + "/COPYRIGHT.TXT")) { QFile file_f1(":/fonts/ttf-bitstream-vera-1.10/COPYRIGHT.TXT"); file_f1.copy(directory + "/COPYRIGHT.TXT"); } if (!QFile::exists(directory + "/RELEASENOTES.TXT")) { QFile file_f2(":/fonts/ttf-bitstream-vera-1.10/RELEASENOTES.TXT"); file_f2.copy(directory + "/RELEASENOTES.TXT"); } if (!QFile::exists(directory + "/VeraMoIt.ttf")) { QFile file_f3(":/fonts/ttf-bitstream-vera-1.10/VeraMoIt.ttf"); file_f3.copy(directory + "/VeraMoIt.ttf"); } if (!QFile::exists(directory + "/local.conf")) { QFile file_f4(":/fonts/ttf-bitstream-vera-1.10/local.conf"); file_f4.copy(directory + "/local.conf"); } if (!QFile::exists(directory + "/VeraMoBd.ttf")) { QFile file_f5(":/fonts/ttf-bitstream-vera-1.10/VeraMoBd.ttf"); file_f5.copy(directory + "/VeraMoBd.ttf"); } if (!QFile::exists(directory + "/VeraMoBd.ttf")) { QFile file_f6(":/fonts/ttf-bitstream-vera-1.10/VeraMoBd.ttf"); file_f6.copy(directory + "/VeraMoBd.ttf"); } if (!QFile::exists(directory + "/README.TXT")) { QFile file_f7(":/fonts/ttf-bitstream-vera-1.10/README.TXT"); file_f7.copy(directory + "/README.TXT"); } if (!QFile::exists(directory + "/VeraMoBI.ttf")) { QFile file_f8(":/fonts/ttf-bitstream-vera-1.10/VeraMoBI.ttf"); file_f8.copy(directory + "/VeraMoBI.ttf"); } if (!QFile::exists(directory + "/VeraMono.ttf")) { QFile file_f9(":/fonts/ttf-bitstream-vera-1.10/VeraMono.ttf"); file_f9.copy(directory + "/VeraMono.ttf"); } if (show_splash) { splash_message.append("Done.\n\n" "All data has been loaded successfully.\n\n" "Starting... Have fun!\n\n"); splash.showMessage(splash_message, Qt::AlignHCenter | Qt::AlignTop); app->processEvents(); } mudlet::debugMode = false; FontManager fm; fm.addFonts(); QString home = QDir::homePath() + "/.config/mudlet"; QString homeLink = QDir::homePath() + "/mudlet-data"; QFile::link(home, homeLink); mudlet::start(); mudlet::self()->show(); if (show_splash) { splash.finish(mudlet::self()); } app->restoreOverrideCursor(); // NOTE: Must restore cursor - BEWARE DEBUGGERS if you terminate application // without doing/reaching this restore - it can be quite hard to accurately // click something in a parent process to the application when you are stuck // with some OS's choice of wait cursor - you might wish to temparily disable // the earlier setOverrideCursor() line and this one. return app->exec(); }
ReportItem::PrintResult ReportItemPara::printMetaPaintChildren(ReportItemMetaPaint *out, const ReportItem::Rect &bounding_rect) { qfLogFuncFrame() << this << bounding_rect.toString(); PrintResult res = PR_PrintedOk; if(m_indexToPrint == 0) { printedText = paraText(); } //qfInfo() << printedText; QString text = printedText.mid(m_indexToPrint); int initial_index_to_print = m_indexToPrint; QString sql_id = sqlId(); /// tiskne se prazdny text bool omit_empty_text = isOmitEmptyText(); if(text.isEmpty() && omit_empty_text) { } else { QString text_to_layout = text; //qfWarning() << "length: " << text.length() << " text: [" << text << "]\n" << text.toUtf8().toHex(); bool text_item_should_be_created = true; style::CompiledTextStyle style; style::Text *p_text_style = effectiveTextStyle(); if(p_text_style) { style = p_text_style->textStyle(); } QFontMetricsF font_metrics = processor()->fontMetrics(style.font()); QTextOption text_option; { if(isTextWrap()) text_option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); //alignment_flags |= Qt::TextWordWrap; int al = textHAlign() | textVAlign(); Qt::Alignment alignment_flags = (Qt::Alignment)al; text_option.setAlignment(alignment_flags); } Rect rendered_bounding_rect; /// velikost boundingRect je v mm, tak to prepocitej na body vystupniho zarizeni rendered_bounding_rect = qmlwidgets::graphics::mm2device(bounding_rect, processor()->paintDevice()); bool render_check_mark = false; QRegExp rx = ReportItemMetaPaint::checkReportSubstitutionRegExp; if(rx.exactMatch(text_to_layout)) { //bool check_on = rx.capturedTexts().value(1) == "1"; rendered_bounding_rect = font_metrics.boundingRect('X'); render_check_mark = true; m_indexToPrint += text_to_layout.length(); } else { if(text_to_layout.isEmpty()) { /// neni omitEmptyString, takze i prazdnej text vyrendruj alespon jako mezeru aby se na to dalo treba kliknout text_to_layout = ' '; } //text.replace(ReportItemMetaPaint::checkOnReportSubstitution, "X"); //text.replace(ReportItemMetaPaint::checkOffReportSubstitution, "X"); //qfInfo().noSpace().color(QFLog::Green) << "index to print: " << indexToPrint << " text: '" << text << "'"; //qfInfo() << "bounding rect:" << bounding_rect.toString(); //qfWarning() << "device physical DPI:" << processor()->paintDevice()->physicalDpiX() << processor()->paintDevice()->physicalDpiY(); //qfWarning().noSpace() << "'" << text << "' font metrics: " << br.toString(); //QString text = element.text().simplified().replace("\\n", "\n"); //qfInfo() << "br:" << br.toString(); //Rect br_debug = br; //bool splitted = false; /// do layout { qreal leading = font_metrics.leading(); qreal height = 0; qreal width = 0; textLayout.setFont(style.font()); textLayout.setTextOption(text_option); textLayout.setText(text_to_layout); textLayout.beginLayout(); bool finished = false; while (!finished) { QTextLine line = textLayout.createLine(); finished = !line.isValid(); if(!finished) { line.setLineWidth(rendered_bounding_rect.width()); /// setWidth() nastavi spravne line.height(), proto musi byt pred merenim popsane vysky. if((line.textLength() == 0) && (line.textStart() + line.textLength() == text_to_layout.length())) { /// nevim kde je chyba, pri vicerakovych textech mi to pridava jeden prazdnej radek na konec, takhle se tomu snazim zabranit (Qt 4.6.3) finished = true; } else { qreal interline_space = (height > 0)? leading: 0; if(height + interline_space + line.height() > rendered_bounding_rect.height()) { res = PR_PrintAgainOnNextPage; if(height == 0) { /// nevejde se ani jeden radek text_item_should_be_created = false; break; } else { /// neco se preci jenom veslo int pos = line.textStart(); m_indexToPrint += pos; break; } } height += interline_space; line.setPosition(QPointF(0., height)); height += line.height(); width = qMax(width, line.naturalTextWidth()); } } if(finished) { m_indexToPrint = printedText.length(); } } textLayout.endLayout(); rendered_bounding_rect.setWidth(width); rendered_bounding_rect.setHeight(height); } } /// velikost boundingRect je v bodech vystupniho zarizeni, tak to prepocitej na mm rendered_bounding_rect = qmlwidgets::graphics::device2mm(rendered_bounding_rect, processor()->paintDevice()); /// rendered rect is left aligned, if text is reight aligned or centered, the ReportItemMetaPaintText::paint() does it if(text_item_should_be_created ) { ReportItemMetaPaintText *mt; if(render_check_mark ) mt = new ReportItemMetaPaintCheck(out, this); else { mt = new ReportItemMetaPaintText(out, this); mt->sqlId = sql_id; //--mt->editGrants = elementAttribute("editGrants"); } //qfInfo() << "creating item:" << mt; mt->pen = style.pen(); mt->font = style.font(); mt->text = text.mid(0, m_indexToPrint - initial_index_to_print); //qfWarning() << "text:" << text; mt->textOption = text_option; mt->renderedRect = rendered_bounding_rect; mt->renderedRect.flags = designedRect.flags; } //qfDebug().color(QFLog::Green, QFLog::Red) << "\tleading:" << processor()->fontMetrics(style.font).leading() << "\theight:" << processor()->fontMetrics(style.font).height(); qfDebug() << "\tchild rendered rect:" << rendered_bounding_rect.toString(); } qfDebug() << "\t<<< CHILDREN paraText return:" << res.toString(); return res; }
void QSvgText::draw(QPainter *p, QSvgExtraStates &states) { applyStyle(p, states); qreal oldOpacity = p->opacity(); p->setOpacity(oldOpacity * states.fillOpacity); // Force the font to have a size of 100 pixels to avoid truncation problems // when the font is very small. qreal scale = 100.0 / p->font().pointSizeF(); Qt::Alignment alignment = states.textAnchor; QTransform oldTransform = p->worldTransform(); p->scale(1 / scale, 1 / scale); qreal y = 0; bool initial = true; qreal px = m_coord.x() * scale; qreal py = m_coord.y() * scale; QSizeF scaledSize = m_size * scale; if (m_type == TEXTAREA) { if (alignment == Qt::AlignHCenter) px += scaledSize.width() / 2; else if (alignment == Qt::AlignRight) px += scaledSize.width(); } QRectF bounds; if (m_size.height() != 0) bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used. bool appendSpace = false; QVector<QString> paragraphs; QStack<QTextCharFormat> formats; QVector<QList<QTextLayout::FormatRange> > formatRanges; paragraphs.push_back(QString()); formatRanges.push_back(QList<QTextLayout::FormatRange>()); for (int i = 0; i < m_tspans.size(); ++i) { if (m_tspans[i] == LINEBREAK) { if (m_type == TEXTAREA) { if (paragraphs.back().isEmpty()) { QFont font = p->font(); font.setPixelSize(font.pointSizeF() * scale); QTextLayout::FormatRange range; range.start = 0; range.length = 1; range.format.setFont(font); formatRanges.back().append(range); paragraphs.back().append(QLatin1Char(' '));; } appendSpace = false; paragraphs.push_back(QString()); formatRanges.push_back(QList<QTextLayout::FormatRange>()); } } else { WhitespaceMode mode = m_tspans[i]->whitespaceMode(); m_tspans[i]->applyStyle(p, states); QFont font = p->font(); font.setPixelSize(font.pointSizeF() * scale); QString newText(m_tspans[i]->text()); newText.replace(QLatin1Char('\t'), QLatin1Char(' ')); newText.replace(QLatin1Char('\n'), QLatin1Char(' ')); bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' ')); if (appendSpace || prependSpace) paragraphs.back().append(QLatin1Char(' ')); bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' '))); if (mode == Default) { newText = newText.simplified(); if (newText.isEmpty()) appendSpaceNext = false; } QTextLayout::FormatRange range; range.start = paragraphs.back().length(); range.length = newText.length(); range.format.setFont(font); range.format.setTextOutline(p->pen()); range.format.setForeground(p->brush()); if (appendSpace) { Q_ASSERT(!formatRanges.back().isEmpty()); ++formatRanges.back().back().length; } else if (prependSpace) { --range.start; ++range.length; } formatRanges.back().append(range); appendSpace = appendSpaceNext; paragraphs.back() += newText; m_tspans[i]->revertStyle(p, states); } } if (states.svgFont) { // SVG fonts not fully supported... QString text = paragraphs.front(); for (int i = 1; i < paragraphs.size(); ++i) { text.append(QLatin1Char('\n')); text.append(paragraphs[i]); } states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor); } else { for (int i = 0; i < paragraphs.size(); ++i) { QTextLayout tl(paragraphs[i]); QTextOption op = tl.textOption(); op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); tl.setTextOption(op); tl.setAdditionalFormats(formatRanges[i]); tl.beginLayout(); forever { QTextLine line = tl.createLine(); if (!line.isValid()) break; if (m_size.width() != 0) line.setLineWidth(scaledSize.width()); } tl.endLayout(); bool endOfBoundsReached = false; for (int i = 0; i < tl.lineCount(); ++i) { QTextLine line = tl.lineAt(i); qreal x = 0; if (alignment == Qt::AlignHCenter) x -= 0.5 * line.naturalTextWidth(); else if (alignment == Qt::AlignRight) x -= line.naturalTextWidth(); if (initial && m_type == TEXT) y -= line.ascent(); initial = false; line.setPosition(QPointF(x, y)); // Check if the current line fits into the bounding rectangle. if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width()) || (m_size.height() != 0 && y + line.height() > scaledSize.height())) { // I need to set the bounds height to 'y-epsilon' to avoid drawing the current // line. Since the font is scaled to 100 units, 1 should be a safe epsilon. bounds.setHeight(y - 1); endOfBoundsReached = true; break; } y += 1.1 * line.height(); } tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds); if (endOfBoundsReached) break; } } p->setWorldTransform(oldTransform, false); p->setOpacity(oldOpacity); revertStyle(p, states); }
// FIXME: we need to figure out a way to derive from Fm::FolderItemDelegate to avoid code duplication. void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_ASSERT(index.isValid()); QStyleOptionViewItemV4 opt = option; initStyleOption(&opt, index); painter->save(); painter->setClipRect(option.rect); opt.decorationAlignment = Qt::AlignHCenter | Qt::AlignTop; opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; // draw the icon QIcon::Mode iconMode; if(opt.state & QStyle::State_Enabled) { if(opt.state & QStyle::State_Selected) iconMode = QIcon::Selected; else { iconMode = QIcon::Normal; } } else iconMode = QIcon::Disabled; QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y()); QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode); painter->drawPixmap(iconPos, pixmap); // draw some emblems for the item if needed // we only support symlink emblem at the moment FmFileInfo* file = static_cast<FmFileInfo*>(index.data(Fm::FolderModel::FileInfoRole).value<void*>()); if(file) { if(fm_file_info_is_symlink(file)) { painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode)); } } // draw text QRectF textRect(opt.rect.x(), opt.rect.y() + opt.decorationSize.height(), opt.rect.width(), opt.rect.height() - opt.decorationSize.height()); QTextLayout layout(opt.text, opt.font); QTextOption textOption; textOption.setAlignment(opt.displayAlignment); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); textOption.setTextDirection(opt.direction); layout.setTextOption(textOption); qreal height = 0; qreal width = 0; int visibleLines = 0; layout.beginLayout(); QString elidedText; for(;;) { QTextLine line = layout.createLine(); if(!line.isValid()) break; line.setLineWidth(textRect.width()); height += opt.fontMetrics.leading(); line.setPosition(QPointF(0, height)); if((height + line.height() + textRect.y()) > textRect.bottom()) { // if part of this line falls outside the textRect, ignore it and quit. QTextLine lastLine = layout.lineAt(visibleLines - 1); elidedText = opt.text.mid(lastLine.textStart()); elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); break; } height += line.height(); width = qMax(width, line.naturalTextWidth()); ++ visibleLines; } layout.endLayout(); QRectF boundRect = layout.boundingRect(); boundRect.setWidth(width); boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); if((opt.state & QStyle::State_Selected) && opt.widget) { QPalette palette = opt.widget->palette(); // qDebug("w: %f, h:%f, m:%f", boundRect.width(), boundRect.height(), layout.minimumWidth()); painter->fillRect(boundRect, palette.highlight()); } else { // only draw shadow for non-selected items // draw shadow, FIXME: is it possible to use QGraphicsDropShadowEffect here? QPen prevPen = painter->pen(); painter->setPen(QPen(shadowColor_)); for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x() + 1, textRect.y() + line.y() + line.ascent() + 1); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft() + QPointF(1, 1)); } } painter->setPen(prevPen); } // draw text for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft()); } } if(opt.state & QStyle::State_HasFocus) { // FIXME: draw focus rect } painter->restore(); }
void QSvgText::draw(QPainter *p, QSvgExtraStates &states) { applyStyle(p, states); QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>( styleProperty(QSvgStyleProperty::FONT)); if (fontStyle && fontStyle->svgFont()) { // SVG fonts not fully supported... QString text = m_paragraphs.front(); for (int i = 1; i < m_paragraphs.size(); ++i) { text.append(QLatin1Char('\n')); text.append(m_paragraphs[i]); } fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment); revertStyle(p, states); return; } // Scale the font to its correct size. QTransform oldTransform = p->worldTransform(); p->scale(1 / m_scale, 1 / m_scale); qreal y = 0; bool initial = true; qreal px = m_coord.x() * m_scale; qreal py = m_coord.y() * m_scale; QSizeF scaledSize = m_size * m_scale; if (m_type == TEXTAREA) { if (m_textAlignment == Qt::AlignHCenter) px += scaledSize.width() / 2; else if (m_textAlignment == Qt::AlignRight) px += scaledSize.width(); } QRectF bounds; if (m_size.height() != 0) bounds = QRectF(0, 0, 1, scaledSize.height()); for (int i = 0; i < m_paragraphs.size(); ++i) { QTextLayout tl(m_paragraphs[i]); QTextOption op = tl.textOption(); op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); tl.setTextOption(op); tl.setAdditionalFormats(m_formatRanges[i]); tl.beginLayout(); forever { QTextLine line = tl.createLine(); if (!line.isValid()) break; if (m_size.width() != 0) line.setLineWidth(scaledSize.width()); } tl.endLayout(); bool endOfBoundsReached = false; for (int i = 0; i < tl.lineCount(); ++i) { QTextLine line = tl.lineAt(i); qreal x = 0; if (m_textAlignment == Qt::AlignHCenter) x -= line.naturalTextWidth() / 2; else if (m_textAlignment == Qt::AlignRight) x -= line.naturalTextWidth(); if (initial && m_type == TEXT) y -= line.ascent(); initial = false; line.setPosition(QPointF(x, y)); if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width()) || (m_size.height() != 0 && y + line.height() > scaledSize.height())) { bounds.setHeight(y); endOfBoundsReached = true; break; } y += 1.1 * line.height(); } tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds); if (endOfBoundsReached) break; } p->setWorldTransform(oldTransform, false); revertStyle(p, states); }
void KStandardItemListWidget::updateIconsLayoutTextCache() { // +------+ // | Icon | // +------+ // // Name role that // might get wrapped above // several lines. // Additional role 1 // Additional role 2 const QHash<QByteArray, QVariant> values = data(); const KItemListStyleOption& option = styleOption(); const qreal padding = option.padding; const qreal maxWidth = size().width() - 2 * padding; const qreal widgetHeight = size().height(); const qreal lineSpacing = m_customizedFontMetrics.lineSpacing(); // Initialize properties for the "text" role. It will be used as anchor // for initializing the position of the other roles. TextInfo* nameTextInfo = m_textInfo.value("text"); const QString nameText = KStringHandler::preProcessWrap(values["text"].toString()); nameTextInfo->staticText.setText(nameText); // Calculate the number of lines required for the name and the required width qreal nameWidth = 0; qreal nameHeight = 0; QTextLine line; const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount; QTextLayout layout(nameTextInfo->staticText.text(), m_customizedFont); layout.setTextOption(nameTextInfo->staticText.textOption()); layout.beginLayout(); int nameLineIndex = 0; while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); nameWidth = qMax(nameWidth, line.naturalTextWidth()); nameHeight += line.height(); ++nameLineIndex; if (nameLineIndex == maxNameLines) { // The maximum number of textlines has been reached. If this is // the case provide an elided text if necessary. const int textLength = line.textStart() + line.textLength(); if (textLength < nameText.length()) { // Elide the last line of the text QString lastTextLine = nameText.mid(line.textStart(), line.textLength()); lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine, Qt::ElideRight, line.naturalTextWidth() - 1); const QString elidedText = nameText.left(line.textStart()) + lastTextLine; nameTextInfo->staticText.setText(elidedText); } break; } } layout.endLayout(); // Use one line for each additional information nameTextInfo->staticText.setTextWidth(maxWidth); nameTextInfo->pos = QPointF(padding, widgetHeight - nameHeight - additionalRolesCount * lineSpacing - padding); m_textRect = QRectF(padding + (maxWidth - nameWidth) / 2, nameTextInfo->pos.y(), nameWidth, nameHeight); // Calculate the position for each additional information qreal y = nameTextInfo->pos.y() + nameHeight; foreach (const QByteArray& role, m_sortedVisibleRoles) { if (role == "text") { continue; } const QString text = roleText(role, values); TextInfo* textInfo = m_textInfo.value(role); textInfo->staticText.setText(text); qreal requiredWidth = 0; QTextLayout layout(text, m_customizedFont); QTextOption textOption; textOption.setWrapMode(QTextOption::NoWrap); layout.setTextOption(textOption); layout.beginLayout(); QTextLine textLine = layout.createLine(); if (textLine.isValid()) { textLine.setLineWidth(maxWidth); requiredWidth = textLine.naturalTextWidth(); if (requiredWidth > maxWidth) { const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth); textInfo->staticText.setText(elidedText); requiredWidth = m_customizedFontMetrics.width(elidedText); } else if (role == "rating") { // Use the width of the rating pixmap, because the rating text is empty. requiredWidth = m_rating.width(); } } layout.endLayout(); textInfo->pos = QPointF(padding, y); textInfo->staticText.setTextWidth(maxWidth); const QRectF textRect(padding + (maxWidth - requiredWidth) / 2, y, requiredWidth, lineSpacing); m_textRect |= textRect; y += lineSpacing; } // Add a padding to the text rectangle m_textRect.adjust(-padding, -padding, padding, padding); }
QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const { const QHash<QByteArray, QVariant> values = view->model()->data(index); const KItemListStyleOption& option = view->styleOption(); const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); switch (static_cast<const KStandardItemListView*>(view)->itemLayout()) { case KStandardItemListWidget::IconsLayout: { const QString text = KStringHandler::preProcessWrap(values["text"].toString()); const qreal itemWidth = view->itemSize().width(); const qreal maxWidth = itemWidth - 2 * option.padding; QTextLine line; // Calculate the number of lines required for wrapping the name QTextOption textOption(Qt::AlignHCenter); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); qreal textHeight = 0; QTextLayout layout(text, option.font); layout.setTextOption(textOption); layout.beginLayout(); while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); line.naturalTextWidth(); textHeight += line.height(); } layout.endLayout(); // Add one line for each additional information textHeight += additionalRolesCount * option.fontMetrics.lineSpacing(); const qreal maxTextHeight = option.maxTextSize.height(); if (maxTextHeight > 0 && textHeight > maxTextHeight) { textHeight = maxTextHeight; } return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3); } case KStandardItemListWidget::CompactLayout: { // For each row exactly one role is shown. Calculate the maximum required width that is necessary // to show all roles without horizontal clipping. qreal maximumRequiredWidth = 0.0; foreach (const QByteArray& role, view->visibleRoles()) { const QString text = roleText(role, values); const qreal requiredWidth = option.fontMetrics.width(text); maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth); } qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth; const qreal maxWidth = option.maxTextSize.width(); if (maxWidth > 0 && width > maxWidth) { width = maxWidth; } const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); return QSizeF(width, height); } case KStandardItemListWidget::DetailsLayout: { const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); return QSizeF(-1, height); } default: Q_ASSERT(false); break; } return QSize(); }
// if painter is nullptr, the method calculate the bounding rectangle of the text and save it to textRect void FolderItemDelegate::drawText(QPainter* painter, QStyleOptionViewItemV4& opt, QRectF& textRect) const { QTextLayout layout(opt.text, opt.font); QTextOption textOption; textOption.setAlignment(opt.displayAlignment); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); textOption.setTextDirection(opt.direction); layout.setTextOption(textOption); qreal height = 0; qreal width = 0; int visibleLines = 0; layout.beginLayout(); QString elidedText; for(;;) { QTextLine line = layout.createLine(); if(!line.isValid()) break; line.setLineWidth(textRect.width()); height += opt.fontMetrics.leading(); line.setPosition(QPointF(0, height)); if((height + line.height() + textRect.y()) > textRect.bottom()) { // if part of this line falls outside the textRect, ignore it and quit. QTextLine lastLine = layout.lineAt(visibleLines - 1); elidedText = opt.text.mid(lastLine.textStart()); elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width()); if(visibleLines == 1) // this is the only visible line width = textRect.width(); break; } height += line.height(); width = qMax(width, line.naturalTextWidth()); ++ visibleLines; } layout.endLayout(); // draw background for selected item QRectF boundRect = layout.boundingRect(); //qDebug() << "bound rect: " << boundRect << "width: " << width; boundRect.setWidth(width); boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y()); if(!painter) { // no painter, calculate the bounding rect only textRect = boundRect; return; } QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if(opt.state & QStyle::State_Selected) { painter->fillRect(boundRect, opt.palette.highlight()); painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); } else painter->setPen(opt.palette.color(cg, QPalette::Text)); // draw text for(int i = 0; i < visibleLines; ++i) { QTextLine line = layout.lineAt(i); if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent()); painter->drawText(pos, elidedText); } else { line.draw(painter, textRect.topLeft()); } } if(opt.state & QStyle::State_HasFocus) { // draw focus rect QStyleOptionFocusRect o; o.QStyleOption::operator=(opt); o.rect = boundRect.toRect(); // subElementRect(SE_ItemViewItemFocusRect, vopt, widget); o.state |= QStyle::State_KeyboardFocusChange; o.state |= QStyle::State_Item; QPalette::ColorGroup cg = (opt.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = opt.palette.color(cg, (opt.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Window); if (const QWidget* widget = opt.widget) { QStyle* style = widget->style() ? widget->style() : qApp->style(); style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget); } } }
void TextDocumentLayout::layoutBlock(const QTextBlock &block) { QTextDocument *doc = document(); qreal margin = doc->documentMargin(); qreal blockMaximumWidth = 0; qreal height = 0; QTextLayout *tl = block.layout(); QTextOption option = doc->defaultTextOption(); tl->setTextOption(option); int extraMargin = 0; if (option.flags() & QTextOption::AddSpaceForLineAndParagraphSeparators) { QFontMetrics fm(block.charFormat().font()); extraMargin += fm.width(QChar(0x21B5)); } tl->beginLayout(); qreal availableWidth = d->width; if (availableWidth <= 0) { availableWidth = qreal(INT_MAX); // similar to text edit with pageSize.width == 0 } availableWidth -= 2*margin + extraMargin; qreal indentMargin = 0; while (1) { QTextLine line = tl->createLine(); if (!line.isValid()) break; line.setLeadingIncluded(true); line.setLineWidth(availableWidth - indentMargin); line.setPosition(QPointF(margin + indentMargin, height)); if(!height) //enter only in the first iteration { indentMargin = indentWidth(block); } height += line.height(); blockMaximumWidth = qMax(blockMaximumWidth, line.naturalTextWidth() + 2*margin); } tl->endLayout(); int previousLineCount = doc->lineCount(); const_cast<QTextBlock&>(block).setLineCount(block.isVisible() ? tl->lineCount() : 0); int lineCount = doc->lineCount(); bool emitDocumentSizeChanged = previousLineCount != lineCount; if (blockMaximumWidth > d->maximumWidth) { // new longest line d->maximumWidth = blockMaximumWidth; d->maximumWidthBlockNumber = block.blockNumber(); emitDocumentSizeChanged = true; } else if (block.blockNumber() == d->maximumWidthBlockNumber && blockMaximumWidth < d->maximumWidth) { // longest line shrinking QTextBlock b = doc->firstBlock(); d->maximumWidth = 0; QTextBlock maximumBlock; while (b.isValid()) { qreal blockMaximumWidth = blockWidth(b); if (blockMaximumWidth > d->maximumWidth) { d->maximumWidth = blockMaximumWidth; maximumBlock = b; } b = b.next(); } if (maximumBlock.isValid()) { d->maximumWidthBlockNumber = maximumBlock.blockNumber(); emitDocumentSizeChanged = true; } } if (emitDocumentSizeChanged)// && !d->blockDocumentSizeChanged) emit documentSizeChanged(documentSize()); emit updateBlock(block); }