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(); }
// 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(); }
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); }
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; }
/// 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 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); }
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(); }