diff options
author | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2018-01-26 13:54:23 -0800 |
---|---|---|
committer | Gabriel de Dietrich <gabriel.dedietrich@qt.io> | 2018-02-05 19:44:50 +0000 |
commit | 8633e1a7b48f71e91f81ef5c667d6eb7a8db3adb (patch) | |
tree | 73b75bbe93cd15eb5a836b45837e465ff192c071 /src/plugins/styles | |
parent | 80515c811a4c455d7f2fb9ded751b2406b08d045 (diff) |
QMacStyle: QMdiSubWindow is now HITheme-free
There are a couple issues. Because the actual class for
the buttons returned by +[NSWindow standardWindowButton:
forStyleMask:] is private, we can't fully configure them
as we could with HITheme. Therefore, we don't get the
mouse hovered state and the zoom button will show the
fullscreen arrow instead of the '+' icon.
Hopefully, QMdiArea will go the way of the dodo soon
enough. It is not a thing on macOS and it has been
replaced by tabbed windows UI on most desktop apps.
Change-Id: Ia581f72611ad0224f42657afbc4d9f94bf5e5a3a
Reviewed-by: Jake Petroules <jake.petroules@qt.io>
Diffstat (limited to 'src/plugins/styles')
-rw-r--r-- | src/plugins/styles/mac/qmacstyle_mac.mm | 433 | ||||
-rw-r--r-- | src/plugins/styles/mac/qmacstyle_mac_p_p.h | 8 |
2 files changed, 213 insertions, 228 deletions
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index f4095cdf06..708ff13ca7 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -288,6 +288,10 @@ static const QColor mainWindowGradientEnd(200, 200, 200); static const int DisclosureOffset = 4; +static const qreal titleBarIconTitleSpacing = 5; +static const qreal titleBarTitleRightMargin = 12; +static const qreal titleBarButtonSpacing = 8; + // Tab bar colors // active: window is active // selected: tab is selected @@ -651,7 +655,6 @@ const int qt_mac_hitheme_version = 0; //the HITheme version we speak const int macItemFrame = 2; // menu item frame width const int macItemHMargin = 3; // menu item hor text margin const int macRightBorder = 12; // right border on mac -const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar. /***************************************************************************** QMacCGStyle utility functions @@ -1238,6 +1241,58 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int h p->restore(); } +QPainterPath QMacStylePrivate::windowPanelPath(const QRectF &r) const +{ + static const qreal CornerPointOffset = 5.5; + static const qreal CornerControlOffset = 2.1; + + QPainterPath path; + // Top-left corner + path.moveTo(r.left(), r.top() + CornerPointOffset); + path.cubicTo(r.left(), r.top() + CornerControlOffset, + r.left() + CornerControlOffset, r.top(), + r.left() + CornerPointOffset, r.top()); + // Top-right corner + path.lineTo(r.right() - CornerPointOffset, r.top()); + path.cubicTo(r.right() - CornerControlOffset, r.top(), + r.right(), r.top() + CornerControlOffset, + r.right(), r.top() + CornerPointOffset); + // Bottom-right corner + path.lineTo(r.right(), r.bottom() - CornerPointOffset); + path.cubicTo(r.right(), r.bottom() - CornerControlOffset, + r.right() - CornerControlOffset, r.bottom(), + r.right() - CornerPointOffset, r.bottom()); + // Bottom-right corner + path.lineTo(r.left() + CornerPointOffset, r.bottom()); + path.cubicTo(r.left() + CornerControlOffset, r.bottom(), + r.left(), r.bottom() - CornerControlOffset, + r.left(), r.bottom() - CornerPointOffset); + path.lineTo(r.left(), r.top() + CornerPointOffset); + + return path; +} + +QMacStylePrivate::CocoaControlType QMacStylePrivate::windowButtonCocoaControl(QStyle::SubControl sc) const +{ + struct WindowButtons { + QStyle::SubControl sc; + QMacStylePrivate::CocoaControlType ct; + }; + + static const WindowButtons buttons[] = { + { QStyle::SC_TitleBarCloseButton, QMacStylePrivate::Button_WindowClose }, + { QStyle::SC_TitleBarMinButton, QMacStylePrivate::Button_WindowMiniaturize }, + { QStyle::SC_TitleBarMaxButton, QMacStylePrivate::Button_WindowZoom } + }; + + for (const auto &wb : buttons) + if (wb.sc == sc) + return wb.ct; + + return NoControl; +} + + #if QT_CONFIG(tabbar) void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const { @@ -1891,6 +1946,37 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const case Button_RadioButton: bv = makeButton(NSRadioButton, NSRegularSquareBezelStyle); break; + case Button_WindowClose: + case Button_WindowMiniaturize: + case Button_WindowZoom: { + const NSWindowButton button = [=] { + switch (widget.first) { + case Button_WindowClose: + return NSWindowCloseButton; + case Button_WindowMiniaturize: + return NSWindowMiniaturizeButton; + case Button_WindowZoom: + return NSWindowZoomButton; + default: + break; + } + Q_UNREACHABLE(); + } (); +#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12) + const auto styleMask = NSWindowStyleMaskTitled + | NSWindowStyleMaskClosable + | NSWindowStyleMaskMiniaturizable + | NSWindowStyleMaskResizable; +#else + const auto styleMask = NSTitledWindowMask + | NSClosableWindowMask + | NSMiniaturizableWindowMask + | NSResizableWindowMask; +#endif + bv = [NSWindow standardWindowButton:button forStyleMask:styleMask]; + [bv retain]; + break; + } case ComboBox: bv = [[NSComboBox alloc] init]; break; @@ -2207,15 +2293,20 @@ void QMacStyle::unpolish(QApplication *) void QMacStyle::polish(QWidget* w) { + if (false #if QT_CONFIG(menu) - if (qobject_cast<QMenu*>(w) -#if QT_CONFIG(combobox) - || qobject_cast<QComboBoxPrivateContainer *>(w) + || qobject_cast<QMenu*>(w) +# if QT_CONFIG(combobox) + || qobject_cast<QComboBoxPrivateContainer *>(w) +# endif #endif - ) { +#if QT_CONFIG(mdiarea) + || qobject_cast<QMdiSubWindow *>(w) +#endif + ) { w->setAttribute(Qt::WA_TranslucentBackground, true); + w->setAutoFillBackground(false); } -#endif #if QT_CONFIG(tabbar) if (QTabBar *tb = qobject_cast<QTabBar*>(w)) { @@ -2893,19 +2984,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = true; break; case SH_WindowFrame_Mask: - ret = 1; - if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) { - mask->region = opt->rect; - mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1); - mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2); - - mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1); - mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1); - mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1); - mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2); - } + ret = false; break; case SH_TabBar_ElideMode: ret = Qt::ElideRight; @@ -3188,6 +3267,15 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai } break; case PE_FrameWindow: + if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) { + if (w && w->inherits("QMdiSubWindow")) { + p->save(); + p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth)); + p->setBrush(frame->palette.window()); + p->drawRect(frame->rect); + p->restore(); + } + } break; case PE_IndicatorDockWidgetResizeHandle: { // The docwidget resize handle is drawn as a one-pixel wide line. @@ -3476,31 +3564,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai p->setPen(Qt::transparent); p->setBrush(opt->palette.window()); p->setRenderHint(QPainter::Antialiasing, true); - QPainterPath path; - static const qreal CornerPointOffset = 5.5; - static const qreal CornerControlOffset = 2.1; - QRectF r = opt->rect; - // Top-left corner - path.moveTo(r.left(), r.top() + CornerPointOffset); - path.cubicTo(r.left(), r.top() + CornerControlOffset, - r.left() + CornerControlOffset, r.top(), - r.left() + CornerPointOffset, r.top()); - // Top-right corner - path.lineTo(r.right() - CornerPointOffset, r.top()); - path.cubicTo(r.right() - CornerControlOffset, r.top(), - r.right(), r.top() + CornerControlOffset, - r.right(), r.top() + CornerPointOffset); - // Bottom-right corner - path.lineTo(r.right(), r.bottom() - CornerPointOffset); - path.cubicTo(r.right(), r.bottom() - CornerControlOffset, - r.right() - CornerControlOffset, r.bottom(), - r.right() - CornerPointOffset, r.bottom()); - // Bottom-right corner - path.lineTo(r.left() + CornerPointOffset, r.bottom()); - path.cubicTo(r.left() + CornerControlOffset, r.bottom(), - r.left(), r.bottom() - CornerControlOffset, - r.left(), r.bottom() - CornerPointOffset); - path.lineTo(r.left(), r.top() + CornerPointOffset); + const QPainterPath path = d->windowPanelPath(opt->rect); p->drawPath(path); p->restore(); } break; @@ -5494,115 +5558,74 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex } break; case CC_TitleBar: - if (const QStyleOptionTitleBar *titlebar - = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { - if (titlebar->state & State_Active) { - if (titlebar->titleBarState & State_Active) - tds = kThemeStateActive; - else - tds = kThemeStateInactive; + if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { + const bool isActive = (titlebar->state & State_Active) + && (titlebar->titleBarState & State_Active); + + p->fillRect(opt->rect, Qt::transparent); + p->setRenderHint(QPainter::Antialiasing); + p->setClipRect(opt->rect, Qt::IntersectClip); + + // FIXME A single drawPath() with 0-sized pen + // doesn't look as good as this double fillPath(). + const auto outterFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height())); + QPainterPath outterFramePath = d->windowPanelPath(outterFrameRect); + p->fillPath(outterFramePath, opt->palette.dark()); + + const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF(); + const auto innerFrameRect = outterFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0); + QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect); + if (isActive) { + QLinearGradient g; + g.setStart(QPointF(0, 0)); + g.setFinalStop(QPointF(0, 2 * opt->rect.height())); + g.setColorAt(0, opt->palette.button().color()); + g.setColorAt(1, opt->palette.dark().color()); + p->fillPath(innerFramePath, g); } else { - tds = kThemeStateInactive; + p->fillPath(innerFramePath, opt->palette.button()); } - HIThemeWindowDrawInfo wdi; - wdi.version = qt_mac_hitheme_version; - wdi.state = tds; - wdi.windowType = QtWinType; - wdi.titleHeight = titlebar->rect.height(); - wdi.titleWidth = titlebar->rect.width(); - wdi.attributes = kThemeWindowHasTitleText; - // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty - // close button, so use HIThemeDrawWindowFrame instead. - if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton) - wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty; - - CGRect titleBarRect; - CGRect tmpRect = titlebar->rect.toCGRect(); - { - QCFType<HIShapeRef> titleRegion; - QRect newr = titlebar->rect.adjusted(0, 0, 2, 0); - HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion); - HIShapeGetBounds(titleRegion, &tmpRect); - newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y)); - titleBarRect = newr.toCGRect(); - } - HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0); if (titlebar->subControls & (SC_TitleBarCloseButton | SC_TitleBarMaxButton | SC_TitleBarMinButton | SC_TitleBarNormalButton)) { - HIThemeWindowWidgetDrawInfo wwdi; - wwdi.version = qt_mac_hitheme_version; - wwdi.widgetState = tds; - if (titlebar->state & State_MouseOver) - wwdi.widgetState = kThemeStateRollover; - wwdi.windowType = QtWinType; - wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox; - wwdi.windowState = wdi.state; - wwdi.titleHeight = wdi.titleHeight; - wwdi.titleWidth = wdi.titleWidth; - ThemeDrawState savedControlState = wwdi.widgetState; - uint sc = SC_TitleBarMinButton; - ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox; - bool active = titlebar->state & State_Active; - - while (sc <= SC_TitleBarCloseButton) { - if (sc & titlebar->subControls) { - uint tmp = sc; - wwdi.widgetState = savedControlState; - wwdi.widgetType = tbw; - if (sc == SC_TitleBarMinButton) - tmp |= SC_TitleBarNormalButton; - if (active && (titlebar->activeSubControls & tmp) - && (titlebar->state & State_Sunken)) - wwdi.widgetState = kThemeStatePressed; - // Draw all sub controllers except the dirty close button - // (it is already handled by HIThemeDrawWindowFrame). - if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) { - HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal); - p->paintEngine()->syncState(); - } - } - sc = sc << 1; - tbw = tbw >> 1; + const bool isHovered = (titlebar->state & State_MouseOver); + static const SubControl buttons[] = { + SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton + }; + for (const auto sc : buttons) { + const auto ct = d->windowButtonCocoaControl(sc); + const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge); + auto *wb = static_cast<NSButton *>(d->cocoaControl(cw)); + wb.enabled = (sc & titlebar->subControls); + [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)]; + Q_UNUSED(isHovered); // FIXME No public API for this + + const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget); + const auto drawBlock = ^ (CGContextRef ctx, const CGRect &rect) { + Q_UNUSED(ctx); + Q_UNUSED(rect); + auto *wbCell = static_cast<NSButtonCell *>(wb.cell); + [wbCell drawWithFrame:rect inView:wb]; + }; + d->drawNSViewInRect(cw, wb, buttonRect, p, widget != nullptr, drawBlock); } } - p->paintEngine()->syncState(); + if (titlebar->subControls & SC_TitleBarLabel) { - int iw = 0; + const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget); if (!titlebar->icon.isNull()) { - QCFType<HIShapeRef> titleRegion2; - HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn, - &titleRegion2); - HIShapeGetBounds(titleRegion2, &tmpRect); - if (tmpRect.size.width != 1) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width(); - } - } - if (!titlebar->text.isEmpty()) { - p->save(); - QCFType<HIShapeRef> titleRegion3; - HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3); - HIShapeGetBounds(titleRegion3, &tmpRect); - p->setClipRect(QRectF::fromCGRect(tmpRect).toRect()); - QRect br = p->clipRegion().boundingRect(); - int x = br.x(), - y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2); - if (br.width() <= (p->fontMetrics().horizontalAdvance(titlebar->text) + iw * 2)) - x += iw; - else - x += br.width() / 2 - p->fontMetrics().horizontalAdvance(titlebar->text) / 2; - if (iw) { - int iconExtent = proxy()->pixelMetric(PM_SmallIconSize); - p->drawPixmap(x - iw, y, - titlebar->icon.pixmap(window, QSize(iconExtent, iconExtent), QIcon::Normal)); - } - drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive, - titlebar->text, QPalette::Text); - p->restore(); + const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize); + const auto iconSize = QSize(iconExtent, iconExtent); + const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing); + // Only render the icon if it'll be fully visible + if (iconPos < tr.right() - titleBarIconTitleSpacing) + p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(window, iconSize, QIcon::Normal)); } + + if (!titlebar->text.isEmpty()) + drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text); } } break; @@ -5849,50 +5872,6 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, } } break; -/* - I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all. - It would be very nice if this would work. - case QStyle::CC_TitleBar: - if (const QStyleOptionTitleBar *tbar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { - HIThemeWindowDrawInfo wdi; - memset(&wdi, 0, sizeof(wdi)); - wdi.version = qt_mac_hitheme_version; - wdi.state = kThemeStateActive; - wdi.windowType = QtWinType; - wdi.titleWidth = tbar->rect.width(); - wdi.titleHeight = tbar->rect.height(); - if (tbar->titleBarState) - wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox - | kThemeWindowHasCollapseBox; - else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint) - wdi.attributes |= kThemeWindowHasCloseBox; - QRect tmpRect = tbar->rect; - tmpRect.setHeight(tmpRect.height() + 100); - CGRect cgRect = tmpRect.toCGRect(); - WindowRegionCode hit; - CGPoint hipt = CGPointMake(pt.x(), pt.y()); - if (HIThemeGetWindowRegionHit(&cgRect, &wdi, &hipt, &hit)) { - switch (hit) { - case kWindowCloseBoxRgn: - sc = QStyle::SC_TitleBarCloseButton; - break; - case kWindowCollapseBoxRgn: - sc = QStyle::SC_TitleBarMinButton; - break; - case kWindowZoomBoxRgn: - sc = QStyle::SC_TitleBarMaxButton; - break; - case kWindowTitleTextRgn: - sc = QStyle::SC_TitleBarLabel; - break; - default: - qDebug("got something else %d", hit); - break; - } - } - } - break; -*/ default: sc = QCommonStyle::hitTestComplexControl(cc, opt, pt, widget); break; @@ -5986,49 +5965,47 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op } break; case CC_TitleBar: - if (const QStyleOptionTitleBar *titlebar - = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { - HIThemeWindowDrawInfo wdi; - memset(&wdi, 0, sizeof(wdi)); - wdi.version = qt_mac_hitheme_version; - wdi.state = kThemeStateActive; - wdi.windowType = QtWinType; - wdi.titleHeight = titlebar->rect.height(); - wdi.titleWidth = titlebar->rect.width(); - wdi.attributes = kThemeWindowHasTitleText; - if (titlebar->subControls & SC_TitleBarCloseButton) - wdi.attributes |= kThemeWindowHasCloseBox; - if (titlebar->subControls & SC_TitleBarMaxButton - | SC_TitleBarNormalButton) - wdi.attributes |= kThemeWindowHasFullZoom; - if (titlebar->subControls & SC_TitleBarMinButton) - wdi.attributes |= kThemeWindowHasCollapseBox; - WindowRegionCode wrc = kWindowGlobalPortRgn; - - if (sc == SC_TitleBarCloseButton) - wrc = kWindowCloseBoxRgn; - else if (sc == SC_TitleBarMinButton) - wrc = kWindowCollapseBoxRgn; - else if (sc == SC_TitleBarMaxButton) - wrc = kWindowZoomBoxRgn; - else if (sc == SC_TitleBarLabel) - wrc = kWindowTitleTextRgn; - else if (sc == SC_TitleBarSysMenu) - ret.setRect(-1024, -1024, 10, proxy()->pixelMetric(PM_TitleBarHeight, - titlebar, widget)); - if (wrc != kWindowGlobalPortRgn) { - QCFType<HIShapeRef> region; - QRect tmpRect = titlebar->rect; - CGRect titleRect = tmpRect.toCGRect(); - HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, ®ion); - HIShapeGetBounds(region, &titleRect); - CFRelease(region); - tmpRect.translate(tmpRect.x() - int(titleRect.origin.x), - tmpRect.y() - int(titleRect.origin.y)); - titleRect = tmpRect.toCGRect(); - HIThemeGetWindowShape(&titleRect, &wdi, wrc, ®ion); - HIShapeGetBounds(region, &titleRect); - ret = QRectF::fromCGRect(titleRect).toRect(); + if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) { + // The title bar layout is as follows: close, min, zoom, icon, title + // [ x _ + @ Window Title ] + // Center the icon and title until it starts to overlap with the buttons. + // The icon doesn't count towards SC_TitleBarLabel, but it's still rendered + // next to the title text. See drawComplexControl(). + if (sc == SC_TitleBarLabel) { + qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1; // FIXME Rounding error? + qreal labelHeight = titlebar->fontMetrics.height(); + + const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget); + qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing; + if (!titlebar->icon.isNull()) { + const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize); + const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();; + controlsSpacing += actualIconSize + titleBarIconTitleSpacing; + } + + const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0); + labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin)); + ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2, + labelWidth, labelHeight); + } else { + const auto currentButton = d->windowButtonCocoaControl(sc); + if (currentButton == QMacStylePrivate::NoControl) + break; + + QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0); + QSizeF buttonSize; + for (int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) { + const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct), + QStyleHelper::SizeLarge); + auto *wb = static_cast<NSButton *>(d->cocoaControl(cw)); + if (ct == currentButton) + buttonSize = QSizeF::fromCGSize(wb.frame.size); + else + buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing; + } + + const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0; + ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect(); } } break; diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 8eee80ce50..cf2609e9ec 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -182,6 +182,7 @@ class QMacStylePrivate : public QCommonStylePrivate Q_DECLARE_PUBLIC(QMacStyle) public: enum CocoaControlType { + NoControl, // For when there's no such a control in Cocoa Box, // QGroupBox Button_CheckBox, Button_Disclosure, // Disclosure triangle, like in QTreeView @@ -189,6 +190,9 @@ public: Button_PullDown, // QPushButton with menu Button_PushButton, Button_RadioButton, + Button_WindowClose, + Button_WindowMiniaturize, + Button_WindowZoom, ComboBox, // Editable QComboBox ProgressIndicator_Determinate, ProgressIndicator_Indeterminate, @@ -272,6 +276,10 @@ public: void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius = 0) const; void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const; + QPainterPath windowPanelPath(const QRectF &r) const; + + CocoaControlType windowButtonCocoaControl(QStyle::SubControl sc) const; + #if QT_CONFIG(tabbar) void tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const; #endif |