summaryrefslogtreecommitdiffstats
path: root/src/widgets
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-06-09 10:28:43 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-06-11 01:19:51 +0200
commit2b2e7b2ac50e5b4f6e1888e594f6e32338dd2a80 (patch)
tree1bcd8503e9779783d110ab4f66b9874f1b8db42a /src/widgets
parent308845cd720969a5f3456caa8cf72023f120aecf (diff)
Correctly support style sheet for toolbutton menus and arrows
QToolButton can show an arrow instead of an icon, and that arrow can, as per the documentation, styled via the ::down/up/left/right-arrow pseudo element. This was not working at all, as the implementation confused the down-arrow with the menu arrow. Implement this correctly for all arrow types. A QToolButton can also have different ways to show a menu, either by using a separate section of the button that can be clicked; this section can be styled via ::menu-button and ::menu-arrow. Or by instant or delayed menu popup when clicking the button itself, in which case the button shows an indicator in the button itelf; that indicator can be styled via the ::menu-indicator pseudo element. The old implementation confused the various options, and the name of the PseudeoElement_ToolButonDownArrow didn't help with that. So rename that element to PseudoElement_ToolButtonMenuIndicator, and render it when there is no separate drop down. Fixes: QTBUG-27640 Pick-to: 6.1 6.2 Change-Id: Ia142a5d7498fa717e70f4e5382305e305b29effa Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Diffstat (limited to 'src/widgets')
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp121
1 files changed, 96 insertions, 25 deletions
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index d729eb631a..b02e4011b2 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -194,7 +194,7 @@ enum PseudoElement {
PseudoElement_GroupBoxIndicator,
PseudoElement_ToolButtonMenu,
PseudoElement_ToolButtonMenuArrow,
- PseudoElement_ToolButtonDownArrow,
+ PseudoElement_ToolButtonMenuIndicator,
PseudoElement_ToolBoxTab,
PseudoElement_ScrollBarSlider,
PseudoElement_ScrollBarAddPage,
@@ -1899,7 +1899,7 @@ QRenderRule QStyleSheetStyle::renderRule(const QObject *obj, const QStyleOption
break;
case PseudoElement_ToolButtonMenu:
case PseudoElement_ToolButtonMenuArrow:
- case PseudoElement_ToolButtonDownArrow:
+ case PseudoElement_ToolButtonMenuIndicator:
state |= complex->state & QStyle::State_MouseOver;
if (complex->state & QStyle::State_Sunken ||
complex->activeSubControls & QStyle::SC_ToolButtonMenu)
@@ -2188,7 +2188,7 @@ static Origin defaultOrigin(int pe)
case PseudoElement_SpinBoxDownButton:
case PseudoElement_PushButtonMenuIndicator:
case PseudoElement_ComboBoxDropDown:
- case PseudoElement_ToolButtonDownArrow:
+ case PseudoElement_ToolButtonMenuIndicator:
case PseudoElement_MenuCheckMark:
case PseudoElement_MenuIcon:
case PseudoElement_MenuRightArrow:
@@ -2229,7 +2229,7 @@ static Qt::Alignment defaultPosition(int pe)
case PseudoElement_ScrollBarLast:
case PseudoElement_SpinBoxDownButton:
case PseudoElement_PushButtonMenuIndicator:
- case PseudoElement_ToolButtonDownArrow:
+ case PseudoElement_ToolButtonMenuIndicator:
return Qt::AlignRight | Qt::AlignBottom;
case PseudoElement_ScrollBarSubLine:
@@ -2249,6 +2249,9 @@ static Qt::Alignment defaultPosition(int pe)
case PseudoElement_SpinBoxDownArrow:
case PseudoElement_ComboBoxArrow:
case PseudoElement_DownArrow:
+ case PseudoElement_UpArrow:
+ case PseudoElement_LeftArrow:
+ case PseudoElement_RightArrow:
case PseudoElement_ToolButtonMenuArrow:
case PseudoElement_SliderGroove:
return Qt::AlignCenter;
@@ -2304,8 +2307,11 @@ QSize QStyleSheetStyle::defaultSize(const QWidget *w, QSize sz, const QRect& rec
case PseudoElement_ComboBoxArrow:
case PseudoElement_DownArrow:
+ case PseudoElement_UpArrow:
+ case PseudoElement_LeftArrow:
+ case PseudoElement_RightArrow:
case PseudoElement_ToolButtonMenuArrow:
- case PseudoElement_ToolButtonDownArrow:
+ case PseudoElement_ToolButtonMenuIndicator:
case PseudoElement_MenuRightArrow:
if (sz.width() == -1)
sz.setWidth(13);
@@ -3237,8 +3243,20 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
rule.configurePalette(&toolOpt.palette, QPalette::ButtonText, QPalette::Button);
toolOpt.font = rule.font.resolve(toolOpt.font);
toolOpt.rect = rule.borderRect(opt->rect);
- bool customArrow = (tool->features & (QStyleOptionToolButton::HasMenu | QStyleOptionToolButton::MenuButtonPopup));
+ bool customArrow = tool->features & QStyleOptionToolButton::Arrow;
+ const auto customArrowElement = [tool]{
+ switch (tool->arrowType) {
+ case Qt::DownArrow: return PseudoElement_DownArrow;
+ case Qt::UpArrow: return PseudoElement_UpArrow;
+ case Qt::LeftArrow: return PseudoElement_LeftArrow;
+ case Qt::RightArrow: return PseudoElement_RightArrow;
+ default: break;
+ }
+ return PseudoElement_None;
+ };
bool customDropDown = tool->features & QStyleOptionToolButton::MenuButtonPopup;
+ bool customDropDownArrow = false;
+ bool customMenuIndicator = !customDropDown && (tool->features & QStyleOptionToolButton::HasMenu);
if (rule.hasNativeBorder()) {
if (tool->subControls & SC_ToolButton) {
//in some case (eg. the button is "auto raised") the style doesn't draw the background
@@ -3252,12 +3270,19 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
if (!(bflags & (State_Sunken | State_On | State_Raised)))
rule.drawBackground(p, toolOpt.rect);
}
- customArrow = customArrow && hasStyleRule(w, PseudoElement_ToolButtonDownArrow);
+ customArrow = customArrow && hasStyleRule(w, customArrowElement());
if (customArrow)
- toolOpt.features &= ~QStyleOptionToolButton::HasMenu;
+ toolOpt.features &= ~QStyleOptionToolButton::Arrow;
customDropDown = customDropDown && hasStyleRule(w, PseudoElement_ToolButtonMenu);
- if (customDropDown)
+ if (customDropDown) {
toolOpt.subControls &= ~QStyle::SC_ToolButtonMenu;
+ customDropDownArrow = hasStyleRule(w, PseudoElement_ToolButtonMenuArrow);
+ if (customDropDownArrow)
+ toolOpt.features &= ~(QStyleOptionToolButton::Menu | QStyleOptionToolButton::HasMenu);
+ }
+ customMenuIndicator = customMenuIndicator && hasStyleRule(w, PseudoElement_ToolButtonMenuIndicator);
+ if (customMenuIndicator)
+ toolOpt.features &= ~QStyleOptionToolButton::HasMenu;
if (rule.baseStyleCanDraw() && !(tool->features & QStyleOptionToolButton::Arrow)) {
baseStyle()->drawComplexControl(cc, &toolOpt, p, w);
@@ -3265,7 +3290,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
QWindowsStyle::drawComplexControl(cc, &toolOpt, p, w);
}
- if (!customArrow && !customDropDown)
+ if (!customArrow && !customDropDown && !customMenuIndicator)
return;
} else {
rule.drawRule(p, opt->rect);
@@ -3275,30 +3300,65 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
drawControl(CE_ToolButtonLabel, &toolOpt, p, w);
}
- QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
- QRect r = subControlRect(CC_ToolButton, opt, QStyle::SC_ToolButtonMenu, w);
+ const QRect cr = toolOpt.rect;
if (customDropDown) {
if (opt->subControls & QStyle::SC_ToolButtonMenu) {
+ QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
+ QRect menuButtonRect = subControlRect(CC_ToolButton, opt, QStyle::SC_ToolButtonMenu, w);
if (subRule.hasDrawable()) {
- subRule.drawRule(p, r);
+ subRule.drawRule(p, menuButtonRect);
} else {
- toolOpt.rect = r;
+ toolOpt.rect = menuButtonRect;
baseStyle()->drawPrimitive(PE_IndicatorButtonDropDown, &toolOpt, p, w);
}
+
+ if (customDropDownArrow) {
+ QRenderRule arrowRule = renderRule(w, opt, PseudoElement_ToolButtonMenuArrow);
+ QRect arrowRect = arrowRule.hasGeometry()
+ ? positionRect(w, arrowRule, PseudoElement_ToolButtonMenuArrow, menuButtonRect, toolOpt.direction)
+ : arrowRule.contentsRect(menuButtonRect);
+ if (arrowRule.hasDrawable()) {
+ arrowRule.drawRule(p, arrowRect);
+ } else {
+ toolOpt.rect = arrowRect;
+ baseStyle()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &toolOpt, p, w);
+ }
+ }
+ }
+ } else if (customMenuIndicator) {
+ QRenderRule subRule = renderRule(w, opt, PseudoElement_ToolButtonMenuIndicator);
+ QRect r = subRule.hasGeometry()
+ ? positionRect(w, subRule, PseudoElement_ToolButtonMenuIndicator, toolOpt.rect, toolOpt.direction)
+ : subRule.contentsRect(opt->rect);
+ if (subRule.hasDrawable()) {
+ subRule.drawRule(p, r);
+ } else {
+ toolOpt.rect = r;
+ baseStyle()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &toolOpt, p, w);
}
}
+ toolOpt.rect = cr;
if (customArrow) {
- QRenderRule subRule2 = customDropDown ? renderRule(w, opt, PseudoElement_ToolButtonMenuArrow)
- : renderRule(w, opt, PseudoElement_ToolButtonDownArrow);
- QRect r2 = customDropDown
- ? positionRect(w, subRule, subRule2, PseudoElement_ToolButtonMenuArrow, r, opt->direction)
- : positionRect(w, rule, subRule2, PseudoElement_ToolButtonDownArrow, opt->rect, opt->direction);
- if (subRule2.hasDrawable()) {
- subRule2.drawRule(p, r2);
+ const auto arrowElement = customArrowElement();
+ QRenderRule subRule = renderRule(w, opt, arrowElement);
+ QRect r = subRule.hasGeometry() ? positionRect(w, subRule, arrowElement, toolOpt.rect, toolOpt.direction)
+ : subRule.contentsRect(toolOpt.rect);
+ if (subRule.hasDrawable()) {
+ subRule.drawRule(p, r);
} else {
- toolOpt.rect = r2;
- baseStyle()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &toolOpt, p, w);
+ toolOpt.rect = r;
+ const auto arrowElement = [&toolOpt] {
+ switch (toolOpt.arrowType) {
+ case Qt::DownArrow: return QStyle::PE_IndicatorArrowDown;
+ case Qt::UpArrow: return QStyle::PE_IndicatorArrowUp;
+ case Qt::LeftArrow: return QStyle::PE_IndicatorArrowLeft;
+ case Qt::RightArrow: return QStyle::PE_IndicatorArrowRight;
+ case Qt::NoArrow: break;
+ }
+ return QStyle::PE_IndicatorArrowDown; // never happens
+ };
+ baseStyle()->drawPrimitive(arrowElement(), &toolOpt, p, w);
}
}
@@ -4786,8 +4846,19 @@ int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const
case PM_MenuButtonIndicator:
#if QT_CONFIG(toolbutton)
// QToolButton adds this directly to the width
- if (qobject_cast<const QToolButton *>(w) && (rule.hasBox() || !rule.hasNativeBorder()))
- return 0;
+ if (qobject_cast<const QToolButton *>(w)) {
+ if (rule.hasBox() || !rule.hasNativeBorder())
+ return 0;
+ if (const auto *tbOpt = qstyleoption_cast<const QStyleOptionToolButton*>(opt)) {
+ if (tbOpt->features & QStyleOptionToolButton::MenuButtonPopup)
+ subRule = renderRule(w, opt, PseudoElement_ToolButtonMenu);
+ else
+ subRule = renderRule(w, opt, PseudoElement_ToolButtonMenuIndicator);
+ if (subRule.hasContentsSize())
+ return subRule.size().width();
+ }
+ break;
+ }
#endif
subRule = renderRule(w, opt, PseudoElement_PushButtonMenuIndicator);
if (subRule.hasContentsSize())