From 5712c62d1cfdcf56c772d8a63d52ad58945f194c Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Wed, 16 May 2018 21:05:03 +0200 Subject: [PATCH] QCommonStyle: properly elide last visible line Rewrite QCommonStylePrivate::viewItemDrawText() to be able to elide lines which are too long and the last visible line. The painting is now done in one pass instead of two and lines which are not visible due to a size constraint are not painted at all. [ChangeLog][QtWidgets][Itemviews] Fixed eliding of multi-line items Task-number: QTBUG-12129 Task-number: QTBUG-14949 Task-number: QTBUG-57891 Change-Id: I3a41938e442663ecd7e5ca56bf6bbd857edafb7d Reviewed-by: Richard Moe Gustavsen --- src/widgets/styles/qcommonstyle.cpp | 79 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index f083359c06..4c01807ca7 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -933,54 +933,53 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt viewItemTextLayout(textLayout, textRect.width()); - qreal height = 0; - qreal width = 0; - const int lineCount = textLayout.lineCount(); - QHash elidedTexts; - for (int j = 0; j < lineCount; ++j) { - const QTextLine line = textLayout.lineAt(j); - if (j + 1 <= lineCount - 1) { - const QTextLine nextLine = textLayout.lineAt(j + 1); - if ((nextLine.y() + nextLine.height()) > textRect.height()) { - int start = line.textStart(); - int length = line.textLength() + nextLine.textLength(); - const QStackTextEngine engine(textLayout.text().mid(start, length), option->font); - elidedTexts.insert(j, engine.elidedText(option->textElideMode, textRect.width())); - height += line.height(); - width = textRect.width(); - continue; - } - } - if (line.naturalTextWidth() > textRect.width()) { - int start = line.textStart(); - int length = line.textLength(); - const QStackTextEngine engine(textLayout.text().mid(start, length), option->font); - elidedTexts.insert(j, engine.elidedText(option->textElideMode, textRect.width())); - height += line.height(); - width = textRect.width(); - continue; - } - width = qMax(width, line.width()); - height += line.height(); - } - + const QRectF boundingRect = textLayout.boundingRect(); const QRect layoutRect = QStyle::alignedRect(option->direction, option->displayAlignment, - QSize(int(width), int(height)), textRect); + boundingRect.size().toSize(), textRect); const QPointF position = layoutRect.topLeft(); + const int lineCount = textLayout.lineCount(); + + qreal height = 0; for (int i = 0; i < lineCount; ++i) { const QTextLine line = textLayout.lineAt(i); - auto it = elidedTexts.constFind(i); - if (it != elidedTexts.constEnd()) { - const QString &elidedText = it.value(); - qreal x = position.x() + line.x(); - qreal y = position.y() + line.y() + line.ascent(); + height += line.height(); + + // above visible rect + if (height + layoutRect.top() <= textRect.top()) + continue; + + const int start = line.textStart(); + const int length = line.textLength(); + + const bool drawElided = line.naturalTextWidth() > textRect.width(); + bool elideLastVisibleLine = false; + if (!drawElided && i + 1 < lineCount) { + const QTextLine nextLine = textLayout.lineAt(i + 1); + const int nextHeight = height + nextLine.height() / 2; + // elide when less than the next half line is visible + if (nextHeight + layoutRect.top() > textRect.height() + textRect.top()) + elideLastVisibleLine = true; + } + + if (drawElided || elideLastVisibleLine) { + QString text = textLayout.text().mid(start, length); + if (elideLastVisibleLine) + text += QChar(0x2026); + const QStackTextEngine engine(text, option->font); + const QString elidedText = engine.elidedText(option->textElideMode, textRect.width()); + const QPointF pos(position.x() + line.x(), + position.y() + line.y() + line.ascent()); p->save(); p->setFont(option->font); - p->drawText(QPointF(x, y), elidedText); + p->drawText(pos, elidedText); p->restore(); - continue; + } else { + line.draw(p, position); } - line.draw(p, position); + + // below visible text, can stop + if (height + layoutRect.top() >= textRect.bottom()) + break; } }