From afbe26768deeac2839af1b35771bb74ba17f13ea Mon Sep 17 00:00:00 2001 From: William Pearson Date: Wed, 12 Apr 2023 17:13:05 -0700 Subject: [PATCH] Draw arrows next to all tool buttons with menus Before, only MenuButtonPopup had an arrow. This makes it more obvious as to whether the button will immediately do something when clicked or if it will open a menu to choose a specific action. --- qrenderdoc/Styles/RDStyle/RDStyle.cpp | 12 ++-- .../RDTweakedNativeStyle.cpp | 56 ++++++++++++++++--- .../RDTweakedNativeStyle.h | 5 ++ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/qrenderdoc/Styles/RDStyle/RDStyle.cpp b/qrenderdoc/Styles/RDStyle/RDStyle.cpp index 150393a06..40ed9ac75 100644 --- a/qrenderdoc/Styles/RDStyle/RDStyle.cpp +++ b/qrenderdoc/Styles/RDStyle/RDStyle.cpp @@ -622,6 +622,7 @@ QSize RDStyle::sizeFromContents(ContentsType type, const QStyleOption *opt, cons if(type == CT_PushButton || type == CT_ToolButton) { const QStyleOptionButton *button = qstyleoption_cast(opt); + const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt); QSize ret = size; @@ -631,6 +632,10 @@ QSize RDStyle::sizeFromContents(ContentsType type, const QStyleOption *opt, cons ret.setWidth(qMax(50, ret.width())); ret.setHeight(qMax(15, ret.height())); } + else if(type == CT_ToolButton && toolbutton) + { + ret = adjustToolButtonSize(toolbutton, size, widget); + } // add margin and border ret.setHeight(ret.height() + Constants::ButtonMargin + Constants::ButtonBorder * 2); @@ -897,17 +902,16 @@ void RDStyle::drawComplexControl(ComplexControl control, const QStyleOptionCompl const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt); QStyleOptionToolButton labelTextIcon = *toolbutton; - labelTextIcon.rect = proxy()->subControlRect(control, opt, SC_ToolButton, widget); + labelTextIcon.rect = subControlRect(control, opt, SC_ToolButton, widget); // draw the label text/icon proxy()->drawControl(CE_ToolButtonLabel, &labelTextIcon, p, widget); // draw the menu arrow, if there is one - if((toolbutton->subControls & SC_ToolButtonMenu) || - (toolbutton->features & QStyleOptionToolButton::HasMenu)) + if(shouldDrawToolButtonMenuArrow(toolbutton)) { QStyleOptionToolButton menu = *toolbutton; - menu.rect = proxy()->subControlRect(control, opt, SC_ToolButtonMenu, widget); + menu.rect = subControlRect(control, opt, SC_ToolButtonMenu, widget); proxy()->drawPrimitive(PE_IndicatorArrowDown, &menu, p, widget); } diff --git a/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp b/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp index 7beb815c7..da254ba6b 100644 --- a/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp +++ b/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.cpp @@ -63,8 +63,7 @@ QRect RDTweakedNativeStyle::subControlRect(ComplexControl cc, const QStyleOption const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt); // return the normal rect if there's no menu - if(!(toolbutton->subControls & SC_ToolButtonMenu) && - !(toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)) + if(!shouldDrawToolButtonMenuArrow(toolbutton)) { return ret; } @@ -107,12 +106,11 @@ QSize RDTweakedNativeStyle::sizeFromContents(ContentsType type, const QStyleOpti { QSize sz = size; - // Toolbuttons are always at least icon sized, for consistency. if(type == QStyle::CT_ToolButton) { const QStyleOptionToolButton *toolbutton = qstyleoption_cast(opt); if(toolbutton) - sz = sz.expandedTo(toolbutton->iconSize); + sz = adjustToolButtonSize(toolbutton, sz, widget); } // menu bar items can be sized for both the icon *and* the text @@ -185,13 +183,24 @@ void RDTweakedNativeStyle::drawComplexControl(ComplexControl control, const QSty backCol.setAlphaF(0.2); QStyleOptionToolButton menu; + bool hasMenu = false; + bool hasSeparateMenu = false; // draw the menu arrow, if there is one - if((toolbutton->subControls & SC_ToolButtonMenu) || - (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)) + if(shouldDrawToolButtonMenuArrow(toolbutton)) { menu = *toolbutton; menu.rect = subControlRect(control, opt, SC_ToolButtonMenu, widget); + hasMenu = true; + // We always draw an arrow if a menu is present (normally Qt only does it for MenuButtonPopup, + // where there is both a button with a default action and a menu triggered by a small arrow, + // and not InstantPopup where there is only a button). If the button uses MenuButtonPopup, + // we want to draw a line to distinguish the menu part of the button and the main part, + // but we don't need that line if the arrow is decorative only. + if(toolbutton->features & QStyleOptionToolButton::MenuButtonPopup) + { + hasSeparateMenu = true; + } } QStyle::State masked = opt->state & (State_On | State_MouseOver); @@ -204,7 +213,7 @@ void RDTweakedNativeStyle::drawComplexControl(ComplexControl control, const QSty QRect rect = opt->rect.adjusted(0, 0, -1, -1); p->setPen(opt->palette.color(QPalette::Shadow)); p->drawRect(rect); - if(menu.rect.isValid()) + if(hasSeparateMenu) p->drawLine(menu.rect.topLeft(), menu.rect.bottomLeft()); // when the mouse is over, make it a little stronger @@ -222,7 +231,7 @@ void RDTweakedNativeStyle::drawComplexControl(ComplexControl control, const QSty // draw the label text/icon drawControl(CE_ToolButtonLabel, &labelTextIcon, p, widget); - if(menu.rect.isValid()) + if(hasMenu) { menu.rect.adjust(2, 0, 0, 0); drawPrimitive(PE_IndicatorArrowDown, &menu, p, widget); @@ -585,3 +594,34 @@ void RDTweakedNativeStyle::drawControl(ControlElement control, const QStyleOptio QProxyStyle::drawControl(control, opt, p, widget); } + +bool RDTweakedNativeStyle::shouldDrawToolButtonMenuArrow(const QStyleOptionToolButton *toolbutton) const +{ + // Qt normally only draws the arrow for MenuButtonPopup; we want it for all tools button with + // menus (including InstantPopup). + return (toolbutton->subControls & SC_ToolButtonMenu) || + (toolbutton->features & QStyleOptionToolButton::HasMenu); +} + +QSize RDTweakedNativeStyle::adjustToolButtonSize(const QStyleOptionToolButton *toolbutton, + const QSize &size, const QWidget *widget) const +{ + QSize sz = size; + + // Toolbuttons are always at least icon sized, for consistency. + sz = sz.expandedTo(toolbutton->iconSize); + + if(shouldDrawToolButtonMenuArrow(toolbutton)) + { + // QToolButton::sizeHint automatically increases the width for MenuButtonPopup separate from + // calling sizeFromContents. But we want to draw the arrow for all tool buttons with menus, + // not just those using MenuButtonPopup. Check for MenuButtonPopup to avoid increasing the + // size twice. + if(!(toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)) + { + sz.setWidth(sz.width() + proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget)); + } + } + + return sz; +} diff --git a/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h b/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h index 2ed8d25b3..9a8db37ee 100644 --- a/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h +++ b/qrenderdoc/Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h @@ -27,6 +27,8 @@ #include #include +class QStyleOptionToolButton; + class RDTweakedNativeStyle : public QProxyStyle { private: @@ -56,4 +58,7 @@ public: const QWidget *widget = NULL) const override; protected: + bool shouldDrawToolButtonMenuArrow(const QStyleOptionToolButton *toolbutton) const; + QSize adjustToolButtonSize(const QStyleOptionToolButton *toolbutton, const QSize &size, + const QWidget *widget) const; };