From 3e665c8df8d0f5e3bb6e4bdda957fbd77f8a76ba Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 15 Mar 2018 18:44:44 -0700 Subject: QMacStyle: Make CE_PushButtonBevel square if large enough MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meaning, if larger than the size of a regular NSButton. No intermediate size square buttons anymore. We'll try to get the closest one later, once the sizing problem is solved. We also refactor the button creation code a bit. Change-Id: I965520469546aea596cd1abec2309b40d70399ce Reviewed-by: Morten Johan Sørvig --- src/plugins/styles/mac/qmacstyle_mac.mm | 128 ++++++++++++++++++++--------- src/plugins/styles/mac/qmacstyle_mac_p_p.h | 3 + 2 files changed, 94 insertions(+), 37 deletions(-) (limited to 'src/plugins/styles/mac') diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 442ecae6e8..f44747c295 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -344,9 +344,15 @@ static const QMarginsF pushButtonShadowMargins[3] = { { 1.5, 0.5, 1.5, 2.5 } }; +static const qreal pushButtonDefaultHeight[3] = { + 32, 28, 24 +}; + static const int toolButtonArrowSize = 7; static const int toolButtonArrowMargin = 2; +static const qreal focusRingWidth = 3.5; + #if QT_CONFIG(tabbar) static bool isVerticalTabs(const QTabBar::Shape shape) { return (shape == QTabBar::RoundedEast @@ -1221,8 +1227,6 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int h void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const { - static const auto focusRingWidth = 3.5; - QPainterPath focusRingPath; qreal hOffset = 0.0; qreal vOffset = 0.0; @@ -1579,6 +1583,55 @@ QSizeF QMacStylePrivate::CocoaControl::defaultFrameSize() const return QSizeF(); } +bool QMacStylePrivate::CocoaControl::getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const +{ + switch (type) { + case Button_CheckBox: + *buttonType = NSSwitchButton; + *bezelStyle = NSRegularSquareBezelStyle; + break; + case Button_Disclosure: + *buttonType = NSOnOffButton; + *bezelStyle = NSDisclosureBezelStyle; + break; + case Button_RadioButton: + *buttonType = NSRadioButton; + *bezelStyle = NSRegularSquareBezelStyle; + break; + case Button_SquareButton: + *buttonType = NSPushOnPushOffButton; + *bezelStyle = NSShadowlessSquareBezelStyle; + break; + case Button_PushButton: + *buttonType = NSPushOnPushOffButton; + *bezelStyle = NSRoundedBezelStyle; + break; + default: + return false; + } + + return true; +} + +QMacStylePrivate::CocoaControlType cocoaControlType(const QStyleOption *opt, const QWidget *w) +{ + if (const auto *btn = qstyleoption_cast(opt)) { + const bool hasMenu = btn->features & QStyleOptionButton::HasMenu; + // When the contents won't fit in a large sized button, + // and WA_MacNormalSize is not set, make the button square. + // Threshold used to be at 34, not 32. + const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge]; + const bool isSquare = (btn->features & QStyleOptionButton::Flat) + || (btn->rect.height() > maxNonSquareHeight + && !(w && w->testAttribute(Qt::WA_MacNormalSize))); + return (isSquare? QMacStylePrivate::Button_SquareButton : + hasMenu ? QMacStylePrivate::Button_PullDown : + QMacStylePrivate::Button_PushButton); + } + + return QMacStylePrivate::NoControl; +} + /** Checks if the actual contents of btn fits inside the free content bounds of 'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton' @@ -1992,19 +2045,9 @@ ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags) return w; } -static NSButton *makeButton(NSButtonType type, NSBezelStyle style) -{ - NSButton *b = [[NSButton alloc] init]; - b.title = @""; - b.buttonType = type; - b.bezelStyle = style; - return b; -} - NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const { NSView *bv = cocoaControls.value(widget, nil); - if (!bv) { switch (widget.type) { case Box: { @@ -2017,11 +2060,16 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const break; } case Button_CheckBox: - bv = makeButton(NSSwitchButton, NSRegularSquareBezelStyle); - break; case Button_Disclosure: - bv = makeButton(NSOnOffButton, NSDisclosureBezelStyle); + case Button_PushButton: + case Button_RadioButton: + case Button_SquareButton: { + NSButton *bc = [[NSButton alloc] init]; + bc.title = @""; + // See below for style and bezel setting. + bv = bc; break; + } case Button_PopupButton: case Button_PullDown: { NSPopUpButton *bc = [[NSPopUpButton alloc] init]; @@ -2031,12 +2079,6 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const bv = bc; break; } - case Button_PushButton: - bv = makeButton(NSMomentaryLightButton, NSRoundedBezelStyle); - break; - case Button_RadioButton: - bv = makeButton(NSRadioButton, NSRegularSquareBezelStyle); - break; case Button_WindowClose: case Button_WindowMiniaturize: case Button_WindowZoom: { @@ -2137,6 +2179,16 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const cocoaControls.insert(widget, bv); } + NSButtonType buttonType; + NSBezelStyle bezelStyle; + if (widget.getCocoaButtonTypeAndBezelStyle(&buttonType, &bezelStyle)) { + // FIXME We need to reset the button's type and + // bezel style properties, even when cached. + auto *button = static_cast(bv); + button.buttonType = buttonType; + button.bezelStyle = bezelStyle; + } + return bv; } @@ -3890,10 +3942,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter || (btn->features & QStyleOptionButton::AutoDefaultButton && d->autoDefaultButton == btn->styleObject)); const bool hasMenu = btn->features & QStyleOptionButton::HasMenu; - // TODO When the contents won't fit in a large sized button, - // and WA_MacNormalSize is not set, make the button square. - const bool isSquare = btn->features & QStyleOptionButton::Flat; - const auto ct = hasMenu ? QMacStylePrivate::Button_PullDown : QMacStylePrivate::Button_PushButton; + const auto ct = cocoaControlType(btn, w); const auto cs = d->effectiveAquaSizeConstrain(opt, w); const auto cw = QMacStylePrivate::CocoaControl(ct, cs); auto *pb = static_cast(d->cocoaControl(cw)); @@ -3901,8 +3950,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter // This is more convoluted than we initialy thought. See for example // differences between plain and menu button frames. QRectF frameRect; - if (isSquare) { - frameRect = btn->rect; + if (cw.type == QMacStylePrivate::Button_SquareButton) { + frameRect = btn->rect + .adjusted(3, 1, -3, -5) + .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth); } else { const auto frameSize = cw.defaultFrameSize(); if (hasMenu) { @@ -3915,7 +3966,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1); else if (cw.size == QStyleHelper::SizeMini) frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0); - } else { + } else if (cw.type == QMacStylePrivate::Button_PushButton) { // Start from the style option's top-left corner. frameRect = QRectF(btn->rect.topLeft(), QSizeF(btn->rect.width(), frameSize.height())); @@ -3927,8 +3978,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } pb.frame = frameRect.toCGRect(); - pb.bezelStyle = isSquare ? NSBezelStyleShadowlessSquare : NSBezelStyleRounded; - pb.buttonType = NSPushOnPushOffButton; pb.enabled = isEnabled; [pb highlight:isPressed]; pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState; @@ -3936,7 +3985,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter [pb.cell drawBezelWithFrame:r inView:pb.superview]; }); - if (hasMenu && isSquare) { + if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) { // Using -[NSPopuButtonCell drawWithFrame:inView:] above won't do // it right because we don't set the text in the native button. const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w); @@ -3963,12 +4012,17 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter // TODO Remove and use QFocusFrame instead. const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, btn, w); const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, btn, w); - auto focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]); - if (cw.type == QMacStylePrivate::Button_PushButton) - focusRect -= pushButtonShadowMargins[cw.size]; - else if (cw.type == QMacStylePrivate::Button_PullDown) - focusRect -= pullDownButtonShadowMargins[cw.size]; - d->drawFocusRing(p, focusRect, hMargin, vMargin, cw); + if (cw.type == QMacStylePrivate::Button_SquareButton) { + const auto focusRect = frameRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth); + d->drawFocusRing(p, focusRect.toAlignedRect(), hMargin, vMargin, 0); + } else { + auto focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]); + if (cw.type == QMacStylePrivate::Button_PushButton) + focusRect -= pushButtonShadowMargins[cw.size]; + else if (cw.type == QMacStylePrivate::Button_PullDown) + focusRect -= pullDownButtonShadowMargins[cw.size]; + d->drawFocusRing(p, focusRect, hMargin, vMargin, cw); + } } } break; diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index af34f8f1e4..d740277e8f 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -190,6 +190,7 @@ public: Button_PullDown, // QPushButton with menu Button_PushButton, Button_RadioButton, + Button_SquareButton, // Oversized QPushButton Button_WindowClose, Button_WindowMiniaturize, Button_WindowZoom, @@ -217,6 +218,8 @@ public: bool operator==(const CocoaControl &other) const; QSizeF defaultFrameSize() const; + + bool getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const; }; -- cgit v1.2.3