2885void QMacStyle::drawPrimitive(PrimitiveElement pe,
const QStyleOption *opt, QPainter *p,
2886 const QWidget *w)
const
2888 Q_D(
const QMacStyle);
2889 const AppearanceSync appSync;
2890 QMacCGContext cg(p);
2891 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
2892 d->resolveCurrentNSView(window);
2894 case PE_IndicatorArrowUp:
2895 case PE_IndicatorArrowDown:
2896 case PE_IndicatorArrowRight:
2897 case PE_IndicatorArrowLeft: {
2899 p->setRenderHint(QPainter::Antialiasing);
2900 const int xOffset = 1;
2901 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2902 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2903#if QT_CONFIG(toolbutton)
2904 if (
const QToolButton *tb = qobject_cast<
const QToolButton *>(w)) {
2906 if (tb->arrowType() != Qt::NoArrow
2907 || tb->popupMode() == QToolButton::MenuButtonPopup)
2908 halfSize -= penWidth;
2912 QTransform transform;
2913 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2917 case PE_IndicatorArrowDown:
2919 case PE_IndicatorArrowUp:
2920 transform.rotate(180);
2922 case PE_IndicatorArrowLeft:
2923 transform.rotate(90);
2925 case PE_IndicatorArrowRight:
2926 transform.rotate(-90);
2929 p->setTransform(transform);
2931 path.moveTo(-halfSize, -halfSize * 0.5);
2932 path.lineTo(0.0, halfSize * 0.5);
2933 path.lineTo(halfSize, -halfSize * 0.5);
2935 const QPen arrowPen(opt->palette.text(), penWidth,
2936 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2937 p->strokePath(path, arrowPen);
2940#if QT_CONFIG(tabbar)
2941 case PE_FrameTabBarBase:
2942 if (
const QStyleOptionTabBarBase *tbb
2943 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2944 if (tbb->documentMode) {
2946 drawTabBase(p, tbb, w);
2950#if QT_CONFIG(tabwidget)
2951 QRegion region(tbb->rect);
2952 region -= tbb->tabBarRect.adjusted(3, 0, -3, 0);
2954 p->setClipRegion(region);
2955 QStyleOptionTabWidgetFrame twf;
2956 twf.QStyleOption::operator=(*tbb);
2957 twf.shape = tbb->shape;
2958 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2959 case QMacStylePrivate::North:
2960 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2962 case QMacStylePrivate::South:
2963 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2965 case QMacStylePrivate::West:
2966 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2968 case QMacStylePrivate::East:
2969 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2972 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
2978 case PE_PanelTipLabel:
2979 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2981 case PE_FrameGroupBox:
2982 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2983 if (groupBox->features & QStyleOptionFrame::Flat) {
2984 QCommonStyle::drawPrimitive(pe, groupBox, p, w);
2987#if QT_CONFIG(tabwidget)
2989 case PE_FrameTabWidget:
2992 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2993 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
3007 auto adjustedRect = opt->rect;
3008 bool needTranslation =
false;
3009 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
3022 adjustedRect.adjust(0, 0, 6, 6);
3023 needTranslation =
true;
3025 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3026#if QT_CONFIG(tabwidget)
3027 if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(opt->styleObject))
3028 clipTabBarFrame(opt,
this, ctx);
3030 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
3031 CGContextScaleCTM(ctx, 1, -1);
3032 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
3033 || [box isMemberOfClass:QDarkNSBox.
class]) {
3034 [box drawRect:rect];
3036 if (needTranslation)
3037 CGContextTranslateCTM(ctx, -3.0, 5.0);
3038 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
3043 case PE_IndicatorToolBarSeparator: {
3045 if (opt->state & State_Horizontal) {
3046 int xpoint = opt->rect.center().x();
3047 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3048 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3050 int ypoint = opt->rect.center().y();
3051 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3052 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3054 QPainterPathStroker theStroker;
3055 theStroker.setCapStyle(Qt::FlatCap);
3056 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3057 path = theStroker.createStroke(path);
3058 const auto dark = isDarkMode() ? opt->palette.dark().color().darker()
3059 : QColor(0, 0, 0, 119);
3060 p->fillPath(path, dark);
3063 case PE_FrameWindow:
3064 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3065 if (qobject_cast<
const QMdiSubWindow*>(w)) {
3067 p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
3068 p->setBrush(frame->palette.window());
3069 p->drawRect(frame->rect);
3074 case PE_IndicatorDockWidgetResizeHandle: {
3077 if (opt->state & State_Horizontal) {
3078 p->setPen(QColor(160, 160, 160));
3079 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3081 p->setPen(QColor(145, 145, 145));
3082 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3086 case PE_IndicatorToolBarHandle: {
3089 int x = opt->rect.x() + 6;
3090 int y = opt->rect.y() + 7;
3091 static const int RectHeight = 2;
3092 if (opt->state & State_Horizontal) {
3093 while (y < opt->rect.height() - RectHeight - 5) {
3095 path.addEllipse(x, y, RectHeight, RectHeight);
3099 while (x < opt->rect.width() - RectHeight - 5) {
3101 path.addEllipse(x, y, RectHeight, RectHeight);
3105 p->setPen(Qt::NoPen);
3106 QColor dark = opt->palette.dark().color().darker();
3107 dark.setAlphaF(0.50);
3108 p->fillPath(path, dark);
3113 case PE_IndicatorHeaderArrow:
3114 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3116 if (header->sortIndicator != QStyleOptionHeader::None)
3117 proxy()->drawPrimitive(
3118 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3119 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3122 case PE_IndicatorMenuCheckMark: {
3124 if (opt->state & State_On)
3125 pc = opt->palette.highlightedText().color();
3127 pc = opt->palette.text().color();
3129 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
3130 static_cast<CGFloat>(pc.greenF()),
3131 static_cast<CGFloat>(pc.blueF()),
3132 static_cast<CGFloat>(pc.alphaF()));
3138 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
3139 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
3140 kCTFontUIFontMenuItemMark;
3144 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
3145 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
3147 CGContextSaveGState(cg);
3148 CGContextSetShouldSmoothFonts(cg, NO);
3151 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
3152 (opt->state & State_Small) ? 1.0 :
3155 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
3156 CGContextScaleCTM(cg, 1, -1);
3158 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
3162 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
3163 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
3164 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
3165 static_assert((
sizeof(values) /
sizeof(values[0])) == numValues);
3166 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
3167 numValues, NULL, NULL);
3169 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
3170 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
3172 CTLineDraw((CTLineRef)line, cg);
3175 CGContextRestoreGState(cg);
3177 case PE_IndicatorItemViewItemCheck:
3178 case PE_IndicatorRadioButton:
3179 case PE_IndicatorCheckBox: {
3180 const bool isEnabled = opt->state & State_Enabled;
3181 const bool isPressed = opt->state & State_Sunken;
3182 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
3183 const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
3184 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3185 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3186 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
3187 tb.enabled = isEnabled;
3188 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
3189 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
3190 [tb highlight:isPressed];
3191 const auto vOffset = [=] {
3193 if (cs == QStyleHelper::SizeMini)
3194 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
3196 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
3198 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3199 CGContextTranslateCTM(ctx, 0, vOffset);
3200 [tb.cell drawInteriorWithFrame:rect inView:tb];
3203 case PE_FrameFocusRect:
3206 case PE_IndicatorBranch: {
3207 if (!(opt->state & State_Children))
3209 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
3210 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
3211 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
3212 bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
3213 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
3215 d->setupNSGraphicsContext(cg, NO);
3217 QRect qtRect = opt->rect.adjusted(DisclosureOffset, 0, -DisclosureOffset, 0);
3218 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
3219 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
3220 CGContextScaleCTM(cg, 1, -1);
3221 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
3223 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
3225 d->restoreNSGraphicsContext(cg);
3229 QPen oldPen = p->pen();
3230 p->setPen(opt->palette.base().color().darker(140));
3231 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3232 p->setPen(opt->palette.base().color().darker(180));
3233 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3237 case PE_FrameLineEdit:
3238 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3239 if (frame->state & State_Sunken) {
3240 const bool isEnabled = opt->state & State_Enabled;
3241 const bool isReadOnly = opt->state & State_ReadOnly;
3242 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
3243 const auto cs = d->effectiveAquaSizeConstrain(opt, w, CT_LineEdit);
3244 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
3245 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
3246 tf.enabled = isEnabled;
3247 tf.editable = !isReadOnly;
3249 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
3250 tf.frame = opt->rect.toCGRect();
3251 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3252 if (!isDarkMode()) {
3257 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
3261 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
3262 tf.drawsBackground = YES;
3263 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
3264 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
3265 green:bgColor.greenF()
3266 blue:bgColor.blueF()
3267 alpha:bgColor.alphaF()];
3268 if (bgColor.alpha() != 255) {
3275 [tf.cell drawWithFrame:rect inView:tf];
3278 QCommonStyle::drawPrimitive(pe, opt, p, w);
3282 case PE_PanelLineEdit:
3284 const QStyleOptionFrame *panel = qstyleoption_cast<
const QStyleOptionFrame *>(opt);
3285 if (isDarkMode() || (panel && panel->lineWidth <= 0)) {
3291 QCommonStyle::drawPrimitive(pe, opt, p, w);
3296 drawPrimitive(PE_FrameLineEdit, opt, p, w);
3302#if QT_CONFIG(lineedit)
3303 if ((opt->state & State_HasFocus) && !qobject_cast<
const QLineEdit*>(w)) {
3304 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3305 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3306 QStyleOptionFrame focusFrame = *panel;
3307 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3308 drawControl(CE_FocusFrame, &focusFrame, p, w);
3314 case PE_PanelScrollAreaCorner: {
3315 const QBrush brush(opt->palette.brush(QPalette::Base));
3316 p->fillRect(opt->rect, brush);
3317 p->setPen(QPen(QColor(217, 217, 217)));
3318 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3319 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3321 case PE_FrameStatusBarItem:
3323#if QT_CONFIG(tabbar)
3324 case PE_IndicatorTabClose: {
3326 QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
3327 const QWidget *closeBtn = w;
3331 tabBar = qobject_cast<QTabBar *>(
const_cast<QWidget*>(w));
3332 closeBtn =
decltype(closeBtn)(property(
"_q_styleSheetRealCloseButton").value<
void *>());
3335 const bool documentMode = tabBar->documentMode();
3336 const QTabBarPrivate *tabBarPrivate =
static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
3337 const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
3338 if (!documentMode ||
3339 (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
3340 (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
3341 const bool hover = (opt->state & State_MouseOver);
3342 const bool selected = (opt->state & State_Selected);
3343 const bool pressed = (opt->state & State_Sunken);
3344 drawTabCloseButton(p, hover, selected, pressed, documentMode);
3349 case PE_PanelStatusBar: {
3350 p->fillRect(opt->rect, opt->palette.window());
3353 if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
3354 p->setPen(titlebarSeparatorLineActive);
3356 p->setPen(titlebarSeparatorLineInactive);
3357 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3361 case PE_PanelMenu: {
3363 p->fillRect(opt->rect, Qt::transparent);
3364 p->setPen(Qt::transparent);
3365 p->setBrush(opt->palette.window());
3366 p->setRenderHint(QPainter::Antialiasing,
true);
3367 const QPainterPath path = d->windowPanelPath(opt->rect);
3373 QCommonStyle::drawPrimitive(pe, opt, p, w);
3413void QMacStyle::drawControl(ControlElement ce,
const QStyleOption *opt, QPainter *p,
3414 const QWidget *w)
const
3416 Q_D(
const QMacStyle);
3417 const AppearanceSync sync;
3418 const QMacAutoReleasePool pool;
3419 QMacCGContext cg(p);
3420 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
3421 d->resolveCurrentNSView(window);
3423 case CE_HeaderSection:
3424 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3425 State flags = header->state;
3426 QRect ir = header->rect;
3430 bool noVerticalHeader =
true;
3431#if QT_CONFIG(tableview)
3433 if (
const QTableView *table = qobject_cast<
const QTableView *>(w->parentWidget()))
3434 noVerticalHeader = !table->verticalHeader()->isVisible();
3437 const bool drawLeftBorder = header->orientation == Qt::Vertical
3438 || header->position == QStyleOptionHeader::OnlyOneSection
3439 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3442 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
3443 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
3444 p->setPen(QPen(header->palette.dark(), 1.0));
3445 if (header->orientation == Qt::Horizontal)
3446 p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
3447 ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
3449 p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
3450 ir.right() - headerSectionSeparatorInset, ir.bottom()));
3454 case CE_ToolButtonLabel:
3455 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
3456 QStyleOptionToolButton myTb = *tb;
3457 myTb.state &= ~State_AutoRaise;
3458#if QT_CONFIG(accessibility)
3459 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
3460 QRect cr = tb->rect;
3463 bool needText =
false;
3465 bool down = tb->state & (State_Sunken | State_On);
3467 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3468 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3474 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3475 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3476 if (tb->icon.isNull() && !tb->text.isEmpty())
3477 tbstyle = Qt::ToolButtonTextOnly;
3480 case Qt::ToolButtonTextOnly: {
3482 alignment = Qt::AlignCenter;
3484 case Qt::ToolButtonIconOnly:
3485 case Qt::ToolButtonTextBesideIcon:
3486 case Qt::ToolButtonTextUnderIcon: {
3488 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3490 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3492 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), p->device()->devicePixelRatio(),
3493 iconMode, iconState);
3496 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3498 QSizeF size = pixmap.deviceIndependentSize();
3499 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3500 pr.setHeight(size.height() + 6);
3501 cr.adjust(0, pr.bottom(), 0, -3);
3502 alignment |= Qt::AlignCenter;
3504 pr.setWidth(size.width() + 8);
3505 cr.adjust(pr.right(), 0, 0, 0);
3506 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3509 if (opt->state & State_Sunken) {
3510 pr.translate(shiftX, shiftY);
3511 pixmap = darkenPixmap(pixmap);
3513 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3521 QPalette pal = tb->palette;
3522 QPalette::ColorRole role = QPalette::NoRole;
3523 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3524 alignment |= Qt::TextHideMnemonic;
3526 cr.translate(shiftX, shiftY);
3527 if (tbstyle == Qt::ToolButtonTextOnly
3528 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3529 QPen pen = p->pen();
3530 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3531 light.setAlphaF(0.375f);
3533 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3535 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3536 pal = QApplication::palette(
"QMenu");
3537 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3538 role = QPalette::HighlightedText;
3541 proxy()->drawItemText(p, cr, alignment, pal,
3542 tb->state & State_Enabled, tb->text, role);
3545 QCommonStyle::drawControl(ce, &myTb, p, w);
3550 QCommonStyle::drawControl(ce, &myTb, p, w);
3554 case CE_ToolBoxTabShape:
3555 QCommonStyle::drawControl(ce, opt, p, w);
3557 case CE_PushButtonBevel:
3558 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3559 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3562 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3563 QCommonStyle::drawControl(ce, opt, p, w);
3567 const bool hasFocus = btn->state & State_HasFocus;
3568 const bool isActive = btn->state & State_Active;
3572 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3573 && isActive && hasFocus)
3574 d->autoDefaultButton = btn->styleObject;
3575 else if (d->autoDefaultButton == btn->styleObject)
3576 d->autoDefaultButton =
nullptr;
3578 const bool isEnabled = btn->state & State_Enabled;
3579 const bool isPressed = btn->state & State_Sunken;
3580 const bool isHighlighted = isActive &&
3581 ((btn->state & State_On)
3582 || (btn->features & QStyleOptionButton::DefaultButton)
3583 || (btn->features & QStyleOptionButton::AutoDefaultButton
3584 && d->autoDefaultButton == btn->styleObject));
3585 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3586 const auto ct = cocoaControlType(btn, w);
3587 const auto cs = d->effectiveAquaSizeConstrain(btn, w);
3588 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3589 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3593 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3594 pb.frame = frameRect.toCGRect();
3596 pb.enabled = isEnabled;
3601 [pb highlight:isPressed];
3604 if (cw.type == QMacStylePrivate::Button_SquareButton) {
3605 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3609 pb.keyEquivalent = isHighlighted ? @
"\r" : @
"";
3612 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3613 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3617 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3620 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3621 const auto ir = frameRect.toRect();
3622 int arrowYOffset = 0;
3627 arrowYOffset -= ir.top();
3628 if (cw.second == QStyleHelper::SizeSmall)
3632 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3634 QStyleOption arrowOpt = *opt;
3636 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
3640 case CE_PushButtonLabel:
3641 if (
const QStyleOptionButton *b = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3642 QStyleOptionButton btn(*b);
3647 const bool isEnabled = btn.state & State_Enabled;
3648 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3649 const bool hasIcon = !btn.icon.isNull();
3650 const bool hasText = !btn.text.isEmpty();
3651 const bool isActive = btn.state & State_Active;
3652 const bool isPressed = btn.state & State_Sunken;
3653 const bool isDefault = (btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
3654 || d->autoDefaultButton == btn.styleObject;
3658 const QRect oldRect = btn.rect;
3660 btn.rect = w->rect();
3661 const auto ct = cocoaControlType(&btn, w);
3664 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
3665 if (isPressed || (isActive && isEnabled && ((btn.state & State_On) || isDefault)))
3666 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3669 if (isEnabled && !isDarkMode() && QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur) {
3670 if (!isDefault && !(btn.state & State_On)) {
3673 btn.palette.setColor(QPalette::ButtonText, Qt::black);
3677 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3678 QCommonStyle::drawControl(ce, &btn, p, w);
3680 QRect freeContentRect = btn.rect;
3681 QRect textRect = itemTextRect(
3682 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3684 if (ct == QMacStylePrivate::Button_SquareButton)
3685 textRect.moveTo(w ? 8 : 11, textRect.top());
3687 textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)])
3688 : 11, textRect.top());
3692 int contentW = textRect.width();
3694 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3695 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3696 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3697 mode = QIcon::Active;
3699 QIcon::State state = QIcon::Off;
3700 if (btn.state & State_On)
3702 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
3703 QSizeF pixmapSize = pixmap.deviceIndependentSize();
3704 contentW += pixmapSize.width() + QMacStylePrivate::PushButtonContentPadding;
3705 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3706 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapSize.height()) / 2;
3707 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapSize.width(), pixmapSize.height());
3708 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3709 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3710 int newOffset = iconDestRect.x() + iconDestRect.width()
3711 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
3712 textRect.adjust(newOffset, 0, newOffset, 0);
3716 textRect = visualRect(btn.direction, freeContentRect, textRect);
3717 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3718 isEnabled, btn.text, QPalette::ButtonText);
3723#if QT_CONFIG(combobox)
3724 case CE_ComboBoxLabel:
3725 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3726 auto comboCopy = *cb;
3727 comboCopy.direction = Qt::LeftToRight;
3729 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
3733#if QT_CONFIG(tabbar)
3734 case CE_TabBarTabShape:
3735 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3736 if (tabOpt->documentMode) {
3738 bool isUnified =
false;
3740 QRect tabRect = tabOpt->rect;
3741 QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
3742 isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y());
3745 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w);
3746 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3752 const bool isActive = tabOpt->state & State_Active;
3753 const bool isEnabled = tabOpt->state & State_Enabled;
3754 const bool isPressed = tabOpt->state & State_Sunken;
3755 const bool isSelected = tabOpt->state & State_Selected;
3756 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3757 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3758 || tabDirection == QMacStylePrivate::West;
3760 QStyleOptionTab::TabPosition tp = tabOpt->position;
3761 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3762 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3763 if (tp == QStyleOptionTab::Beginning)
3764 tp = QStyleOptionTab::End;
3765 else if (tp == QStyleOptionTab::End)
3766 tp = QStyleOptionTab::Beginning;
3768 if (sp == QStyleOptionTab::NextIsSelected)
3769 sp = QStyleOptionTab::PreviousIsSelected;
3770 else if (sp == QStyleOptionTab::PreviousIsSelected)
3771 sp = QStyleOptionTab::NextIsSelected;
3780 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3782 const bool needsInactiveHack = (!isActive && isSelected);
3783 const bool isBigSurOrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur;
3784 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3785 QMacStylePrivate::Button_PushButton :
3786 QMacStylePrivate::Button_PopupButton;
3787 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
3788 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3789 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3791 auto vOffset = isPopupButton ? 1 : 2;
3792 if (isBigSurOrAbove) {
3798 if (tabDirection == QMacStylePrivate::East)
3800 const auto outerAdjust = isPopupButton ? 1 : 4;
3801 const auto innerAdjust = isPopupButton ? 20 : 10;
3802 QRectF frameRect = tabOpt->rect;
3804 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3806 frameRect = frameRect.translated(0, vOffset);
3808 case QStyleOptionTab::Beginning:
3810 if (!isSelected && tabDirection == QMacStylePrivate::West)
3811 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3813 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3815 if (isSelected && isBigSurOrAbove) {
3818 frameRect = frameRect.adjusted(0, 0, 1, 0);
3822 case QStyleOptionTab::Middle:
3823 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3825 if (isSelected && isBigSurOrAbove) {
3828 frameRect = frameRect.adjusted(-1, 0, 1, 0);
3831 case QStyleOptionTab::Moving:
3832 case QStyleOptionTab::End:
3834 if (isSelected || tabDirection == QMacStylePrivate::West)
3835 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3837 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3839 if (isSelected && isBigSurOrAbove) {
3841 frameRect = frameRect.adjusted(-1, 0, 0, 0);
3844 case QStyleOptionTab::OnlyOneTab:
3845 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3848 pb.frame = frameRect.toCGRect();
3850 if (!isPopupButton) {
3854 pb.buttonType = NSButtonTypePushOnPushOff;
3857 pb.enabled = isEnabled;
3858 [pb highlight:isPressed];
3862 if (QOperatingSystemVersion::current() > QOperatingSystemVersion::MacOSBigSur)
3863 pb.state = (isActive && isSelected) ? NSControlStateValueOn : NSControlStateValueOff;
3865 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3867 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3868 CGContextClipToRect(ctx, opt->rect.toCGRect());
3869 if (!isSelected || needsInactiveHack) {
3871 if (!verticalTabs && tp == QStyleOptionTab::End) {
3872 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3873 CGContextScaleCTM(ctx, -1, 1);
3874 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3875 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3876 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3877 CGContextScaleCTM(ctx, 1, -1);
3878 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3879 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3880 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3881 CGContextScaleCTM(ctx, 1, -1);
3882 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3888 if (tabDirection == QMacStylePrivate::West) {
3889 CGContextTranslateCTM(ctx, 0, frameRect.right());
3890 CGContextRotateCTM(ctx, -M_PI_2);
3891 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3892 }
else if (tabDirection == QMacStylePrivate::East) {
3893 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3894 CGContextRotateCTM(ctx, M_PI_2);
3899 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3900 NSPopUpButtonCell *pbCell = nil;
3902 if (isPopupButton && (tp == QStyleOptionTab::OnlyOneTab || isBigSurOrAbove)) {
3906 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3907 oldPosition = pbCell.arrowPosition;
3908 pbCell.arrowPosition = NSPopUpNoArrow;
3909 if (pb.state == NSControlStateValueOff) {
3911 rAdjusted.origin.x -= 3;
3912 rAdjusted.size.width += 6;
3913 if (isBigSurOrAbove) {
3914 if (tp == QStyleOptionTab::End)
3915 rAdjusted.origin.x -= 2;
3920 [pb.cell drawBezelWithFrame:rAdjusted inView:pb.superview];
3923 pbCell.arrowPosition = oldPosition;
3926 if (needsInactiveHack) {
3928 const qreal pixelRatio = p->device()->devicePixelRatio();
3929 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3930 tabPixmap.setDevicePixelRatio(pixelRatio);
3931 tabPixmap.fill(Qt::transparent);
3932 QPainter tabPainter(&tabPixmap);
3933 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3934 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3935 drawBezelBlock(ctx, r);
3940 const qreal inactiveGray = 0.898;
3941 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3942 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3943 for (
int l = 0; l < tabPixmap.height(); ++l) {
3944 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3945 for (
int i = 0; i < tabPixmap.width(); ++i) {
3946 if (qAlpha(line[i]) == 255) {
3947 line[i] = inactiveGrayRGB;
3948 }
else if (qAlpha(line[i]) > 128) {
3949 const int g = qRound(inactiveGray * qRed(line[i]));
3950 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3956 p->drawImage(opt->rect, tabPixmap);
3958 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3961 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3962 && tp != QStyleOptionTab::End
3963 && tp != QStyleOptionTab::OnlyOneTab) {
3964 static const QPen separatorPen(Qt::black, 1.0);
3966 p->setOpacity(isEnabled ? 0.105 : 0.06);
3967 p->setPen(separatorPen);
3968 if (tabDirection == QMacStylePrivate::West) {
3969 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3970 opt->rect.right() - 0.5, opt->rect.bottom()));
3971 }
else if (tabDirection == QMacStylePrivate::East) {
3972 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3973 opt->rect.right() - 0.5, opt->rect.bottom()));
3975 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3976 opt->rect.right(), opt->rect.bottom() - 0.5));
3982 case CE_TabBarTabLabel:
3983 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3984 QStyleOptionTab myTab = *tab;
3985 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
3986 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3987 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3988 || tabDirection == QMacStylePrivate::West;
3994 const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value(
"QComboMenuItem");
3996 if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
3997 if (
const auto *tabBar = qobject_cast<
const QTabBar *>(w))
3998 if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
3999 myTab.palette.setColor(foregroundRole, Qt::white);
4001 if (myTab.documentMode && isDarkMode()) {
4002 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
4003 myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray);
4006 int heightOffset = 0;
4009 }
else if (nonDefaultFont) {
4010 if (p->fontMetrics().height() == myTab.rect.height())
4013 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4015 QCommonStyle::drawControl(ce, &myTab, p, w);
4019#if QT_CONFIG(dockwidget)
4020 case CE_DockWidgetTitle:
4021 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
4022 const bool isVertical = dwOpt->verticalTitleBar;
4023 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
4026 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
4028 p->translate(-effectiveRect.left(), -effectiveRect.top());
4032 p->fillRect(effectiveRect, opt->palette.window());
4035 p->setPen(opt->palette.dark().color());
4036 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
4038 if (!dwOpt->title.isEmpty()) {
4039 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt, w);
4041 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
4042 effectiveRect.top() + titleRect.left() - opt->rect.left(),
4046 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
4047 proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
4048 dwOpt->state & State_Enabled, text, QPalette::WindowText);
4054 case CE_FocusFrame: {
4055 const auto *ff = qobject_cast<
const QFocusFrame *>(w);
4056 const auto *ffw = ff ? ff->widget() :
nullptr;
4057 const auto ct = [=] {
4059 if (qobject_cast<
const QCheckBox*>(ffw))
4060 return QMacStylePrivate::Button_CheckBox;
4061 if (qobject_cast<
const QRadioButton*>(ffw))
4062 return QMacStylePrivate::Button_RadioButton;
4063 if (qobject_cast<
const QLineEdit*>(ffw) || qobject_cast<
const QTextEdit*>(ffw))
4064 return QMacStylePrivate::TextField;
4065 if (
const auto *pb = qobject_cast<
const QPushButton *>(ffw)) {
4067 auto sizePolicy = QStyleHelper::widgetSizePolicy(ffw, opt);
4068 if (sizePolicy == QStyleHelper::SizeDefault)
4069 sizePolicy = QStyleHelper::SizeLarge;
4071 || (pb->rect().height() != pushButtonDefaultHeight[sizePolicy])) {
4072 return QMacStylePrivate::Button_SquareButton;
4074 if (pb->menu() !=
nullptr)
4075 return QMacStylePrivate::Button_PullDown;
4076 return QMacStylePrivate::Button_PushButton;
4080 return QMacStylePrivate::Box;
4082 auto cs = QStyleHelper::widgetSizePolicy(ffw, opt);
4083 if (cs == QStyleHelper::SizeDefault)
4084 cs = QStyleHelper::SizeLarge;
4085 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, w);
4086 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w);
4087 d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
4089 case CE_MenuEmptyArea:
4091 if (qobject_cast<
const QAbstractItemView *>(w))
4092 proxy()->drawPrimitive(PE_PanelMenu, opt, p, w);
4096 case CE_MenuHMargin:
4097 case CE_MenuVMargin:
4098 case CE_MenuTearoff:
4099 case CE_MenuScroller:
4100 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4101 const bool active = mi->state & State_Selected;
4103 p->fillRect(mi->rect, mi->palette.highlight());
4105 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt, w);
4107 if (ce == CE_MenuTearoff) {
4108 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4109 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4110 mi->rect.x() + mi->rect.width() - 4,
4111 mi->rect.y() + mi->rect.height() / 2 - 1);
4112 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4113 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4114 mi->rect.x() + mi->rect.width() - 4,
4115 mi->rect.y() + mi->rect.height() / 2);
4116 }
else if (ce == CE_MenuScroller) {
4117 const QSize scrollerSize = QSize(10, 8);
4118 const int scrollerVOffset = 5;
4119 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
4120 const int right = left + scrollerSize.width();
4123 if (opt->state & State_DownArrow) {
4124 bottom = mi->rect.y() + scrollerVOffset;
4125 top = bottom + scrollerSize.height();
4127 bottom = mi->rect.bottom() - scrollerVOffset;
4128 top = bottom - scrollerSize.height();
4131 p->setRenderHint(QPainter::Antialiasing);
4133 path.moveTo(left, bottom);
4134 path.lineTo(right, bottom);
4135 path.lineTo((left + right) / 2, top);
4136 p->fillPath(path, opt->palette.buttonText());
4138 }
else if (ce != CE_MenuItem) {
4142 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4143 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
4144 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
4145 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
4149 const int maxpmw = mi->maxIconWidth;
4150 const bool enabled = mi->state & State_Enabled;
4152 int xpos = mi->rect.x() + 18;
4153 int checkcol = maxpmw;
4155 p->setPen(mi->palette.text().color());
4157 p->setPen(mi->palette.highlightedText().color());
4159 p->setPen(mi->palette.buttonText().color());
4162 QStyleOption checkmarkOpt;
4163 checkmarkOpt.initFrom(w);
4165 const int mw = checkcol + macItemFrame;
4166 const int mh = mi->rect.height() + macItemFrame;
4167 const int xp = mi->rect.x() + macItemFrame;
4168 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
4170 checkmarkOpt.state.setFlag(State_On, active);
4171 checkmarkOpt.state.setFlag(State_Enabled, enabled);
4172 if (widgetSize == QStyleHelper::SizeMini)
4173 checkmarkOpt.state |= State_Mini;
4174 else if (widgetSize == QStyleHelper::SizeSmall)
4175 checkmarkOpt.state |= State_Small;
4178 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
4179 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
4181 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w);
4183 if (!mi->icon.isNull()) {
4184 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4187 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4188 QSize iconSize(smallIconSize, smallIconSize);
4189#if QT_CONFIG(combobox)
4190 if (
const QComboBox *comboBox = qobject_cast<
const QComboBox *>(w)) {
4191 iconSize = comboBox->iconSize();
4194 QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
4195 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
4196 QSize size = pixmap.deviceIndependentSize().toSize();
4197 QRect pmr(QPoint(0, 0), size);
4198 pmr.moveCenter(cr.center());
4199 p->drawPixmap(pmr.topLeft(), pixmap);
4200 xpos += size.width() + 6;
4203 QString s = mi->text;
4204 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
4205 | Qt::TextSingleLine | Qt::AlignAbsolute;
4206 int yPos = mi->rect.y();
4207 if (widgetSize == QStyleHelper::SizeMini)
4210 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
4211 const int tabwidth = isSubMenu ? 9 : mi->reservedShortcutWidth;
4213 QString rightMarginText;
4215 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
4218 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
4219 if (tabIndex >= 0) {
4221 rightMarginText = s.mid(tabIndex + 1);
4222 s = s.left(tabIndex);
4226 if (!rightMarginText.isEmpty()) {
4227 p->setFont(qt_app_fonts_hash()->value(
"QMenuItem", p->font()));
4228 int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
4230 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
4232 xp -= macItemHMargin + macItemFrame + 3;
4234 const QKeySequence seq = QKeySequence::fromString(rightMarginText, QKeySequence::NativeText);
4235 if (seq.count() == 1) {
4237 const int maxKeyWidth = p->fontMetrics().maxWidth();
4238 const QChar key = rightMarginText.at(rightMarginText.length() - 1);
4239 const QString modifiers = rightMarginText.left(rightMarginText.size() - 1);
4240 p->drawText(xp + tabwidth - maxKeyWidth, yPos, maxKeyWidth, mi->rect.height(), text_flags, key);
4242 p->drawText(xp, yPos, tabwidth - maxKeyWidth, mi->rect.height(),
4243 text_flags | Qt::AlignRight | Qt::TextDontClip, modifiers);
4245 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, rightMarginText);
4251 const int xm = macItemFrame + maxpmw + macItemHMargin;
4252 QFont myFont = mi->font;
4258 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4263 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
4264 Q_ASSERT(fontEngine);
4265 if (fontEngine->type() == QFontEngine::Multi) {
4266 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
4267 Q_ASSERT(fontEngine);
4269 if (fontEngine->type() == QFontEngine::Mac) {
4270 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
4273 const auto pc = p->pen().color();
4274 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
4279 s = qt_mac_removeMnemonics(s);
4281 QMacCGContext cgCtx(p);
4282 d->setupNSGraphicsContext(cgCtx, YES);
4288 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
4289 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
4290 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0],
4291 NSUnderlineStyleAttributeName: [NSNumber numberWithInt: myFont.underline() ? NSUnderlineStyleSingle
4292 : NSUnderlineStyleNone]}];
4294 d->restoreNSGraphicsContext(cgCtx);
4297 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
4298 mi->rect.height(), text_flags, s);
4304 case CE_MenuBarItem:
4305 case CE_MenuBarEmptyArea:
4306 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4307 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
4308 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
4309 p->fillRect(mi->rect, bg);
4311 if (ce != CE_MenuBarItem)
4314 if (!mi->icon.isNull()) {
4315 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4316 drawItemPixmap(p, mi->rect,
4317 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4318 | Qt::TextSingleLine,
4319 mi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(),
4320 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4322 drawItemText(p, mi->rect,
4323 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4324 | Qt::TextSingleLine,
4325 mi->palette, mi->state & State_Enabled,
4326 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
4330 case CE_ProgressBarLabel:
4331 case CE_ProgressBarGroove:
4334 case CE_ProgressBarContents:
4335 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4336 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4337 const bool vertical = !(pb->state & QStyle::State_Horizontal);
4338 const bool inverted = pb->invertedAppearance;
4339 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4343 QRect rect = pb->rect;
4345 rect = rect.transposed();
4346 const CGRect cgRect = rect.toCGRect();
4348 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w);
4349 const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
4350 QIndeterminateProgressIndicator *ipi = nil;
4351 if (isIndeterminate || animation)
4352 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
4353 if (isIndeterminate) {
4361 if (!animation && opt->styleObject) {
4362 auto *animation =
new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
4364 animation->setFrameRate(QStyleAnimation::FifteenFps);
4365 d->startAnimation(animation);
4366 [ipi startAnimation];
4369 d->setupNSGraphicsContext(cg, NO);
4370 d->setupVerticalInvertedXform(cg, reverse, vertical, cgRect);
4371 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
4372 d->restoreNSGraphicsContext(cg);
4375 d->stopAnimation(opt->styleObject);
4376 [ipi stopAnimation];
4379 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
4380 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
4381 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
4382 d->setupVerticalInvertedXform(ctx, reverse, vertical, rect);
4383 pi.minValue = pb->minimum;
4384 pi.maxValue = pb->maximum;
4385 pi.doubleValue = pb->progress;
4393#ifndef QT_NO_MDIAREA
4394 if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
4398 if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
4399 p->fillRect(opt->rect, opt->palette.window());
4401 QPen lineColor = QColor(82, 82, 82, 192);
4402 lineColor.setWidth(1);
4404 p->setRenderHint(QPainter::Antialiasing);
4405 p->setPen(lineColor);
4406 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4407 const int NumLines = 3;
4408 for (
int l = 0; l < NumLines; ++l) {
4409 const int offset = (l * 4 + 3);
4411 if (layoutDirection == Qt::LeftToRight) {
4412 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4413 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4415 start = QPoint(offset, opt->rect.height() - 1);
4416 end = QPoint(1, opt->rect.height() - offset);
4418 p->drawLine(start, end);
4424 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
4425 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
4427 const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
4428 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4429 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
4430 sv.frame = opt->rect.toCGRect();
4431 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
4432 [sv drawDividerInRect:rect];
4435 QPen oldPen = p->pen();
4436 p->setPen(opt->palette.dark().color());
4437 if (opt->state & QStyle::State_Horizontal)
4438 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4440 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4445 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
4446 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4447 if (!rubber->opaque) {
4450 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4451 fillColor.setHsvF(0, 0, 0.53, 0.25);
4452 if (opt->rect.width() * opt->rect.height() <= 3) {
4453 p->fillRect(opt->rect, strokeColor);
4455 QPen oldPen = p->pen();
4456 QBrush oldBrush = p->brush();
4457 QPen pen(strokeColor);
4459 p->setBrush(fillColor);
4460 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
4461 if (adjusted.isValid())
4462 p->drawRect(adjusted);
4464 p->setBrush(oldBrush);
4467 p->fillRect(opt->rect, fillColor);
4471#ifndef QT_NO_TOOLBAR
4473 const QStyleOptionToolBar *toolBar = qstyleoption_cast<
const QStyleOptionToolBar *>(opt);
4474 const bool darkMode = isDarkMode();
4481#if QT_CONFIG(mainwindow)
4482 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4483 if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
4486 p->setCompositionMode(QPainter::CompositionMode_Source);
4487 p->fillRect(opt->rect, Qt::transparent);
4494 const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
4495 const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowToolbarEnd.y() + 1);
4496 if (isEndOfUnifiedArea) {
4497 const int margin = qt_mac_aqua_get_metric(SeparatorSize);
4498 const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
4499 p->fillRect(separatorRect, darkMode ? darkModeSeparatorLine : opt->palette.dark().color());
4508 QLinearGradient linearGrad;
4509 if (opt->state & State_Horizontal)
4510 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4512 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
4514 QColor mainWindowGradientBegin = darkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
4515 QColor mainWindowGradientEnd = darkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
4517 linearGrad.setColorAt(0, mainWindowGradientBegin);
4518 linearGrad.setColorAt(1, mainWindowGradientEnd);
4519 p->fillRect(opt->rect, linearGrad);
4522 QRect toolbarRect = darkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
4523 if (opt->state & State_Horizontal) {
4524 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
4525 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
4526 p->setPen(darkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
4527 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
4529 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
4530 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
4531 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
4532 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
4540 QCommonStyle::drawControl(ce, opt, p, w);
4554QRect QMacStyle::subElementRect(SubElement sr,
const QStyleOption *opt,
4555 const QWidget *widget)
const
4557 Q_D(
const QMacStyle);
4559 const int controlSize = getControlSize(opt, widget);
4562#if QT_CONFIG(itemviews)
4563 case SE_ItemViewItemText:
4564 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
4565 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget);
4567 rect = QCommonStyle::subElementRect(sr, opt, widget);
4568 if (vopt->features & QStyleOptionViewItem::HasDecoration)
4569 rect.adjust(-fw, 0, 0, 0);
4573 case SE_ToolBoxTabContents:
4574 rect = QCommonStyle::subElementRect(sr, opt, widget);
4576 case SE_PushButtonBevel:
4577 case SE_PushButtonContents:
4578 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4587 const auto ct = cocoaControlType(btn, widget);
4588 const auto cs = d->effectiveAquaSizeConstrain(btn, widget);
4589 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4590 auto frameRect = cw.adjustedControlFrame(btn->rect);
4591 if (sr == SE_PushButtonContents) {
4592 frameRect -= cw.titleMargins();
4593 }
else if (cw.type != QMacStylePrivate::Button_SquareButton) {
4594 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4595 frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:frameRect.toCGRect()]);
4596 if (cw.type == QMacStylePrivate::Button_PushButton)
4597 frameRect -= pushButtonShadowMargins[cw.size];
4598 else if (cw.type == QMacStylePrivate::Button_PullDown)
4599 frameRect -= pullDownButtonShadowMargins[cw.size];
4601 rect = frameRect.toRect();
4604 case SE_HeaderLabel: {
4605 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
4606 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
4607 opt->rect.width() - margin * 2, opt->rect.height() - 2);
4608 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
4610 if (header->sortIndicator != QStyleOptionHeader::None) {
4611 if (opt->state & State_Horizontal)
4612 rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
4614 rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
4617 rect = visualRect(opt->direction, opt->rect, rect);
4620 case SE_HeaderArrow: {
4621 int h = opt->rect.height();
4622 int w = opt->rect.width();
4623 int x = opt->rect.x();
4624 int y = opt->rect.y();
4625 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
4627 if (opt->state & State_Horizontal) {
4628 rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
4629 headerSectionArrowHeight, h - margin * 2 - 5);
4631 rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
4632 w - margin * 2 - 5, headerSectionArrowHeight);
4634 rect = visualRect(opt->direction, opt->rect, rect);
4637 case SE_ProgressBarGroove:
4641 case SE_ProgressBarLabel:
4643 case SE_ProgressBarContents:
4646 case SE_TreeViewDisclosureItem: {
4649 rect.setLeft(rect.left() + 2 + DisclosureOffset);
4652#if QT_CONFIG(tabwidget)
4653 case SE_TabWidgetLeftCorner:
4654 if (
const QStyleOptionTabWidgetFrame *twf
4655 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4656 switch (twf->shape) {
4657 case QTabBar::RoundedNorth:
4658 case QTabBar::TriangularNorth:
4659 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4661 case QTabBar::RoundedSouth:
4662 case QTabBar::TriangularSouth:
4663 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4664 twf->leftCornerWidgetSize);
4669 rect = visualRect(twf->direction, twf->rect, rect);
4672 case SE_TabWidgetRightCorner:
4673 if (
const QStyleOptionTabWidgetFrame *twf
4674 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4675 switch (twf->shape) {
4676 case QTabBar::RoundedNorth:
4677 case QTabBar::TriangularNorth:
4678 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4679 twf->rightCornerWidgetSize);
4681 case QTabBar::RoundedSouth:
4682 case QTabBar::TriangularSouth:
4683 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4684 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4685 twf->rightCornerWidgetSize);
4690 rect = visualRect(twf->direction, twf->rect, rect);
4693 case SE_TabWidgetTabContents:
4694 rect = QCommonStyle::subElementRect(sr, opt, widget);
4695 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4696 if (twf->lineWidth != 0) {
4697 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4698 case QMacStylePrivate::North:
4699 rect.adjust(+1, +14, -1, -1);
4701 case QMacStylePrivate::South:
4702 rect.adjust(+1, +1, -1, -14);
4704 case QMacStylePrivate::West:
4705 rect.adjust(+14, +1, -1, -1);
4707 case QMacStylePrivate::East:
4708 rect.adjust(+1, +1, -14, -1);
4713 case SE_TabBarTabText:
4714 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4715 QRect dummyIconRect;
4716 d->tabLayout(tab, widget, &rect, &dummyIconRect);
4719 case SE_TabBarTabLeftButton:
4720 case SE_TabBarTabRightButton:
4721 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4722 bool selected = tab->state & State_Selected;
4723 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget);
4724 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget);
4727 bool verticalTabs = tab->shape == QTabBar::RoundedEast
4728 || tab->shape == QTabBar::RoundedWest
4729 || tab->shape == QTabBar::TriangularEast
4730 || tab->shape == QTabBar::TriangularWest;
4732 QRect tr = tab->rect;
4733 if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
4734 verticalShift = -verticalShift;
4736 qSwap(horizontalShift, verticalShift);
4737 horizontalShift *= -1;
4738 verticalShift *= -1;
4740 if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
4741 horizontalShift = -horizontalShift;
4743 tr.adjust(0, 0, horizontalShift, verticalShift);
4746 tr.setBottom(tr.bottom() - verticalShift);
4747 tr.setRight(tr.right() - horizontalShift);
4750 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4751 int w = size.width();
4752 int h = size.height();
4753 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4754 int midWidth = ((tr.width() - w) / 2);
4756 bool atTheTop =
true;
4757 switch (tab->shape) {
4758 case QTabBar::RoundedWest:
4759 case QTabBar::TriangularWest:
4760 atTheTop = (sr == SE_TabBarTabLeftButton);
4762 case QTabBar::RoundedEast:
4763 case QTabBar::TriangularEast:
4764 atTheTop = (sr == SE_TabBarTabRightButton);
4767 if (sr == SE_TabBarTabLeftButton)
4768 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4770 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4771 rect = visualRect(tab->direction, tab->rect, rect);
4775 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4777 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4782 case SE_LineEditContents:
4783 rect = QCommonStyle::subElementRect(sr, opt, widget);
4784#if QT_CONFIG(combobox)
4785 if (widget && qobject_cast<
const QComboBox*>(widget->parentWidget()))
4786 rect.adjust(-1, -2, 0, 0);
4789 rect.adjust(-1, -1, 0, +1);
4791 case SE_CheckBoxLayoutItem:
4793 if (controlSize == QStyleHelper::SizeLarge) {
4794 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4795 }
else if (controlSize == QStyleHelper::SizeSmall) {
4796 setLayoutItemMargins(+1, +5, 0 , -6, &rect, opt->direction);
4798 setLayoutItemMargins(0, +7, 0 , -6, &rect, opt->direction);
4801 case SE_ComboBoxLayoutItem:
4802#ifndef QT_NO_TOOLBAR
4803 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4812 if (controlSize == QStyleHelper::SizeLarge) {
4813 rect.adjust(+3, +2, -3, -4);
4814 }
else if (controlSize == QStyleHelper::SizeSmall) {
4815 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4817 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4821 case SE_LabelLayoutItem:
4823 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4825 case SE_ProgressBarLayoutItem: {
4827 int bottom =
SIZE(3, 8, 8);
4828 if (opt->state & State_Horizontal) {
4829 rect.adjust(0, +1, 0, -bottom);
4831 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
4835 case SE_PushButtonLayoutItem:
4836 if (
const QStyleOptionButton *buttonOpt
4837 = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4838 if ((buttonOpt->features & QStyleOptionButton::Flat))
4840 if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) {
4842 if (controlSize == QStyleHelper::SizeLarge)
4843 rect.adjust(+6, +4, -6, -8);
4844 else if (controlSize == QStyleHelper::SizeSmall)
4845 rect.adjust(+5, +4, -5, -6);
4847 rect.adjust(+1, 0, -1, -2);
4852 if (controlSize == QStyleHelper::SizeLarge) {
4853 rect.adjust(0, +4, 0, -8);
4854 }
else if (controlSize == QStyleHelper::SizeSmall) {
4855 rect.adjust(0, +4, 0, -6);
4857 rect.adjust(0, 0, 0, -2);
4860 case SE_RadioButtonLayoutItem:
4862 if (controlSize == QStyleHelper::SizeLarge) {
4863 setLayoutItemMargins(+2, +2 ,
4864 0, -4 , &rect, opt->direction);
4865 }
else if (controlSize == QStyleHelper::SizeSmall) {
4866 rect.adjust(0, +6, 0 , -5);
4868 rect.adjust(0, +6, 0 , -7);
4871 case SE_SliderLayoutItem:
4872 if (
const QStyleOptionSlider *sliderOpt
4873 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4875 if (sliderOpt->tickPosition == QSlider::NoTicks) {
4876 int above =
SIZE(3, 0, 2);
4877 int below =
SIZE(4, 3, 0);
4878 if (sliderOpt->orientation == Qt::Horizontal) {
4879 rect.adjust(0, +above, 0, -below);
4881 rect.adjust(+above, 0, -below, 0);
4883 }
else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4884 int below =
SIZE(3, 2, 0);
4885 if (sliderOpt->orientation == Qt::Horizontal) {
4886 rect.setHeight(rect.height() - below);
4888 rect.setWidth(rect.width() - below);
4890 }
else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4891 int above =
SIZE(3, 2, 0);
4892 if (sliderOpt->orientation == Qt::Horizontal) {
4893 rect.setTop(rect.top() + above);
4895 rect.setLeft(rect.left() + above);
4900 case SE_FrameLayoutItem:
4902 if (
const QFrame *frame = qobject_cast<
const QFrame *>(widget)) {
4904 switch (frame->frameStyle() & QFrame::Shape_Mask) {
4906 rect.adjust(0, +1, 0, -1);
4909 rect.adjust(+1, 0, -1, 0);
4916 case SE_GroupBoxLayoutItem:
4918 if (
const QStyleOptionGroupBox *groupBoxOpt =
4919 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4921
4922
4923
4924
4925 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4926 | QStyle::SC_GroupBoxLabel)) {
4928 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4929 delta =
SIZE(8, 4, 4);
4931 delta =
SIZE(15, 12, 12);
4933 rect.setTop(rect.top() + delta);
4936 rect.setBottom(rect.bottom() - 1);
4938#if QT_CONFIG(tabwidget)
4939 case SE_TabWidgetLayoutItem:
4940 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4941 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4943
4944
4945
4946
4947 rect = tabWidgetOpt->rect;
4948 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4949 rect.setTop(rect.top() + SIZE(6 , 3 , 2 ));
4953#if QT_CONFIG(dockwidget)
4954 case SE_DockWidgetCloseButton:
4955 case SE_DockWidgetFloatButton:
4956 case SE_DockWidgetTitleBarText:
4957 case SE_DockWidgetIcon: {
4958 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
4959 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget);
4960 QRect srect = opt->rect;
4962 const QStyleOptionDockWidget *dwOpt
4963 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4964 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4965 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4967 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4971 if (verticalTitleBar)
4972 srect = srect.transposed();
4975 int right = srect.right();
4976 int left = srect.left();
4980 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4981 opt, widget).actualSize(QSize(iconSize, iconSize));
4982 sz += QSize(buttonMargin, buttonMargin);
4983 if (verticalTitleBar)
4984 sz = sz.transposed();
4985 closeRect = QRect(left,
4986 srect.center().y() - sz.height()/2,
4987 sz.width(), sz.height());
4988 left = closeRect.right() + 1;
4990 if (sr == SE_DockWidgetCloseButton) {
4997 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4998 opt, widget).actualSize(QSize(iconSize, iconSize));
4999 sz += QSize(buttonMargin, buttonMargin);
5000 if (verticalTitleBar)
5001 sz = sz.transposed();
5002 floatRect = QRect(left,
5003 srect.center().y() - sz.height()/2,
5004 sz.width(), sz.height());
5005 left = floatRect.right() + 1;
5007 if (sr == SE_DockWidgetFloatButton) {
5013 if (
const QDockWidget *dw = qobject_cast<
const QDockWidget*>(widget)) {
5015 if (dw->isFloating())
5016 icon = dw->windowIcon();
5018 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
5019 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
5020 if (verticalTitleBar)
5021 sz = sz.transposed();
5022 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
5023 sz.width(), sz.height());
5024 right = iconRect.left() - 1;
5027 if (sr == SE_DockWidgetIcon) {
5032 QRect textRect = QRect(left, srect.top(),
5033 right - left, srect.height());
5034 if (sr == SE_DockWidgetTitleBarText) {
5040 if (verticalTitleBar) {
5041 rect = QRect(srect.left() + rect.top() - srect.top(),
5042 srect.top() + srect.right() - rect.right(),
5043 rect.height(), rect.width());
5045 rect = visualRect(opt->direction, srect, rect);
5051 rect = QCommonStyle::subElementRect(sr, opt, widget);
5083void QMacStyle::drawComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt, QPainter *p,
5084 const QWidget *widget)
const
5086 Q_D(
const QMacStyle);
5087 const AppearanceSync sync;
5088 QMacCGContext cg(p);
5089 QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
nullptr;
5090 d->resolveCurrentNSView(window);
5093 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5095 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
5096 const bool drawKnob = sb->subControls & SC_ScrollBarSlider && sb->minimum != sb->maximum;
5097 if (!drawTrack && !drawKnob)
5100 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5102 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
5103 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
5105 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
5106 static const CGFloat expandedKnobWidths[] = { 11.0, 9.0, 9.0 };
5107 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt, widget);
5108 const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
5110 const QStyle *realStyle = widget ? widget->style() : proxy();
5111 const bool isTransient = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget);
5113 d->stopAnimation(opt->styleObject);
5114 bool wasActive =
false;
5115 CGFloat opacity = 0.0;
5116 CGFloat expandScale = 1.0;
5117 CGFloat expandOffset = 0.0;
5118 bool shouldExpand =
false;
5120 if (QObject *styleObject = opt->styleObject) {
5121 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
5122 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
5123 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
5124 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
5125 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
5126 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
5130 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
5133 oldPos != sb->sliderPosition ||
5134 oldMin != sb->minimum ||
5135 oldMax != sb->maximum ||
5136 oldRect != sb->rect ||
5137 oldState != sb->state ||
5138 oldActiveControls != sb->activeSubControls) {
5144 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
5145 styleObject->setProperty(
"_q_stylemin", sb->minimum);
5146 styleObject->setProperty(
"_q_stylemax", sb->maximum);
5147 styleObject->setProperty(
"_q_stylerect", sb->rect);
5148 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
5149 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
5151 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5154 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
5155 d->startAnimation(anim);
5156 }
else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5159 anim->setCurrentTime(0);
5161 }
else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5162 d->stopAnimation(styleObject);
5166 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5167 if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5170 if (oldActiveControls)
5171 anim->setActive(
true);
5173 wasActive = anim->wasActive();
5174 opacity = anim->currentValue();
5177 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
5179 if (!anim && !oldActiveControls) {
5181 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
5182 d->startAnimation(anim);
5184 if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
5185 expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
5186 expandOffset = 5.5 * (1.0 - anim->currentValue());
5189 expandScale = maxExpandScale;
5195 d->setupNSGraphicsContext(cg, NO );
5197 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5198 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
5199 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5201 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget);
5202 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
5206 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
5208 scroller.knobStyle = NSScrollerKnobStyleDefault;
5211 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
5213 if (!setupScroller(scroller, sb))
5217 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
5218 CGContextSetAlpha(cg, opacity);
5223 if (!isTransient || opt->activeSubControls || wasActive) {
5224 CGRect trackRect = scroller.bounds;
5226 trackRect.origin.y += expandOffset;
5228 trackRect.origin.x += expandOffset;
5229 [scroller drawKnobSlotInRect:trackRect highlight:NO];
5239 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
5240 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
5242 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
5243 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
5244 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
5245 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
5246 const CGFloat knobRadius = knobWidth / 2.0;
5249 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
5251 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
5252 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
5253 CGContextAddPath(cg, knobPath);
5254 CGContextSetAlpha(cg, 0.5);
5255 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
5256 CGContextSetFillColorWithColor(cg, knobColor);
5257 CGContextFillPath(cg);
5259 [scroller drawKnob];
5261 if (!isTransient && opt->activeSubControls) {
5266 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
5267 [scroller drawKnob];
5273 CGContextEndTransparencyLayer(cg);
5275 d->restoreNSGraphicsContext(cg);
5279 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5280 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5281 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5282 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5283 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5284 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5285 if (!setupSlider(slider, sl))
5288 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5289 const bool hasDoubleTicks = sl->tickPosition == QSlider::TicksBothSides;
5290 const bool drawKnob = sl->subControls & SC_SliderHandle;
5291 const bool drawBar = sl->subControls & SC_SliderGroove;
5292 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
5293 const bool isPressed = sl->state & State_Sunken;
5297 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
5298 pressPoint.x = CGRectGetMidX(knobRect);
5299 pressPoint.y = CGRectGetMidY(knobRect);
5308 [slider.cell startTrackingAt:pressPoint inView:slider];
5309 [slider.cell startTrackingAt:pressPoint inView:slider];
5312 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
5315 const bool verticalFlip = !isHorizontal && !sl->upsideDown;
5318 if (sl->upsideDown) {
5319 CGContextTranslateCTM(ctx, rect.size.width, rect.origin.y);
5320 CGContextScaleCTM(ctx, -1, 1);
5322 CGContextTranslateCTM(ctx, 0, rect.origin.y);
5324 }
else if (verticalFlip) {
5325 CGContextTranslateCTM(ctx, rect.origin.x, rect.size.height);
5326 CGContextScaleCTM(ctx, 1, -1);
5329 if (hasDoubleTicks) {
5332 CGContextTranslateCTM(ctx, 0, 4);
5334 CGContextTranslateCTM(ctx, 1, 0);
5341 const bool drawAllParts = drawKnob && drawBar && (!hasTicks || drawTicks);
5342 if (drawAllParts && !hasDoubleTicks && (!verticalFlip || drawTicks)) {
5346 if (verticalFlip && drawTicks) {
5349 slider.intValue = slider.maxValue - slider.intValue + slider.minValue;
5351 [slider drawRect:CGRectZero];
5355 NSSliderCell *cell = slider.cell;
5357 const int numberOfTickMarks = slider.numberOfTickMarks;
5360 slider.numberOfTickMarks = 0;
5362 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
5364 if (!isHorizontal && !sl->upsideDown && (hasDoubleTicks || !hasTicks)) {
5372 [cell drawBarInside:barRect flipped:
true];
5374 [cell drawBarInside:barRect flipped:!verticalFlip];
5378 slider.numberOfTickMarks = numberOfTickMarks;
5381 if (hasTicks && drawTicks) {
5382 if (!drawBar && hasDoubleTicks)
5383 slider.numberOfTickMarks = numberOfTickMarks;
5385 [cell drawTickMarks];
5387 if (hasDoubleTicks) {
5389 CGAffineTransform tickMarksFlip;
5390 const CGRect tickMarkRect = [cell rectOfTickMarkAtIndex:0];
5392 tickMarksFlip = CGAffineTransformMakeTranslation(0, rect.size.height - tickMarkRect.size.height - 3);
5393 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, 1, -1);
5395 tickMarksFlip = CGAffineTransformMakeTranslation(rect.size.width - tickMarkRect.size.width / 2, 0);
5396 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, -1, 1);
5398 CGContextConcatCTM(ctx, tickMarksFlip);
5399 [cell drawTickMarks];
5400 CGContextConcatCTM(ctx, CGAffineTransformInvert(tickMarksFlip));
5407 slider.numberOfTickMarks = 0;
5416 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5417 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5421#if QT_CONFIG(spinbox)
5423 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5424 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5425 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5426 QStyleOptionFrame frame;
5427 static_cast<QStyleOption &>(frame) = *opt;
5428 frame.rect = lineEditRect;
5429 frame.state |= State_Sunken;
5430 frame.lineWidth = 1;
5431 frame.midLineWidth = 0;
5432 frame.features = QStyleOptionFrame::None;
5433 frame.frameShape = QFrame::Box;
5434 drawPrimitive(PE_FrameLineEdit, &frame, p, widget);
5436 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5437 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget)
5438 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5440 d->setupNSGraphicsContext(cg, NO);
5442 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
5443 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5444 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5445 cell.enabled = (sb->state & State_Enabled);
5447 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
5449 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
5450 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
5451 const CGFloat x = CGRectGetMidX(newRect);
5452 const CGFloat y = upPressed ? -3 : 3;
5453 const CGPoint pressPoint = CGPointMake(x, y);
5456 if (upPressed || downPressed)
5457 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
5459 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
5461 if (upPressed || downPressed)
5462 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
5464 d->restoreNSGraphicsContext(cg);
5469#if QT_CONFIG(combobox)
5471 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5472 const bool isEnabled = combo->state & State_Enabled;
5473 const bool isPressed = combo->state & State_Sunken;
5475 const auto ct = cocoaControlType(combo, widget);
5476 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5477 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5478 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
5479 cc.enabled = isEnabled;
5480 QRectF frameRect = cw.adjustedControlFrame(combo->rect);
5481 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5483 auto *pb =
static_cast<NSPopUpButton *>(cc);
5485 if (cw.size == QStyleHelper::SizeSmall) {
5486 frameRect = frameRect.translated(0, 1);
5487 }
else if (cw.size == QStyleHelper::SizeMini) {
5489 frameRect = frameRect.translated(2, -0.5);
5491 pb.frame = frameRect.toCGRect();
5492 [pb highlight:isPressed];
5493 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5494 [pb.cell drawBezelWithFrame:r inView:pb.superview];
5496 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5498 auto *cb =
static_cast<NSComboBox *>(cc);
5499 const auto frameRect = cw.adjustedControlFrame(combo->rect);
5500 cb.frame = frameRect.toCGRect();
5503 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
5504 cell.highlighted = isPressed;
5509 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5511 [cb.cell drawWithFrame:r inView:cb];
5515 if (combo->state & State_HasFocus) {
5517 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, combo, widget);
5518 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, combo, widget);
5520 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5521 focusRect = QRectF::fromCGRect([cc alignmentRectForFrame:cc.frame]);
5522 focusRect -= pullDownButtonShadowMargins[cw.size];
5523 if (cw.size == QStyleHelper::SizeSmall)
5524 focusRect = focusRect.translated(0, 1);
5525 else if (cw.size == QStyleHelper::SizeMini)
5526 focusRect = focusRect.translated(2, -1);
5527 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5528 focusRect = frameRect - comboBoxFocusRingMargins[cw.size];
5530 d->drawFocusRing(p, focusRect, hMargin, vMargin, cw);
5536 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5537 const bool isActive = (titlebar->state & State_Active)
5538 && (titlebar->titleBarState & State_Active);
5540 p->fillRect(opt->rect, Qt::transparent);
5541 p->setRenderHint(QPainter::Antialiasing);
5542 p->setClipRect(opt->rect, Qt::IntersectClip);
5546 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
5547 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
5548 p->fillPath(outerFramePath, opt->palette.dark());
5550 const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
5551 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
5552 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
5553 p->fillPath(innerFramePath, opt->palette.button());
5555 if (titlebar->subControls & (SC_TitleBarCloseButton
5556 | SC_TitleBarMaxButton
5557 | SC_TitleBarMinButton
5558 | SC_TitleBarNormalButton)) {
5559 const bool isHovered = (titlebar->state & State_MouseOver);
5560 static const SubControl buttons[] = {
5561 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
5563 for (
const auto sc : buttons) {
5564 const auto ct = d->windowButtonCocoaControl(sc);
5565 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
5566 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5567 wb.enabled = (sc & titlebar->subControls) && isActive;
5568 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
5569 Q_UNUSED(isHovered);
5571 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget);
5572 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5573 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
5574 [wbCell drawWithFrame:rect inView:wb];
5579 if (titlebar->subControls & SC_TitleBarLabel) {
5580 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
5581 if (!titlebar->icon.isNull()) {
5582 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5583 const auto iconSize = QSize(iconExtent, iconExtent);
5584 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
5586 if (iconPos < tr.right() - titleBarIconTitleSpacing)
5587 p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(iconSize, QIcon::Normal));
5590 if (!titlebar->text.isEmpty())
5591 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
5596 if (
const QStyleOptionGroupBox *gb
5597 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5599 QStyleOptionGroupBox groupBox(*gb);
5600 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
5602 groupBox.state |= QStyle::State_Mini;
5604 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
5606 const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
5607 const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
5608 if (didModifySubControls)
5609 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
5610 QCommonStyle::drawComplexControl(cc, &groupBox, p, widget);
5611 if (didModifySubControls) {
5612 const QRect rect = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel, widget);
5613 const bool rtl = groupBox.direction == Qt::RightToLeft;
5614 const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
5615 const QFont savedFont = p->font();
5616 if (!flat && d->smallSystemFont)
5617 p->setFont(*d->smallSystemFont);
5618 proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
5620 p->setFont(savedFont);
5625 if (
const QStyleOptionToolButton *tb
5626 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
5627#if QT_CONFIG(accessibility)
5628 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
5629 if (tb->subControls & SC_ToolButtonMenu) {
5630 QStyleOption arrowOpt = *tb;
5631 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5632 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5633 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5634 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5635 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
5636 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
5637 d->drawToolbarButtonArrow(tb, p);
5639 if (tb->state & State_On) {
5640 NSView *view = window ? (NSView *)window->winId() : nil;
5643 isKey = [view.window isKeyWindow];
5645 QBrush brush(brushForToolButton(isKey));
5647 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
5648 p->setRenderHint(QPainter::Antialiasing);
5649 p->fillPath(path, brush);
5651 proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
5655 auto bflags = tb->state;
5656 if (tb->subControls & SC_ToolButton)
5657 bflags |= State_Sunken;
5658 auto mflags = tb->state;
5659 if (tb->subControls & SC_ToolButtonMenu)
5660 mflags |= State_Sunken;
5662 if (tb->subControls & SC_ToolButton) {
5663 if (bflags & (State_Sunken | State_On | State_Raised)) {
5664 const bool isEnabled = tb->state & State_Enabled;
5665 const bool isPressed = tb->state & State_Sunken;
5666 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5667 const auto ct = QMacStylePrivate::Button_PushButton;
5668 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5669 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5670 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5671 pb.bezelStyle = NSBezelStyleShadowlessSquare;
5672 pb.frame = opt->rect.toCGRect();
5673 pb.buttonType = NSButtonTypePushOnPushOff;
5674 pb.enabled = isEnabled;
5675 [pb highlight:isPressed];
5676 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5677 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
5678 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5679 [pb.cell drawBezelWithFrame:rect inView:pb];
5684 if (tb->subControls & SC_ToolButtonMenu) {
5685 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5686 QStyleOption arrowOpt = *tb;
5687 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
5688 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
5689 toolButtonArrowSize,
5690 toolButtonArrowSize);
5691 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5692 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
5693 d->drawToolbarButtonArrow(tb, p);
5695 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
5696 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
5697 QStyleOptionToolButton label = *tb;
5698 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5699 proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
5705 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
5706 QStyleHelper::drawDial(dial, p);
5710 QCommonStyle::drawComplexControl(cc, opt, p, widget);
5801QRect QMacStyle::subControlRect(ComplexControl cc,
const QStyleOptionComplex *opt, SubControl sc,
5802 const QWidget *widget)
const
5804 Q_D(
const QMacStyle);
5808 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5809 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5810 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5812 NSScrollerPart part = NSScrollerNoPart;
5813 if (sc == SC_ScrollBarSlider) {
5814 part = NSScrollerKnob;
5815 }
else if (sc == SC_ScrollBarGroove) {
5816 part = NSScrollerKnobSlot;
5817 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5818 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5819 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5820 part = NSScrollerDecrementPage;
5822 part = NSScrollerIncrementPage;
5826 if (part != NSScrollerNoPart) {
5827 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5828 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5829 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5830 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5831 if (setupScroller(scroller, sb))
5832 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5837 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5838 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5839 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5840 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5841 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5842 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5843 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5844 if (!setupSlider(slider, sl))
5847 NSSliderCell *cell = slider.cell;
5848 if (sc == SC_SliderHandle) {
5849 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5851 ret.setTop(sl->rect.top());
5852 ret.setBottom(sl->rect.bottom());
5854 ret.setLeft(sl->rect.left());
5855 ret.setRight(sl->rect.right());
5857 }
else if (sc == SC_SliderGroove) {
5858 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5859 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5860 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5862 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5864 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5869 if (sl->upsideDown) {
5870 ret = QRect(sl->rect.right() - ret.right(), sl->rect.top(), ret.width(), sl->rect.height());
5872 ret.setTop(sl->rect.top());
5873 ret.setBottom(sl->rect.bottom());
5876 if (!sl->upsideDown) {
5877 ret = QRect(sl->rect.left(), sl->rect.bottom() - ret.bottom(), sl->rect.width(), ret.height());
5879 ret.setLeft(sl->rect.left());
5880 ret.setRight(sl->rect.right());
5886 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5892 if (sc == SC_TitleBarLabel) {
5893 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5894 qreal labelHeight = titlebar->fontMetrics.height();
5896 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
5897 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5898 if (!titlebar->icon.isNull()) {
5899 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5900 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
5901 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5904 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5905 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5906 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5907 labelWidth, labelHeight);
5909 const auto currentButton = d->windowButtonCocoaControl(sc);
5910 if (currentButton == QMacStylePrivate::NoControl)
5913 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5915 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5916 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5917 QStyleHelper::SizeLarge);
5918 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5919 if (ct == currentButton)
5920 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5922 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5925 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5926 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5931 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5932 const auto ct = cocoaControlType(combo, widget);
5933 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5934 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5935 const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
5938 case SC_ComboBoxEditField:{
5939 ret = editRect.toAlignedRect();
5941 case SC_ComboBoxArrow:{
5942 ret = editRect.toAlignedRect();
5943 ret.setX(ret.x() + ret.width());
5944 ret.setWidth(combo->rect.right() - ret.right());
5946 case SC_ComboBoxListBoxPopup:{
5947 if (combo->editable) {
5948 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5949 const int comboTop = combo->rect.top();
5950 ret = QRect(qRound(inner.origin.x),
5952 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5953 editRect.bottom() - comboTop + 2);
5955 ret = QRect(combo->rect.x() + 4 - 11,
5956 combo->rect.y() + 1,
5957 editRect.width() + 10 + 11,
5967 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5968 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5969 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5970 bool hasNoText = !checkable && groupBox->text.isEmpty();
5972 case SC_GroupBoxLabel:
5973 case SC_GroupBoxCheckBox: {
5975 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5976 const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
5977 || !QApplication::desktopSettingsAware();
5978 const int margin = flat || hasNoText ? 0 : 9;
5979 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5981 const QFontMetricsF fm = flat || fontIsSet || !d->smallSystemFont
5982 ? QFontMetricsF(groupBox->fontMetrics)
5983 : QFontMetricsF(*d->smallSystemFont);
5984 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5985 const int tw = qCeil(s.width());
5986 const int h = qCeil(fm.height());
5989 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5991 if (flat && checkable)
5992 labelRect.moveLeft(labelRect.left() + 4);
5993 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
5994 bool rtl = groupBox->direction == Qt::RightToLeft;
5995 if (sc == SC_GroupBoxLabel) {
5997 int newSum = indicatorWidth + 1;
5998 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5999 labelRect.moveLeft(newLeft);
6001 labelRect.moveTop(labelRect.top() + 3);
6003 labelRect.moveTop(labelRect.top() + 4);
6005 int newLeft = labelRect.left() - (rtl ? 3 : -3);
6006 labelRect.moveLeft(newLeft);
6007 labelRect.moveTop(labelRect.top() + 3);
6009 int newLeft = labelRect.left() - (rtl ? 3 : 2);
6010 labelRect.moveLeft(newLeft);
6011 labelRect.moveTop(labelRect.top() + 4);
6016 if (sc == SC_GroupBoxCheckBox) {
6017 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
6018 int top = flat ? ret.top() + 1 : ret.top() + 5;
6019 ret.setRect(left, top,
6020 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
6024 case SC_GroupBoxContents:
6025 case SC_GroupBoxFrame: {
6026 QFontMetrics fm = groupBox->fontMetrics;
6029 if (widget && !widget->testAttribute(Qt::WA_SetFont)
6030 && QApplication::desktopSettingsAware())
6031 fm = QFontMetrics(qt_app_fonts_hash()->value(
"QSmallFont", QFont()));
6036 yOffset = -qCeil(QFontMetricsF(fm).height());
6037 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
6038 if (sc == SC_GroupBoxContents) {
6040 ret.adjust(3, -5, -3, -4);
6042 ret.adjust(3, 3, -3, -4);
6047 ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget);
6052#if QT_CONFIG(spinbox)
6054 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6055 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin, widget);
6056 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
6060 case QStyleHelper::SizeLarge:
6064 case QStyleHelper::SizeSmall:
6068 case QStyleHelper::SizeMini:
6078 case SC_SpinBoxDown: {
6079 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
6083 const int x = spin->rect.width() - spinner_w;
6084 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
6087 case QStyleHelper::SizeLarge:
6090 case QStyleHelper::SizeSmall:
6091 hackTranslateX = -2;
6093 case QStyleHelper::SizeMini:
6094 hackTranslateX = -1;
6100 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
6101 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
6102 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
6103 ret = QRectF::fromCGRect(outRect).toRect();
6107 ret.setHeight(ret.height() / 2);
6109 case SC_SpinBoxDown:
6110 ret.setY(ret.y() + ret.height() / 2);
6116 ret.translate(hackTranslateX, 0);
6117 ret = visualRect(spin->direction, spin->rect, ret);
6120 case SC_SpinBoxEditField:
6121 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
6122 if (spin->buttonSymbols != QAbstractSpinBox::NoButtons) {
6123 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
6124 ret = visualRect(spin->direction, spin->rect, ret);
6128 ret = QCommonStyle::subControlRect(cc, spin, sc, widget);
6135 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6136 if (sc == SC_ToolButtonMenu) {
6137#if QT_CONFIG(accessibility)
6138 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
6139 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
6141 ret.adjust(-1, 0, 0, 0);
6145 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6151QSize QMacStyle::sizeFromContents(ContentsType ct,
const QStyleOption *opt,
6152 const QSize &csz,
const QWidget *widget)
const
6154 Q_D(
const QMacStyle);
6156 bool useAquaGuideline =
true;
6159#if QT_CONFIG(spinbox)
6161 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6162 const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons);
6163 const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0;
6164 sz += QSize(buttonWidth, 0);
6168 case QStyle::CT_TabWidget:
6171 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6203#if QT_CONFIG(tabwidget)
6204 if (
const QStyleOptionTabWidgetFrame *twf
6205 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
6207 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
6208 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
6210 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
6211 if (tabDirection == QMacStylePrivate::North
6212 || tabDirection == QMacStylePrivate::South) {
6213 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
6215 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
6221#if QT_CONFIG(tabbar)
6222 case QStyle::CT_TabBarTab:
6223 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
6224 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
6225 || !QApplication::desktopSettingsAware();
6226 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
6227 const bool verticalTabs = tabDirection == QMacStylePrivate::East
6228 || tabDirection == QMacStylePrivate::West;
6230 sz = sz.transposed();
6232 int defaultTabHeight;
6233 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6235 case QStyleHelper::SizeLarge:
6236 if (tab->documentMode)
6237 defaultTabHeight = 24;
6239 defaultTabHeight = 21;
6241 case QStyleHelper::SizeSmall:
6242 defaultTabHeight = 18;
6244 case QStyleHelper::SizeMini:
6245 defaultTabHeight = 16;
6251 const bool widthSet = !differentFont && tab->icon.isNull();
6253 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
6254 sz.rwidth() = textSize.width();
6255 sz.rheight() = qMax(defaultTabHeight, textSize.height());
6257 sz.rheight() = qMax(defaultTabHeight, sz.height());
6259 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget);
6262 sz = sz.transposed();
6264 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
6265 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
6267 int widgetWidth = 0;
6268 int widgetHeight = 0;
6270 if (tab->leftButtonSize.isValid()) {
6272 widgetWidth += tab->leftButtonSize.width();
6273 widgetHeight += tab->leftButtonSize.height();
6275 if (tab->rightButtonSize.isValid()) {
6277 widgetWidth += tab->rightButtonSize.width();
6278 widgetHeight += tab->rightButtonSize.height();
6282 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
6283 sz.setHeight(sz.height() + widgetHeight + padding);
6286 sz.setWidth(sz.width() + widgetWidth + padding);
6287 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
6292 case QStyle::CT_PushButton: {
6293 bool isFlat =
false;
6294 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
6295 if (btn->features & QStyleOptionButton::CommandLinkButton)
6296 return QCommonStyle::sizeFromContents(ct, opt, sz, widget);
6297 isFlat = btn->features & QStyleOptionButton::Flat;
6304 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz);
6306 if (macsz.width() != -1)
6307 sz.setWidth(macsz.width());
6309 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
6311 if (controlSize != QStyleHelper::SizeMini)
6314 if (controlSize == QStyleHelper::SizeLarge) {
6317 if (sz.height() > 16)
6318 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6320 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeLarge]);
6324 if (controlSize == QStyleHelper::SizeMini)
6327 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeSmall]);
6333 case QStyle::CT_MenuItem:
6334 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
6335 int maxpmw = mi->maxIconWidth;
6336#if QT_CONFIG(combobox)
6337 const QComboBox *comboBox = qobject_cast<
const QComboBox *>(widget);
6341 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
6343 h = qt_mac_aqua_get_metric(MenuSeparatorHeight);
6345 h = mi->fontMetrics.height() + 2;
6346 if (!mi->icon.isNull()) {
6347#if QT_CONFIG(combobox)
6349 const QSize &iconSize = comboBox->iconSize();
6350 h = qMax(h, iconSize.height() + 4);
6351 maxpmw = qMax(maxpmw, iconSize.width());
6355 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
6356 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
6360 if (mi->text.contains(QLatin1Char(
'\t')))
6362 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
6368#if QT_CONFIG(combobox)
6369 if (comboBox && comboBox->isVisible()) {
6370 QStyleOptionComboBox cmb;
6371 cmb.initFrom(comboBox);
6372 cmb.editable =
false;
6373 cmb.subControls = QStyle::SC_ComboBoxEditField;
6374 cmb.activeSubControls = QStyle::SC_None;
6375 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
6376 QStyle::SC_ComboBoxEditField,
6386 case CT_MenuBarItem:
6393 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
6394 if (tb->features & QStyleOptionToolButton::Menu)
6395 sz.rwidth() += toolButtonArrowMargin;
6398 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
6399 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
6400 if (!cb->editable) {
6403 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 24;
6405 if (controlSize != QStyleHelper::SizeMini)
6409 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
6410 sz.rheight() += popupButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6418 if (controlSize == QStyleHelper::SizeMini)
6421 sz.setHeight(pushButtonDefaultHeight[controlSize]);
6427 if (proxy() ==
this) {
6430 QStyleHintReturnMask menuMask;
6431 QStyleOption myOption = *opt;
6432 myOption.rect.setSize(sz);
6433 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask))
6434 sz = menuMask.region.boundingRect().size();
6437 case CT_HeaderSection:{
6438 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
6439 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6440 if (header->text.contains(QLatin1Char(
'\n')))
6441 useAquaGuideline =
false;
6445 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6446 const int minimumSize = 24;
6447 if (slider->orientation == Qt::Horizontal)
6448 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6450 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6453#if QT_CONFIG(itemviews)
6454 case CT_ItemViewItem:
6455 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
6456 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6457 sz.setHeight(sz.height() + 2);
6463 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6466 if (useAquaGuideline && ct != CT_PushButton) {
6469 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
6470 if (macsz.width() != -1)
6471 sz.setWidth(macsz.width());
6472 if (macsz.height() != -1)
6473 sz.setHeight(macsz.height());
6479 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
6480 if (combo->editable) {
6481 const auto widgetSize = d->aquaSizeConstrain(opt, widget);
6482 QMacStylePrivate::CocoaControl cw;
6483 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
6484 cw.size = widgetSize;
6485 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
6486 sz.rwidth() -= qRound(diffRect.size.width);
6487 sz.rheight() -= qRound(diffRect.size.height);