void YTDelegate::layoutText(QTextLayout& textLayout, QString text, QSize constraint) const { QTextOption textOption(Qt::AlignJustify); textLayout.setTextOption(textOption); textLayout.setText(text); textLayout.beginLayout(); int lHeight = 0; while(true){ QTextLine line = textLayout.createLine(); if(!line.isValid()) break; line.setLineWidth(constraint.width()); line.setPosition(QPointF(0, lHeight)); if(lHeight + line.height() > constraint.height()) { QTextLine lastLine = textLayout.lineAt(textLayout.lineCount() - 2); QString lastString = text.mid(lastLine.textStart()); QFontMetrics fm(textLayout.font()); text.chop(lastString.length()); text += fm.elidedText(lastString, Qt::ElideRight, constraint.width()-1); textLayout.endLayout(); layoutText(textLayout, text, constraint); return; } lHeight += line.height(); lHeight += line.leading(); } textLayout.endLayout(); }
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(); }
static QSize viewItemTextSize ( const QStyleOptionViewItemV4 *option ) { QStyle *style = option->widget ? option->widget->style() : QApplication::style(); QTextOption textOption; textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere ); QTextLayout textLayout; textLayout.setTextOption ( textOption ); textLayout.setFont ( option->font ); textLayout.setText ( option->text ); const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, option, option->widget ) + 1; QRect bounds ( 0,0,100 - 2*textMargin,600 ); qreal height = 0, widthUsed = 0; viewItemTextLayout ( textLayout, bounds.width(), height, widthUsed ); const QSize size ( qCeil ( widthUsed ), qCeil ( height ) ); return QSize ( size.width() + 2 * textMargin, size.height() ); }
void tst_QRawFont::unsupportedWritingSystem() { QFETCH(QFont::HintingPreference, hintingPreference); QFontDatabase fontDatabase; int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf")); QFont font("QtBidiTestFont"); font.setHintingPreference(hintingPreference); font.setPixelSize(12.0); QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any); QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); QCOMPARE(rawFont.pixelSize(), 12.0); rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew); QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); QCOMPARE(rawFont.pixelSize(), 12.0); QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); QTextLayout layout; layout.setFont(font); layout.setText(arabicText); layout.beginLayout(); layout.createLine(); layout.endLayout(); QList<QGlyphRun> glyphRuns = layout.glyphRuns(); QCOMPARE(glyphRuns.size(), 1); QGlyphRun glyphs = glyphRuns.at(0); QRawFont layoutFont = glyphs.rawFont(); QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont")); QCOMPARE(layoutFont.pixelSize(), 12.0); rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic); QCOMPARE(rawFont.familyName(), layoutFont.familyName()); QCOMPARE(rawFont.pixelSize(), 12.0); fontDatabase.removeApplicationFont(id); }
/// Calculate single line layout for given text with specified font. /// This function automatically add ellipsis text if the naural width /// is larger than given region. /// \layout The result layout. /// \font The font object. /// \string The text needs to be layouted. /// \align Alignment. /// \rect The region. /// \ellipsis Add ellipse to left or right if necessary. /// Returns the line height. int calculateSingleLineLayout(QTextLayout & layout, const QFont & font, const QString & string, const Qt::Alignment align, const QRect & rect, const Qt::TextElideMode ellipsis) { QFontMetrics fm(font); // Check if we need to add ellipsis. QString result_string = string; int width = ellipsisText(string, fm, rect.width(), ellipsis, result_string); // Construct the layout. layout.clearLayout(); layout.setCacheEnabled(false); layout.setText(result_string); layout.setFont(font); layout.beginLayout(); QTextLine line = layout.createLine(); if (line.isValid()) { line.setLineWidth(rect.width()); } layout.endLayout(); // Calculate the position. int x = rect.left(); int y = rect.top(); int h = static_cast<int>(line.height()); if (align & Qt::AlignHCenter) { x = ((rect.width() - width) >> 1) + x; }
void QStaticTextPrivate::paintText(const QPointF &topLeftPosition, QPainter *p) { bool preferRichText = textFormat == Qt::RichText || (textFormat == Qt::AutoText && Qt::mightBeRichText(text)); if (!preferRichText) { QTextLayout textLayout; textLayout.setText(text); textLayout.setFont(font); textLayout.setTextOption(textOption); qreal leading = QFontMetricsF(font).leading(); qreal height = -leading; textLayout.beginLayout(); while (1) { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; if (textWidth >= 0.0) line.setLineWidth(textWidth); height += leading; line.setPosition(QPointF(0.0, height)); height += line.height(); } textLayout.endLayout(); actualSize = textLayout.boundingRect().size(); textLayout.draw(p, topLeftPosition); } else { QTextDocument document; #ifndef QT_NO_CSSPARSER QColor color = p->pen().color(); document.setDefaultStyleSheet(QString::fromLatin1("body { color: #%1%2%3 }") .arg(QString::number(color.red(), 16), 2, QLatin1Char('0')) .arg(QString::number(color.green(), 16), 2, QLatin1Char('0')) .arg(QString::number(color.blue(), 16), 2, QLatin1Char('0'))); #endif document.setDefaultFont(font); document.setDocumentMargin(0.0); #ifndef QT_NO_TEXTHTMLPARSER document.setHtml(text); #else document.setPlainText(text); #endif if (textWidth >= 0.0) document.setTextWidth(textWidth); else document.adjustSize(); document.setDefaultTextOption(textOption); p->save(); p->translate(topLeftPosition); QAbstractTextDocumentLayout::PaintContext ctx; ctx.palette.setColor(QPalette::Text, p->pen().color()); document.documentLayout()->draw(p, ctx); p->restore(); if (textWidth >= 0.0) document.adjustSize(); // Find optimal size actualSize = document.size(); } }
void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd) { Q_ASSERT(textDocument); #ifndef QT_NO_IM int preeditLength = block.isValid() ? block.layout()->preeditAreaText().length() : 0; int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1; #endif QVarLengthArray<QTextLayout::FormatRange> colorChanges; mergeFormats(block.layout(), &colorChanges); QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position; if (QTextList *textList = block.textList()) { QPointF pos = blockPosition; QTextLayout *layout = block.layout(); if (layout->lineCount() > 0) { QTextLine firstLine = layout->lineAt(0); Q_ASSERT(firstLine.isValid()); setCurrentLine(firstLine); QRectF textRect = firstLine.naturalTextRect(); pos += textRect.topLeft(); if (block.textDirection() == Qt::RightToLeft) pos.rx() += textRect.width(); const QTextCharFormat charFormat = block.charFormat(); QFont font(charFormat.font()); QFontMetricsF fontMetrics(font); QTextListFormat listFormat = textList->format(); QString listItemBullet; switch (listFormat.style()) { case QTextListFormat::ListCircle: listItemBullet = QChar(0x25E6); // White bullet break; case QTextListFormat::ListSquare: listItemBullet = QChar(0x25AA); // Black small square break; case QTextListFormat::ListDecimal: case QTextListFormat::ListLowerAlpha: case QTextListFormat::ListUpperAlpha: case QTextListFormat::ListLowerRoman: case QTextListFormat::ListUpperRoman: listItemBullet = textList->itemText(block); break; default: listItemBullet = QChar(0x2022); // Black bullet break; }; QSizeF size(fontMetrics.width(listItemBullet), fontMetrics.height()); qreal xoff = fontMetrics.width(QLatin1Char(' ')); if (block.textDirection() == Qt::LeftToRight) xoff = -xoff - size.width(); setPosition(pos + QPointF(xoff, 0)); QTextLayout layout; layout.setFont(font); layout.setText(listItemBullet); // Bullet layout.beginLayout(); QTextLine line = layout.createLine(); line.setPosition(QPointF(0, 0)); layout.endLayout(); QList<QGlyphRun> glyphRuns = layout.glyphRuns(); for (int i=0; i<glyphRuns.size(); ++i) addUnselectedGlyphs(glyphRuns.at(i)); } } int textPos = block.position(); QTextBlock::iterator blockIterator = block.begin(); while (!blockIterator.atEnd()) { QTextFragment fragment = blockIterator.fragment(); QString text = fragment.text(); if (text.isEmpty()) continue; QTextCharFormat charFormat = fragment.charFormat(); QFont font(charFormat.font()); QFontMetricsF fontMetrics(font); int fontHeight = fontMetrics.descent() + fontMetrics.ascent(); int valign = charFormat.verticalAlignment(); if (valign == QTextCharFormat::AlignSuperScript) setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2)); else if (valign == QTextCharFormat::AlignSubScript) setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6)); else setPosition(blockPosition); if (text.contains(QChar::ObjectReplacementCharacter)) { QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat)); if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) { int blockRelativePosition = textPos - block.position(); QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition); if (!currentLine().isValid() || line.lineNumber() != currentLine().lineNumber()) { setCurrentLine(line); } QQuickTextNodeEngine::SelectionState selectionState = (selectionStart < textPos + text.length() && selectionEnd >= textPos) ? QQuickTextNodeEngine::Selected : QQuickTextNodeEngine::Unselected; addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos); } textPos += text.length(); } else { if (charFormat.foreground().style() != Qt::NoBrush) setTextColor(charFormat.foreground().color()); else if (charFormat.isAnchor()) setTextColor(anchorColor); else setTextColor(textColor); int fragmentEnd = textPos + fragment.length(); #ifndef QT_NO_IM if (preeditPosition >= 0 && (preeditPosition + block.position()) >= textPos && (preeditPosition + block.position()) <= fragmentEnd) { fragmentEnd += preeditLength; } #endif if (charFormat.background().style() != Qt::NoBrush) { QTextLayout::FormatRange additionalFormat; additionalFormat.start = textPos - block.position(); additionalFormat.length = fragmentEnd - textPos; additionalFormat.format = charFormat; colorChanges << additionalFormat; } textPos = addText(block, charFormat, textColor, colorChanges, textPos, fragmentEnd, selectionStart, selectionEnd); } ++blockIterator; } #ifndef QT_NO_IM if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) { setPosition(blockPosition); textPos = block.position() + preeditPosition; QTextLine line = block.layout()->lineForTextPosition(preeditPosition); if (!currentLine().isValid() || line.lineNumber() != currentLine().lineNumber()) { setCurrentLine(line); } textPos = addText(block, block.charFormat(), textColor, colorChanges, textPos, textPos + preeditLength, selectionStart, selectionEnd); } #endif setCurrentLine(QTextLine()); // Reset current line because the text layout changed m_hasContents = true; }
void DTPatientListDelegate::drawHightlightText(QPainter *painter, QString text, QString substring, QRect pos, Qt::CaseSensitivity cs, bool boldFont, QColor highlight) const { if (!painter || (text.length() == 0)) return; painter->save(); QVector<QTextLayout::FormatRange> selections; QTextLayout textLayout; textLayout.setText(text); if (substring.length() != 0) { int idx = -1; int start = 0; while (1) { idx = text.indexOf(substring, start,cs); if (idx == -1) break; QTextLayout::FormatRange* range = new QTextLayout::FormatRange; range->start = idx; range->length = substring.length(); range->format.setBackground(QBrush(QColor(highlight))); selections.append(*range); start += substring.length(); } } if (boldFont) { QFont f = textLayout.font(); f.setBold(true); textLayout.setFont(f); } int leading = painter->fontMetrics().leading(); qreal height = 0; textLayout.beginLayout(); while (1) { QTextLine line = textLayout.createLine(); if (!line.isValid()) break; line.setLineWidth(pos.width()); height += leading; line.setPosition(QPointF(0, height)); height += line.height(); } textLayout.endLayout(); textLayout.draw(painter, pos.topLeft(), selections); painter->restore(); }
void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { QStyleOptionViewItemV4 opt = option; initStyleOption ( &opt, index ); painter->save(); painter->setClipRect ( opt.rect ); opt.features |= QStyleOptionViewItem::WrapText; opt.text = index.data().toString(); opt.textElideMode = Qt::ElideRight; opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter; QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); //const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); const int iconSize = 48; QRect iconbox = opt.rect; const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, 0, opt.widget ) + 1; QRect textRect = opt.rect; QRect textHighlightRect = textRect; // clip the decoration on top, remove width padding textRect.adjust ( textMargin,iconSize + textMargin + 5,-textMargin,0 ); textHighlightRect.adjust ( 0,iconSize + 5,0,0 ); // draw background { QSize textSize = viewItemTextSize ( &opt ); QPalette::ColorGroup cg; QStyleOptionViewItemV4 opt2(opt); if((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled)) { if(! ( opt.state & QStyle::State_Active )) cg = QPalette::Inactive; else cg = QPalette::Normal; } else { cg = QPalette::Disabled; } opt2.palette.setCurrentColorGroup(cg); // fill in background, if any if ( opt.backgroundBrush.style() != Qt::NoBrush ) { QPointF oldBO = painter->brushOrigin(); painter->setBrushOrigin ( opt.rect.topLeft() ); painter->fillRect ( opt.rect, opt.backgroundBrush ); painter->setBrushOrigin ( oldBO ); } if ( opt.showDecorationSelected ) { drawSelectionRect(painter,opt2, opt.rect); drawFocusRect(painter,opt2, opt.rect); //painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) ); } else { //if ( opt.state & QStyle::State_Selected ) { //QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt, opt.widget ); //painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, QPalette::Highlight ) ); drawSelectionRect(painter,opt2, textHighlightRect); drawFocusRect(painter,opt2, textHighlightRect); } } } // draw the icon { QIcon::Mode mode = QIcon::Normal; if ( ! ( opt.state & QStyle::State_Enabled ) ) mode = QIcon::Disabled; else if ( opt.state & QStyle::State_Selected ) mode = QIcon::Selected; QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off; iconbox.setHeight ( iconSize ); opt.icon.paint ( painter, iconbox, Qt::AlignCenter, mode, state ); } // set the text colors QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if ( cg == QPalette::Normal && ! ( opt.state & QStyle::State_Active ) ) cg = QPalette::Inactive; if ( opt.state & QStyle::State_Selected ) { painter->setPen ( opt.palette.color ( cg, QPalette::HighlightedText ) ); } else { painter->setPen ( opt.palette.color ( cg, QPalette::Text ) ); } // draw the text QTextOption textOption; textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere ); textOption.setTextDirection ( opt.direction ); textOption.setAlignment ( QStyle::visualAlignment ( opt.direction, opt.displayAlignment ) ); QTextLayout textLayout; textLayout.setTextOption ( textOption ); textLayout.setFont ( opt.font ); textLayout.setText ( opt.text ); qreal width, height; viewItemTextLayout ( textLayout, iconbox.width(), height, width ); const int lineCount = textLayout.lineCount(); const QRect layoutRect = QStyle::alignedRect ( opt.direction, opt.displayAlignment, QSize ( iconbox.width(), int ( height ) ), textRect ); const QPointF position = layoutRect.topLeft(); for ( int i = 0; i < lineCount; ++i ) { const QTextLine line = textLayout.lineAt ( i ); line.draw ( painter, position ); } painter->restore(); }
// copied from QItemDelegate to be able to add the 'format' parameter void HighlightingItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text, const QVector<QTextLayout::FormatRange> &format) const { QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) cg = QPalette::Inactive; if (option.state & QStyle::State_Selected) { painter->fillRect(rect, option.palette.brush(cg, QPalette::Highlight)); painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } if (text.isEmpty()) return; if (option.state & QStyle::State_Editing) { painter->save(); painter->setPen(option.palette.color(cg, QPalette::Text)); painter->drawRect(rect.adjusted(0, 0, -1, -1)); painter->restore(); } const QStyleOptionViewItem opt = option; const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, widget) + 1; QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding const bool wrapText = opt.features & QStyleOptionViewItem::WrapText; QTextOption textOption; textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap); textOption.setTextDirection(option.direction); textOption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment)); QTextLayout textLayout; textLayout.setTextOption(textOption); textLayout.setFont(option.font); textLayout.setText(replaceNewLine(text)); QSizeF textLayoutSize = doTextLayout(&textLayout, textRect.width()); if (textRect.width() < textLayoutSize.width() || textRect.height() < textLayoutSize.height()) { QString elided; int start = 0; int end = text.indexOf(QChar::LineSeparator, start); if (end == -1) { elided += option.fontMetrics.elidedText(text, option.textElideMode, textRect.width()); } else { while (end != -1) { elided += option.fontMetrics.elidedText(text.mid(start, end - start), option.textElideMode, textRect.width()); elided += QChar::LineSeparator; start = end + 1; end = text.indexOf(QChar::LineSeparator, start); } // let's add the last line (after the last QChar::LineSeparator) elided += option.fontMetrics.elidedText(text.mid(start), option.textElideMode, textRect.width()); } textLayout.setText(elided); textLayoutSize = doTextLayout(&textLayout, textRect.width()); } const QSize layoutSize(textRect.width(), int(textLayoutSize.height())); const QRect layoutRect = QStyle::alignedRect(option.direction, option.displayAlignment, layoutSize, textRect); // if we still overflow even after eliding the text, enable clipping if (!hasClipping() && (textRect.width() < textLayoutSize.width() || textRect.height() < textLayoutSize.height())) { painter->save(); painter->setClipRect(layoutRect); textLayout.draw(painter, layoutRect.topLeft(), format, layoutRect); painter->restore(); } else { textLayout.draw(painter, layoutRect.topLeft(), format, layoutRect); } }