QMacStyle: Make CE_PushButtonBevel square if large enough

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 <morten.sorvig@qt.io>
bb10
Gabriel de Dietrich 2018-03-15 18:44:44 -07:00
parent bec1e609ec
commit 3e665c8df8
2 changed files with 94 additions and 37 deletions

View File

@ -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<const QStyleOptionButton *>(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<NSButton *>(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<NSButton *>(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;

View File

@ -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;
};