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 <richard.gustavsen@qt.io>
bb10
Christian Ehrlicher 2018-05-16 21:05:03 +02:00
parent 2cf5c5a602
commit 5712c62d1c
1 changed files with 39 additions and 40 deletions

View File

@ -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<int, QString> 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<qreal>(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;
}
}