diff options
Diffstat (limited to 'src/widgets/styles')
-rw-r--r-- | src/widgets/styles/qcommonstyle.cpp | 174 | ||||
-rw-r--r-- | src/widgets/styles/qcommonstyle_p.h | 10 | ||||
-rw-r--r-- | src/widgets/styles/qstylesheetstyle.cpp | 36 |
3 files changed, 140 insertions, 80 deletions
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 1980dc47a9..56bc329827 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -846,8 +846,6 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut } #endif // QT_CONFIG(toolbutton) -#if QT_CONFIG(itemviews) - static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth) { qreal height = 0; @@ -866,6 +864,80 @@ static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth) return QSizeF(widthUsed, height); } +QString QCommonStylePrivate::calculateElidedText(const QString &text, const QTextOption &textOption, + const QFont &font, const QRect &textRect, const Qt::Alignment valign, + Qt::TextElideMode textElideMode, int flags, + bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const +{ + QTextLayout textLayout(text, font); + textLayout.setTextOption(textOption); + + viewItemTextLayout(textLayout, textRect.width()); + + const QRectF boundingRect = textLayout.boundingRect(); + // don't care about LTR/RTL here, only need the height + const QRect layoutRect = QStyle::alignedRect(Qt::LayoutDirectionAuto, valign, + boundingRect.size().toSize(), textRect); + + if (paintStartPosition) + *paintStartPosition = QPointF(textRect.x(), layoutRect.top()); + + QString ret; + qreal height = 0; + const int lineCount = textLayout.lineCount(); + for (int i = 0; i < lineCount; ++i) { + const QTextLine line = textLayout.lineAt(i); + height += line.height(); + + // above visible rect + if (height + layoutRect.top() <= textRect.top()) { + if (paintStartPosition) + paintStartPosition->ry() += line.height(); + 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 && lastVisibleLineShouldBeElided) { + 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; + } + + QString text = textLayout.text().mid(start, length); + if (drawElided || elideLastVisibleLine) { + if (elideLastVisibleLine) { + if (text.endsWith(QChar::LineSeparator)) + text.chop(1); + text += QChar(0x2026); + } + const QStackTextEngine engine(text, font); + ret += engine.elidedText(textElideMode, textRect.width(), flags); + + // no newline for the last line (last visible or real) + // sometimes drawElided is true but no eliding is done so the text ends + // with QChar::LineSeparator - don't add another one. This happened with + // arabic text in the testcase for QTBUG-72805 + if (i < lineCount - 1 && + !ret.endsWith(QChar::LineSeparator)) + ret += QChar::LineSeparator; + } else { + ret += text; + } + + // below visible text, can stop + if (height + layoutRect.top() >= textRect.bottom()) + break; + } + return ret; +} + +#if QT_CONFIG(itemviews) + QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int role) const { const QWidget *widget = option->widget; @@ -938,67 +1010,15 @@ void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewIt textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap); textOption.setTextDirection(option->direction); textOption.setAlignment(QStyle::visualAlignment(option->direction, option->displayAlignment)); - QTextLayout textLayout(option->text, option->font); - textLayout.setTextOption(textOption); - - viewItemTextLayout(textLayout, textRect.width()); - - const QRectF boundingRect = textLayout.boundingRect(); - const QRect layoutRect = QStyle::alignedRect(option->direction, option->displayAlignment, - boundingRect.size().toSize(), textRect); - QPointF paintPosition = QPointF(textRect.x(), layoutRect.top()); - - QString newText; - qreal height = 0; - const int lineCount = textLayout.lineCount(); - for (int i = 0; i < lineCount; ++i) { - const QTextLine line = textLayout.lineAt(i); - height += line.height(); - - // above visible rect - if (height + layoutRect.top() <= textRect.top()) { - paintPosition.ry() += line.height(); - 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; - } - - QString text = textLayout.text().mid(start, length); - if (drawElided || elideLastVisibleLine) { - if (elideLastVisibleLine) { - if (text.endsWith(QChar::LineSeparator)) - text.chop(1); - text += QChar(0x2026); - } - const QStackTextEngine engine(text, option->font); - newText += engine.elidedText(option->textElideMode, textRect.width()); - // sometimes drawElided is true but no eliding is done so the text ends - // with QChar::LineSeparator - don't add another one. This happened with - // arabic text in the testcase for QTBUG-72805 - if (i < lineCount - 1 && - !newText.endsWith(QChar::LineSeparator)) - newText += QChar::LineSeparator; - } else { - newText += text; - } - // below visible text, can stop - if (height + layoutRect.top() >= textRect.bottom()) - break; - } + QPointF paintPosition; + const QString newText = calculateElidedText(option->text, textOption, + option->font, textRect, option->displayAlignment, + option->textElideMode, 0, + true, &paintPosition); - textLayout.setText(newText); + QTextLayout textLayout(newText, option->font); + textLayout.setTextOption(textOption); viewItemTextLayout(textLayout, textRect.width()); textLayout.draw(p, paintPosition); } @@ -1140,6 +1160,25 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect } #endif // QT_CONFIG(itemviews) +#if QT_CONFIG(toolbutton) +QString QCommonStylePrivate::toolButtonElideText(const QStyleOptionToolButton *option, + const QRect &textRect, int flags) const +{ + if (option->fontMetrics.horizontalAdvance(option->text) <= textRect.width()) + return option->text; + + QString text = option->text; + text.replace('\n', QChar::LineSeparator); + QTextOption textOption; + textOption.setWrapMode(QTextOption::ManualWrap); + textOption.setTextDirection(option->direction); + + return calculateElidedText(text, textOption, + option->font, textRect, Qt::AlignTop, + Qt::ElideMiddle, flags, + false, nullptr); +} +#endif // QT_CONFIG(toolbutton) #if QT_CONFIG(tabbar) /*! \internal @@ -1689,8 +1728,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, alignment |= Qt::AlignLeft | Qt::AlignVCenter; } tr.translate(shiftX, shiftY); - const QString text = toolbutton->fontMetrics.elidedText(toolbutton->text, Qt::ElideMiddle, - tr.width(), alignment); + const QString text = d->toolButtonElideText(toolbutton, tr, alignment); proxy()->drawItemText(p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette, toolbutton->state & State_Enabled, text, QPalette::ButtonText); @@ -3102,13 +3140,17 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, ///we need to access the widget here because the style option doesn't //have all the information we need (ie. the layout's margin) const QToolBar *tb = qobject_cast<const QToolBar*>(widget); - const int margin = tb && tb->layout() ? tb->layout()->margin() : 2; + const QMargins margins = tb && tb->layout() ? tb->layout()->contentsMargins() : QMargins(2, 2, 2, 2); const int handleExtent = proxy()->pixelMetric(QStyle::PM_ToolBarHandleExtent, opt, tb); if (tbopt->state & QStyle::State_Horizontal) { - r = QRect(margin, margin, handleExtent, tbopt->rect.height() - 2*margin); + r = QRect(margins.left(), margins.top(), + handleExtent, + tbopt->rect.height() - (margins.top() + margins.bottom())); r = QStyle::visualRect(tbopt->direction, tbopt->rect, r); } else { - r = QRect(margin, margin, tbopt->rect.width() - 2*margin, handleExtent); + r = QRect(margins.left(), margins.top(), + tbopt->rect.width() - (margins.left() + margins.right()), + handleExtent); } } } diff --git a/src/widgets/styles/qcommonstyle_p.h b/src/widgets/styles/qcommonstyle_p.h index b347c8563a..296f89ce5f 100644 --- a/src/widgets/styles/qcommonstyle_p.h +++ b/src/widgets/styles/qcommonstyle_p.h @@ -62,6 +62,7 @@ QT_BEGIN_NAMESPACE // class QStringList; +class QTextOption; // Private class class Q_WIDGETS_EXPORT QCommonStylePrivate : public QStylePrivate @@ -85,6 +86,10 @@ public: #endif } + QString calculateElidedText(const QString &text, const QTextOption &textOption, + const QFont &font, const QRect &textRect, const Qt::Alignment valign, + Qt::TextElideMode textElideMode, int flags, + bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const; #if QT_CONFIG(itemviews) void viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const; void viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect, @@ -110,6 +115,11 @@ public: && option.viewItemPosition == cachedOption->viewItemPosition); } #endif +#if QT_CONFIG(toolbutton) + QString toolButtonElideText(const QStyleOptionToolButton *toolbutton, + const QRect &textRect, int flags) const; +#endif + mutable QIcon tabBarcloseButtonIcon; #if QT_CONFIG(tabbar) void tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *pixmapRect) const; diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index c0f0321fce..1ad67f248a 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3708,21 +3708,17 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); QStyleOptionMenuItem newMi = mi; newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); - checkableOffset = newMi.rect.width(); + // align with icons if there are some + checkableOffset = std::max(m->maxIconWidth, newMi.rect.width()); if (subSubRule.hasDrawable() || checked) drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); } - int iconOffset = 0; if (!mi.icon.isNull()) { QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; if (act && !dis) mode = QIcon::Active; - QPixmap pixmap; - if (checked) - pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode, QIcon::On); - else - pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode); + const QPixmap pixmap(mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode, checked ? QIcon::On : QIcon::Off)); const int pixw = pixmap.width() / pixmap.devicePixelRatio(); const int pixh = pixmap.height() / pixmap.devicePixelRatio(); QRenderRule iconRule = renderRule(w, opt, PseudoElement_MenuIcon); @@ -3741,15 +3737,20 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q QRect pmr(0, 0, pixw, pixh); pmr.moveCenter(iconRect.center()); p->drawPixmap(pmr.topLeft(), pixmap); - iconOffset = iconRule.geo->width; } + int textOffset = 0; + // padding overrules it all + if (!subRule.hasBox() || subRule.box()->paddings[LeftEdge] == 0) { + textOffset = checkableOffset; + if (!m->icon.isNull() || !checkable) + textOffset += m->maxIconWidth; + } QRect textRect = subRule.contentsRect(opt->rect); - if (opt->direction == Qt::LeftToRight) - textRect.setLeft(textRect.left() + checkableOffset + iconOffset); - else - textRect.setRight(textRect.right() - checkableOffset - iconOffset); + textRect.setLeft(textRect.left() + textOffset); textRect.setWidth(textRect.width() - mi.tabWidth); + const QRect vTextRect = visualRect(opt->direction, m->rect, textRect); + QStringRef s(&mi.text); p->setPen(mi.palette.buttonText().color()); if (!s.isEmpty()) { @@ -3763,7 +3764,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q p->drawText(vShortcutRect, text_flags, s.mid(t + 1).toString()); s = s.left(t); } - p->drawText(textRect, text_flags, s.left(t).toString()); + p->drawText(vTextRect, text_flags, s.left(t).toString()); } if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow @@ -5093,10 +5094,11 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op if (mi->text.contains(QLatin1Char('\t'))) sz.rwidth() += 12; //as in QCommonStyle bool checkable = mi->checkType != QStyleOptionMenuItem::NotCheckable; + int checkableWidth = 0; if (checkable) { QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); QRect checkmarkRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); - sz.rwidth() += checkmarkRect.width(); + checkableWidth = std::max(mi->maxIconWidth, checkmarkRect.width()); } if (!mi->icon.isNull()) { QPixmap pixmap = mi->icon.pixmap(pixelMetric(PM_SmallIconSize)); @@ -5107,6 +5109,12 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op const QRect r = fm.boundingRect(QRect(), Qt::TextSingleLine | Qt::TextShowMnemonic, mi->text); sz = sz.expandedTo(r.size()); } + // padding overrules it all + if (!subRule.hasBox() || subRule.box()->paddings[LeftEdge] == 0) { + sz.rwidth() += checkableWidth; + if (!mi->icon.isNull() || !checkable) + sz.rwidth() += mi->maxIconWidth; + } return subRule.boxSize(subRule.adjustSize(sz)); } } |