From 02f8fe67b87217bcfa0134809df347646a046539 Mon Sep 17 00:00:00 2001 From: kleuter Date: Wed, 12 May 2021 21:25:01 +0200 Subject: [PATCH] 5.15: fix for QTBUG-89133 & QTBUG-81452 using cherry pick (https://codereview.qt-project.org/c/qt/qtbase/+/327677) --- .../src/plugins/styles/mac/qmacstyle_mac.mm | 128 +++++++++++++----- .../src/widgets/widgets/qpushbutton.cpp | 21 +++ .../src/widgets/widgets/qpushbutton_p.h | 7 +- 3 files changed, 119 insertions(+), 37 deletions(-) diff --git a/5.15.2/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm b/5.15.2/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm index 51dbec4..d21c276 100644 --- a/5.15.2/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/5.15.2/qtbase/src/plugins/styles/mac/qmacstyle_mac.mm @@ -195,6 +195,10 @@ const int QMacStylePrivate::PushButtonLeftOffset = 6; const int QMacStylePrivate::PushButtonRightOffset = 12; const int QMacStylePrivate::PushButtonContentPadding = 6; +const int pushButtonBevelRectOffsets[3] = { + QMacStylePrivate::PushButtonLeftOffset, 5, 5 +}; + QVector > QMacStylePrivate::scrollBars; // Title bar gradient colors for Lion were determined by inspecting PSDs exported @@ -1174,6 +1178,8 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int case SegmentedControl_Middle: case TextField: { auto innerRect = targetRect; + if (cw.type == Button_SquareButton) + innerRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin)); if (cw.type == TextField) innerRect = innerRect.adjusted(hMargin, vMargin, -hMargin, -vMargin).adjusted(0.5, 0.5, -0.5, -0.5); const auto outerRect = innerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth); @@ -1208,9 +1214,38 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int focusRingPath.addEllipse(rbOuterRect); break; } - case Button_PopupButton: case Button_PullDown: - case Button_PushButton: + case Button_PushButton: { + const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur; + QRectF focusRect; + auto *pb = static_cast(cocoaControl(cw)); + const QRectF frameRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin)); + pb.frame = frameRect.toCGRect(); + 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]; + //fix focus ring drawn slightly off for pull downs + if (cw.size == QStyleHelper::SizeLarge) + focusRect = focusRect.adjusted(0, 0, 0, -1); + else if (cw.size == QStyleHelper::SizeMini) + focusRect = focusRect.adjusted(0, -1, 0, 0); + } + if (isBigSurOrAbove) + focusRect = focusRect.translated(0, 1); + const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4; + const qreal outerRadius = innerRadius + focusRingWidth; + hOffset = focusRect.left(); + vOffset = focusRect.top(); + const auto innerRect = focusRect.translated(-focusRect.topLeft()); + const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin); + focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius); + focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius); + break; + } + case Button_PopupButton: case SegmentedControl_Single: { const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4; const qreal outerRadius = innerRadius + focusRingWidth; @@ -1568,7 +1603,8 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) const auto frameSize = defaultFrameSize(); if (type == QMacStylePrivate::Button_SquareButton) { frameRect = rect.adjusted(3, 1, -3, -1) - .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth); + .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth) + .adjusted(-6.5, 0, 6.5, 0); } else if (type == QMacStylePrivate::Button_PushButton) { // Start from the style option's top-left corner. frameRect = QRectF(rect.topLeft(), @@ -1577,6 +1613,8 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) frameRect = frameRect.translated(0, 1.5); else if (size == QStyleHelper::SizeMini) frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4); + frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0, + pushButtonBevelRectOffsets[size], 0); } else { // Center in the style option's rect. frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0), @@ -1589,6 +1627,9 @@ QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1); else if (size == QStyleHelper::SizeMini) frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0); + if (type == QMacStylePrivate::Button_PullDown) + frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0, + pushButtonBevelRectOffsets[size], 0); } else if (type == QMacStylePrivate::ComboBox) { frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0); } @@ -3716,24 +3757,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter arrowOpt.rect = ar; proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w); } - - - if (btn->state & State_HasFocus) { - // 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); - QRectF focusRect; - if (cw.type == QMacStylePrivate::Button_SquareButton) { - focusRect = frameRect; - } else { - 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; case CE_PushButtonLabel: @@ -3768,7 +3791,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QRect textRect = itemTextRect( btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text); if (hasMenu) { - textRect.moveTo(w ? 15 : 11, textRect.top()); // Supports Qt Quick Controls + if (ct == QMacStylePrivate::Button_SquareButton) + textRect.moveTo(w ? 8 : 11, textRect.top()); + else + textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)]) + : 11, textRect.top()); // Supports Qt Quick Controls } // Draw the icon: if (hasIcon) { @@ -3988,8 +4015,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter rAdjusted.origin.x -= 3; rAdjusted.size.width += 6; if (isBigSurOrAbove) { - rAdjusted.origin.y -= 1; - rAdjusted.size.height += 1; if (tp == QStyleOptionTab::End) rAdjusted.origin.x -= 2; } @@ -4166,6 +4191,15 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter return QMacStylePrivate::Button_RadioButton; if (ffw->inherits("QLineEdit") || ffw->inherits("QTextEdit")) return QMacStylePrivate::TextField; + if (const auto *pb = qobject_cast(ffw)) { + if (pb->isFlat() || (pb->rect().height() + > pushButtonDefaultHeight[QStyleHelper::SizeLarge] + && !(pb->testAttribute(Qt::WA_MacNormalSize)))) + return QMacStylePrivate::Button_SquareButton; + if (pb->menu() != nullptr) + return QMacStylePrivate::Button_PullDown; + return QMacStylePrivate::Button_PushButton; + } } return QMacStylePrivate::Box; // Not really, just make it the default @@ -4909,14 +4943,24 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, = qstyleoption_cast(opt)) { if ((buttonOpt->features & QStyleOptionButton::Flat)) break; // leave rect alone + if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) { + rect = opt->rect; + if (controlSize == QStyleHelper::SizeLarge) + rect.adjust(+6, +4, -6, -8); + else if (controlSize == QStyleHelper::SizeSmall) + rect.adjust(+5, +4, -5, -6); + else + rect.adjust(+1, 0, -1, -2); + break; + } } rect = opt->rect; if (controlSize == QStyleHelper::SizeLarge) { - rect.adjust(+6, +4, -6, -8); + rect.adjust(0, +4, 0, -8); } else if (controlSize == QStyleHelper::SizeSmall) { - rect.adjust(+5, +4, -5, -6); + rect.adjust(0, +4, 0, -6); } else { - rect.adjust(+1, 0, -1, -2); + rect.adjust(0, 0, 0, -2); } break; case SE_RadioButtonLayoutItem: @@ -6345,14 +6389,16 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, break; #endif case QStyle::CT_PushButton: { - if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) + bool isFlat = false; + if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { if (btn->features & QStyleOptionButton::CommandLinkButton) return QCommonStyle::sizeFromContents(ct, opt, sz, widget); + isFlat = btn->features & QStyleOptionButton::Flat; + } // By default, we fit the contents inside a normal rounded push button. // Do this by add enough space around the contents so that rounded // borders (including highlighting when active) will show. - // TODO Use QFocusFrame and get rid of these horrors. QSize macsz; const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz); // FIXME See comment in CT_PushButton case in qt_aqua_get_known_size(). @@ -6363,12 +6409,24 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, // All values as measured from HIThemeGetButtonBackgroundBounds() if (controlSize != QStyleHelper::SizeMini) sz.rwidth() += 12; // We like 12 over here. - if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16) - sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16; - else if (controlSize == QStyleHelper::SizeMini) - sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this. - else - sz.setHeight(pushButtonDefaultHeight[controlSize]); + + if (controlSize == QStyleHelper::SizeLarge) { + if (!isFlat) + sz.rwidth() -= 12; + if (sz.height() > 16) + sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16; + else + sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeLarge]); + } else { + if (!isFlat) + sz.rwidth() -= 10; + if (controlSize == QStyleHelper::SizeMini) + sz.setHeight(24); + else + sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeSmall]); + } + if (isFlat) + sz.rwidth() -= 13; break; } case QStyle::CT_MenuItem: diff --git a/5.15.2/qtbase/src/widgets/widgets/qpushbutton.cpp b/5.15.2/qtbase/src/widgets/widgets/qpushbutton.cpp index 3d075bf..ce2994c 100644 --- a/5.15.2/qtbase/src/widgets/widgets/qpushbutton.cpp +++ b/5.15.2/qtbase/src/widgets/widgets/qpushbutton.cpp @@ -332,6 +332,8 @@ void QPushButton::initStyleOption(QStyleOptionButton *option) const option->state |= QStyle::State_On; if (!d->flat && !d->down) option->state |= QStyle::State_Raised; + if (underMouse() && hasMouseTracking()) + option->state.setFlag(QStyle::State_MouseOver, d->hovering); option->text = d->text; option->icon = d->icon; option->iconSize = iconSize(); @@ -581,6 +583,13 @@ void QPushButton::showMenu() d->_q_popupPressed(); } +void QPushButtonPrivate::init() +{ + Q_Q(QPushButton); + q->setAttribute(Qt::WA_MacShowFocusRect); + resetLayoutItemMargins(); +} + void QPushButtonPrivate::_q_popupPressed() { Q_Q(QPushButton); @@ -691,6 +700,18 @@ bool QPushButton::event(QEvent *e) updateGeometry(); } else if (e->type() == QEvent::PolishRequest) { updateGeometry(); + } else if (e->type() == QEvent::MouseMove) { + const QMouseEvent *mouseEvent = static_cast(e); + if (testAttribute(Qt::WA_Hover)) { + bool hit = false; + if (underMouse()) + hit = hitButton(mouseEvent->pos()); + + if (hit != d->hovering) { + update(rect()); + d->hovering = hit; + } + } } return QAbstractButton::event(e); } diff --git a/5.15.2/qtbase/src/widgets/widgets/qpushbutton_p.h b/5.15.2/qtbase/src/widgets/widgets/qpushbutton_p.h index 439b6e3..a0bf218 100644 --- a/5.15.2/qtbase/src/widgets/widgets/qpushbutton_p.h +++ b/5.15.2/qtbase/src/widgets/widgets/qpushbutton_p.h @@ -69,9 +69,11 @@ public: QPushButtonPrivate() : QAbstractButtonPrivate(QSizePolicy::PushButton), autoDefault(Auto), - defaultButton(false), flat(false), menuOpen(false), lastAutoDefault(false) {} + defaultButton(false), flat(false), menuOpen(false), hovering(false), + lastAutoDefault(false) + {} - inline void init() { resetLayoutItemMargins(); } + void init(); static QPushButtonPrivate* get(QPushButton *b) { return b->d_func(); } #if QT_CONFIG(menu) QPoint adjustedMenuPosition(); @@ -89,6 +91,7 @@ public: uint defaultButton : 1; uint flat : 1; uint menuOpen : 1; + uint hovering : 1; mutable uint lastAutoDefault : 1; };