1281void QMacStylePrivate::drawFocusRing(QPainter *p,
const QRectF &targetRect,
int hMargin,
int vMargin,
const CocoaControl &cw)
const
1283 QPainterPath focusRingPath;
1284 focusRingPath.setFillRule(Qt::OddEvenFill);
1286 qreal hOffset = 0.0;
1287 qreal vOffset = 0.0;
1290 case Button_SquareButton:
1291 case SegmentedControl_Middle:
1293 auto innerRect = targetRect;
1294 qreal innerRadius = 0.0;
1295 if (cw.type == Button_SquareButton)
1296 innerRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
1297 if (cw.type == TextField) {
1298 innerRect = innerRect.adjusted(hMargin, vMargin, -hMargin, -vMargin).adjusted(0.5, 0.5, -0.5, -0.5);
1299 if (qt_apple_runningWithLiquidGlass())
1300 innerRadius = textFieldBezelCornerRadius - 0.5;
1302 const auto outerRect = innerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1303 const auto outerRadius = innerRadius + focusRingWidth;
1304 if (innerRadius > 0.0)
1305 focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
1307 focusRingPath.addRect(innerRect);
1308 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1311 case Button_CheckBox: {
1312 const auto cbInnerRadius = (cw.size == QStyleHelper::SizeMini ? 2.0 : 3.0);
1313 const auto cbSize = cw.size == QStyleHelper::SizeLarge ? 13 :
1314 cw.size == QStyleHelper::SizeSmall ? 11 : 9;
1315 hOffset = hMargin + (cw.size == QStyleHelper::SizeLarge ? (qt_apple_runningWithLiquidGlass() ? 1.5 : 2.5) :
1316 cw.size == QStyleHelper::SizeSmall ? (qt_apple_runningWithLiquidGlass() ? 1.5 : 2.0) : 1.0);
1317 vOffset = 0.5 * qreal(targetRect.height() - cbSize);
1318 if (qt_apple_runningWithLiquidGlass()) {
1319 if (cw.size == QStyleHelper::SizeSmall)
1321 if (cw.size == QStyleHelper::SizeMini)
1324 const auto cbInnerRect = QRectF(0, 0, cbSize, cbSize);
1325 const auto cbOuterRadius = cbInnerRadius + focusRingWidth;
1326 const auto cbOuterRect = cbInnerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1327 focusRingPath.addRoundedRect(cbOuterRect, cbOuterRadius, cbOuterRadius);
1328 focusRingPath.addRoundedRect(cbInnerRect, cbInnerRadius, cbInnerRadius);
1331 case Button_RadioButton: {
1332 const auto rbSize = cw.size == QStyleHelper::SizeLarge ? 15 :
1333 cw.size == QStyleHelper::SizeSmall ? 13 : 9;
1334 hOffset = hMargin + (cw.size == QStyleHelper::SizeLarge ? (qt_apple_runningWithLiquidGlass() ? 0.5 : 1.5) :
1335 cw.size == QStyleHelper::SizeSmall ? (qt_apple_runningWithLiquidGlass() ? 0.5 : 1.0) : 1.0);
1336 vOffset = 0.5 * qreal(targetRect.height() - rbSize);
1337 const auto rbInnerRect = QRectF(0, 0, rbSize, rbSize);
1338 const auto rbOuterRect = rbInnerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1339 focusRingPath.addEllipse(rbInnerRect);
1340 focusRingPath.addEllipse(rbOuterRect);
1343 case Button_PullDown:
1344 case Button_PushButton: {
1346 auto *pb =
static_cast<NSButton *>(cocoaControl(cw));
1347 const QRectF frameRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
1348 pb.frame = frameRect.toCGRect();
1350 if (qt_apple_runningWithLiquidGlass())
1351 focusRect = QRectF::fromCGRect(qt_alignmentRectForFrame(pb.frame, cw.size, cw.type));
1353 focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
1355 if (cw.type == QMacStylePrivate::Button_PushButton) {
1356 adjustPushButtonShadowMargins(focusRect, cw.size);
1357 if (cw.size == QStyleHelper::SizeMini)
1358 focusRect.adjust(0, 3, 0, -3);
1359 }
else if (cw.type == QMacStylePrivate::Button_PullDown) {
1360 focusRect -= pullDownButtonShadowMargins[cw.size];
1362 if (cw.size == QStyleHelper::SizeLarge)
1363 focusRect = focusRect.adjusted(0, 0, 0, -1);
1364 else if (cw.size == QStyleHelper::SizeMini)
1365 focusRect = focusRect.adjusted(0, -1, 0, 0);
1367 focusRect = focusRect.translated(0, 1);
1368 const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
1369 const qreal outerRadius = innerRadius + focusRingWidth;
1370 hOffset = focusRect.left();
1371 vOffset = focusRect.top();
1372 const auto innerRect = focusRect.translated(-focusRect.topLeft());
1373 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1374 focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
1375 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1378 case Button_PopupButton:
1379 case SegmentedControl_Single: {
1380 QRectF focusRect = targetRect;
1382 if (!qt_apple_runningWithLiquidGlass())
1383 focusRect.translate(0, -1.5);
1384 const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
1385 const qreal outerRadius = innerRadius + focusRingWidth;
1386 hOffset = focusRect.left();
1387 vOffset = focusRect.top();
1388 const auto innerRect = focusRect.translated(-focusRect.topLeft());
1389 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1390 focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
1391 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1395 case SegmentedControl_First:
1396 case SegmentedControl_Last: {
1397 hOffset = targetRect.left();
1398 vOffset = targetRect.top();
1399 const qreal innerRadius = 8;
1400 const qreal outerRadius = innerRadius + focusRingWidth;
1401 const auto innerRect = targetRect.translated(-targetRect.topLeft());
1402 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1404 const auto cbFocusFramePath = [](
const QRectF &rect, qreal tRadius, qreal bRadius) {
1408 const auto topLeftCorner = QRectF(rect.topLeft(), QSizeF(tRadius, tRadius));
1409 path.arcMoveTo(topLeftCorner, 180);
1410 path.arcTo(topLeftCorner, 180, -90);
1412 path.moveTo(rect.topLeft());
1414 const auto rightEdge = rect.right() - bRadius;
1415 path.arcTo(rightEdge, rect.top(), bRadius, bRadius, 90, -90);
1416 path.arcTo(rightEdge, rect.bottom() - bRadius, bRadius, bRadius, 0, -90);
1418 path.arcTo(rect.left(), rect.bottom() - tRadius, tRadius, tRadius, 270, -90);
1420 path.lineTo(rect.bottomLeft());
1421 path.closeSubpath();
1426 const auto innerPath = cbFocusFramePath(innerRect, 0, innerRadius);
1427 focusRingPath.addPath(innerPath);
1428 const auto outerPath = cbFocusFramePath(outerRect, 2 * focusRingWidth, outerRadius);
1429 focusRingPath.addPath(outerPath);
1436 auto focusRingColor = qt_mac_toQColor(NSColor.keyboardFocusIndicatorColor.CGColor);
1441 focusRingColor.setAlphaF(0.39);
1445 p->setRenderHint(QPainter::Antialiasing);
1447 if (cw.type == SegmentedControl_First) {
1450 p->translate(hOffset, vOffset);
1451 p->fillPath(focusRingPath, focusRingColor);
3227 const QWidget *w)
const
3229 Q_D(
const QMacStyle);
3230 QMacCGContext cg(p);
3232 qCWarning(lcMacStyle) <<
"drawPrimitive:" << pe <<
"invalid (nullptr) graphics context";
3234 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
3235 d->resolveCurrentNSView(window);
3237 case PE_IndicatorArrowUp:
3238 case PE_IndicatorArrowDown:
3239 case PE_IndicatorArrowRight:
3240 case PE_IndicatorArrowLeft: {
3242 p->setRenderHint(QPainter::Antialiasing);
3243 const int xOffset = 1;
3244 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
3245 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
3246#if QT_CONFIG(toolbutton)
3247 if (
const QToolButton *tb = qobject_cast<
const QToolButton *>(w)) {
3249 if (tb->arrowType() != Qt::NoArrow
3250 || tb->popupMode() == QToolButton::MenuButtonPopup)
3251 halfSize -= penWidth;
3255 QTransform transform;
3256 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
3260 case PE_IndicatorArrowDown:
3262 case PE_IndicatorArrowUp:
3263 transform.rotate(180);
3265 case PE_IndicatorArrowLeft:
3266 transform.rotate(90);
3268 case PE_IndicatorArrowRight:
3269 transform.rotate(-90);
3272 p->setTransform(transform);
3274 path.moveTo(-halfSize, -halfSize * 0.5);
3275 path.lineTo(0.0, halfSize * 0.5);
3276 path.lineTo(halfSize, -halfSize * 0.5);
3278 const QPen arrowPen(opt->palette.text(), penWidth,
3279 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
3280 p->strokePath(path, arrowPen);
3283#if QT_CONFIG(tabbar)
3284 case PE_FrameTabBarBase:
3285 if (
const QStyleOptionTabBarBase *tbb
3286 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
3287 if (tbb->documentMode) {
3289 drawTabBase(p, tbb, w);
3293#if QT_CONFIG(tabwidget)
3294 QRegion region(tbb->rect);
3295 region -= tbb->tabBarRect.adjusted(3, 0, -3, 0);
3297 p->setClipRegion(region);
3298 QStyleOptionTabWidgetFrame twf;
3299 twf.QStyleOption::operator=(*tbb);
3300 twf.shape = tbb->shape;
3301 switch (QMacStylePrivate::tabDirection(twf.shape)) {
3302 case QMacStylePrivate::North:
3303 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
3305 case QMacStylePrivate::South:
3306 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3308 case QMacStylePrivate::West:
3309 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
3311 case QMacStylePrivate::East:
3312 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3315 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
3321 case PE_PanelTipLabel:
3322 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
3324 case PE_FrameGroupBox:
3325 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
3326 if (groupBox->features & QStyleOptionFrame::Flat) {
3327 QCommonStyle::drawPrimitive(pe, groupBox, p, w);
3330#if QT_CONFIG(tabwidget)
3332 case PE_FrameTabWidget:
3335 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
3336 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
3350 auto adjustedRect = opt->rect;
3351 bool needTranslation =
false;
3353 if (!qt_apple_runningWithLiquidGlass() && !
isDarkMode()) {
3366 adjustedRect.adjust(0, 0, 6, 6);
3367 needTranslation =
true;
3369 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3370#if QT_CONFIG(tabwidget)
3371 if (qobject_cast<QTabWidget *>(opt->styleObject))
3372 clipTabBarFrame(opt,
this, ctx);
3374 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
3375 CGContextScaleCTM(ctx, 1, -1);
3376 if ([box isMemberOfClass:QDarkNSBox.
class]) {
3377 [box drawRect:rect];
3379 if (needTranslation)
3380 CGContextTranslateCTM(ctx, -3.0, 5.0);
3381 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
3386 case PE_IndicatorToolBarSeparator: {
3388 if (opt->state & State_Horizontal) {
3389 int xpoint = opt->rect.center().x();
3390 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3391 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3393 int ypoint = opt->rect.center().y();
3394 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3395 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3397 QPainterPathStroker theStroker;
3398 theStroker.setCapStyle(Qt::FlatCap);
3399 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3400 path = theStroker.createStroke(path);
3401 const auto dark =
isDarkMode() ? opt->palette.dark().color().darker()
3402 : QColor(0, 0, 0, 119);
3403 p->fillPath(path, dark);
3406 case PE_FrameWindow:
3407 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3408 if (qobject_cast<
const QMdiSubWindow*>(w)) {
3410 p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
3411 p->setBrush(frame->palette.window());
3412 p->drawRect(frame->rect);
3417 case PE_IndicatorDockWidgetResizeHandle: {
3420 if (opt->state & State_Horizontal) {
3421 p->setPen(QColor(160, 160, 160));
3422 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3424 p->setPen(QColor(145, 145, 145));
3425 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3429 case PE_IndicatorToolBarHandle: {
3432 int x = opt->rect.x() + 6;
3433 int y = opt->rect.y() + 7;
3434 static const int RectHeight = 2;
3435 if (opt->state & State_Horizontal) {
3436 while (y < opt->rect.height() - RectHeight - 5) {
3438 path.addEllipse(x, y, RectHeight, RectHeight);
3442 while (x < opt->rect.width() - RectHeight - 5) {
3444 path.addEllipse(x, y, RectHeight, RectHeight);
3448 p->setPen(Qt::NoPen);
3449 QColor dark = opt->palette.dark().color().darker();
3450 dark.setAlphaF(0.50);
3451 p->fillPath(path, dark);
3456 case PE_IndicatorHeaderArrow:
3457 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3459 if (header->sortIndicator != QStyleOptionHeader::None)
3460 proxy()->drawPrimitive(
3461 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3462 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3465 case PE_IndicatorMenuCheckMark: {
3469 if (opt->state & State_On)
3470 pc = opt->palette.highlightedText().color();
3472 pc = opt->palette.text().color();
3474 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
3475 static_cast<CGFloat>(pc.greenF()),
3476 static_cast<CGFloat>(pc.blueF()),
3477 static_cast<CGFloat>(pc.alphaF()));
3483 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
3484 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
3485 kCTFontUIFontMenuItemMark;
3489 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
3490 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
3492 CGContextSaveGState(cg);
3493 CGContextSetShouldSmoothFonts(cg, NO);
3496 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
3497 (opt->state & State_Small) ? 1.0 :
3500 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
3501 CGContextScaleCTM(cg, 1, -1);
3503 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
3507 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
3508 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
3509 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
3510 static_assert((
sizeof(values) /
sizeof(values[0])) == numValues);
3511 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
3512 numValues, NULL, NULL);
3514 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
3515 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
3517 CTLineDraw((CTLineRef)line, cg);
3520 CGContextRestoreGState(cg);
3522 case PE_IndicatorItemViewItemCheck:
3523 case PE_IndicatorRadioButton:
3524 case PE_IndicatorCheckBox: {
3525 const bool isEnabled = opt->state & State_Enabled;
3526 const bool isPressed = opt->state & State_Sunken;
3527 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
3528 const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
3529 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3530 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3531 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
3532 tb.enabled = isEnabled;
3533 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
3534 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
3535 [tb highlight:isPressed];
3536 const auto vOffset = [=] {
3538 if (cs == QStyleHelper::SizeMini)
3539 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
3541 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
3543 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3544 CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y + vOffset);
3545 [tb.cell drawInteriorWithFrame:tb.bounds inView:tb];
3548 case PE_FrameFocusRect:
3551 case PE_IndicatorBranch: {
3552 if (!(opt->state & State_Children))
3556 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
3557 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
3558 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
3559 bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
3560 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
3561 [triangleCell setUserInterfaceLayoutDirection:qt_macLayoutDirectionFromQt(opt->direction)];
3563 d->setupNSGraphicsContext(cg, NO);
3566 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
3567 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
3568 CGContextScaleCTM(cg, 1, -1);
3569 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
3571 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
3573 d->restoreNSGraphicsContext(cg);
3577 QPen oldPen = p->pen();
3578 p->setPen(opt->palette.base().color().darker(140));
3579 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3580 p->setPen(opt->palette.base().color().darker(180));
3581 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3585 case PE_FrameLineEdit:
3586 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
3587 if (frame->state & State_Sunken) {
3588 const bool isEnabled = opt->state & State_Enabled;
3589 const bool isReadOnly = opt->state & State_ReadOnly;
3590 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
3591 const auto cs = d->effectiveAquaSizeConstrain(opt, w, CT_LineEdit);
3592 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
3593 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
3594 tf.enabled = isEnabled;
3595 tf.editable = !isReadOnly;
3596 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
3597 const bool hasCustomBackground = hasCustomTextFieldBackground(frame->palette);
3599 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
3600 tf.frame = opt->rect.toCGRect();
3601 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3602 if (!isDarkMode() && !hasCustomBackground) {
3609 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
3613 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
3614 tf.drawsBackground = YES;
3615 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
3616 green:bgColor.greenF()
3617 blue:bgColor.blueF()
3618 alpha:bgColor.alphaF()];
3619 if (bgColor.alpha() != 255) {
3626 CGRect fixedRect = rect;
3627 if (qt_apple_runningWithLiquidGlass() && tf.bezeled) {
3633 fixedRect = CGRectInset(rect, 1., 1.);
3635 [tf.cell drawWithFrame:fixedRect inView:tf];
3637 if (hasCustomBackground)
3638 drawTextFieldCustomBackground(p, opt->rect, bgColor);
3640 QCommonStyle::drawPrimitive(pe, opt, p, w);
3644 case PE_PanelLineEdit:
3646 const QStyleOptionFrame *panel = qstyleoption_cast<
const QStyleOptionFrame *>(opt);
3649 const bool hasCustomBackground = panel && hasCustomTextFieldBackground(panel->palette);
3650 if ((panel && panel->lineWidth <= 0) || (
isDarkMode() && !hasCustomBackground)) {
3656 QCommonStyle::drawPrimitive(pe, opt, p, w);
3661 drawPrimitive(PE_FrameLineEdit, opt, p, w);
3667#if QT_CONFIG(lineedit)
3668 if ((opt->state & State_HasFocus) && !qobject_cast<
const QLineEdit*>(w)) {
3669 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3670 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3671 QStyleOptionFrame focusFrame = *panel;
3672 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3673 drawControl(CE_FocusFrame, &focusFrame, p, w);
3679 case PE_PanelScrollAreaCorner: {
3680 const QBrush brush(opt->palette.brush(QPalette::Base));
3681 p->fillRect(opt->rect, brush);
3682 p->setPen(QPen(QColor(217, 217, 217)));
3683 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3684 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3686 case PE_FrameStatusBarItem:
3688#if QT_CONFIG(tabbar)
3689 case PE_IndicatorTabClose: {
3691 QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
3692 const QWidget *closeBtn = w;
3696 tabBar = qobject_cast<QTabBar *>(
const_cast<QWidget*>(w));
3697 closeBtn =
decltype(closeBtn)(property(
"_q_styleSheetRealCloseButton").value<
void *>());
3700 const bool documentMode = tabBar->documentMode();
3701 const QTabBarPrivate *tabBarPrivate =
static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
3702 const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
3703 if (!documentMode ||
3704 (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
3705 (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
3706 const bool hover = (opt->state & State_MouseOver);
3707 const bool selected = (opt->state & State_Selected);
3708 const bool pressed = (opt->state & State_Sunken);
3709 drawTabCloseButton(p, hover, selected, pressed, documentMode);
3714 case PE_PanelStatusBar: {
3715 p->fillRect(opt->rect, opt->palette.window());
3718 if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
3719 p->setPen(titlebarSeparatorLineActive);
3721 p->setPen(titlebarSeparatorLineInactive);
3722 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3726 case PE_PanelMenu: {
3728 p->fillRect(opt->rect, Qt::transparent);
3729 p->setPen(Qt::transparent);
3730 p->setBrush(opt->palette.window());
3731 p->setRenderHint(QPainter::Antialiasing,
true);
3732 const QPainterPath path = d->windowPanelPath(opt->rect);
3738 QCommonStyle::drawPrimitive(pe, opt, p, w);
3779 const QWidget *w)
const
3781 Q_D(
const QMacStyle);
3782 const QMacAutoReleasePool pool;
3783 QMacCGContext cg(p);
3785 qCWarning(lcMacStyle) <<
"drawControl:" << ce <<
"invalid (nullptr) graphics context";
3787 QWindow *window = w && w->window() ? w->window()->windowHandle() :
nullptr;
3788 d->resolveCurrentNSView(window);
3790 case CE_HeaderSection:
3791 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3792 State flags = header->state;
3793 QRect ir = header->rect;
3797 bool noVerticalHeader =
true;
3798#if QT_CONFIG(tableview)
3800 if (
const QTableView *table = qobject_cast<
const QTableView *>(w->parentWidget()))
3801 noVerticalHeader = !table->verticalHeader()->isVisible();
3804 const bool drawLeftBorder = header->orientation == Qt::Vertical
3805 || header->position == QStyleOptionHeader::OnlyOneSection
3806 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3809 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
3810 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
3811 p->setPen(QPen(header->palette.dark(), 1.0));
3812 if (header->orientation == Qt::Horizontal)
3821 case CE_ToolButtonLabel:
3822 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
3823 QStyleOptionToolButton myTb = *tb;
3824 myTb.state &= ~State_AutoRaise;
3825#if QT_CONFIG(accessibility)
3826 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
3827 QRect cr = tb->rect;
3830 bool needText =
false;
3832 bool down = tb->state & (State_Sunken | State_On);
3834 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3835 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3841 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3842 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3843 if (tb->icon.isNull() && !tb->text.isEmpty())
3844 tbstyle = Qt::ToolButtonTextOnly;
3847 case Qt::ToolButtonTextOnly: {
3849 alignment = Qt::AlignCenter;
3851 case Qt::ToolButtonIconOnly:
3852 case Qt::ToolButtonTextBesideIcon:
3853 case Qt::ToolButtonTextUnderIcon: {
3855 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3857 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3859 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), p->device()->devicePixelRatio(),
3860 iconMode, iconState);
3863 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3865 QSizeF size = pixmap.deviceIndependentSize();
3866 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3867 pr.setHeight(size.height() + 6);
3868 cr.adjust(0, pr.bottom(), 0, -3);
3869 alignment |= Qt::AlignCenter;
3871 pr.setWidth(size.width() + 8);
3872 cr.adjust(pr.right(), 0, 0, 0);
3873 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3876 if (opt->state & State_Sunken) {
3877 pr.translate(shiftX, shiftY);
3878 pixmap = darkenPixmap(pixmap);
3880 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3888 QPalette pal = tb->palette;
3889 QPalette::ColorRole role = QPalette::NoRole;
3890 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3891 alignment |= Qt::TextHideMnemonic;
3893 cr.translate(shiftX, shiftY);
3894 if (tbstyle == Qt::ToolButtonTextOnly
3895 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3896 QPen pen = p->pen();
3897 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3898 light.setAlphaF(0.375f);
3900 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3902 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3903 pal = QApplication::palette(
"QMenu");
3904 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3905 role = QPalette::HighlightedText;
3908 proxy()->drawItemText(p, cr, alignment, pal,
3909 tb->state & State_Enabled, tb->text, role);
3912 QCommonStyle::drawControl(ce, &myTb, p, w);
3917 QCommonStyle::drawControl(ce, &myTb, p, w);
3921 case CE_ToolBoxTabShape:
3922 QCommonStyle::drawControl(ce, opt, p, w);
3924 case CE_PushButtonBevel:
3925 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3926 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3929 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3930 QCommonStyle::drawControl(ce, opt, p, w);
3934 const bool hasFocus = btn->state & State_HasFocus;
3935 const bool isActive = btn->state & State_Active;
3939 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3940 && isActive && hasFocus)
3941 d->autoDefaultButton = btn->styleObject;
3942 else if (d->autoDefaultButton == btn->styleObject)
3943 d->autoDefaultButton =
nullptr;
3945 const bool isEnabled = btn->state & State_Enabled;
3946 const bool isPressed = btn->state & State_Sunken;
3947 const bool isHighlighted = isActive &&
3948 ((btn->state & State_On)
3949 || (btn->features & QStyleOptionButton::DefaultButton)
3950 || (btn->features & QStyleOptionButton::AutoDefaultButton
3951 && d->autoDefaultButton == btn->styleObject));
3952 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3953 const auto ct = cocoaControlType(btn, w);
3954 const auto cs = d->effectiveAquaSizeConstrain(btn, w);
3955 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3956 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3960 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3961 pb.frame = frameRect.toCGRect();
3963 pb.enabled = isEnabled;
3968 [pb highlight:isPressed];
3971 if (cw.type == QMacStylePrivate::Button_SquareButton) {
3972 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3976 pb.keyEquivalent = isHighlighted ? @
"\r" : @
"";
3979 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3980 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3984 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3987 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3988 const auto ir = frameRect.toRect();
3989 int arrowYOffset = 0;
3994 arrowYOffset -= ir.top();
3995 if (cw.second == QStyleHelper::SizeSmall)
3999 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
4001 QStyleOption arrowOpt = *opt;
4003 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
4007 case CE_PushButtonLabel:
4008 if (
const QStyleOptionButton *b = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4009 QStyleOptionButton btn(*b);
4014 const bool isEnabled = btn.state & State_Enabled;
4015 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
4016 const bool hasIcon = !btn.icon.isNull();
4017 const bool hasText = !btn.text.isEmpty();
4018 const bool isActive = btn.state & State_Active;
4019 const bool isPressed = btn.state & State_Sunken;
4020 const bool isDefault = (btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
4021 || d->autoDefaultButton == btn.styleObject;
4025 const QRect oldRect = btn.rect;
4027 btn.rect = w->rect();
4028 const auto ct = cocoaControlType(&btn, w);
4031 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
4032 if (isPressed || (isActive && isEnabled && ((btn.state & State_On) || isDefault)))
4033 btn.palette.setColor(QPalette::ButtonText, Qt::white);
4037 if (!isDefault && !(btn.state & State_On)) {
4040 btn.palette.setColor(QPalette::ButtonText, Qt::black);
4044 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
4045 QCommonStyle::drawControl(ce, &btn, p, w);
4047 QRect freeContentRect = btn.rect;
4048 QRect textRect = itemTextRect(
4049 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
4051 if (ct == QMacStylePrivate::Button_SquareButton)
4052 textRect.moveTo(w ? 8 : 11, textRect.top());
4054 textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)])
4055 : 11, textRect.top());
4059 int contentW = textRect.width();
4061 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
4062 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
4063 if (mode == QIcon::Normal && btn.state & State_HasFocus)
4064 mode = QIcon::Active;
4066 QIcon::State state = QIcon::Off;
4067 if (btn.state & State_On)
4069 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
4070 QSizeF pixmapSize = pixmap.deviceIndependentSize();
4071 contentW += pixmapSize.width() + QMacStylePrivate::PushButtonContentPadding;
4072 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
4073 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapSize.height()) / 2;
4074 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapSize.width(), pixmapSize.height());
4075 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
4076 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
4077 int newOffset = iconDestRect.x() + iconDestRect.width()
4078 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
4079 textRect.adjust(newOffset, 0, newOffset, 0);
4083 textRect = visualRect(btn.direction, freeContentRect, textRect);
4084 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
4085 isEnabled, btn.text, QPalette::ButtonText);
4090#if QT_CONFIG(combobox)
4091 case CE_ComboBoxLabel:
4092 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4093 auto comboCopy = *cb;
4094 comboCopy.direction = Qt::LeftToRight;
4096 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
4100#if QT_CONFIG(tabbar)
4101 case CE_TabBarTabShape:
4102 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4103 if (tabOpt->documentMode) {
4105 bool isUnified =
false;
4107 QRect tabRect = tabOpt->rect;
4108 QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
4109 isUnified = isInMacUnifiedToolbarArea(w->window(), windowTabStart.y());
4112 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w);
4113 drawTabShape(p, tabOpt, isUnified, tabOverlap);
4142 const bool isActive = tabOpt->state & State_Active;
4143 const bool isEnabled = tabOpt->state & State_Enabled;
4144 const bool isPressed = tabOpt->state & State_Sunken;
4145 const bool isSelected = tabOpt->state & State_Selected;
4146 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
4147 const bool verticalTabs = tabDirection == QMacStylePrivate::East
4148 || tabDirection == QMacStylePrivate::West;
4150 QStyleOptionTab::TabPosition tp = tabOpt->position;
4151 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
4152 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
4153 if (tp == QStyleOptionTab::Beginning)
4154 tp = QStyleOptionTab::End;
4155 else if (tp == QStyleOptionTab::End)
4156 tp = QStyleOptionTab::Beginning;
4158 if (sp == QStyleOptionTab::NextIsSelected)
4159 sp = QStyleOptionTab::PreviousIsSelected;
4160 else if (sp == QStyleOptionTab::PreviousIsSelected)
4161 sp = QStyleOptionTab::NextIsSelected;
4170 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
4172 const bool needsInactiveHack = !isActive && isSelected;
4173 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
4174 QMacStylePrivate::Button_PushButton :
4175 QMacStylePrivate::Button_PopupButton;
4176 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
4177 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4178 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4181 if (tabDirection == QMacStylePrivate::East)
4183 const auto outerAdjust = isPopupButton ? 1 : 4;
4184 const auto innerAdjust = isPopupButton ? 20 : 10;
4185 QRectF frameRect = tabOpt->rect;
4187 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
4189 frameRect = frameRect.translated(0, vOffset);
4191 case QStyleOptionTab::Beginning:
4193 if (!isSelected && tabDirection == QMacStylePrivate::West)
4194 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
4196 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
4201 frameRect = frameRect.adjusted(0, 0, 1, 0);
4204 case QStyleOptionTab::Middle:
4205 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
4210 frameRect = frameRect.adjusted(-1, 0, 1, 0);
4213 case QStyleOptionTab::Moving:
4214 case QStyleOptionTab::End:
4216 if (isSelected || tabDirection == QMacStylePrivate::West)
4217 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
4219 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
4223 frameRect = frameRect.adjusted(-1, 0, 0, 0);
4226 case QStyleOptionTab::OnlyOneTab:
4227 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
4230 pb.frame = frameRect.toCGRect();
4232 if (!isPopupButton) {
4236 pb.buttonType = NSButtonTypePushOnPushOff;
4239 pb.enabled = isEnabled;
4240 [pb highlight:isPressed];
4242 pb.state = (isActive && isSelected) ? NSControlStateValueOn : NSControlStateValueOff;
4244 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
4245 CGContextClipToRect(ctx, opt->rect.toCGRect());
4246 if (!isSelected || needsInactiveHack) {
4248 if (!verticalTabs && tp == QStyleOptionTab::End) {
4249 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
4250 CGContextScaleCTM(ctx, -1, 1);
4251 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
4252 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
4253 CGContextTranslateCTM(ctx, 0, opt->rect.top());
4254 CGContextScaleCTM(ctx, 1, -1);
4255 CGContextTranslateCTM(ctx, 0, -frameRect.right());
4256 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
4257 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
4258 CGContextScaleCTM(ctx, 1, -1);
4259 CGContextTranslateCTM(ctx, 0, -frameRect.left());
4265 if (tabDirection == QMacStylePrivate::West) {
4266 CGContextTranslateCTM(ctx, 0, frameRect.right());
4267 CGContextRotateCTM(ctx, -M_PI_2);
4268 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
4269 }
else if (tabDirection == QMacStylePrivate::East) {
4270 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
4271 CGContextRotateCTM(ctx, M_PI_2);
4276 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
4277 NSPopUpButtonCell *pbCell = nil;
4279 if (isPopupButton) {
4283 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
4284 oldPosition = pbCell.arrowPosition;
4285 pbCell.arrowPosition = NSPopUpNoArrow;
4286 if (pb.state == NSControlStateValueOff) {
4288 rAdjusted.origin.x -= 3;
4289 rAdjusted.size.width += 6;
4290 if (tp == QStyleOptionTab::End)
4291 rAdjusted.origin.x -= 2;
4294 if (qt_apple_runningWithLiquidGlass()) {
4303 const CGFloat deltaW = 20.0;
4304 rAdjusted = CGContextGetClipBoundingBox(ctx);
4305 if (tp == QStyleOptionTab::Beginning) {
4310 rAdjusted.size.width += deltaW;
4312 if (tabDirection == QMacStylePrivate::West && isSelected && isActive) {
4316 rAdjusted.origin.x -= deltaW;
4318 }
else if (tp == QStyleOptionTab::Middle) {
4320 rAdjusted.origin.x -= deltaW;
4321 rAdjusted.size.width += deltaW * 2;
4322 }
else if (tp == QStyleOptionTab::End) {
4323 if (isSelected && isActive && tabDirection != QMacStylePrivate::West)
4324 rAdjusted.origin.x -= deltaW;
4325 rAdjusted.size.width += deltaW;
4329 [pb.cell drawBezelWithFrame:rAdjusted inView:pb.superview];
4332 pbCell.arrowPosition = oldPosition;
4335 if (needsInactiveHack) {
4337 const qreal pixelRatio = p->device()->devicePixelRatio();
4338 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
4339 tabPixmap.setDevicePixelRatio(pixelRatio);
4340 tabPixmap.fill(Qt::transparent);
4341 QPainter tabPainter(&tabPixmap);
4342 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
4343 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
4344 drawBezelBlock(ctx, r);
4349 const qreal inactiveGray = 0.898;
4350 const int inactiveGray8 = qRound(inactiveGray * 255.0);
4351 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
4352 for (
int l = 0; l < tabPixmap.height(); ++l) {
4353 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
4354 for (
int i = 0; i < tabPixmap.width(); ++i) {
4355 if (qAlpha(line[i]) == 255) {
4356 line[i] = inactiveGrayRGB;
4357 }
else if (qAlpha(line[i]) > 128) {
4358 const int g = qRound(inactiveGray * qRed(line[i]));
4359 line[i] = qRgba(g, g, g, qAlpha(line[i]));
4365 p->drawImage(opt->rect, tabPixmap);
4367 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
4370 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
4371 && tp != QStyleOptionTab::End
4372 && tp != QStyleOptionTab::OnlyOneTab) {
4373 static const QPen separatorPen(Qt::black, 1.0);
4375 p->setOpacity(isEnabled ? 0.105 : 0.06);
4376 p->setPen(separatorPen);
4377 if (tabDirection == QMacStylePrivate::West) {
4378 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
4379 opt->rect.right() - 0.5, opt->rect.bottom()));
4380 }
else if (tabDirection == QMacStylePrivate::East) {
4381 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
4382 opt->rect.right() - 0.5, opt->rect.bottom()));
4384 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
4385 opt->rect.right(), opt->rect.bottom() - 0.5));
4391 case CE_TabBarTabLabel:
4392 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4393 QStyleOptionTab myTab = *tab;
4394 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
4395 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
4396 const bool verticalTabs = tabDirection == QMacStylePrivate::East
4397 || tabDirection == QMacStylePrivate::West;
4403 const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value(
"QComboMenuItem");
4405 if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
4406 if (
const auto *tabBar = qobject_cast<
const QTabBar *>(w))
4407 if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
4408 myTab.palette.setColor(foregroundRole, Qt::white);
4410 if (myTab.documentMode && isDarkMode()) {
4411 if (
const auto *tabBar = qobject_cast<
const QTabBar *>(w)) {
4412 if (!tabBar->tabTextColor(myTab.tabIndex).isValid()) {
4413 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
4414 myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray);
4419 int heightOffset = 0;
4422 }
else if (nonDefaultFont) {
4423 if (p->fontMetrics().height() == myTab.rect.height())
4426 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4428 QCommonStyle::drawControl(ce, &myTab, p, w);
4432#if QT_CONFIG(dockwidget)
4433 case CE_DockWidgetTitle:
4434 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
4435 const bool isVertical = dwOpt->verticalTitleBar;
4436 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
4439 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
4441 p->translate(-effectiveRect.left(), -effectiveRect.top());
4445 p->fillRect(effectiveRect, opt->palette.window());
4448 p->setPen(opt->palette.dark().color());
4449 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
4451 if (!dwOpt->title.isEmpty()) {
4452 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt, w);
4454 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
4455 effectiveRect.top() + titleRect.left() - opt->rect.left(),
4459 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
4460 proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
4461 dwOpt->state & State_Enabled, text, QPalette::WindowText);
4467 case CE_FocusFrame: {
4468 const auto *ff = qobject_cast<
const QFocusFrame *>(w);
4469 const auto *ffw = ff ? ff->widget() :
nullptr;
4470 const auto ct = [=] {
4472 if (qobject_cast<
const QCheckBox*>(ffw))
4473 return QMacStylePrivate::Button_CheckBox;
4474 if (qobject_cast<
const QRadioButton*>(ffw))
4475 return QMacStylePrivate::Button_RadioButton;
4476 if (qobject_cast<
const QLineEdit*>(ffw) || qobject_cast<
const QTextEdit*>(ffw))
4477 return QMacStylePrivate::TextField;
4478 if (
const auto *pb = qobject_cast<
const QPushButton *>(ffw)) {
4480 auto sizePolicy = QStyleHelper::widgetSizePolicy(ffw, opt);
4481 if (sizePolicy == QStyleHelper::SizeDefault)
4482 sizePolicy = QStyleHelper::SizeLarge;
4484 || (pb->rect().height() != pushButtonDefaultHeight[sizePolicy])) {
4485 return QMacStylePrivate::Button_SquareButton;
4487 if (pb->menu() !=
nullptr)
4488 return QMacStylePrivate::Button_PullDown;
4489 return QMacStylePrivate::Button_PushButton;
4493 return QMacStylePrivate::Box;
4495 auto cs = QStyleHelper::widgetSizePolicy(ffw, opt);
4496 if (cs == QStyleHelper::SizeDefault)
4497 cs = QStyleHelper::SizeLarge;
4498 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, w);
4499 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w);
4500 d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
4502 case CE_MenuEmptyArea:
4504 if (qobject_cast<
const QAbstractItemView *>(w))
4505 proxy()->drawPrimitive(PE_PanelMenu, opt, p, w);
4509 case CE_MenuHMargin:
4510 case CE_MenuVMargin:
4511 case CE_MenuTearoff:
4512 case CE_MenuScroller:
4513 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4514 const bool active = mi->state & State_Selected;
4516 p->fillRect(mi->rect, mi->palette.highlight());
4518 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt, w);
4520 if (ce == CE_MenuTearoff) {
4521 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4522 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4523 mi->rect.x() + mi->rect.width() - 4,
4524 mi->rect.y() + mi->rect.height() / 2 - 1);
4525 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4526 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4527 mi->rect.x() + mi->rect.width() - 4,
4528 mi->rect.y() + mi->rect.height() / 2);
4529 }
else if (ce == CE_MenuScroller) {
4530 const QSize scrollerSize = QSize(10, 8);
4531 const int scrollerVOffset = 5;
4532 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
4533 const int right = left + scrollerSize.width();
4536 if (opt->state & State_DownArrow) {
4537 bottom = mi->rect.y() + scrollerVOffset;
4538 top = bottom + scrollerSize.height();
4540 bottom = mi->rect.bottom() - scrollerVOffset;
4541 top = bottom - scrollerSize.height();
4544 p->setRenderHint(QPainter::Antialiasing);
4546 path.moveTo(left, bottom);
4547 path.lineTo(right, bottom);
4548 path.lineTo((left + right) / 2, top);
4549 p->fillPath(path, opt->palette.buttonText());
4551 }
else if (ce != CE_MenuItem) {
4555 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4556 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
4557 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
4558 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
4562 const int maxpmw = mi->maxIconWidth;
4563 const bool enabled = mi->state & State_Enabled;
4565 int xpos = mi->rect.x() + 18;
4566 int checkcol = maxpmw;
4568 p->setPen(mi->palette.text().color());
4570 p->setPen(mi->palette.highlightedText().color());
4572 p->setPen(mi->palette.buttonText().color());
4575 QStyleOption checkmarkOpt;
4576 checkmarkOpt.initFrom(w);
4581 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
4583 checkmarkOpt.state.setFlag(State_On, active);
4584 checkmarkOpt.state.setFlag(State_Enabled, enabled);
4585 if (widgetSize == QStyleHelper::SizeMini)
4586 checkmarkOpt.state |= State_Mini;
4587 else if (widgetSize == QStyleHelper::SizeSmall)
4588 checkmarkOpt.state |= State_Small;
4591 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
4592 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
4594 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w);
4596 if (!mi->icon.isNull()) {
4597 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4600 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4601 QSize iconSize(smallIconSize, smallIconSize);
4602#if QT_CONFIG(combobox)
4603 if (
const QComboBox *comboBox = qobject_cast<
const QComboBox *>(w)) {
4604 iconSize = comboBox->iconSize();
4607 QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
4608 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
4609 QSize size = pixmap.deviceIndependentSize().toSize();
4610 QRect pmr(QPoint(0, 0), size);
4611 pmr.moveCenter(cr.center());
4612 p->drawPixmap(pmr.topLeft(), pixmap);
4613 xpos += size.width() + 6;
4616 QString s = mi->text;
4617 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
4618 | Qt::TextSingleLine | Qt::AlignAbsolute;
4619 int yPos = mi->rect.y();
4620 if (widgetSize == QStyleHelper::SizeMini)
4623 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
4624 const int tabwidth = isSubMenu ? 9 : mi->reservedShortcutWidth;
4626 QString rightMarginText;
4628 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
4631 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
4632 if (tabIndex >= 0) {
4634 rightMarginText = s.mid(tabIndex + 1);
4635 s = s.left(tabIndex);
4639 if (!rightMarginText.isEmpty()) {
4640 p->setFont(qt_app_fonts_hash()->value(
"QMenuItem", p->font()));
4643 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
4647 const QKeySequence seq = QKeySequence::fromString(rightMarginText, QKeySequence::NativeText);
4648 if (seq.count() == 1) {
4650 const int maxKeyWidth = p->fontMetrics().maxWidth();
4651 const QChar key = rightMarginText.at(rightMarginText.length() - 1);
4652 const QString modifiers = rightMarginText.left(rightMarginText.size() - 1);
4653 p->drawText(xp + tabwidth - maxKeyWidth, yPos, maxKeyWidth, mi->rect.height(), text_flags, key);
4655 p->drawText(xp, yPos, tabwidth - maxKeyWidth, mi->rect.height(),
4656 text_flags | Qt::AlignRight | Qt::TextDontClip, modifiers);
4658 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, rightMarginText);
4665 QFont myFont = mi->font;
4671 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4676 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
4677 Q_ASSERT(fontEngine);
4678 if (fontEngine->type() == QFontEngine::Multi) {
4679 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
4680 Q_ASSERT(fontEngine);
4682 if (fontEngine->type() == QFontEngine::Mac) {
4683 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
4686 const auto pc = p->pen().color();
4687 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
4692 s = qt_mac_removeMnemonics(s);
4694 QMacCGContext cgCtx(p);
4695 d->setupNSGraphicsContext(cgCtx, YES);
4701 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
4702 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
4703 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0],
4704 NSUnderlineStyleAttributeName: [NSNumber numberWithInt: myFont.underline() ? NSUnderlineStyleSingle
4705 : NSUnderlineStyleNone],
4706 NSStrikethroughStyleAttributeName: [NSNumber numberWithInt: myFont.strikeOut() ? NSUnderlineStyleSingle
4707 : NSUnderlineStyleNone]}];
4709 d->restoreNSGraphicsContext(cgCtx);
4712 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
4713 mi->rect.height(), text_flags, s);
4719 case CE_MenuBarItem:
4720 case CE_MenuBarEmptyArea:
4721 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
4722 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
4723 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
4724 p->fillRect(mi->rect, bg);
4726 if (ce != CE_MenuBarItem)
4729 if (!mi->icon.isNull()) {
4730 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4731 drawItemPixmap(p, mi->rect,
4732 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4733 | Qt::TextSingleLine,
4734 mi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(),
4735 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4737 drawItemText(p, mi->rect,
4738 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4739 | Qt::TextSingleLine,
4740 mi->palette, mi->state & State_Enabled,
4741 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
4745 case CE_ProgressBarLabel:
4746 case CE_ProgressBarGroove:
4749 case CE_ProgressBarContents:
4750 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4751 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4752 const bool vertical = !(pb->state & QStyle::State_Horizontal);
4753 const bool inverted = pb->invertedAppearance;
4754 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4757 QRect rect = pb->rect;
4759 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w);
4760 const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
4761 if (isIndeterminate) {
4769 if (!animation && opt->styleObject) {
4770 auto *animation =
new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
4772 animation->setFrameRate(QStyleAnimation::FifteenFps);
4773 d->startAnimation(animation);
4776 if (qt_apple_runningWithLiquidGlass()) {
4777 d->drawProgressBar(p, pb);
4780 rect = rect.transposed();
4781 d->setupNSGraphicsContext(cg, NO);
4782 d->setupVerticalInvertedXform(cg, reverse, vertical, rect.toCGRect());
4784 =
static_cast<QIndeterminateProgressIndicator *>(
4785 d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }))) {
4786 [ipi startAnimation];
4787 [ipi drawWithFrame:rect.toCGRect() inView:d->backingStoreNSView];
4789 d->restoreNSGraphicsContext(cg);
4793 d->stopAnimation(opt->styleObject);
4795 =
static_cast<QIndeterminateProgressIndicator *>(
4796 d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize })))
4797 [ipi stopAnimation];
4799 if (qt_apple_runningWithLiquidGlass()) {
4800 d->drawProgressBar(p, pb);
4803 rect = rect.transposed();
4804 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
4805 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
4806 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &cgrect) {
4807 d->setupVerticalInvertedXform(ctx, reverse, vertical, cgrect);
4808 pi.minValue = pb->minimum;
4809 pi.maxValue = pb->maximum;
4810 pi.doubleValue = pb->progress;
4811 [pi drawRect:cgrect]; });
4818#ifndef QT_NO_MDIAREA
4819 if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
4823 if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
4824 p->fillRect(opt->rect, opt->palette.window());
4826 QPen lineColor = QColor(82, 82, 82, 192);
4827 lineColor.setWidth(1);
4829 p->setRenderHint(QPainter::Antialiasing);
4830 p->setPen(lineColor);
4831 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4832 const int NumLines = 3;
4833 for (
int l = 0; l < NumLines; ++l) {
4834 const int offset = (l * 4 + 3);
4836 if (layoutDirection == Qt::LeftToRight) {
4837 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4838 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4840 start = QPoint(offset, opt->rect.height() - 1);
4841 end = QPoint(1, opt->rect.height() - offset);
4843 p->drawLine(start, end);
4849 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
4850 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
4852 const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
4853 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4854 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
4855 sv.frame = opt->rect.toCGRect();
4856 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
4857 [sv drawDividerInRect:rect];
4860 QPen oldPen = p->pen();
4861 p->setPen(opt->palette.dark().color());
4862 if (opt->state & QStyle::State_Horizontal)
4863 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4865 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4870 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
4871 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4872 if (!rubber->opaque) {
4875 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4876 fillColor.setHsvF(0, 0, 0.53, 0.25);
4877 if (opt->rect.width() * opt->rect.height() <= 3) {
4878 p->fillRect(opt->rect, strokeColor);
4880 QPen oldPen = p->pen();
4881 QBrush oldBrush = p->brush();
4882 QPen pen(strokeColor);
4884 p->setBrush(fillColor);
4885 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
4886 if (adjusted.isValid())
4887 p->drawRect(adjusted);
4889 p->setBrush(oldBrush);
4892 p->fillRect(opt->rect, fillColor);
4896#ifndef QT_NO_TOOLBAR
4898 const QStyleOptionToolBar *toolBar = qstyleoption_cast<
const QStyleOptionToolBar *>(opt);
4900 const QColor separatorColor = darkMode ? darkModeSeparatorLine : opt->palette.dark().color();
4907#if QT_CONFIG(mainwindow)
4908 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4909 if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
4912 p->setCompositionMode(QPainter::CompositionMode_Source);
4913 p->fillRect(opt->rect, Qt::transparent);
4920 const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
4921 const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window(), windowToolbarEnd.y() + 1);
4922 if (isEndOfUnifiedArea) {
4923 const int margin = qt_mac_aqua_get_metric(SeparatorSize);
4924 const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
4925 p->fillRect(separatorRect, separatorColor);
4933 p->fillRect(opt->rect, opt->palette.window());
4936 p->setPen(separatorColor);
4937 QRect toolbarRect = darkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
4938 if (opt->state & State_Horizontal) {
4939 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
4940 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
4942 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
4943 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
4951 QCommonStyle::drawControl(ce, opt, p, w);
4966 const QWidget *widget)
const
4968 Q_D(
const QMacStyle);
4970 const int controlSize = getControlSize(opt, widget);
4973#if QT_CONFIG(itemviews)
4974 case SE_ItemViewItemText:
4975 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
4976 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget);
4978 rect = QCommonStyle::subElementRect(sr, opt, widget);
4979 if (vopt->features & QStyleOptionViewItem::HasDecoration)
4980 rect.adjust(-fw, 0, 0, 0);
4984 case SE_ToolBoxTabContents:
4985 rect = QCommonStyle::subElementRect(sr, opt, widget);
4987 case SE_PushButtonBevel:
4988 case SE_PushButtonContents:
4989 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4998 const auto ct = cocoaControlType(btn, widget);
4999 const auto cs = d->effectiveAquaSizeConstrain(btn, widget);
5000 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5001 auto frameRect = cw.adjustedControlFrame(btn->rect);
5002 if (sr == SE_PushButtonContents) {
5003 frameRect -= cw.titleMargins();
5004 }
else if (cw.type != QMacStylePrivate::Button_SquareButton) {
5005 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5006 frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:frameRect.toCGRect()]);
5007 if (cw.type == QMacStylePrivate::Button_PushButton)
5008 frameRect -= pushButtonShadowMargins[cw.size];
5009 else if (cw.type == QMacStylePrivate::Button_PullDown)
5010 frameRect -= pullDownButtonShadowMargins[cw.size];
5012 rect = frameRect.toRect();
5015 case SE_HeaderLabel: {
5016 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
5017 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
5018 opt->rect.width() - margin * 2, opt->rect.height() - 2);
5019 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
5021 if (header->sortIndicator != QStyleOptionHeader::None) {
5022 if (opt->state & State_Horizontal)
5028 rect = visualRect(opt->direction, opt->rect, rect);
5031 case SE_HeaderArrow: {
5032 int h = opt->rect.height();
5033 int w = opt->rect.width();
5034 int x = opt->rect.x();
5035 int y = opt->rect.y();
5036 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, widget);
5038 if (opt->state & State_Horizontal) {
5045 rect = visualRect(opt->direction, opt->rect, rect);
5048 case SE_ProgressBarGroove:
5052 case SE_ProgressBarLabel:
5054 case SE_ProgressBarContents:
5057 case SE_TreeViewDisclosureItem: {
5063#if QT_CONFIG(tabwidget)
5064 case SE_TabWidgetLeftCorner:
5065 if (
const QStyleOptionTabWidgetFrame *twf
5066 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5067 switch (twf->shape) {
5068 case QTabBar::RoundedNorth:
5069 case QTabBar::TriangularNorth:
5070 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
5072 case QTabBar::RoundedSouth:
5073 case QTabBar::TriangularSouth:
5074 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
5075 twf->leftCornerWidgetSize);
5080 rect = visualRect(twf->direction, twf->rect, rect);
5083 case SE_TabWidgetRightCorner:
5084 if (
const QStyleOptionTabWidgetFrame *twf
5085 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5086 switch (twf->shape) {
5087 case QTabBar::RoundedNorth:
5088 case QTabBar::TriangularNorth:
5089 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
5090 twf->rightCornerWidgetSize);
5092 case QTabBar::RoundedSouth:
5093 case QTabBar::TriangularSouth:
5094 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
5095 twf->rect.height() - twf->rightCornerWidgetSize.height()),
5096 twf->rightCornerWidgetSize);
5101 rect = visualRect(twf->direction, twf->rect, rect);
5104 case SE_TabWidgetTabContents:
5105 rect = QCommonStyle::subElementRect(sr, opt, widget);
5106 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5107 if (twf->lineWidth != 0) {
5108 switch (QMacStylePrivate::tabDirection(twf->shape)) {
5109 case QMacStylePrivate::North:
5110 rect.adjust(+1, +14, -1, -1);
5112 case QMacStylePrivate::South:
5113 rect.adjust(+1, +1, -1, -14);
5115 case QMacStylePrivate::West:
5116 rect.adjust(+14, +1, -1, -1);
5118 case QMacStylePrivate::East:
5119 rect.adjust(+1, +1, -14, -1);
5124 case SE_TabBarTabText:
5125 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5126 QRect dummyIconRect;
5127 d->tabLayout(tab, widget, &rect, &dummyIconRect);
5130 case SE_TabBarTabLeftButton:
5131 case SE_TabBarTabRightButton:
5132 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5133 bool selected = tab->state & State_Selected;
5134 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget);
5135 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget);
5138 bool verticalTabs = tab->shape == QTabBar::RoundedEast
5139 || tab->shape == QTabBar::RoundedWest
5140 || tab->shape == QTabBar::TriangularEast
5141 || tab->shape == QTabBar::TriangularWest;
5143 QRect tr = tab->rect;
5144 if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
5145 verticalShift = -verticalShift;
5147 qSwap(horizontalShift, verticalShift);
5148 horizontalShift *= -1;
5149 verticalShift *= -1;
5151 if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
5152 horizontalShift = -horizontalShift;
5154 tr.adjust(0, 0, horizontalShift, verticalShift);
5157 tr.setBottom(tr.bottom() - verticalShift);
5158 tr.setRight(tr.right() - horizontalShift);
5161 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
5162 int w = size.width();
5163 int h = size.height();
5164 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
5165 int midWidth = ((tr.width() - w) / 2);
5167 bool atTheTop =
true;
5168 switch (tab->shape) {
5169 case QTabBar::RoundedWest:
5170 case QTabBar::TriangularWest:
5171 atTheTop = (sr == SE_TabBarTabLeftButton);
5173 case QTabBar::RoundedEast:
5174 case QTabBar::TriangularEast:
5175 atTheTop = (sr == SE_TabBarTabRightButton);
5178 if (sr == SE_TabBarTabLeftButton)
5179 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
5181 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
5182 rect = visualRect(tab->direction, tab->rect, rect);
5186 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
5188 rect = QRect(midWidth, tr.y() + hpadding, w, h);
5193 case SE_LineEditContents:
5194 rect = QCommonStyle::subElementRect(sr, opt, widget);
5195#if QT_CONFIG(combobox)
5196 if (widget && qobject_cast<
const QComboBox*>(widget->parentWidget()))
5197 rect.adjust(-1, -2, 0, 0);
5200 rect.adjust(-1, -1, 0, +1);
5202 case SE_CheckBoxLayoutItem:
5204 if (controlSize == QStyleHelper::SizeLarge) {
5205 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
5206 }
else if (controlSize == QStyleHelper::SizeSmall) {
5207 setLayoutItemMargins(+1, +5, 0 , -6, &rect, opt->direction);
5209 setLayoutItemMargins(0, +7, 0 , -6, &rect, opt->direction);
5212 case SE_ComboBoxLayoutItem:
5213#ifndef QT_NO_TOOLBAR
5214 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5223 if (controlSize == QStyleHelper::SizeLarge) {
5224 rect.adjust(+3, +2, -3, -4);
5225 }
else if (controlSize == QStyleHelper::SizeSmall) {
5226 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
5228 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
5232 case SE_LabelLayoutItem:
5234 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
5236 case SE_ProgressBarLayoutItem: {
5238 int bottom =
SIZE(3, 8, 8);
5239 if (opt->state & State_Horizontal) {
5240 rect.adjust(0, +1, 0, -bottom);
5242 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
5246 case SE_PushButtonLayoutItem:
5247 if (
const QStyleOptionButton *buttonOpt
5248 = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
5249 if ((buttonOpt->features & QStyleOptionButton::Flat))
5251 if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) {
5253 if (controlSize == QStyleHelper::SizeLarge)
5254 rect.adjust(+6, +4, -6, -8);
5255 else if (controlSize == QStyleHelper::SizeSmall)
5256 rect.adjust(+5, +4, -5, -6);
5258 rect.adjust(+1, 0, -1, -2);
5263 if (controlSize == QStyleHelper::SizeLarge) {
5264 rect.adjust(0, +4, 0, -8);
5265 }
else if (controlSize == QStyleHelper::SizeSmall) {
5266 rect.adjust(0, +4, 0, -6);
5268 rect.adjust(0, 0, 0, -2);
5271 case SE_RadioButtonLayoutItem:
5273 if (controlSize == QStyleHelper::SizeLarge) {
5274 setLayoutItemMargins(+2, +2 ,
5275 0, -4 , &rect, opt->direction);
5276 }
else if (controlSize == QStyleHelper::SizeSmall) {
5277 rect.adjust(0, +6, 0 , -5);
5279 rect.adjust(0, +6, 0 , -7);
5282 case SE_SliderLayoutItem:
5283 if (
const QStyleOptionSlider *sliderOpt
5284 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5286 if (sliderOpt->tickPosition == QSlider::NoTicks) {
5287 int above =
SIZE(3, 0, 2);
5288 int below =
SIZE(4, 3, 0);
5289 if (sliderOpt->orientation == Qt::Horizontal) {
5290 rect.adjust(0, +above, 0, -below);
5292 rect.adjust(+above, 0, -below, 0);
5294 }
else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
5295 int below =
SIZE(3, 2, 0);
5296 if (sliderOpt->orientation == Qt::Horizontal) {
5297 rect.setHeight(rect.height() - below);
5299 rect.setWidth(rect.width() - below);
5301 }
else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
5302 int above =
SIZE(3, 2, 0);
5303 if (sliderOpt->orientation == Qt::Horizontal) {
5304 rect.setTop(rect.top() + above);
5306 rect.setLeft(rect.left() + above);
5311 case SE_FrameLayoutItem:
5313 if (
const QFrame *frame = qobject_cast<
const QFrame *>(widget)) {
5315 switch (frame->frameStyle() & QFrame::Shape_Mask) {
5317 rect.adjust(0, +1, 0, -1);
5320 rect.adjust(+1, 0, -1, 0);
5327 case SE_GroupBoxLayoutItem:
5329 if (
const QStyleOptionGroupBox *groupBoxOpt =
5330 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5332
5333
5334
5335
5336 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
5337 | QStyle::SC_GroupBoxLabel)) {
5339 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
5340 delta =
SIZE(8, 4, 4);
5342 delta =
SIZE(15, 12, 12);
5344 rect.setTop(rect.top() + delta);
5347 rect.setBottom(rect.bottom() - 1);
5349#if QT_CONFIG(tabwidget)
5350 case SE_TabWidgetLayoutItem:
5351 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
5352 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5354
5355
5356
5357
5358 rect = tabWidgetOpt->rect;
5359 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
5360 rect.setTop(rect.top() + SIZE(6 , 3 , 2 ));
5364#if QT_CONFIG(dockwidget)
5365 case SE_DockWidgetCloseButton:
5366 case SE_DockWidgetFloatButton:
5367 case SE_DockWidgetTitleBarText:
5368 case SE_DockWidgetIcon: {
5369 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
5370 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget);
5371 QRect srect = opt->rect;
5373 const QStyleOptionDockWidget *dwOpt
5374 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
5375 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
5376 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
5378 const bool verticalTitleBar = dwOpt->verticalTitleBar;
5382 if (verticalTitleBar)
5383 srect = srect.transposed();
5386 int right = srect.right();
5387 int left = srect.left();
5391 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
5392 opt, widget).actualSize(QSize(iconSize, iconSize));
5393 sz += QSize(buttonMargin, buttonMargin);
5394 if (verticalTitleBar)
5395 sz = sz.transposed();
5396 closeRect = QRect(left,
5397 srect.center().y() - sz.height()/2,
5398 sz.width(), sz.height());
5399 left = closeRect.right() + 1;
5401 if (sr == SE_DockWidgetCloseButton) {
5408 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
5409 opt, widget).actualSize(QSize(iconSize, iconSize));
5410 sz += QSize(buttonMargin, buttonMargin);
5411 if (verticalTitleBar)
5412 sz = sz.transposed();
5413 floatRect = QRect(left,
5414 srect.center().y() - sz.height()/2,
5415 sz.width(), sz.height());
5416 left = floatRect.right() + 1;
5418 if (sr == SE_DockWidgetFloatButton) {
5424 if (
const QDockWidget *dw = qobject_cast<
const QDockWidget*>(widget)) {
5426 if (dw->isFloating())
5427 icon = dw->windowIcon();
5429 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
5430 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
5431 if (verticalTitleBar)
5432 sz = sz.transposed();
5433 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
5434 sz.width(), sz.height());
5435 right = iconRect.left() - 1;
5438 if (sr == SE_DockWidgetIcon) {
5443 QRect textRect = QRect(left, srect.top(),
5444 right - left, srect.height());
5445 if (sr == SE_DockWidgetTitleBarText) {
5451 if (verticalTitleBar) {
5452 rect = QRect(srect.left() + rect.top() - srect.top(),
5453 srect.top() + srect.right() - rect.right(),
5454 rect.height(), rect.width());
5456 rect = visualRect(opt->direction, srect, rect);
5462 rect = QCommonStyle::subElementRect(sr, opt, widget);
5495 const QWidget *widget)
const
5497 Q_D(
const QMacStyle);
5498 QMacCGContext cg(p);
5500 qCWarning(lcMacStyle) <<
"drawComplexControl:" << cc <<
"invalid (nullptr) graphics context";
5501 QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
nullptr;
5502 d->resolveCurrentNSView(window);
5505 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5508 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
5509 const bool drawKnob = sb->subControls & SC_ScrollBarSlider && sb->minimum != sb->maximum;
5510 if (!drawTrack && !drawKnob)
5513 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5515 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
5516 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
5518 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
5519 static const CGFloat expandedKnobWidths[] = { 11.0, 9.0, 9.0 };
5520 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt, widget);
5521 const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
5523 const QStyle *realStyle = widget ? widget->style() : proxy();
5524 const bool isTransient = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget);
5526 d->stopAnimation(opt->styleObject);
5527 bool wasActive =
false;
5528 CGFloat opacity = 0.0;
5529 CGFloat expandScale = 1.0;
5530 CGFloat expandOffset = 0.0;
5531 bool shouldExpand =
false;
5533 if (QObject *styleObject = opt->styleObject) {
5534 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
5535 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
5536 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
5537 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
5538 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
5539 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
5543 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
5546 oldPos != sb->sliderPosition ||
5547 oldMin != sb->minimum ||
5548 oldMax != sb->maximum ||
5549 oldRect != sb->rect ||
5550 oldState != sb->state ||
5551 oldActiveControls != sb->activeSubControls) {
5557 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
5558 styleObject->setProperty(
"_q_stylemin", sb->minimum);
5559 styleObject->setProperty(
"_q_stylemax", sb->maximum);
5560 styleObject->setProperty(
"_q_stylerect", sb->rect);
5561 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
5562 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
5564 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5567 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
5568 d->startAnimation(anim);
5569 }
else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5572 anim->setCurrentTime(0);
5574 }
else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5575 d->stopAnimation(styleObject);
5579 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5580 if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5583 if (oldActiveControls)
5584 anim->setActive(
true);
5586 wasActive = anim->wasActive();
5587 opacity = anim->currentValue();
5590 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
5592 if (!anim && !oldActiveControls) {
5594 anim =
new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
5595 d->startAnimation(anim);
5597 if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
5598 expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
5599 expandOffset = 5.5 * (1.0 - anim->currentValue());
5602 expandScale = maxExpandScale;
5608 d->setupNSGraphicsContext(cg, NO );
5610 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5611 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
5612 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5614 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette, widget);
5615 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
5619 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
5621 scroller.knobStyle = NSScrollerKnobStyleDefault;
5624 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
5626 if (!setupScroller(scroller, sb))
5630 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
5631 CGContextSetAlpha(cg, opacity);
5636 if (!isTransient || opt->activeSubControls || wasActive) {
5637 CGRect trackRect = scroller.bounds;
5639 trackRect.origin.y += expandOffset;
5641 trackRect.origin.x += expandOffset;
5642 [scroller drawKnobSlotInRect:trackRect highlight:NO];
5652 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
5653 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
5655 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
5656 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
5657 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
5658 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
5659 const CGFloat knobRadius = knobWidth / 2.0;
5662 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
5664 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
5665 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
5666 CGContextAddPath(cg, knobPath);
5667 CGContextSetAlpha(cg, 0.5);
5668 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
5669 CGContextSetFillColorWithColor(cg, knobColor);
5670 CGContextFillPath(cg);
5672 [scroller drawKnob];
5674 if (!isTransient && opt->activeSubControls) {
5679 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
5680 [scroller drawKnob];
5686 CGContextEndTransparencyLayer(cg);
5688 d->restoreNSGraphicsContext(cg);
5692 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5693 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5694 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5695 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5696 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5697 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5698 if (!setupSlider(slider, sl))
5701 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5702 const bool hasDoubleTicks = sl->tickPosition == QSlider::TicksBothSides;
5703 const bool drawKnob = sl->subControls & SC_SliderHandle;
5704 const bool drawBar = sl->subControls & SC_SliderGroove;
5705 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
5706 const bool isPressed = qt_apple_runningWithLiquidGlass() ?
false : sl->state & State_Sunken;
5710 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
5711 pressPoint.x = CGRectGetMidX(knobRect);
5712 pressPoint.y = CGRectGetMidY(knobRect);
5727 [slider.cell startTrackingAt:pressPoint inView:slider];
5728 [slider.cell startTrackingAt:pressPoint inView:slider];
5731 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
5734 const bool verticalFlip = !isHorizontal && !sl->upsideDown;
5737 if (sl->upsideDown) {
5738 CGContextTranslateCTM(ctx, rect.size.width, rect.origin.y);
5739 CGContextScaleCTM(ctx, -1, 1);
5741 CGContextTranslateCTM(ctx, 0, rect.origin.y);
5743 }
else if (verticalFlip) {
5744 CGContextTranslateCTM(ctx, rect.origin.x, rect.size.height);
5745 CGContextScaleCTM(ctx, 1, -1);
5748 if (hasDoubleTicks) {
5751 CGContextTranslateCTM(ctx, 0, 4);
5753 CGContextTranslateCTM(ctx, 1, 0);
5760 const bool drawAllParts = drawKnob && drawBar && (!hasTicks || drawTicks);
5761 if (drawAllParts && !hasDoubleTicks && (!verticalFlip || drawTicks)) {
5765 if (verticalFlip && drawTicks) {
5768 slider.intValue = slider.maxValue - slider.intValue + slider.minValue;
5770 [slider drawRect:CGRectZero];
5774 NSSliderCell *cell = slider.cell;
5776 const int numberOfTickMarks = slider.numberOfTickMarks;
5779 slider.numberOfTickMarks = 0;
5781 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
5783 if (!isHorizontal && !sl->upsideDown && (hasDoubleTicks || !hasTicks)) {
5791 [cell drawBarInside:barRect flipped:
true];
5793 [cell drawBarInside:barRect flipped:!verticalFlip];
5797 slider.numberOfTickMarks = numberOfTickMarks;
5800 if (hasTicks && drawTicks) {
5801 if (!drawBar && hasDoubleTicks)
5802 slider.numberOfTickMarks = numberOfTickMarks;
5804 if (qt_apple_runningWithLiquidGlass())
5805 drawTickMarks(ctx, slider, sl);
5807 [cell drawTickMarks];
5809 if (hasDoubleTicks) {
5811 CGAffineTransform tickMarksFlip;
5812 const CGRect tickMarkRect = [cell rectOfTickMarkAtIndex:0];
5814 tickMarksFlip = CGAffineTransformMakeTranslation(0, rect.size.height - tickMarkRect.size.height - 3);
5815 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, 1, -1);
5817 tickMarksFlip = CGAffineTransformMakeTranslation(rect.size.width - tickMarkRect.size.width / 2, 0);
5818 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, -1, 1);
5820 CGContextConcatCTM(ctx, tickMarksFlip);
5821 [cell drawTickMarks];
5822 CGContextConcatCTM(ctx, CGAffineTransformInvert(tickMarksFlip));
5829 slider.numberOfTickMarks = 0;
5830 if (qt_apple_runningWithLiquidGlass())
5831 drawSliderKnob(ctx, slider);
5841 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5842 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5846#if QT_CONFIG(spinbox)
5848 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5849 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5850 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5851 QStyleOptionFrame frame;
5852 static_cast<QStyleOption &>(frame) = *opt;
5853 frame.rect = lineEditRect;
5854 frame.state |= State_Sunken;
5855 frame.lineWidth = 1;
5856 frame.midLineWidth = 0;
5857 frame.features = QStyleOptionFrame::None;
5858 frame.frameShape = QFrame::Box;
5859 drawPrimitive(PE_FrameLineEdit, &frame, p, widget);
5861 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5862 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget)
5863 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5866 d->setupNSGraphicsContext(cg, NO);
5868 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
5869 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5870 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5871 const auto controlSize = cell.controlSize;
5872 if (qt_apple_runningWithLiquidGlass())
5873 cell.controlSize = NSControlSizeMini;
5874 cell.enabled = (sb->state & State_Enabled);
5876 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
5878 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
5879 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
5880 const CGFloat x = CGRectGetMidX(newRect);
5881 const CGFloat y = upPressed ? -3 : 3;
5882 const CGPoint pressPoint = CGPointMake(x, y);
5885 if (upPressed || downPressed)
5886 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
5888 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
5890 if (upPressed || downPressed)
5891 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
5893 d->restoreNSGraphicsContext(cg);
5894 if (qt_apple_runningWithLiquidGlass())
5895 cell.controlSize = controlSize;
5900#if QT_CONFIG(combobox)
5902 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5903 const bool isEnabled = combo->state & State_Enabled;
5904 const bool isPressed = combo->state & State_Sunken;
5906 const auto ct = cocoaControlType(combo, widget);
5907 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5908 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5909 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
5910 cc.enabled = isEnabled;
5911 QRectF frameRect = cw.adjustedControlFrame(combo->rect);
5912 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5914 auto *pb =
static_cast<NSPopUpButton *>(cc);
5916 if (cw.size == QStyleHelper::SizeSmall) {
5917 frameRect = frameRect.translated(0, 1);
5918 }
else if (cw.size == QStyleHelper::SizeMini) {
5920 frameRect = frameRect.translated(2, -0.5);
5922 pb.frame = frameRect.toCGRect();
5923 [pb highlight:isPressed];
5924 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5925 [pb.cell drawBezelWithFrame:r inView:pb.superview];
5927 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5929 auto *cb =
static_cast<NSComboBox *>(cc);
5930 const auto frameRect = cw.adjustedControlFrame(combo->rect);
5931 cb.frame = frameRect.toCGRect();
5934 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
5935 cell.highlighted = isPressed;
5940 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
5942 [cb.cell drawWithFrame:r inView:cb];
5946 if (combo->state & State_HasFocus) {
5948 const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, combo, widget);
5949 const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, combo, widget);
5951 if (cw.type == QMacStylePrivate::Button_PopupButton) {
5952 if (qt_apple_runningWithLiquidGlass())
5953 focusRect = QRectF::fromCGRect(qt_alignmentRectForFrame(cc.frame, cw.size, cw.type));
5955 focusRect = QRectF::fromCGRect([cc alignmentRectForFrame:cc.frame]);
5956 focusRect -= pullDownButtonShadowMargins[cw.size];
5957 if (cw.size == QStyleHelper::SizeSmall)
5958 focusRect = focusRect.translated(0, 1);
5959 else if (cw.size == QStyleHelper::SizeMini)
5960 focusRect = focusRect.translated(2, -1);
5961 }
else if (cw.type == QMacStylePrivate::ComboBox) {
5962 focusRect = frameRect - comboBoxFocusRingMargins[cw.size];
5964 d->drawFocusRing(p, focusRect, hMargin, vMargin, cw);
5970 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5971 const bool isActive = (titlebar->state & State_Active)
5972 && (titlebar->titleBarState & State_Active);
5974 p->fillRect(opt->rect, Qt::transparent);
5975 p->setRenderHint(QPainter::Antialiasing);
5976 p->setClipRect(opt->rect, Qt::IntersectClip);
5980 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
5981 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
5982 p->fillPath(outerFramePath, opt->palette.dark());
5984 const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
5985 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
5986 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
5987 p->fillPath(innerFramePath, opt->palette.button());
5989 if (titlebar->subControls & (SC_TitleBarCloseButton
5990 | SC_TitleBarMaxButton
5991 | SC_TitleBarMinButton
5992 | SC_TitleBarNormalButton)) {
5993 const bool isHovered = (titlebar->state & State_MouseOver);
5994 static const SubControl buttons[] = {
5995 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
5997 for (
const auto sc : buttons) {
5998 const auto ct = d->windowButtonCocoaControl(sc);
5999 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
6000 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
6001 wb.enabled = (sc & titlebar->subControls) && isActive;
6002 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
6003 Q_UNUSED(isHovered);
6005 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget);
6006 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
6007 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
6008 [wbCell drawWithFrame:rect inView:wb];
6013 if (titlebar->subControls & SC_TitleBarLabel) {
6014 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
6015 if (!titlebar->icon.isNull()) {
6016 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
6017 const auto iconSize = QSize(iconExtent, iconExtent);
6018 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
6020 if (iconPos < tr.right() - titleBarIconTitleSpacing)
6021 p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(iconSize, QIcon::Normal));
6024 if (!titlebar->text.isEmpty())
6025 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
6030 if (
const QStyleOptionGroupBox *gb
6031 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
6033 QStyleOptionGroupBox groupBox(*gb);
6034 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
6036 groupBox.state |= QStyle::State_Mini;
6038 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
6040 const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
6041 const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
6042 if (didModifySubControls)
6043 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
6044 QCommonStyle::drawComplexControl(cc, &groupBox, p, widget);
6045 if (didModifySubControls) {
6046 const QRect rect = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel, widget);
6047 const bool rtl = groupBox.direction == Qt::RightToLeft;
6048 const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
6049 const QFont savedFont = p->font();
6050 if (!flat && d->smallSystemFont)
6051 p->setFont(*d->smallSystemFont);
6052 proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
6054 p->setFont(savedFont);
6059 if (
const QStyleOptionToolButton *tb
6060 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
6061#if QT_CONFIG(accessibility)
6062 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
6063 if (tb->subControls & SC_ToolButtonMenu) {
6064 QStyleOption arrowOpt = *tb;
6065 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
6066 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
6067 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
6068 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
6069 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
6070 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
6071 d->drawToolbarButtonArrow(tb, p);
6073 if (tb->state & State_On) {
6074 NSView *view = window ? (NSView *)window->winId() : nil;
6077 isKey = [view.window isKeyWindow];
6079 QBrush brush(brushForToolButton(isKey));
6081 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
6082 p->setRenderHint(QPainter::Antialiasing);
6083 p->fillPath(path, brush);
6085 proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
6089 auto bflags = tb->state;
6090 if (tb->subControls & SC_ToolButton)
6091 bflags |= State_Sunken;
6092 auto mflags = tb->state;
6093 if (tb->subControls & SC_ToolButtonMenu)
6094 mflags |= State_Sunken;
6096 if (tb->subControls & SC_ToolButton) {
6097 if (bflags & (State_Sunken | State_On | State_Raised)) {
6098 const bool isEnabled = tb->state & State_Enabled;
6099 const bool isPressed = tb->state & State_Sunken;
6100 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
6101 const auto ct = QMacStylePrivate::Button_PushButton;
6102 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6103 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6104 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
6105 pb.bezelStyle = NSBezelStyleShadowlessSquare;
6106 pb.frame = opt->rect.toCGRect();
6107 pb.buttonType = NSButtonTypePushOnPushOff;
6108 pb.enabled = isEnabled;
6109 [pb highlight:isPressed];
6110 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
6111 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
6112 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
6113 [pb.cell drawBezelWithFrame:rect inView:pb];
6118 if (tb->subControls & SC_ToolButtonMenu) {
6119 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
6120 QStyleOption arrowOpt = *tb;
6125 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
6126 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
6127 d->drawToolbarButtonArrow(tb, p);
6129 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
6130 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
6131 QStyleOptionToolButton label = *tb;
6132 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
6133 proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
6139 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
6140 QStyleHelper::drawDial(dial, p);
6144 QCommonStyle::drawComplexControl(cc, opt, p, widget);
6236 const QWidget *widget)
const
6238 Q_D(
const QMacStyle);
6242 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6243 const bool isHorizontal = sb->orientation == Qt::Horizontal;
6244 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
6246 NSScrollerPart part = NSScrollerNoPart;
6247 if (sc == SC_ScrollBarSlider) {
6248 part = NSScrollerKnob;
6249 }
else if (sc == SC_ScrollBarGroove) {
6250 part = NSScrollerKnobSlot;
6251 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
6252 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
6253 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
6254 part = NSScrollerDecrementPage;
6256 part = NSScrollerIncrementPage;
6260 if (part != NSScrollerNoPart) {
6261 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
6262 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6263 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6264 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
6265 if (setupScroller(scroller, sb))
6266 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
6271 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6272 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
6273 const bool isHorizontal = sl->orientation == Qt::Horizontal;
6274 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
6275 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6276 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6277 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
6278 if (!setupSlider(slider, sl))
6281 NSSliderCell *cell = slider.cell;
6282 if (sc == SC_SliderHandle) {
6283 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
6285 ret.setTop(sl->rect.top());
6286 ret.setBottom(sl->rect.bottom());
6288 ret.setLeft(sl->rect.left());
6289 ret.setRight(sl->rect.right());
6291 }
else if (sc == SC_SliderGroove) {
6292 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
6293 }
else if (hasTicks && sc == SC_SliderTickmarks) {
6294 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
6296 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
6298 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
6303 if (sl->upsideDown) {
6304 ret = QRect(sl->rect.right() - ret.right(), sl->rect.top(), ret.width(), sl->rect.height());
6306 ret.setTop(sl->rect.top());
6307 ret.setBottom(sl->rect.bottom());
6310 if (!sl->upsideDown) {
6311 ret = QRect(sl->rect.left(), sl->rect.bottom() - ret.bottom(), sl->rect.width(), ret.height());
6313 ret.setLeft(sl->rect.left());
6314 ret.setRight(sl->rect.right());
6320 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
6326 if (sc == SC_TitleBarLabel) {
6327 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
6328 qreal labelHeight = titlebar->fontMetrics.height();
6330 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
6331 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
6332 if (!titlebar->icon.isNull()) {
6333 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
6334 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
6335 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
6338 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
6339 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
6340 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
6341 labelWidth, labelHeight);
6343 const auto currentButton = d->windowButtonCocoaControl(sc);
6344 if (currentButton == QMacStylePrivate::NoControl)
6347 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
6349 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
6350 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
6351 QStyleHelper::SizeLarge);
6352 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
6353 if (ct == currentButton)
6354 buttonSize = QSizeF::fromCGSize(wb.frame.size);
6356 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
6359 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
6360 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
6365 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
6366 const auto ct = cocoaControlType(combo, widget);
6367 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
6368 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
6369 const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
6372 case SC_ComboBoxEditField:{
6373 ret = editRect.toAlignedRect();
6375 case SC_ComboBoxArrow:{
6376 ret = editRect.toAlignedRect();
6377 ret.setX(ret.x() + ret.width());
6378 ret.setWidth(combo->rect.right() - ret.right());
6380 case SC_ComboBoxListBoxPopup:{
6381 if (combo->editable) {
6382 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
6383 const int comboTop = combo->rect.top();
6384 ret = QRect(qRound(inner.origin.x),
6386 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
6387 editRect.bottom() - comboTop + 2);
6389 ret = QRect(combo->rect.x() + 4 - 11,
6390 combo->rect.y() + 1,
6391 editRect.width() + 10 + 11,
6401 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
6402 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
6403 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
6404 bool hasNoText = !checkable && groupBox->text.isEmpty();
6406 case SC_GroupBoxLabel:
6407 case SC_GroupBoxCheckBox: {
6409 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
6410 const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
6411 || !QApplication::desktopSettingsAware();
6412 const int margin = flat || hasNoText ? 0 : 9;
6413 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
6415 const QFontMetricsF fm = flat || fontIsSet || !d->smallSystemFont
6416 ? QFontMetricsF(groupBox->fontMetrics)
6417 : QFontMetricsF(*d->smallSystemFont);
6418 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
6419 const int tw = qCeil(s.width());
6420 const int h = qCeil(fm.height());
6423 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
6425 if (flat && checkable)
6426 labelRect.moveLeft(labelRect.left() + 4);
6427 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
6428 bool rtl = groupBox->direction == Qt::RightToLeft;
6429 if (sc == SC_GroupBoxLabel) {
6431 int newSum = indicatorWidth + 1;
6432 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
6433 labelRect.moveLeft(newLeft);
6435 labelRect.moveTop(labelRect.top() + 3);
6437 labelRect.moveTop(labelRect.top() + 4);
6439 int newLeft = labelRect.left() - (rtl ? 3 : -3);
6440 labelRect.moveLeft(newLeft);
6441 labelRect.moveTop(labelRect.top() + 3);
6443 int newLeft = labelRect.left() - (rtl ? 3 : 2);
6444 labelRect.moveLeft(newLeft);
6445 labelRect.moveTop(labelRect.top() + 4);
6450 if (sc == SC_GroupBoxCheckBox) {
6451 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
6452 int top = flat ? ret.top() + 1 : ret.top() + 5;
6453 ret.setRect(left, top,
6454 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
6458 case SC_GroupBoxContents:
6459 case SC_GroupBoxFrame: {
6460 QFontMetrics fm = groupBox->fontMetrics;
6463 if (widget && !widget->testAttribute(Qt::WA_SetFont)
6464 && QApplication::desktopSettingsAware())
6465 fm = QFontMetrics(qt_app_fonts_hash()->value(
"QSmallFont", QFont()));
6470 yOffset = -qCeil(QFontMetricsF(fm).height());
6471 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
6472 if (sc == SC_GroupBoxContents) {
6474 ret.adjust(3, -5, -3, -4);
6476 ret.adjust(3, 3, -3, -4);
6481 ret = QCommonStyle::subControlRect(cc, groupBox, sc, widget);
6486#if QT_CONFIG(spinbox)
6488 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6489 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin, widget);
6490 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
6494 case QStyleHelper::SizeLarge:
6498 case QStyleHelper::SizeSmall:
6502 case QStyleHelper::SizeMini:
6512 case SC_SpinBoxDown: {
6513 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
6517 const int x = spin->rect.width() - spinner_w;
6518 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
6521 case QStyleHelper::SizeLarge:
6524 case QStyleHelper::SizeSmall:
6525 hackTranslateX = -2;
6527 case QStyleHelper::SizeMini:
6528 hackTranslateX = -1;
6534 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
6535 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
6536 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
6537 ret = QRectF::fromCGRect(outRect).toRect();
6541 ret.setHeight(ret.height() / 2);
6543 case SC_SpinBoxDown:
6544 ret.setY(ret.y() + ret.height() / 2);
6550 ret.translate(hackTranslateX, 0);
6551 ret = visualRect(spin->direction, spin->rect, ret);
6554 case SC_SpinBoxEditField:
6555 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
6556 if (spin->buttonSymbols != QAbstractSpinBox::NoButtons) {
6557 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
6558 ret = visualRect(spin->direction, spin->rect, ret);
6562 ret = QCommonStyle::subControlRect(cc, spin, sc, widget);
6569 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6570 if (sc == SC_ToolButtonMenu) {
6571#if QT_CONFIG(accessibility)
6572 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
6573 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
6575 ret.adjust(-1, 0, 0, 0);
6579 ret = QCommonStyle::subControlRect(cc, opt, sc, widget);
6586 const QSize &csz,
const QWidget *widget)
const
6588 Q_D(
const QMacStyle);
6590 bool useAquaGuideline =
true;
6593#if QT_CONFIG(spinbox)
6595 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
6596 const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons);
6597 const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0;
6598 sz += QSize(buttonWidth, 0);
6602 case QStyle::CT_TabWidget:
6605 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6637#if QT_CONFIG(tabwidget)
6638 if (
const QStyleOptionTabWidgetFrame *twf
6639 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
6641 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
6642 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
6644 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
6645 if (tabDirection == QMacStylePrivate::North
6646 || tabDirection == QMacStylePrivate::South) {
6647 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
6649 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
6655#if QT_CONFIG(tabbar)
6656 case QStyle::CT_TabBarTab:
6657 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
6658 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
6659 || !QApplication::desktopSettingsAware();
6660 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
6661 const bool verticalTabs = tabDirection == QMacStylePrivate::East
6662 || tabDirection == QMacStylePrivate::West;
6664 sz = sz.transposed();
6666 int defaultTabHeight;
6667 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6669 case QStyleHelper::SizeLarge:
6670 if (tab->documentMode)
6671 defaultTabHeight = 24;
6673 defaultTabHeight = 21;
6675 if (qt_apple_runningWithLiquidGlass() && !tab->documentMode) {
6683 defaultTabHeight = 23;
6686 case QStyleHelper::SizeSmall:
6687 defaultTabHeight = 18;
6689 case QStyleHelper::SizeMini:
6690 defaultTabHeight = 16;
6696 const bool widthSet = !differentFont && tab->icon.isNull();
6698 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
6699 sz.rwidth() = textSize.width();
6700 sz.rheight() = qMax(defaultTabHeight, textSize.height());
6702 sz.rheight() = qMax(defaultTabHeight, sz.height());
6704 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget);
6707 sz = sz.transposed();
6709 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
6710 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
6712 int widgetWidth = 0;
6713 int widgetHeight = 0;
6715 if (tab->leftButtonSize.isValid()) {
6717 widgetWidth += tab->leftButtonSize.width();
6718 widgetHeight += tab->leftButtonSize.height();
6720 if (tab->rightButtonSize.isValid()) {
6722 widgetWidth += tab->rightButtonSize.width();
6723 widgetHeight += tab->rightButtonSize.height();
6727 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
6728 sz.setHeight(sz.height() + widgetHeight + padding);
6731 sz.setWidth(sz.width() + widgetWidth + padding);
6732 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
6737 case QStyle::CT_PushButton: {
6738 bool isFlat =
false;
6739 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
6740 if (btn->features & QStyleOptionButton::CommandLinkButton)
6741 return QCommonStyle::sizeFromContents(ct, opt, sz, widget);
6742 isFlat = btn->features & QStyleOptionButton::Flat;
6749 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz);
6751 if (macsz.width() != -1)
6752 sz.setWidth(macsz.width());
6754 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
6756 if (controlSize != QStyleHelper::SizeMini)
6759 if (controlSize == QStyleHelper::SizeLarge) {
6762 if (sz.height() > 16)
6763 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6765 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeLarge]);
6767 if (!isFlat && !qt_apple_runningWithLiquidGlass())
6769 if (controlSize == QStyleHelper::SizeMini)
6772 sz.setHeight(pushButtonDefaultHeight[QStyleHelper::SizeSmall]);
6778 case QStyle::CT_MenuItem:
6779 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
6780 int maxpmw = mi->maxIconWidth;
6781#if QT_CONFIG(combobox)
6782 const QComboBox *comboBox = qobject_cast<
const QComboBox *>(widget);
6786 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
6790 h = mi->fontMetrics.height() + 2;
6791 if (!mi->icon.isNull()) {
6792#if QT_CONFIG(combobox)
6794 const QSize &iconSize = comboBox->iconSize();
6795 h = qMax(h, iconSize.height() + 4);
6796 maxpmw = qMax(maxpmw, iconSize.width());
6800 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
6801 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
6805 if (mi->text.contains(QLatin1Char(
'\t')))
6807 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
6813#if QT_CONFIG(combobox)
6814 if (comboBox && comboBox->isVisible()) {
6815 QStyleOptionComboBox cmb;
6816 cmb.initFrom(comboBox);
6817 cmb.editable =
false;
6818 cmb.subControls = QStyle::SC_ComboBoxEditField;
6819 cmb.activeSubControls = QStyle::SC_None;
6820 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
6821 QStyle::SC_ComboBoxEditField,
6831 case CT_MenuBarItem:
6838 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
6839 if (tb->features & QStyleOptionToolButton::Menu)
6843 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
6844 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
6845 if (!cb->editable) {
6848 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 24;
6850 if (controlSize != QStyleHelper::SizeMini)
6854 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
6855 sz.rheight() += popupButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6863 if (controlSize == QStyleHelper::SizeMini)
6866 sz.setHeight(pushButtonDefaultHeight[controlSize]);
6872 if (proxy() ==
this) {
6875 QStyleHintReturnMask menuMask;
6876 QStyleOption myOption = *opt;
6877 myOption.rect.setSize(sz);
6878 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask))
6879 sz = menuMask.region.boundingRect().size();
6882 case CT_HeaderSection:{
6883 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
6884 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6885 if (header->text.contains(QLatin1Char(
'\n')))
6886 useAquaGuideline =
false;
6890 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
6891 const int minimumSize = 24;
6892 if (slider->orientation == Qt::Horizontal)
6893 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6895 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6898#if QT_CONFIG(itemviews)
6899 case CT_ItemViewItem:
6900 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
6901 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6902 sz.setHeight(sz.height() + 2);
6908 sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
6911 if (useAquaGuideline && ct != CT_PushButton) {
6914 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
6915 if (macsz.width() != -1)
6916 sz.setWidth(macsz.width());
6917 if (macsz.height() != -1)
6918 sz.setHeight(macsz.height());
6924 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
6925 if (combo->editable) {
6926 const auto widgetSize = d->aquaSizeConstrain(opt, widget);
6927 QMacStylePrivate::CocoaControl cw;
6928 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
6929 cw.size = widgetSize;
6930 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
6931 sz.rwidth() -= qRound(diffRect.size.width);
6932 sz.rheight() -= qRound(diffRect.size.height);