3188 const QWidget *w)
const
3190 Q_D(
const QMacStyle);
3191 QMacCGContext cg(p);
3193 qCWarning(lcMacStyle) <<
"drawPrimitive:" << pe <<
"invalid (nullptr) graphics context";
3195 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
3196 d->resolveCurrentNSView(window);
3198 case PE_IndicatorArrowUp:
3199 case PE_IndicatorArrowDown:
3200 case PE_IndicatorArrowRight:
3201 case PE_IndicatorArrowLeft: {
3203 p->setRenderHint(QPainter::Antialiasing);
3204 const int xOffset = 1;
3205 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
3206 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
3207#if QT_CONFIG(toolbutton)
3208 if (
const QToolButton *tb = qobject_cast<
const QToolButton *>(w)) {
3210 if (tb->arrowType() != Qt::NoArrow
3211 || tb->popupMode() == QToolButton::MenuButtonPopup)
3212 halfSize -= penWidth;
3216 QTransform transform;
3217 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
3221 case PE_IndicatorArrowDown:
3223 case PE_IndicatorArrowUp:
3224 transform.rotate(180);
3226 case PE_IndicatorArrowLeft:
3227 transform.rotate(90);
3229 case PE_IndicatorArrowRight:
3230 transform.rotate(-90);
3233 p->setTransform(transform);
3235 path.moveTo(-halfSize, -halfSize * 0.5);
3236 path.lineTo(0.0, halfSize * 0.5);
3237 path.lineTo(halfSize, -halfSize * 0.5);
3239 const QPen arrowPen(opt->palette.text(), penWidth,
3240 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
3241 p->strokePath(path, arrowPen);
3244#if QT_CONFIG(tabbar)
3245 case PE_FrameTabBarBase:
3246 if (
const QStyleOptionTabBarBase *tbb
3247 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
3248 if (tbb->documentMode) {
3250 drawTabBase(p, tbb, w);
3254#if QT_CONFIG(tabwidget)
3255 QRegion region(tbb->rect);
3256 region -= tbb->tabBarRect.adjusted(3, 0, -3, 0);
3258 p->setClipRegion(region);
3259 QStyleOptionTabWidgetFrame twf;
3260 twf.QStyleOption::operator=(*tbb);
3261 twf.shape = tbb->shape;
3262 switch (QMacStylePrivate::tabDirection(twf.shape)) {
3263 case QMacStylePrivate::North:
3264 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
3266 case QMacStylePrivate::South:
3267 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3269 case QMacStylePrivate::West:
3270 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
3272 case QMacStylePrivate::East:
3273 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3276 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
3282 case PE_PanelTipLabel:
3283 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
3285 case PE_FrameGroupBox:
3286 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
3287 if (groupBox->features & QStyleOptionFrame::Flat) {
3288 QCommonStyle::drawPrimitive(pe, groupBox, p, w);
3291#if QT_CONFIG(tabwidget)
3293 case PE_FrameTabWidget:
3296 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
3297 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
3311 auto adjustedRect = opt->rect;
3312 bool needTranslation =
false;
3314 if (!qt_apple_runningWithLiquidGlass() && !
isDarkMode()) {
3327 adjustedRect.adjust(0, 0, 6, 6);
3328 needTranslation =
true;
3330 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3331#if QT_CONFIG(tabwidget)
3332 if (qobject_cast<QTabWidget *>(opt->styleObject))
3333 clipTabBarFrame(opt,
this, ctx);
3335 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
3336 CGContextScaleCTM(ctx, 1, -1);
3337 if ([box isMemberOfClass:QDarkNSBox.
class]) {
3338 [box drawRect:rect];
3340 if (needTranslation)
3341 CGContextTranslateCTM(ctx, -3.0, 5.0);
3342 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
3347 case PE_IndicatorToolBarSeparator: {
3349 if (opt->state & State_Horizontal) {
3350 int xpoint = opt->rect.center().x();
3351 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3352 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3354 int ypoint = opt->rect.center().y();
3355 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3356 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3358 QPainterPathStroker theStroker;
3359 theStroker.setCapStyle(Qt::FlatCap);
3360 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3361 path = theStroker.createStroke(path);
3362 const auto dark =
isDarkMode() ? opt->palette.dark().color().darker()
3363 : QColor(0, 0, 0, 119);
3364 p->fillPath(path, dark);
3367 case PE_FrameWindow:
3368 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3369 if (qobject_cast<
const QMdiSubWindow*>(w)) {
3371 p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
3372 p->setBrush(frame->palette.window());
3373 p->drawRect(frame->rect);
3378 case PE_IndicatorDockWidgetResizeHandle: {
3381 if (opt->state & State_Horizontal) {
3382 p->setPen(QColor(160, 160, 160));
3383 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3385 p->setPen(QColor(145, 145, 145));
3386 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3390 case PE_IndicatorToolBarHandle: {
3393 int x = opt->rect.x() + 6;
3394 int y = opt->rect.y() + 7;
3395 static const int RectHeight = 2;
3396 if (opt->state & State_Horizontal) {
3397 while (y < opt->rect.height() - RectHeight - 5) {
3399 path.addEllipse(x, y, RectHeight, RectHeight);
3403 while (x < opt->rect.width() - RectHeight - 5) {
3405 path.addEllipse(x, y, RectHeight, RectHeight);
3409 p->setPen(Qt::NoPen);
3410 QColor dark = opt->palette.dark().color().darker();
3411 dark.setAlphaF(0.50);
3412 p->fillPath(path, dark);
3417 case PE_IndicatorHeaderArrow:
3418 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3420 if (header->sortIndicator != QStyleOptionHeader::None)
3421 proxy()->drawPrimitive(
3422 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3423 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3426 case PE_IndicatorMenuCheckMark: {
3430 if (opt->state & State_On)
3431 pc = opt->palette.highlightedText().color();
3433 pc = opt->palette.text().color();
3435 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
3436 static_cast<CGFloat>(pc.greenF()),
3437 static_cast<CGFloat>(pc.blueF()),
3438 static_cast<CGFloat>(pc.alphaF()));
3444 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
3445 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
3446 kCTFontUIFontMenuItemMark;
3450 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
3451 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
3453 CGContextSaveGState(cg);
3454 CGContextSetShouldSmoothFonts(cg, NO);
3457 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
3458 (opt->state & State_Small) ? 1.0 :
3461 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
3462 CGContextScaleCTM(cg, 1, -1);
3464 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
3468 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
3469 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
3470 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
3471 static_assert((
sizeof(values) /
sizeof(values[0])) == numValues);
3472 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
3473 numValues, NULL, NULL);
3475 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
3476 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
3478 CTLineDraw((CTLineRef)line, cg);
3481 CGContextRestoreGState(cg);
3483 case PE_IndicatorItemViewItemCheck:
3484 case PE_IndicatorRadioButton:
3485 case PE_IndicatorCheckBox: {
3486 const bool isEnabled = opt->state & State_Enabled;
3487 const bool isPressed = opt->state & State_Sunken;
3488 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
3489 const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
3490 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3491 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3492 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
3493 tb.enabled = isEnabled;
3494 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
3495 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
3496 [tb highlight:isPressed];
3497 const auto vOffset = [=] {
3499 if (cs == QStyleHelper::SizeMini)
3500 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
3502 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
3504 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3505 CGContextTranslateCTM(ctx, 0, vOffset);
3506 [tb.cell drawInteriorWithFrame:rect inView:tb];
3509 case PE_FrameFocusRect:
3512 case PE_IndicatorBranch: {
3513 if (!(opt->state & State_Children))
3517 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
3518 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
3519 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
3520 bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
3521 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
3522 [triangleCell setUserInterfaceLayoutDirection:qt_macLayoutDirectionFromQt(opt->direction)];
3524 d->setupNSGraphicsContext(cg, NO);
3527 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
3528 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
3529 CGContextScaleCTM(cg, 1, -1);
3530 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
3532 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
3534 d->restoreNSGraphicsContext(cg);
3538 QPen oldPen = p->pen();
3539 p->setPen(opt->palette.base().color().darker(140));
3540 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3541 p->setPen(opt->palette.base().color().darker(180));
3542 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3546 case PE_FrameLineEdit:
3547 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3548 if (frame->state & State_Sunken) {
3549 const bool isEnabled = opt->state & State_Enabled;
3550 const bool isReadOnly = opt->state & State_ReadOnly;
3551 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
3552 const auto cs = d->effectiveAquaSizeConstrain(opt, w, CT_LineEdit);
3553 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
3554 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
3555 tf.enabled = isEnabled;
3556 tf.editable = !isReadOnly;
3557 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
3558 bool hasCustomBackground =
false;
3559 if (qt_apple_runningWithLiquidGlass()) {
3568 NSColor *sysColor = [NSColor.textBackgroundColor colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
3569 const QColor defaultColor = QColor::fromRgbF(sysColor.redComponent, sysColor.greenComponent,
3570 sysColor.blueComponent, sysColor.alphaComponent);
3571 hasCustomBackground = bgColor != defaultColor;
3574 if (hasCustomBackground) {
3578 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
3579 tf.frame = opt->rect.toCGRect();
3580 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3581 if (!isDarkMode() || hasCustomBackground) {
3588 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
3592 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
3593 tf.drawsBackground = YES;
3594 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
3595 green:bgColor.greenF()
3596 blue:bgColor.blueF()
3597 alpha:bgColor.alphaF()];
3598 if (bgColor.alpha() != 255) {
3605 CGRect fixedRect = rect;
3606 if (qt_apple_runningWithLiquidGlass()) {
3611 fixedRect = CGRectInset(rect, 1., 1.);
3613 [tf.cell drawWithFrame:fixedRect inView:tf];
3616 QCommonStyle::drawPrimitive(pe, opt, p, w);
3620 case PE_PanelLineEdit:
3622 const QStyleOptionFrame *panel = qstyleoption_cast<
const QStyleOptionFrame *>(opt);
3623 if (
isDarkMode() || (panel && panel->lineWidth <= 0)) {
3629 QCommonStyle::drawPrimitive(pe, opt, p, w);
3634 drawPrimitive(PE_FrameLineEdit, opt, p, w);
3640#if QT_CONFIG(lineedit)
3641 if ((opt->state & State_HasFocus) && !qobject_cast<
const QLineEdit*>(w)) {
3642 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3643 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3644 QStyleOptionFrame focusFrame = *panel;
3645 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3646 drawControl(CE_FocusFrame, &focusFrame, p, w);
3652 case PE_PanelScrollAreaCorner: {
3653 const QBrush brush(opt->palette.brush(QPalette::Base));
3654 p->fillRect(opt->rect, brush);
3655 p->setPen(QPen(QColor(217, 217, 217)));
3656 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3657 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3659 case PE_FrameStatusBarItem:
3661#if QT_CONFIG(tabbar)
3662 case PE_IndicatorTabClose: {
3664 QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
3665 const QWidget *closeBtn = w;
3669 tabBar = qobject_cast<QTabBar *>(
const_cast<QWidget*>(w));
3670 closeBtn =
decltype(closeBtn)(property(
"_q_styleSheetRealCloseButton").value<
void *>());
3673 const bool documentMode = tabBar->documentMode();
3674 const QTabBarPrivate *tabBarPrivate =
static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
3675 const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
3676 if (!documentMode ||
3677 (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
3678 (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
3679 const bool hover = (opt->state & State_MouseOver);
3680 const bool selected = (opt->state & State_Selected);
3681 const bool pressed = (opt->state & State_Sunken);
3682 drawTabCloseButton(p, hover, selected, pressed, documentMode);
3687 case PE_PanelStatusBar: {
3688 p->fillRect(opt->rect, opt->palette.window());
3691 if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
3692 p->setPen(titlebarSeparatorLineActive);
3694 p->setPen(titlebarSeparatorLineInactive);
3695 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3699 case PE_PanelMenu: {
3701 p->fillRect(opt->rect, Qt::transparent);
3702 p->setPen(Qt::transparent);
3703 p->setBrush(opt->palette.window());
3704 p->setRenderHint(QPainter::Antialiasing,
true);
3705 const QPainterPath path = d->windowPanelPath(opt->rect);
3711 QCommonStyle::drawPrimitive(pe, opt, p, w);
3752 const QWidget *w)
const
3754 Q_D(
const QMacStyle);
3755 const QMacAutoReleasePool pool;
3756 QMacCGContext cg(p);
3758 qCWarning(lcMacStyle) <<
"drawControl:" << ce <<
"invalid (nullptr) graphics context";
3760 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
3761 d->resolveCurrentNSView(window);
3763 case CE_HeaderSection:
3764 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3765 State flags = header->state;
3766 QRect ir = header->rect;
3770 bool noVerticalHeader =
true;
3771#if QT_CONFIG(tableview)
3773 if (
const QTableView *table = qobject_cast<
const QTableView *>(w->parentWidget()))
3774 noVerticalHeader = !table->verticalHeader()->isVisible();
3777 const bool drawLeftBorder = header->orientation == Qt::Vertical
3778 || header->position == QStyleOptionHeader::OnlyOneSection
3779 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3782 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
3783 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
3784 p->setPen(QPen(header->palette.dark(), 1.0));
3785 if (header->orientation == Qt::Horizontal)
3794 case CE_ToolButtonLabel:
3795 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
3796 QStyleOptionToolButton myTb = *tb;
3797 myTb.state &= ~State_AutoRaise;
3798#if QT_CONFIG(accessibility)
3799 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
3800 QRect cr = tb->rect;
3803 bool needText =
false;
3805 bool down = tb->state & (State_Sunken | State_On);
3807 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3808 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3814 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3815 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3816 if (tb->icon.isNull() && !tb->text.isEmpty())
3817 tbstyle = Qt::ToolButtonTextOnly;
3820 case Qt::ToolButtonTextOnly: {
3822 alignment = Qt::AlignCenter;
3824 case Qt::ToolButtonIconOnly:
3825 case Qt::ToolButtonTextBesideIcon:
3826 case Qt::ToolButtonTextUnderIcon: {
3828 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3830 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3832 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), p->device()->devicePixelRatio(),
3833 iconMode, iconState);
3836 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3838 QSizeF size = pixmap.deviceIndependentSize();
3839 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3840 pr.setHeight(size.height() + 6);
3841 cr.adjust(0, pr.bottom(), 0, -3);
3842 alignment |= Qt::AlignCenter;
3844 pr.setWidth(size.width() + 8);
3845 cr.adjust(pr.right(), 0, 0, 0);
3846 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3849 if (opt->state & State_Sunken) {
3850 pr.translate(shiftX, shiftY);
3851 pixmap = darkenPixmap(pixmap);
3853 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3861 QPalette pal = tb->palette;
3862 QPalette::ColorRole role = QPalette::NoRole;
3863 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3864 alignment |= Qt::TextHideMnemonic;
3866 cr.translate(shiftX, shiftY);
3867 if (tbstyle == Qt::ToolButtonTextOnly
3868 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3869 QPen pen = p->pen();
3870 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3871 light.setAlphaF(0.375f);
3873 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3875 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3876 pal = QApplication::palette(
"QMenu");
3877 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3878 role = QPalette::HighlightedText;
3881 proxy()->drawItemText(p, cr, alignment, pal,
3882 tb->state & State_Enabled, tb->text, role);
3885 QCommonStyle::drawControl(ce, &myTb, p, w);
3890 QCommonStyle::drawControl(ce, &myTb, p, w);
3894 case CE_ToolBoxTabShape:
3895 QCommonStyle::drawControl(ce, opt, p, w);
3897 case CE_PushButtonBevel:
3898 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3899 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3902 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3903 QCommonStyle::drawControl(ce, opt, p, w);
3907 const bool hasFocus = btn->state & State_HasFocus;
3908 const bool isActive = btn->state & State_Active;
3912 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3913 && isActive && hasFocus)
3914 d->autoDefaultButton = btn->styleObject;
3915 else if (d->autoDefaultButton == btn->styleObject)
3916 d->autoDefaultButton =
nullptr;
3918 const bool isEnabled = btn->state & State_Enabled;
3919 const bool isPressed = btn->state & State_Sunken;
3920 const bool isHighlighted = isActive &&
3921 ((btn->state & State_On)
3922 || (btn->features & QStyleOptionButton::DefaultButton)
3923 || (btn->features & QStyleOptionButton::AutoDefaultButton
3924 && d->autoDefaultButton == btn->styleObject));
3925 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3926 const auto ct = cocoaControlType(btn, w);
3927 const auto cs = d->effectiveAquaSizeConstrain(btn, w);
3928 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3929 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3933 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3934 pb.frame = frameRect.toCGRect();
3936 pb.enabled = isEnabled;
3941 [pb highlight:isPressed];
3944 if (cw.type == QMacStylePrivate::Button_SquareButton) {
3945 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3949 pb.keyEquivalent = isHighlighted ? @
"\r" : @
"";
3952 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3953 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3957 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3960 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3961 const auto ir = frameRect.toRect();
3962 int arrowYOffset = 0;
3967 arrowYOffset -= ir.top();
3968 if (cw.second == QStyleHelper::SizeSmall)
3972 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3974 QStyleOption arrowOpt = *opt;
3976 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
3980 case CE_PushButtonLabel:
3981 if (
const QStyleOptionButton *b = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3982 QStyleOptionButton btn(*b);
3987 const bool isEnabled = btn.state & State_Enabled;
3988 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3989 const bool hasIcon = !btn.icon.isNull();
3990 const bool hasText = !btn.text.isEmpty();
3991 const bool isActive = btn.state & State_Active;
3992 const bool isPressed = btn.state & State_Sunken;
3993 const bool isDefault = (btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
3994 || d->autoDefaultButton == btn.styleObject;
3998 const QRect oldRect = btn.rect;
4000 btn.rect = w->rect();
4001 const auto ct = cocoaControlType(&btn, w);
4004 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
4005 if (isPressed || (isActive && isEnabled && ((btn.state & State_On) || isDefault)))
4006 btn.palette.setColor(QPalette::ButtonText, Qt::white);
4010 if (!isDefault && !(btn.state & State_On)) {
4013 btn.palette.setColor(QPalette::ButtonText, Qt::black);
4017 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
4018 QCommonStyle::drawControl(ce, &btn, p, w);
4020 QRect freeContentRect = btn.rect;
4021 QRect textRect = itemTextRect(
4022 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
4024 if (ct == QMacStylePrivate::Button_SquareButton)
4025 textRect.moveTo(w ? 8 : 11, textRect.top());
4027 textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)])
4028 : 11, textRect.top());
4032 int contentW = textRect.width();
4034 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
4035 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
4036 if (mode == QIcon::Normal && btn.state & State_HasFocus)
4037 mode = QIcon::Active;
4039 QIcon::State state = QIcon::Off;
4040 if (btn.state & State_On)
4042 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
4043 QSizeF pixmapSize = pixmap.deviceIndependentSize();
4044 contentW += pixmapSize.width() + QMacStylePrivate::PushButtonContentPadding;
4045 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
4046 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapSize.height()) / 2;
4047 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapSize.width(), pixmapSize.height());
4048 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
4049 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
4050 int newOffset = iconDestRect.x() + iconDestRect.width()
4051 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
4052 textRect.adjust(newOffset, 0, newOffset, 0);
4056 textRect = visualRect(btn.direction, freeContentRect, textRect);
4057 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
4058 isEnabled, btn.text, QPalette::ButtonText);
4063#if QT_CONFIG(combobox)
4064 case CE_ComboBoxLabel:
4065 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4066 auto comboCopy = *cb;
4067 comboCopy.direction = Qt::LeftToRight;
4069 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
4073#if QT_CONFIG(tabbar)
4074 case CE_TabBarTabShape:
4075 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4076 if (tabOpt->documentMode) {
4078 bool isUnified =
false;
4080 QRect tabRect = tabOpt->rect;
4081 QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
4082 isUnified = isInMacUnifiedToolbarArea(w->window(), windowTabStart.y());
4085 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w);
4086 drawTabShape(p, tabOpt, isUnified, tabOverlap);
4115 const bool isActive = tabOpt->state & State_Active;
4116 const bool isEnabled = tabOpt->state & State_Enabled;
4117 const bool isPressed = tabOpt->state & State_Sunken;
4118 const bool isSelected = tabOpt->state & State_Selected;
4119 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
4120 const bool verticalTabs = tabDirection == QMacStylePrivate::East
4121 || tabDirection == QMacStylePrivate::West;
4123 QStyleOptionTab::TabPosition tp = tabOpt->position;
4124 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
4125 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
4126 if (tp == QStyleOptionTab::Beginning)
4127 tp = QStyleOptionTab::End;
4128 else if (tp == QStyleOptionTab::End)
4129 tp = QStyleOptionTab::Beginning;
4131 if (sp == QStyleOptionTab::NextIsSelected)
4132 sp = QStyleOptionTab::PreviousIsSelected;
4133 else if (sp == QStyleOptionTab::PreviousIsSelected)
4134 sp = QStyleOptionTab::NextIsSelected;
4143 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
4145 const bool needsInactiveHack = !isActive && isSelected;
4146 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
4147 QMacStylePrivate::Button_PushButton :
4148 QMacStylePrivate::Button_PopupButton;
4149 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
4150 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4151 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4154 if (tabDirection == QMacStylePrivate::East)
4156 const auto outerAdjust = isPopupButton ? 1 : 4;
4157 const auto innerAdjust = isPopupButton ? 20 : 10;
4158 QRectF frameRect = tabOpt->rect;
4160 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
4162 frameRect = frameRect.translated(0, vOffset);
4164 case QStyleOptionTab::Beginning:
4166 if (!isSelected && tabDirection == QMacStylePrivate::West)
4167 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
4169 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
4174 frameRect = frameRect.adjusted(0, 0, 1, 0);
4177 case QStyleOptionTab::Middle:
4178 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
4183 frameRect = frameRect.adjusted(-1, 0, 1, 0);
4186 case QStyleOptionTab::Moving:
4187 case QStyleOptionTab::End:
4189 if (isSelected || tabDirection == QMacStylePrivate::West)
4190 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
4192 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
4196 frameRect = frameRect.adjusted(-1, 0, 0, 0);
4199 case QStyleOptionTab::OnlyOneTab:
4200 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
4203 pb.frame = frameRect.toCGRect();
4205 if (!isPopupButton) {
4209 pb.buttonType = NSButtonTypePushOnPushOff;
4212 pb.enabled = isEnabled;
4213 [pb highlight:isPressed];
4215 pb.state = (isActive && isSelected) ? NSControlStateValueOn : NSControlStateValueOff;
4217 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
4218 CGContextClipToRect(ctx, opt->rect.toCGRect());
4219 if (!isSelected || needsInactiveHack) {
4221 if (!verticalTabs && tp == QStyleOptionTab::End) {
4222 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
4223 CGContextScaleCTM(ctx, -1, 1);
4224 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
4225 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
4226 CGContextTranslateCTM(ctx, 0, opt->rect.top());
4227 CGContextScaleCTM(ctx, 1, -1);
4228 CGContextTranslateCTM(ctx, 0, -frameRect.right());
4229 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
4230 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
4231 CGContextScaleCTM(ctx, 1, -1);
4232 CGContextTranslateCTM(ctx, 0, -frameRect.left());
4238 if (tabDirection == QMacStylePrivate::West) {
4239 CGContextTranslateCTM(ctx, 0, frameRect.right());
4240 CGContextRotateCTM(ctx, -M_PI_2);
4241 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
4242 }
else if (tabDirection == QMacStylePrivate::East) {
4243 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
4244 CGContextRotateCTM(ctx, M_PI_2);
4249 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
4250 NSPopUpButtonCell *pbCell = nil;
4252 if (isPopupButton) {
4256 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
4257 oldPosition = pbCell.arrowPosition;
4258 pbCell.arrowPosition = NSPopUpNoArrow;
4259 if (pb.state == NSControlStateValueOff) {
4261 rAdjusted.origin.x -= 3;
4262 rAdjusted.size.width += 6;
4263 if (tp == QStyleOptionTab::End)
4264 rAdjusted.origin.x -= 2;
4267 if (qt_apple_runningWithLiquidGlass()) {
4276 const CGFloat deltaW = 20.0;
4277 rAdjusted = CGContextGetClipBoundingBox(ctx);
4278 if (tp == QStyleOptionTab::Beginning) {
4283 rAdjusted.size.width += deltaW;
4285 if (tabDirection == QMacStylePrivate::West && isSelected && isActive) {
4289 rAdjusted.origin.x -= deltaW;
4291 }
else if (tp == QStyleOptionTab::Middle) {
4293 rAdjusted.origin.x -= deltaW;
4294 rAdjusted.size.width += deltaW * 2;
4295 }
else if (tp == QStyleOptionTab::End) {
4296 if (isSelected && isActive && tabDirection != QMacStylePrivate::West)
4297 rAdjusted.origin.x -= deltaW;
4298 rAdjusted.size.width += deltaW;
4302 [pb.cell drawBezelWithFrame:rAdjusted inView:pb.superview];
4305 pbCell.arrowPosition = oldPosition;
4308 if (needsInactiveHack) {
4310 const qreal pixelRatio = p->device()->devicePixelRatio();
4311 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
4312 tabPixmap.setDevicePixelRatio(pixelRatio);
4313 tabPixmap.fill(Qt::transparent);
4314 QPainter tabPainter(&tabPixmap);
4315 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
4316 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
4317 drawBezelBlock(ctx, r);
4322 const qreal inactiveGray = 0.898;
4323 const int inactiveGray8 = qRound(inactiveGray * 255.0);
4324 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
4325 for (
int l = 0; l < tabPixmap.height(); ++l) {
4326 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
4327 for (
int i = 0; i < tabPixmap.width(); ++i) {
4328 if (qAlpha(line[i]) == 255) {
4329 line[i] = inactiveGrayRGB;
4330 }
else if (qAlpha(line[i]) > 128) {
4331 const int g = qRound(inactiveGray * qRed(line[i]));
4332 line[i] = qRgba(g, g, g, qAlpha(line[i]));
4338 p->drawImage(opt->rect, tabPixmap);
4340 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
4343 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
4344 && tp != QStyleOptionTab::End
4345 && tp != QStyleOptionTab::OnlyOneTab) {
4346 static const QPen separatorPen(Qt::black, 1.0);
4348 p->setOpacity(isEnabled ? 0.105 : 0.06);
4349 p->setPen(separatorPen);
4350 if (tabDirection == QMacStylePrivate::West) {
4351 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
4352 opt->rect.right() - 0.5, opt->rect.bottom()));
4353 }
else if (tabDirection == QMacStylePrivate::East) {
4354 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
4355 opt->rect.right() - 0.5, opt->rect.bottom()));
4357 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
4358 opt->rect.right(), opt->rect.bottom() - 0.5));
4364 case CE_TabBarTabLabel:
4365 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4366 QStyleOptionTab myTab = *tab;
4367 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
4368 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
4369 const bool verticalTabs = tabDirection == QMacStylePrivate::East
4370 || tabDirection == QMacStylePrivate::West;
4376 const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value(
"QComboMenuItem");
4378 if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
4379 if (
const auto *tabBar = qobject_cast<
const QTabBar *>(w))
4380 if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
4381 myTab.palette.setColor(foregroundRole, Qt::white);
4383 if (myTab.documentMode && isDarkMode()) {
4384 if (
const auto *tabBar = qobject_cast<
const QTabBar *>(w)) {
4385 if (!tabBar->tabTextColor(myTab.tabIndex).isValid()) {
4386 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
4387 myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray);
4392 int heightOffset = 0;
4395 }
else if (nonDefaultFont) {
4396 if (p->fontMetrics().height() == myTab.rect.height())
4399 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4401 QCommonStyle::drawControl(ce, &myTab, p, w);
4405#if QT_CONFIG(dockwidget)
4406 case CE_DockWidgetTitle:
4407 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
4408 const bool isVertical = dwOpt->verticalTitleBar;
4409 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
4412 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
4414 p->translate(-effectiveRect.left(), -effectiveRect.top());
4418 p->fillRect(effectiveRect, opt->palette.window());
4421 p->setPen(opt->palette.dark().color());
4422 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
4424 if (!dwOpt->title.isEmpty()) {
4425 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt, w);
4427 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
4428 effectiveRect.top() + titleRect.left() - opt->rect.left(),
4432 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
4433 proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
4434 dwOpt->state & State_Enabled, text, QPalette::WindowText);
4440 case CE_FocusFrame: {
4441 const auto *ff = qobject_cast<
const QFocusFrame *>(w);
4442 const auto *ffw = ff ? ff->widget() :
nullptr;
4443 const auto ct = [=] {
4445 if (qobject_cast<
const QCheckBox*>(ffw))
4446 return QMacStylePrivate::Button_CheckBox;
4447 if (qobject_cast<
const QRadioButton*>(ffw))
4448 return QMacStylePrivate::Button_RadioButton;
4449 if (qobject_cast<
const QLineEdit*>(ffw) || qobject_cast<
const QTextEdit*>(ffw))
4450 return QMacStylePrivate::TextField;
4451 if (
const auto *pb = qobject_cast<
const QPushButton *>(ffw)) {
4453 auto sizePolicy = QStyleHelper::widgetSizePolicy(ffw, opt);
4454 if (sizePolicy == QStyleHelper::SizeDefault)
4455 sizePolicy = QStyleHelper::SizeLarge;
4457 || (pb->rect().height() != pushButtonDefaultHeight[sizePolicy])) {
4458 return QMacStylePrivate::Button_SquareButton;
4460 if (pb->menu() !=
nullptr)
4461 return QMacStylePrivate::Button_PullDown;
4462 return QMacStylePrivate::Button_PushButton;
4466 return QMacStylePrivate::Box;
4468 auto cs = QStyleHelper::widgetSizePolicy(ffw, opt);
4469 if (cs == QStyleHelper::SizeDefault)
4470 cs = QStyleHelper::SizeLarge;
4471 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, w);
4472 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w);
4473 d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
4475 case CE_MenuEmptyArea:
4477 if (qobject_cast<
const QAbstractItemView *>(w))
4478 proxy()->drawPrimitive(PE_PanelMenu, opt, p, w);
4482 case CE_MenuHMargin:
4483 case CE_MenuVMargin:
4484 case CE_MenuTearoff:
4485 case CE_MenuScroller:
4486 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4487 const bool active = mi->state & State_Selected;
4489 p->fillRect(mi->rect, mi->palette.highlight());
4491 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt, w);
4493 if (ce == CE_MenuTearoff) {
4494 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4495 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4496 mi->rect.x() + mi->rect.width() - 4,
4497 mi->rect.y() + mi->rect.height() / 2 - 1);
4498 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4499 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4500 mi->rect.x() + mi->rect.width() - 4,
4501 mi->rect.y() + mi->rect.height() / 2);
4502 }
else if (ce == CE_MenuScroller) {
4503 const QSize scrollerSize = QSize(10, 8);
4504 const int scrollerVOffset = 5;
4505 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
4506 const int right = left + scrollerSize.width();
4509 if (opt->state & State_DownArrow) {
4510 bottom = mi->rect.y() + scrollerVOffset;
4511 top = bottom + scrollerSize.height();
4513 bottom = mi->rect.bottom() - scrollerVOffset;
4514 top = bottom - scrollerSize.height();
4517 p->setRenderHint(QPainter::Antialiasing);
4519 path.moveTo(left, bottom);
4520 path.lineTo(right, bottom);
4521 path.lineTo((left + right) / 2, top);
4522 p->fillPath(path, opt->palette.buttonText());
4524 }
else if (ce != CE_MenuItem) {
4528 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4529 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
4530 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
4531 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
4535 const int maxpmw = mi->maxIconWidth;
4536 const bool enabled = mi->state & State_Enabled;
4538 int xpos = mi->rect.x() + 18;
4539 int checkcol = maxpmw;
4541 p->setPen(mi->palette.text().color());
4543 p->setPen(mi->palette.highlightedText().color());
4545 p->setPen(mi->palette.buttonText().color());
4548 QStyleOption checkmarkOpt;
4549 checkmarkOpt.initFrom(w);
4554 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
4556 checkmarkOpt.state.setFlag(State_On, active);
4557 checkmarkOpt.state.setFlag(State_Enabled, enabled);
4558 if (widgetSize == QStyleHelper::SizeMini)
4559 checkmarkOpt.state |= State_Mini;
4560 else if (widgetSize == QStyleHelper::SizeSmall)
4561 checkmarkOpt.state |= State_Small;
4564 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
4565 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
4567 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w);
4569 if (!mi->icon.isNull()) {
4570 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4573 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4574 QSize iconSize(smallIconSize, smallIconSize);
4575#if QT_CONFIG(combobox)
4576 if (
const QComboBox *comboBox = qobject_cast<
const QComboBox *>(w)) {
4577 iconSize = comboBox->iconSize();
4580 QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
4581 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
4582 QSize size = pixmap.deviceIndependentSize().toSize();
4583 QRect pmr(QPoint(0, 0), size);
4584 pmr.moveCenter(cr.center());
4585 p->drawPixmap(pmr.topLeft(), pixmap);
4586 xpos += size.width() + 6;
4589 QString s = mi->text;
4590 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
4591 | Qt::TextSingleLine | Qt::AlignAbsolute;
4592 int yPos = mi->rect.y();
4593 if (widgetSize == QStyleHelper::SizeMini)
4596 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
4597 const int tabwidth = isSubMenu ? 9 : mi->reservedShortcutWidth;
4599 QString rightMarginText;
4601 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
4604 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
4605 if (tabIndex >= 0) {
4607 rightMarginText = s.mid(tabIndex + 1);
4608 s = s.left(tabIndex);
4612 if (!rightMarginText.isEmpty()) {
4613 p->setFont(qt_app_fonts_hash()->value(
"QMenuItem", p->font()));
4616 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
4620 const QKeySequence seq = QKeySequence::fromString(rightMarginText, QKeySequence::NativeText);
4621 if (seq.count() == 1) {
4623 const int maxKeyWidth = p->fontMetrics().maxWidth();
4624 const QChar key = rightMarginText.at(rightMarginText.length() - 1);
4625 const QString modifiers = rightMarginText.left(rightMarginText.size() - 1);
4626 p->drawText(xp + tabwidth - maxKeyWidth, yPos, maxKeyWidth, mi->rect.height(), text_flags, key);
4628 p->drawText(xp, yPos, tabwidth - maxKeyWidth, mi->rect.height(),
4629 text_flags | Qt::AlignRight | Qt::TextDontClip, modifiers);
4631 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, rightMarginText);
4638 QFont myFont = mi->font;
4644 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4649 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
4650 Q_ASSERT(fontEngine);
4651 if (fontEngine->type() == QFontEngine::Multi) {
4652 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
4653 Q_ASSERT(fontEngine);
4655 if (fontEngine->type() == QFontEngine::Mac) {
4656 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
4659 const auto pc = p->pen().color();
4660 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
4665 s = qt_mac_removeMnemonics(s);
4667 QMacCGContext cgCtx(p);
4668 d->setupNSGraphicsContext(cgCtx, YES);
4674 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
4675 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
4676 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0],
4677 NSUnderlineStyleAttributeName: [NSNumber numberWithInt: myFont.underline() ? NSUnderlineStyleSingle
4678 : NSUnderlineStyleNone],
4679 NSStrikethroughStyleAttributeName: [NSNumber numberWithInt: myFont.strikeOut() ? NSUnderlineStyleSingle
4680 : NSUnderlineStyleNone]}];
4682 d->restoreNSGraphicsContext(cgCtx);
4685 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
4686 mi->rect.height(), text_flags, s);
4692 case CE_MenuBarItem:
4693 case CE_MenuBarEmptyArea:
4694 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4695 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
4696 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
4697 p->fillRect(mi->rect, bg);
4699 if (ce != CE_MenuBarItem)
4702 if (!mi->icon.isNull()) {
4703 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4704 drawItemPixmap(p, mi->rect,
4705 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4706 | Qt::TextSingleLine,
4707 mi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(),
4708 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4710 drawItemText(p, mi->rect,
4711 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4712 | Qt::TextSingleLine,
4713 mi->palette, mi->state & State_Enabled,
4714 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
4718 case CE_ProgressBarLabel:
4719 case CE_ProgressBarGroove:
4722 case CE_ProgressBarContents:
4723 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4724 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4725 const bool vertical = !(pb->state & QStyle::State_Horizontal);
4726 const bool inverted = pb->invertedAppearance;
4727 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4730 QRect rect = pb->rect;
4732 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w);
4733 const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
4734 if (isIndeterminate) {
4742 if (!animation && opt->styleObject) {
4743 auto *animation =
new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
4745 animation->setFrameRate(QStyleAnimation::FifteenFps);
4746 d->startAnimation(animation);
4749 if (qt_apple_runningWithLiquidGlass()) {
4750 d->drawProgressBar(p, pb);
4753 rect = rect.transposed();
4754 d->setupNSGraphicsContext(cg, NO);
4755 d->setupVerticalInvertedXform(cg, reverse, vertical, rect.toCGRect());
4757 =
static_cast<QIndeterminateProgressIndicator *>(
4758 d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }))) {
4759 [ipi startAnimation];
4760 [ipi drawWithFrame:rect.toCGRect() inView:d->backingStoreNSView];
4762 d->restoreNSGraphicsContext(cg);
4766 d->stopAnimation(opt->styleObject);
4768 =
static_cast<QIndeterminateProgressIndicator *>(
4769 d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize })))
4770 [ipi stopAnimation];
4772 if (qt_apple_runningWithLiquidGlass()) {
4773 d->drawProgressBar(p, pb);
4776 rect = rect.transposed();
4777 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
4778 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
4779 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &cgrect) {
4780 d->setupVerticalInvertedXform(ctx, reverse, vertical, cgrect);
4781 pi.minValue = pb->minimum;
4782 pi.maxValue = pb->maximum;
4783 pi.doubleValue = pb->progress;
4784 [pi drawRect:cgrect]; });
4791#ifndef QT_NO_MDIAREA
4792 if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
4796 if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
4797 p->fillRect(opt->rect, opt->palette.window());
4799 QPen lineColor = QColor(82, 82, 82, 192);
4800 lineColor.setWidth(1);
4802 p->setRenderHint(QPainter::Antialiasing);
4803 p->setPen(lineColor);
4804 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4805 const int NumLines = 3;
4806 for (
int l = 0; l < NumLines; ++l) {
4807 const int offset = (l * 4 + 3);
4809 if (layoutDirection == Qt::LeftToRight) {
4810 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4811 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4813 start = QPoint(offset, opt->rect.height() - 1);
4814 end = QPoint(1, opt->rect.height() - offset);
4816 p->drawLine(start, end);
4822 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
4823 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
4825 const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
4826 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4827 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
4828 sv.frame = opt->rect.toCGRect();
4829 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
4830 [sv drawDividerInRect:rect];
4833 QPen oldPen = p->pen();
4834 p->setPen(opt->palette.dark().color());
4835 if (opt->state & QStyle::State_Horizontal)
4836 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4838 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4843 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
4844 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4845 if (!rubber->opaque) {
4848 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4849 fillColor.setHsvF(0, 0, 0.53, 0.25);
4850 if (opt->rect.width() * opt->rect.height() <= 3) {
4851 p->fillRect(opt->rect, strokeColor);
4853 QPen oldPen = p->pen();
4854 QBrush oldBrush = p->brush();
4855 QPen pen(strokeColor);
4857 p->setBrush(fillColor);
4858 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
4859 if (adjusted.isValid())
4860 p->drawRect(adjusted);
4862 p->setBrush(oldBrush);
4865 p->fillRect(opt->rect, fillColor);
4869#ifndef QT_NO_TOOLBAR
4871 const QStyleOptionToolBar *toolBar = qstyleoption_cast<
const QStyleOptionToolBar *>(opt);
4873 const QColor separatorColor = darkMode ? darkModeSeparatorLine : opt->palette.dark().color();
4880#if QT_CONFIG(mainwindow)
4881 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4882 if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
4885 p->setCompositionMode(QPainter::CompositionMode_Source);
4886 p->fillRect(opt->rect, Qt::transparent);
4893 const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
4894 const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window(), windowToolbarEnd.y() + 1);
4895 if (isEndOfUnifiedArea) {
4896 const int margin = qt_mac_aqua_get_metric(SeparatorSize);
4897 const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
4898 p->fillRect(separatorRect, separatorColor);
4906 p->fillRect(opt->rect, opt->palette.window());
4909 p->setPen(separatorColor);
4910 QRect toolbarRect = darkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
4911 if (opt->state & State_Horizontal) {
4912 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
4913 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
4915 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
4916 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
4924 QCommonStyle::drawControl(ce, opt, p, w);
4939 const QWidget *widget)
const
4941 Q_D(
const QMacStyle);
4943 const int controlSize = getControlSize(opt, widget);
4946#if QT_CONFIG(itemviews)
4947 case SE_ItemViewItemText:
4948 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
4949 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget);
4951 rect = QCommonStyle::subElementRect(sr, opt, widget);
4952 if (vopt->features & QStyleOptionViewItem::HasDecoration)
4953 rect.adjust(-fw, 0, 0, 0);
4957 case SE_ToolBoxTabContents:
4958 rect = QCommonStyle::subElementRect(sr, opt, widget);
4960 case SE_PushButtonBevel:
4961 case SE_PushButtonContents:
4962 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4971 const auto ct = cocoaControlType(btn, widget);
4972 const auto cs = d->effectiveAquaSizeConstrain(btn, widget);
4973 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4974 auto frameRect = cw.adjustedControlFrame(btn->rect);
4975 if (sr == SE_PushButtonContents) {
4976 frameRect -= cw.titleMargins();
4977 }
else if (cw.type != QMacStylePrivate::Button_SquareButton) {
4978 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4979 frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:frameRect.toCGRect()]);
4980 if (cw.type == QMacStylePrivate::Button_PushButton)
4981 frameRect -= pushButtonShadowMargins[cw.size];
4982 else if (cw.type == QMacStylePrivate::Button_PullDown)
4983 frameRect -= pullDownButtonShadowMargins[cw.size];
4985 rect = frameRect.toRect();
4988 case SE_HeaderLabel: {
4989 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
4990 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
4991 opt->rect.width() - margin * 2, opt->rect.height() - 2);
4992 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
4994 if (header->sortIndicator != QStyleOptionHeader::None) {
4995 if (opt->state & State_Horizontal)
5001 rect = visualRect(opt->direction, opt->rect, rect);
5004 case SE_HeaderArrow: {
5005 int h = opt->rect.height();
5006 int w = opt->rect.width();
5007 int x = opt->rect.x();
5008 int y = opt->rect.y();
5009 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
5011 if (opt->state & State_Horizontal) {
5018 rect = visualRect(opt->direction, opt->rect, rect);
5021 case SE_ProgressBarGroove:
5025 case SE_ProgressBarLabel:
5027 case SE_ProgressBarContents:
5030 case SE_TreeViewDisclosureItem: {
5036#if QT_CONFIG(tabwidget)
5037 case SE_TabWidgetLeftCorner:
5038 if (
const QStyleOptionTabWidgetFrame *twf
5039 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5040 switch (twf->shape) {
5041 case QTabBar::RoundedNorth:
5042 case QTabBar::TriangularNorth:
5043 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
5045 case QTabBar::RoundedSouth:
5046 case QTabBar::TriangularSouth:
5047 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
5048 twf->leftCornerWidgetSize);
5053 rect = visualRect(twf->direction, twf->rect, rect);
5056 case SE_TabWidgetRightCorner:
5057 if (
const QStyleOptionTabWidgetFrame *twf
5058 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5059 switch (twf->shape) {
5060 case QTabBar::RoundedNorth:
5061 case QTabBar::TriangularNorth:
5062 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
5063 twf->rightCornerWidgetSize);
5065 case QTabBar::RoundedSouth:
5066 case QTabBar::TriangularSouth:
5067 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
5068 twf->rect.height() - twf->rightCornerWidgetSize.height()),
5069 twf->rightCornerWidgetSize);
5074 rect = visualRect(twf->direction, twf->rect, rect);
5077 case SE_TabWidgetTabContents:
5078 rect = QCommonStyle::subElementRect(sr, opt, widget);
5079 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5080 if (twf->lineWidth != 0) {
5081 switch (QMacStylePrivate::tabDirection(twf->shape)) {
5082 case QMacStylePrivate::North:
5083 rect.adjust(+1, +14, -1, -1);
5085 case QMacStylePrivate::South:
5086 rect.adjust(+1, +1, -1, -14);
5088 case QMacStylePrivate::West:
5089 rect.adjust(+14, +1, -1, -1);
5091 case QMacStylePrivate::East:
5092 rect.adjust(+1, +1, -14, -1);
5097 case SE_TabBarTabText:
5098 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5099 QRect dummyIconRect;
5100 d->tabLayout(tab, widget, &rect, &dummyIconRect);
5103 case SE_TabBarTabLeftButton:
5104 case SE_TabBarTabRightButton:
5105 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5106 bool selected = tab->state & State_Selected;
5107 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget);
5108 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget);
5111 bool verticalTabs = tab->shape == QTabBar::RoundedEast
5112 || tab->shape == QTabBar::RoundedWest
5113 || tab->shape == QTabBar::TriangularEast
5114 || tab->shape == QTabBar::TriangularWest;
5116 QRect tr = tab->rect;
5117 if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
5118 verticalShift = -verticalShift;
5120 qSwap(horizontalShift, verticalShift);
5121 horizontalShift *= -1;
5122 verticalShift *= -1;
5124 if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
5125 horizontalShift = -horizontalShift;
5127 tr.adjust(0, 0, horizontalShift, verticalShift);
5130 tr.setBottom(tr.bottom() - verticalShift);
5131 tr.setRight(tr.right() - horizontalShift);
5134 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
5135 int w = size.width();
5136 int h = size.height();
5137 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
5138 int midWidth = ((tr.width() - w) / 2);
5140 bool atTheTop =
true;
5141 switch (tab->shape) {
5142 case QTabBar::RoundedWest:
5143 case QTabBar::TriangularWest:
5144 atTheTop = (sr == SE_TabBarTabLeftButton);
5146 case QTabBar::RoundedEast:
5147 case QTabBar::TriangularEast:
5148 atTheTop = (sr == SE_TabBarTabRightButton);
5151 if (sr == SE_TabBarTabLeftButton)
5152 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
5154 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
5155 rect = visualRect(tab->direction, tab->rect, rect);
5159 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
5161 rect = QRect(midWidth, tr.y() + hpadding, w, h);
5166 case SE_LineEditContents:
5167 rect = QCommonStyle::subElementRect(sr, opt, widget);
5168#if QT_CONFIG(combobox)
5169 if (widget && qobject_cast<
const QComboBox*>(widget->parentWidget()))
5170 rect.adjust(-1, -2, 0, 0);
5173 rect.adjust(-1, -1, 0, +1);
5175 case SE_CheckBoxLayoutItem:
5177 if (controlSize == QStyleHelper::SizeLarge) {
5178 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
5179 }
else if (controlSize == QStyleHelper::SizeSmall) {
5180 setLayoutItemMargins(+1, +5, 0 , -6, &rect, opt->direction);
5182 setLayoutItemMargins(0, +7, 0 , -6, &rect, opt->direction);
5185 case SE_ComboBoxLayoutItem:
5186#ifndef QT_NO_TOOLBAR
5187 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5196 if (controlSize == QStyleHelper::SizeLarge) {
5197 rect.adjust(+3, +2, -3, -4);
5198 }
else if (controlSize == QStyleHelper::SizeSmall) {
5199 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
5201 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
5205 case SE_LabelLayoutItem:
5207 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
5209 case SE_ProgressBarLayoutItem: {
5211 int bottom =
SIZE(3, 8, 8);
5212 if (opt->state & State_Horizontal) {
5213 rect.adjust(0, +1, 0, -bottom);
5215 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
5219 case SE_PushButtonLayoutItem:
5220 if (
const QStyleOptionButton *buttonOpt
5221 = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
5222 if ((buttonOpt->features & QStyleOptionButton::Flat))
5224 if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) {
5226 if (controlSize == QStyleHelper::SizeLarge)
5227 rect.adjust(+6, +4, -6, -8);
5228 else if (controlSize == QStyleHelper::SizeSmall)
5229 rect.adjust(+5, +4, -5, -6);
5231 rect.adjust(+1, 0, -1, -2);
5236 if (controlSize == QStyleHelper::SizeLarge) {
5237 rect.adjust(0, +4, 0, -8);
5238 }
else if (controlSize == QStyleHelper::SizeSmall) {
5239 rect.adjust(0, +4, 0, -6);
5241 rect.adjust(0, 0, 0, -2);
5244 case SE_RadioButtonLayoutItem:
5246 if (controlSize == QStyleHelper::SizeLarge) {
5247 setLayoutItemMargins(+2, +2 ,
5248 0, -4 , &rect, opt->direction);
5249 }
else if (controlSize == QStyleHelper::SizeSmall) {
5250 rect.adjust(0, +6, 0 , -5);
5252 rect.adjust(0, +6, 0 , -7);
5255 case SE_SliderLayoutItem:
5256 if (
const QStyleOptionSlider *sliderOpt
5257 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5259 if (sliderOpt->tickPosition == QSlider::NoTicks) {
5260 int above =
SIZE(3, 0, 2);
5261 int below =
SIZE(4, 3, 0);
5262 if (sliderOpt->orientation == Qt::Horizontal) {
5263 rect.adjust(0, +above, 0, -below);
5265 rect.adjust(+above, 0, -below, 0);
5267 }
else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
5268 int below =
SIZE(3, 2, 0);
5269 if (sliderOpt->orientation == Qt::Horizontal) {
5270 rect.setHeight(rect.height() - below);
5272 rect.setWidth(rect.width() - below);
5274 }
else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
5275 int above =
SIZE(3, 2, 0);
5276 if (sliderOpt->orientation == Qt::Horizontal) {
5277 rect.setTop(rect.top() + above);
5279 rect.setLeft(rect.left() + above);
5284 case SE_FrameLayoutItem:
5286 if (
const QFrame *frame = qobject_cast<
const QFrame *>(widget)) {
5288 switch (frame->frameStyle() & QFrame::Shape_Mask) {
5290 rect.adjust(0, +1, 0, -1);
5293 rect.adjust(+1, 0, -1, 0);
5300 case SE_GroupBoxLayoutItem:
5302 if (
const QStyleOptionGroupBox *groupBoxOpt =
5303 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5305
5306
5307
5308
5309 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
5310 | QStyle::SC_GroupBoxLabel)) {
5312 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
5313 delta =
SIZE(8, 4, 4);
5315 delta =
SIZE(15, 12, 12);
5317 rect.setTop(rect.top() + delta);
5320 rect.setBottom(rect.bottom() - 1);
5322#if QT_CONFIG(tabwidget)
5323 case SE_TabWidgetLayoutItem:
5324 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
5325 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5327
5328
5329
5330
5331 rect = tabWidgetOpt->rect;
5332 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
5333 rect.setTop(rect.top() + SIZE(6 , 3 , 2 ));
5337#if QT_CONFIG(dockwidget)
5338 case SE_DockWidgetCloseButton:
5339 case SE_DockWidgetFloatButton:
5340 case SE_DockWidgetTitleBarText:
5341 case SE_DockWidgetIcon: {
5342 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
5343 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget);
5344 QRect srect = opt->rect;
5346 const QStyleOptionDockWidget *dwOpt
5347 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
5348 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
5349 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
5351 const bool verticalTitleBar = dwOpt->verticalTitleBar;
5355 if (verticalTitleBar)
5356 srect = srect.transposed();
5359 int right = srect.right();
5360 int left = srect.left();
5364 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
5365 opt, widget).actualSize(QSize(iconSize, iconSize));
5366 sz += QSize(buttonMargin, buttonMargin);
5367 if (verticalTitleBar)
5368 sz = sz.transposed();
5369 closeRect = QRect(left,
5370 srect.center().y() - sz.height()/2,
5371 sz.width(), sz.height());
5372 left = closeRect.right() + 1;
5374 if (sr == SE_DockWidgetCloseButton) {
5381 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
5382 opt, widget).actualSize(QSize(iconSize, iconSize));
5383 sz += QSize(buttonMargin, buttonMargin);
5384 if (verticalTitleBar)
5385 sz = sz.transposed();
5386 floatRect = QRect(left,
5387 srect.center().y() - sz.height()/2,
5388 sz.width(), sz.height());
5389 left = floatRect.right() + 1;
5391 if (sr == SE_DockWidgetFloatButton) {
5397 if (
const QDockWidget *dw = qobject_cast<
const QDockWidget*>(widget)) {
5399 if (dw->isFloating())
5400 icon = dw->windowIcon();
5402 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
5403 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
5404 if (verticalTitleBar)
5405 sz = sz.transposed();
5406 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
5407 sz.width(), sz.height());
5408 right = iconRect.left() - 1;
5411 if (sr == SE_DockWidgetIcon) {
5416 QRect textRect = QRect(left, srect.top(),
5417 right - left, srect.height());
5418 if (sr == SE_DockWidgetTitleBarText) {
5424 if (verticalTitleBar) {
5425 rect = QRect(srect.left() + rect.top() - srect.top(),
5426 srect.top() + srect.right() - rect.right(),
5427 rect.height(), rect.width());
5429 rect = visualRect(opt->direction, srect, rect);
5435 rect = QCommonStyle::subElementRect(sr, opt, widget);
5468 const QWidget *widget)
const
5470 Q_D(
const QMacStyle);
5471 QMacCGContext cg(p);
5473 qCWarning(lcMacStyle) <<
"drawComplexControl:" << cc <<
"invalid (nullptr) graphics context";
5474 QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
nullptr;
5475 d->resolveCurrentNSView(window);
5478 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5481 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
5482 const bool drawKnob = sb->subControls & SC_ScrollBarSlider && sb->minimum != sb->maximum;
5483 if (!drawTrack && !drawKnob)
5486 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5488 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
5489 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
5491 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
5492 static const CGFloat expandedKnobWidths[] = { 11.0, 9.0, 9.0 };
5493 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt, widget);
5494 const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
5496 const QStyle *realStyle = widget ? widget->style() : proxy();
5497 const bool isTransient = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget);
5499 d->stopAnimation(opt->styleObject);
5500 bool wasActive =
false;
5501 CGFloat opacity = 0.0;
5502 CGFloat expandScale = 1.0;
5503 CGFloat expandOffset = 0.0;
5504 bool shouldExpand =
false;
5506 if (QObject *styleObject = opt->styleObject) {
5507 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
5508 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
5509 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
5510 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
5511 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
5512 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
5516 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
5519 oldPos != sb->sliderPosition ||
5520 oldMin != sb->minimum ||
5521 oldMax != sb->maximum ||
5522 oldRect != sb->rect ||
5523 oldState != sb->state ||
5524 oldActiveControls != sb->activeSubControls) {
5530 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
5531 styleObject->setProperty(
"_q_stylemin", sb->minimum);
5532 styleObject->setProperty(
"_q_stylemax", sb->maximum);
5533 styleObject->setProperty(
"_q_stylerect", sb->rect);
5534 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
5535 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
5537 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5540 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
5541 d->startAnimation(anim);
5542 }
else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5545 anim->setCurrentTime(0);
5547 }
else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5548 d->stopAnimation(styleObject);
5552 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5553 if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5556 if (oldActiveControls)
5557 anim->setActive(
true);
5559 wasActive = anim->wasActive();
5560 opacity = anim->currentValue();
5563 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
5565 if (!anim && !oldActiveControls) {
5567 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
5568 d->startAnimation(anim);
5570 if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
5571 expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
5572 expandOffset = 5.5 * (1.0 - anim->currentValue());
5575 expandScale = maxExpandScale;
5581 d->setupNSGraphicsContext(cg, NO );
5583 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5584 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
5585 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5587 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget);
5588 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
5592 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
5594 scroller.knobStyle = NSScrollerKnobStyleDefault;
5597 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
5599 if (!setupScroller(scroller, sb))
5603 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
5604 CGContextSetAlpha(cg, opacity);
5609 if (!isTransient || opt->activeSubControls || wasActive) {
5610 CGRect trackRect = scroller.bounds;
5612 trackRect.origin.y += expandOffset;
5614 trackRect.origin.x += expandOffset;
5615 [scroller drawKnobSlotInRect:trackRect highlight:NO];
5625 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
5626 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
5628 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
5629 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
5630 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
5631 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
5632 const CGFloat knobRadius = knobWidth / 2.0;
5635 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
5637 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
5638 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
5639 CGContextAddPath(cg, knobPath);
5640 CGContextSetAlpha(cg, 0.5);
5641 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
5642 CGContextSetFillColorWithColor(cg, knobColor);
5643 CGContextFillPath(cg);
5645 [scroller drawKnob];
5647 if (!isTransient && opt->activeSubControls) {
5652 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
5653 [scroller drawKnob];
5659 CGContextEndTransparencyLayer(cg);
5661 d->restoreNSGraphicsContext(cg);
5665 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5666 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5667 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5668 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5669 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5670 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5671 if (!setupSlider(slider, sl))
5674 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5675 const bool hasDoubleTicks = sl->tickPosition == QSlider::TicksBothSides;
5676 const bool drawKnob = sl->subControls & SC_SliderHandle;
5677 const bool drawBar = sl->subControls & SC_SliderGroove;
5678 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
5679 const bool isPressed = qt_apple_runningWithLiquidGlass() ?
false : sl->state & State_Sunken;
5683 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
5684 pressPoint.x = CGRectGetMidX(knobRect);
5685 pressPoint.y = CGRectGetMidY(knobRect);
5700 [slider.cell startTrackingAt:pressPoint inView:slider];
5701 [slider.cell startTrackingAt:pressPoint inView:slider];
5704 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
5707 const bool verticalFlip = !isHorizontal && !sl->upsideDown;
5710 if (sl->upsideDown) {
5711 CGContextTranslateCTM(ctx, rect.size.width, rect.origin.y);
5712 CGContextScaleCTM(ctx, -1, 1);
5714 CGContextTranslateCTM(ctx, 0, rect.origin.y);
5716 }
else if (verticalFlip) {
5717 CGContextTranslateCTM(ctx, rect.origin.x, rect.size.height);
5718 CGContextScaleCTM(ctx, 1, -1);
5721 if (hasDoubleTicks) {
5724 CGContextTranslateCTM(ctx, 0, 4);
5726 CGContextTranslateCTM(ctx, 1, 0);
5733 const bool drawAllParts = drawKnob && drawBar && (!hasTicks || drawTicks);
5734 if (drawAllParts && !hasDoubleTicks && (!verticalFlip || drawTicks)) {
5738 if (verticalFlip && drawTicks) {
5741 slider.intValue = slider.maxValue - slider.intValue + slider.minValue;
5743 [slider drawRect:CGRectZero];
5747 NSSliderCell *cell = slider.cell;
5749 const int numberOfTickMarks = slider.numberOfTickMarks;
5752 slider.numberOfTickMarks = 0;
5754 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
5756 if (!isHorizontal && !sl->upsideDown && (hasDoubleTicks || !hasTicks)) {
5764 [cell drawBarInside:barRect flipped:
true];
5766 [cell drawBarInside:barRect flipped:!verticalFlip];
5770 slider.numberOfTickMarks = numberOfTickMarks;
5773 if (hasTicks && drawTicks) {
5774 if (!drawBar && hasDoubleTicks)
5775 slider.numberOfTickMarks = numberOfTickMarks;
5777 if (qt_apple_runningWithLiquidGlass())
5778 drawTickMarks(ctx, slider, sl);
5780 [cell drawTickMarks];
5782 if (hasDoubleTicks) {
5784 CGAffineTransform tickMarksFlip;
5785 const CGRect tickMarkRect = [cell rectOfTickMarkAtIndex:0];
5787 tickMarksFlip = CGAffineTransformMakeTranslation(0, rect.size.height - tickMarkRect.size.height - 3);
5788 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, 1, -1);
5790 tickMarksFlip = CGAffineTransformMakeTranslation(rect.size.width - tickMarkRect.size.width / 2, 0);
5791 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, -1, 1);
5793 CGContextConcatCTM(ctx, tickMarksFlip);
5794 [cell drawTickMarks];
5795 CGContextConcatCTM(ctx, CGAffineTransformInvert(tickMarksFlip));
5802 slider.numberOfTickMarks = 0;
5803 if (qt_apple_runningWithLiquidGlass())
5804 drawSliderKnob(ctx, slider);
5814 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5815 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5819#if QT_CONFIG(spinbox)
5821 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5822 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5823 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5824 QStyleOptionFrame frame;
5825 static_cast<QStyleOption &>(frame) = *opt;
5826 frame.rect = lineEditRect;
5827 frame.state |= State_Sunken;
5828 frame.lineWidth = 1;
5829 frame.midLineWidth = 0;
5830 frame.features = QStyleOptionFrame::None;
5831 frame.frameShape = QFrame::Box;
5832 drawPrimitive(PE_FrameLineEdit, &frame, p, widget);
5834 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5835 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget)
5836 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5839 d->setupNSGraphicsContext(cg, NO);
5841 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
5842 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5843 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5844 const auto controlSize = cell.controlSize;
5845 if (qt_apple_runningWithLiquidGlass())
5846 cell.controlSize = NSControlSizeMini;
5847 cell.enabled = (sb->state & State_Enabled);
5849 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
5851 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
5852 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
5853 const CGFloat x = CGRectGetMidX(newRect);
5854 const CGFloat y = upPressed ? -3 : 3;
5855 const CGPoint pressPoint = CGPointMake(x, y);
5858 if (upPressed || downPressed)
5859 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
5861 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
5863 if (upPressed || downPressed)
5864 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
5866 d->restoreNSGraphicsContext(cg);
5867 if (qt_apple_runningWithLiquidGlass())
5868 cell.controlSize = controlSize;
5873#if QT_CONFIG(combobox)
5875 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5876 const bool isEnabled = combo->state & State_Enabled;
5877 const bool isPressed = combo->state & State_Sunken;
5879 const auto ct = cocoaControlType(combo, widget);
5880 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5881 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5882 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
5883 cc.enabled = isEnabled;
5884 QRectF frameRect = cw.adjustedControlFrame(combo->rect);
5885 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5887 auto *pb =
static_cast<NSPopUpButton *>(cc);
5889 if (cw.size == QStyleHelper::SizeSmall) {
5890 frameRect = frameRect.translated(0, 1);
5891 }
else if (cw.size == QStyleHelper::SizeMini) {
5893 frameRect = frameRect.translated(2, -0.5);
5895 pb.frame = frameRect.toCGRect();
5896 [pb highlight:isPressed];
5897 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5898 [pb.cell drawBezelWithFrame:r inView:pb.superview];
5900 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5902 auto *cb =
static_cast<NSComboBox *>(cc);
5903 const auto frameRect = cw.adjustedControlFrame(combo->rect);
5904 cb.frame = frameRect.toCGRect();
5907 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
5908 cell.highlighted = isPressed;
5913 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5915 [cb.cell drawWithFrame:r inView:cb];
5919 if (combo->state & State_HasFocus) {
5921 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, combo, widget);
5922 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, combo, widget);
5924 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5925 if (qt_apple_runningWithLiquidGlass())
5926 focusRect = QRectF::fromCGRect(qt_alignmentRectForFrame(cc.frame, cw.size, cw.type));
5928 focusRect = QRectF::fromCGRect([cc alignmentRectForFrame:cc.frame]);
5929 focusRect -= pullDownButtonShadowMargins[cw.size];
5930 if (cw.size == QStyleHelper::SizeSmall)
5931 focusRect = focusRect.translated(0, 1);
5932 else if (cw.size == QStyleHelper::SizeMini)
5933 focusRect = focusRect.translated(2, -1);
5934 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5935 focusRect = frameRect - comboBoxFocusRingMargins[cw.size];
5937 d->drawFocusRing(p, focusRect, hMargin, vMargin, cw);
5943 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5944 const bool isActive = (titlebar->state & State_Active)
5945 && (titlebar->titleBarState & State_Active);
5947 p->fillRect(opt->rect, Qt::transparent);
5948 p->setRenderHint(QPainter::Antialiasing);
5949 p->setClipRect(opt->rect, Qt::IntersectClip);
5953 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
5954 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
5955 p->fillPath(outerFramePath, opt->palette.dark());
5957 const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
5958 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
5959 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
5960 p->fillPath(innerFramePath, opt->palette.button());
5962 if (titlebar->subControls & (SC_TitleBarCloseButton
5963 | SC_TitleBarMaxButton
5964 | SC_TitleBarMinButton
5965 | SC_TitleBarNormalButton)) {
5966 const bool isHovered = (titlebar->state & State_MouseOver);
5967 static const SubControl buttons[] = {
5968 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
5970 for (
const auto sc : buttons) {
5971 const auto ct = d->windowButtonCocoaControl(sc);
5972 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
5973 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5974 wb.enabled = (sc & titlebar->subControls) && isActive;
5975 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
5976 Q_UNUSED(isHovered);
5978 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget);
5979 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5980 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
5981 [wbCell drawWithFrame:rect inView:wb];
5986 if (titlebar->subControls & SC_TitleBarLabel) {
5987 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
5988 if (!titlebar->icon.isNull()) {
5989 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5990 const auto iconSize = QSize(iconExtent, iconExtent);
5991 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
5993 if (iconPos < tr.right() - titleBarIconTitleSpacing)
5994 p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(iconSize, QIcon::Normal));
5997 if (!titlebar->text.isEmpty())
5998 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
6003 if (
const QStyleOptionGroupBox *gb
6004 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
6006 QStyleOptionGroupBox groupBox(*gb);
6007 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
6009 groupBox.state |= QStyle::State_Mini;
6011 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
6013 const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
6014 const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
6015 if (didModifySubControls)
6016 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
6017 QCommonStyle::drawComplexControl(cc, &groupBox, p, widget);
6018 if (didModifySubControls) {
6019 const QRect rect = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel, widget);
6020 const bool rtl = groupBox.direction == Qt::RightToLeft;
6021 const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
6022 const QFont savedFont = p->font();
6023 if (!flat && d->smallSystemFont)
6024 p->setFont(*d->smallSystemFont);
6025 proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
6027 p->setFont(savedFont);
6032 if (
const QStyleOptionToolButton *tb
6033 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
6034#if QT_CONFIG(accessibility)
6035 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
6036 if (tb->subControls & SC_ToolButtonMenu) {
6037 QStyleOption arrowOpt = *tb;
6038 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
6039 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
6040 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
6041 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
6042 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
6043 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
6044 d->drawToolbarButtonArrow(tb, p);
6046 if (tb->state & State_On) {
6047 NSView *view = window ? (NSView *)window->winId() : nil;
6050 isKey = [view.window isKeyWindow];
6052 QBrush brush(brushForToolButton(isKey));
6054 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
6055 p->setRenderHint(QPainter::Antialiasing);
6056 p->fillPath(path, brush);
6058 proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
6062 auto bflags = tb->state;
6063 if (tb->subControls & SC_ToolButton)
6064 bflags |= State_Sunken;
6065 auto mflags = tb->state;
6066 if (tb->subControls & SC_ToolButtonMenu)
6067 mflags |= State_Sunken;
6069 if (tb->subControls & SC_ToolButton) {
6070 if (bflags & (State_Sunken | State_On | State_Raised)) {
6071 const bool isEnabled = tb->state & State_Enabled;
6072 const bool isPressed = tb->state & State_Sunken;
6073 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
6074 const auto ct = QMacStylePrivate::Button_PushButton;
6075 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6076 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6077 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
6078 pb.bezelStyle = NSBezelStyleShadowlessSquare;
6079 pb.frame = opt->rect.toCGRect();
6080 pb.buttonType = NSButtonTypePushOnPushOff;
6081 pb.enabled = isEnabled;
6082 [pb highlight:isPressed];
6083 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
6084 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
6085 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
6086 [pb.cell drawBezelWithFrame:rect inView:pb];
6091 if (tb->subControls & SC_ToolButtonMenu) {
6092 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
6093 QStyleOption arrowOpt = *tb;
6098 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
6099 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
6100 d->drawToolbarButtonArrow(tb, p);
6102 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
6103 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
6104 QStyleOptionToolButton label = *tb;
6105 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
6106 proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
6112 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
6113 QStyleHelper::drawDial(dial, p);
6117 QCommonStyle::drawComplexControl(cc, opt, p, widget);
6209 const QWidget *widget)
const
6211 Q_D(
const QMacStyle);
6215 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6216 const bool isHorizontal = sb->orientation == Qt::Horizontal;
6217 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
6219 NSScrollerPart part = NSScrollerNoPart;
6220 if (sc == SC_ScrollBarSlider) {
6221 part = NSScrollerKnob;
6222 }
else if (sc == SC_ScrollBarGroove) {
6223 part = NSScrollerKnobSlot;
6224 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
6225 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
6226 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
6227 part = NSScrollerDecrementPage;
6229 part = NSScrollerIncrementPage;
6233 if (part != NSScrollerNoPart) {
6234 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
6235 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6236 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6237 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
6238 if (setupScroller(scroller, sb))
6239 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
6244 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6245 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
6246 const bool isHorizontal = sl->orientation == Qt::Horizontal;
6247 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
6248 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6249 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6250 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
6251 if (!setupSlider(slider, sl))
6254 NSSliderCell *cell = slider.cell;
6255 if (sc == SC_SliderHandle) {
6256 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
6258 ret.setTop(sl->rect.top());
6259 ret.setBottom(sl->rect.bottom());
6261 ret.setLeft(sl->rect.left());
6262 ret.setRight(sl->rect.right());
6264 }
else if (sc == SC_SliderGroove) {
6265 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
6266 }
else if (hasTicks && sc == SC_SliderTickmarks) {
6267 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
6269 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
6271 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
6276 if (sl->upsideDown) {
6277 ret = QRect(sl->rect.right() - ret.right(), sl->rect.top(), ret.width(), sl->rect.height());
6279 ret.setTop(sl->rect.top());
6280 ret.setBottom(sl->rect.bottom());
6283 if (!sl->upsideDown) {
6284 ret = QRect(sl->rect.left(), sl->rect.bottom() - ret.bottom(), sl->rect.width(), ret.height());
6286 ret.setLeft(sl->rect.left());
6287 ret.setRight(sl->rect.right());
6293 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
6299 if (sc == SC_TitleBarLabel) {
6300 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
6301 qreal labelHeight = titlebar->fontMetrics.height();
6303 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
6304 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
6305 if (!titlebar->icon.isNull()) {
6306 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
6307 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
6308 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
6311 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
6312 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
6313 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
6314 labelWidth, labelHeight);
6316 const auto currentButton = d->windowButtonCocoaControl(sc);
6317 if (currentButton == QMacStylePrivate::NoControl)
6320 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
6322 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
6323 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
6324 QStyleHelper::SizeLarge);
6325 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
6326 if (ct == currentButton)
6327 buttonSize = QSizeF::fromCGSize(wb.frame.size);
6329 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
6332 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
6333 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
6338 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
6339 const auto ct = cocoaControlType(combo, widget);
6340 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
6341 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6342 const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
6345 case SC_ComboBoxEditField:{
6346 ret = editRect.toAlignedRect();
6348 case SC_ComboBoxArrow:{
6349 ret = editRect.toAlignedRect();
6350 ret.setX(ret.x() + ret.width());
6351 ret.setWidth(combo->rect.right() - ret.right());
6353 case SC_ComboBoxListBoxPopup:{
6354 if (combo->editable) {
6355 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
6356 const int comboTop = combo->rect.top();
6357 ret = QRect(qRound(inner.origin.x),
6359 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
6360 editRect.bottom() - comboTop + 2);
6362 ret = QRect(combo->rect.x() + 4 - 11,
6363 combo->rect.y() + 1,
6364 editRect.width() + 10 + 11,
6374 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
6375 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
6376 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
6377 bool hasNoText = !checkable && groupBox->text.isEmpty();
6379 case SC_GroupBoxLabel:
6380 case SC_GroupBoxCheckBox: {
6382 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
6383 const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
6384 || !QApplication::desktopSettingsAware();
6385 const int margin = flat || hasNoText ? 0 : 9;
6386 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
6388 const QFontMetricsF fm = flat || fontIsSet || !d->smallSystemFont
6389 ? QFontMetricsF(groupBox->fontMetrics)
6390 : QFontMetricsF(*d->smallSystemFont);
6391 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
6392 const int tw = qCeil(s.width());
6393 const int h = qCeil(fm.height());
6396 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
6398 if (flat && checkable)
6399 labelRect.moveLeft(labelRect.left() + 4);
6400 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
6401 bool rtl = groupBox->direction == Qt::RightToLeft;
6402 if (sc == SC_GroupBoxLabel) {
6404 int newSum = indicatorWidth + 1;
6405 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
6406 labelRect.moveLeft(newLeft);
6408 labelRect.moveTop(labelRect.top() + 3);
6410 labelRect.moveTop(labelRect.top() + 4);
6412 int newLeft = labelRect.left() - (rtl ? 3 : -3);
6413 labelRect.moveLeft(newLeft);
6414 labelRect.moveTop(labelRect.top() + 3);
6416 int newLeft = labelRect.left() - (rtl ? 3 : 2);
6417 labelRect.moveLeft(newLeft);
6418 labelRect.moveTop(labelRect.top() + 4);
6423 if (sc == SC_GroupBoxCheckBox) {
6424 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
6425 int top = flat ? ret.top() + 1 : ret.top() + 5;
6426 ret.setRect(left, top,
6427 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
6431 case SC_GroupBoxContents:
6432 case SC_GroupBoxFrame: {
6433 QFontMetrics fm = groupBox->fontMetrics;
6436 if (widget && !widget->testAttribute(Qt::WA_SetFont)
6437 && QApplication::desktopSettingsAware())
6438 fm = QFontMetrics(qt_app_fonts_hash()->value(
"QSmallFont", QFont()));
6443 yOffset = -qCeil(QFontMetricsF(fm).height());
6444 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
6445 if (sc == SC_GroupBoxContents) {
6447 ret.adjust(3, -5, -3, -4);
6449 ret.adjust(3, 3, -3, -4);
6454 ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget);
6459#if QT_CONFIG(spinbox)
6461 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6462 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin, widget);
6463 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
6467 case QStyleHelper::SizeLarge:
6471 case QStyleHelper::SizeSmall:
6475 case QStyleHelper::SizeMini:
6485 case SC_SpinBoxDown: {
6486 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
6490 const int x = spin->rect.width() - spinner_w;
6491 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
6494 case QStyleHelper::SizeLarge:
6497 case QStyleHelper::SizeSmall:
6498 hackTranslateX = -2;
6500 case QStyleHelper::SizeMini:
6501 hackTranslateX = -1;
6507 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
6508 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
6509 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
6510 ret = QRectF::fromCGRect(outRect).toRect();
6514 ret.setHeight(ret.height() / 2);
6516 case SC_SpinBoxDown:
6517 ret.setY(ret.y() + ret.height() / 2);
6523 ret.translate(hackTranslateX, 0);
6524 ret = visualRect(spin->direction, spin->rect, ret);
6527 case SC_SpinBoxEditField:
6528 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
6529 if (spin->buttonSymbols != QAbstractSpinBox::NoButtons) {
6530 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
6531 ret = visualRect(spin->direction, spin->rect, ret);
6535 ret = QCommonStyle::subControlRect(cc, spin, sc, widget);
6542 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6543 if (sc == SC_ToolButtonMenu) {
6544#if QT_CONFIG(accessibility)
6545 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
6546 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
6548 ret.adjust(-1, 0, 0, 0);
6552 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6559 const QSize &csz,
const QWidget *widget)
const
6561 Q_D(
const QMacStyle);
6563 bool useAquaGuideline =
true;
6566#if QT_CONFIG(spinbox)
6568 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6569 const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons);
6570 const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0;
6571 sz += QSize(buttonWidth, 0);
6575 case QStyle::CT_TabWidget:
6578 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
6606
6607
6608
6610#if QT_CONFIG(tabwidget)
6611 if (
const QStyleOptionTabWidgetFrame *twf
6612 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
6614 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
6615 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
6617 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
6618 if (tabDirection == QMacStylePrivate::North
6619 || tabDirection == QMacStylePrivate::South) {
6620 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
6622 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
6628#if QT_CONFIG(tabbar)
6629 case QStyle::CT_TabBarTab:
6630 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
6631 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
6632 || !QApplication::desktopSettingsAware();
6633 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
6634 const bool verticalTabs = tabDirection == QMacStylePrivate::East
6635 || tabDirection == QMacStylePrivate::West;
6637 sz = sz.transposed();
6639 int defaultTabHeight;
6640 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6642 case QStyleHelper::SizeLarge:
6643 if (tab->documentMode)
6644 defaultTabHeight = 24;
6646 defaultTabHeight = 21;
6648 if (qt_apple_runningWithLiquidGlass() && !tab->documentMode) {
6656 defaultTabHeight = 23;
6659 case QStyleHelper::SizeSmall:
6660 defaultTabHeight = 18;
6662 case QStyleHelper::SizeMini:
6663 defaultTabHeight = 16;
6669 const bool widthSet = !differentFont && tab->icon.isNull();
6671 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
6672 sz.rwidth() = textSize.width();
6673 sz.rheight() = qMax(defaultTabHeight, textSize.height());
6675 sz.rheight() = qMax(defaultTabHeight, sz.height());
6677 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget);
6680 sz = sz.transposed();
6682 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
6683 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
6685 int widgetWidth = 0;
6686 int widgetHeight = 0;
6688 if (tab->leftButtonSize.isValid()) {
6690 widgetWidth += tab->leftButtonSize.width();
6691 widgetHeight += tab->leftButtonSize.height();
6693 if (tab->rightButtonSize.isValid()) {
6695 widgetWidth += tab->rightButtonSize.width();
6696 widgetHeight += tab->rightButtonSize.height();
6700 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
6701 sz.setHeight(sz.height() + widgetHeight + padding);
6704 sz.setWidth(sz.width() + widgetWidth + padding);
6705 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
6710 case QStyle::CT_PushButton: {
6711 bool isFlat =
false;
6712 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
6713 if (btn->features & QStyleOptionButton::CommandLinkButton)
6714 return QCommonStyle::sizeFromContents(ct, opt, sz, widget);
6715 isFlat = btn->features & QStyleOptionButton::Flat;
6722 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz);
6724 if (macsz.width() != -1)
6725 sz.setWidth(macsz.width());
6727 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
6729 if (controlSize != QStyleHelper::SizeMini)
6732 if (controlSize == QStyleHelper::SizeLarge) {
6735 if (sz.height() > 16)
6736 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6738 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeLarge]);
6740 if (!isFlat && !qt_apple_runningWithLiquidGlass())
6742 if (controlSize == QStyleHelper::SizeMini)
6745 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeSmall]);
6751 case QStyle::CT_MenuItem:
6752 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
6753 int maxpmw = mi->maxIconWidth;
6754#if QT_CONFIG(combobox)
6755 const QComboBox *comboBox = qobject_cast<
const QComboBox *>(widget);
6759 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
6763 h = mi->fontMetrics.height() + 2;
6764 if (!mi->icon.isNull()) {
6765#if QT_CONFIG(combobox)
6767 const QSize &iconSize = comboBox->iconSize();
6768 h = qMax(h, iconSize.height() + 4);
6769 maxpmw = qMax(maxpmw, iconSize.width());
6773 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
6774 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
6778 if (mi->text.contains(QLatin1Char(
'\t')))
6780 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
6786#if QT_CONFIG(combobox)
6787 if (comboBox && comboBox->isVisible()) {
6788 QStyleOptionComboBox cmb;
6789 cmb.initFrom(comboBox);
6790 cmb.editable =
false;
6791 cmb.subControls = QStyle::SC_ComboBoxEditField;
6792 cmb.activeSubControls = QStyle::SC_None;
6793 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
6794 QStyle::SC_ComboBoxEditField,
6804 case CT_MenuBarItem:
6811 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
6812 if (tb->features & QStyleOptionToolButton::Menu)
6816 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
6817 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
6818 if (!cb->editable) {
6821 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 24;
6823 if (controlSize != QStyleHelper::SizeMini)
6827 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
6828 sz.rheight() += popupButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6836 if (controlSize == QStyleHelper::SizeMini)
6839 sz.setHeight(pushButtonDefaultHeight[controlSize]);
6845 if (proxy() ==
this) {
6848 QStyleHintReturnMask menuMask;
6849 QStyleOption myOption = *opt;
6850 myOption.rect.setSize(sz);
6851 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask))
6852 sz = menuMask.region.boundingRect().size();
6855 case CT_HeaderSection:{
6856 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
6857 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6858 if (header->text.contains(QLatin1Char(
'\n')))
6859 useAquaGuideline =
false;
6863 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6864 const int minimumSize = 24;
6865 if (slider->orientation == Qt::Horizontal)
6866 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6868 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6871#if QT_CONFIG(itemviews)
6872 case CT_ItemViewItem:
6873 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
6874 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6875 sz.setHeight(sz.height() + 2);
6881 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6884 if (useAquaGuideline && ct != CT_PushButton) {
6887 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
6888 if (macsz.width() != -1)
6889 sz.setWidth(macsz.width());
6890 if (macsz.height() != -1)
6891 sz.setHeight(macsz.height());
6897 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
6898 if (combo->editable) {
6899 const auto widgetSize = d->aquaSizeConstrain(opt, widget);
6900 QMacStylePrivate::CocoaControl cw;
6901 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
6902 cw.size = widgetSize;
6903 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
6904 sz.rwidth() -= qRound(diffRect.size.width);
6905 sz.rheight() -= qRound(diffRect.size.height);