195static bool isDarkMode() {
return qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; }
235#ifndef QT_NO_ACCESSIBILITY
242 return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
244 return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
275 if (qFuzzyIsNull(length))
277 const qreal proportion = sb
->pageStep / length;
280 if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
283 scroller.frame = sb->rect.toCGRect();
284 scroller.floatValue = value;
285 scroller.knobProportion = proportion;
297 [slider initWithFrame:sl->rect.toCGRect()];
316 if (sl->orientation == Qt::Horizontal)
317 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
319 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
321 slider.numberOfTickMarks = 0;
326 [slider layoutSubtreeIfNeeded];
329 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
331 pressPoint.x = CGRectGetMidX(knobRect);
332 pressPoint.y = CGRectGetMidY(knobRect);
333 [slider.cell startTrackingAt:pressPoint inView:slider];
341 const auto tabDirection = QMacStylePrivate::tabDirection(shape);
342 if (QMacStylePrivate::verticalTabs(tabDirection)) {
343 int newX, newY, newRot;
344 if (tabDirection == QMacStylePrivate::East) {
345 newX = tabRect.width();
350 newY = tabRect.y() + tabRect.height();
353 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
354 QTransform transform;
355 transform.translate(newX, newY);
356 transform.rotate(newRot);
357 p->setTransform(transform,
true);
364 QRect rect = tabOpt->rect;
365 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
366 rect = rect.adjusted(-tabOverlap, 0, 0, 0);
368 rect = rect.adjusted(0, -tabOverlap, 0, 0);
370 p->translate(rect.x(), rect.y());
373 const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
375 const int width = tabRect.width();
376 const int height = tabRect.height();
380 const QRect bodyRect(1, 2, width - 2, height - 3);
381 const QRect topLineRect(1, 0, width - 2, 1);
382 const QRect bottomLineRect(1, height - 1, width - 2, 1);
385 if (tabOpt->documentMode && isUnified) {
387 p->setCompositionMode(QPainter::CompositionMode_Source);
388 p->fillRect(tabRect, QColor(Qt::transparent));
391 p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
393 p->fillRect(topLineRect, tabBarTabLineSelected());
395 p->fillRect(bodyRect, tabBarTabBackgroundSelected());
402 p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
404 p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
409 const QRect leftLineRect(0, 1, 1, height - 2);
410 const QRect rightLineRect(width - 1, 1, 1, height - 2);
411 const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
412 p->fillRect(leftLineRect, separatorLineColor);
413 p->fillRect(rightLineRect, separatorLineColor);
424 const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
425 const int width = tabRect.width();
426 const int height = tabRect.height();
430 const QRect bodyRect(0, 1, width, height - 1);
431 const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
432 p->fillRect(bodyRect, bodyColor);
435 const QRect topLineRect(0, 0, width, 1);
436 const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
437 p->fillRect(topLineRect, topLineColor);
440 const QRect bottomLineRect(0, height - 1, width, 1);
441 bool isDocument =
false;
444 const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
445 p->fillRect(bottomLineRect, bottomLineColor);
459 QString returnText(original.size(), QChar());
462 int l = original.length();
464 if (original.at(currPos) == QLatin1Char(
'&')) {
469 }
else if (original.at(currPos) == QLatin1Char(
'(') && l >= 4 &&
470 original.at(currPos + 1) == QLatin1Char(
'&') &&
471 original.at(currPos + 2) != QLatin1Char(
'&') &&
472 original.at(currPos + 3) == QLatin1Char(
')')) {
475 while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
482 returnText[finalDest] = original.at(currPos);
487 returnText.truncate(finalDest);
493 if (window->handle()) {
494 if (NSWindow *nswindow =
static_cast<NSWindow*>(
495 QGuiApplication::platformNativeInterface()->
496 nativeResourceForWindow(QByteArrayLiteral(
"nswindow"),
497 const_cast<QWindow *>(window)))) {
498 return [nswindow isMainWindow];
504#define LargeSmallMini(option, large, small, mini)
505 (option->state & QStyle::State_Small) ? small : ((option->state & QStyle::State_Mini) ? mini : large)
508
509
515
516
615 qDebug(
"Not sure how to return this...");
894 static const qreal CornerPointOffset = 5.5;
895 static const qreal CornerControlOffset = 2.1;
899 path.moveTo(r.left(), r.top() + CornerPointOffset);
900 path.cubicTo(r.left(), r.top() + CornerControlOffset,
901 r.left() + CornerControlOffset, r.top(),
902 r.left() + CornerPointOffset, r.top());
904 path.lineTo(r.right() - CornerPointOffset, r.top());
905 path.cubicTo(r.right() - CornerControlOffset, r.top(),
906 r.right(), r.top() + CornerControlOffset,
907 r.right(), r.top() + CornerPointOffset);
909 path.lineTo(r.right(), r.bottom() - CornerPointOffset);
910 path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
911 r.right() - CornerControlOffset, r.bottom(),
912 r.right() - CornerPointOffset, r.bottom());
914 path.lineTo(r.left() + CornerPointOffset, r.bottom());
915 path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
916 r.left(), r.bottom() - CornerControlOffset,
917 r.left(), r.bottom() - CornerPointOffset);
918 path.lineTo(r.left(), r.top() + CornerPointOffset);
948 QRect tr = opt->rect;
949 const bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
950 || opt->shape == QStyleOptionTab::RoundedWest
951 || opt->shape == QStyleOptionTab::TriangularEast
952 || opt->shape == QStyleOptionTab::TriangularWest;
954 tr.setRect(0, 0, tr.height(), tr.width());
956 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
957 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
958 const int hpadding = 4;
959 const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
960 if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
961 verticalShift = -verticalShift;
962 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
965 if (!opt->leftButtonSize.isEmpty()) {
966 const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
967 tr.setLeft(tr.left() + 4 + buttonSize);
969 if (opt->rightButtonSize.isEmpty())
970 tr.setRight(tr.right() - 4 - buttonSize);
973 if (!opt->rightButtonSize.isEmpty()) {
974 const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
975 tr.setRight(tr.right() - 4 - buttonSize);
977 if (opt->leftButtonSize.isEmpty())
978 tr.setLeft(tr.left() + 4 + buttonSize);
982 if (!opt->icon.isNull()) {
983 QSize iconSize = opt->iconSize;
984 if (!iconSize.isValid()) {
985 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
986 iconSize = QSize(iconExtent, iconExtent);
988 QSize tabIconSize = opt->icon.actualSize(iconSize,
989 (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
990 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
992 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
994 const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2 - hpadding;
996 if (opt->documentMode) {
998 const int textWidth =
999 opt->fontMetrics.boundingRect(tr, Qt::AlignCenter | Qt::TextShowMnemonic, opt->text).width();
1000 *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
1001 tr.center().y() - tabIconSize.height() / 2,
1002 tabIconSize.width(), tabIconSize.height());
1004 *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
1005 tabIconSize.width(), tabIconSize.height());
1008 *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
1010 tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
1011 tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
1015 tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
1023 case QStyleOptionTab::RoundedSouth:
1024 case QStyleOptionTab::TriangularSouth:
1026 case QStyleOptionTab::RoundedNorth:
1027 case QStyleOptionTab::TriangularNorth:
1029 case QStyleOptionTab::RoundedWest:
1030 case QStyleOptionTab::TriangularWest:
1032 case QStyleOptionTab::RoundedEast:
1033 case QStyleOptionTab::TriangularEast:
1040 return (direction == QMacStylePrivate::East
1041 || direction == QMacStylePrivate::West);
1045 QStyle::ContentsType ct,
1046 QSize szHint, QSize *insz)
const
1097 return QSizeF(-1, pushButtonDefaultHeight[
size]);
1101 return QSizeF(-1, popupButtonDefaultHeight[
size]);
1104 return QSizeF(-1, comboBoxDefaultHeight[
size]);
1112 const auto frameSize = defaultFrameSize();
1114 frameRect = rect.adjusted(3, 1, -3, -1)
1115 .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
1118 frameRect = QRectF(rect.topLeft(),
1119 QSizeF(rect.width(), frameSize.height()));
1121 frameRect = frameRect.translated(0, 1.5);
1123 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
1126 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1127 QSizeF(rect.width(), frameSize.height()));
1128 frameRect = frameRect.translated(rect.topLeft());
1131 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1133 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1135 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1137 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1148 if (qt_apple_runningWithLiquidGlass())
1149 return QMarginsF(10, 5, 10, 5);
1151 return QMarginsF(12, 5, 12, 7);
1154 return QMarginsF(12, 4, 12, 9);
1156 return QMarginsF(10, 1, 10, 2);
1161 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1163 return QMarginsF(7.5, 2, 20.5, 4);
1165 return QMarginsF(4.5, 0, 16.5, 2);
1169 return QMarginsF(6, 1, 6, 2);
1177 case Button_CheckBox:
1178 *buttonType = NSButtonTypeSwitch;
1179 *bezelStyle = NSBezelStyleRegularSquare;
1181 case Button_Disclosure:
1182 *buttonType = NSButtonTypeOnOff;
1183 *bezelStyle = NSBezelStyleDisclosure;
1185 case Button_RadioButton:
1186 *buttonType = NSButtonTypeRadio;
1187 *bezelStyle = NSBezelStyleRegularSquare;
1189 case Button_SquareButton:
1190 *buttonType = NSButtonTypePushOnPushOff;
1191 *bezelStyle = NSBezelStyleShadowlessSquare;
1193 case Button_PushButton:
1194 *buttonType = NSButtonTypePushOnPushOff;
1195 *bezelStyle = NSBezelStyleRounded;
1206 if (
const auto *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
1213 || (btn->rect.height() > maxNonSquareHeight);
1220 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
1221 if (combo->editable)
1231
1232
1233
1236 CGRect innerBounds = outerBounds;
1241 switch (cocoaWidget
.size) {
1243 innerBounds.origin.x += 3;
1244 innerBounds.origin.y += 3;
1245 innerBounds.size.width -= 6;
1246 innerBounds.size.height -= 7;
1249 innerBounds.origin.x += 2;
1250 innerBounds.origin.y += 2;
1251 innerBounds.size.width -= 5;
1252 innerBounds.size.height -= 6;
1256 innerBounds.origin.x += 2;
1257 innerBounds.origin.y += 2;
1258 innerBounds.size.width -= 5;
1259 innerBounds.size.height -= 6;
1262 switch (cocoaWidget
.size) {
1264 innerBounds.origin.x += 3;
1265 innerBounds.origin.y += 3;
1266 innerBounds.size.width -= 7;
1267 innerBounds.size.height -= 8;
1270 innerBounds.origin.x += 3;
1271 innerBounds.origin.y += 3;
1272 innerBounds.size.width -= 4;
1273 innerBounds.size.height -= 8;
1277 innerBounds.origin.x += 3;
1278 innerBounds.origin.y += 2;
1279 innerBounds.size.width -= 6;
1280 innerBounds.size.height -= 8;
1288
1289
1290
1293 QRectF ret = outerBounds;
1297 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1301 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1305 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1306 ret.setHeight(10.5);
1314 ret.adjust(10, 1, -23, -4);
1317 ret.adjust(10, 4, -20, -3);
1320 ret.adjust(9, 0, -19, 0);
1333 if (
auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
1334 smallSystemFont = *ssf;
1335 if (
auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
1336 miniSystemFont = *msf;
1341 QMacAutoReleasePool pool;
1342 for (NSView *b : cocoaControls)
1344 for (NSCell *cell : cocoaCells)
1350 if (cocoaControl.type == QMacStylePrivate::NoControl
1351 || cocoaControl.size == QStyleHelper::SizeDefault)
1355 if (
__builtin_available(macOS 10.14, *)) {
1363 NSView *bv = cocoaControls.value(cocoaControl, nil);
1365 switch (cocoaControl
.type) {
1367 NSBox *box = [[NSBox alloc] init];
1370 box.titlePosition = NSNoTitle;
1374 bv = [[QDarkNSBox alloc] init];
1381 NSButton *bc = [[NSButton alloc] init];
1389 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1391 if (cocoaControl.type == Button_PullDown)
1399 const NSWindowButton button = [=] {
1400 switch (cocoaControl
.type) {
1401 case Button_WindowClose:
1402 return NSWindowCloseButton;
1403 case Button_WindowMiniaturize:
1404 return NSWindowMiniaturizeButton;
1405 case Button_WindowZoom:
1406 return NSWindowZoomButton;
1412 const auto styleMask = NSWindowStyleMaskTitled
1413 | NSWindowStyleMaskClosable
1414 | NSWindowStyleMaskMiniaturizable
1415 | NSWindowStyleMaskResizable;
1416 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1421 bv = [[NSSearchField alloc] init];
1424 bv = [[NSComboBox alloc] init];
1426 case ProgressIndicator_Determinate:
1427 bv = [[NSProgressIndicator alloc] init];
1429 case ProgressIndicator_Indeterminate:
1430 bv = [[QIndeterminateProgressIndicator alloc] init];
1432 case Scroller_Horizontal:
1433 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1435 case Scroller_Vertical:
1438 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1440 case Slider_Horizontal:
1441 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1443 case Slider_Vertical:
1446 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1448 case SplitView_Horizontal:
1449 bv = [[NSSplitView alloc] init];
1451 case SplitView_Vertical:
1452 bv = [[QVerticalSplitView alloc] init];
1455 bv = [[NSTextField alloc] init];
1461 if ([bv isKindOfClass:[NSControl
class]]) {
1462 auto *ctrl =
static_cast<NSControl *>(bv);
1463 switch (cocoaControl
.size) {
1464 case QStyleHelper::SizeSmall:
1465 ctrl.controlSize = NSControlSizeSmall;
1467 case QStyleHelper::SizeMini:
1468 ctrl.controlSize = NSControlSizeMini;
1475 auto *pi =
static_cast<NSProgressIndicator *>(bv);
1477 switch (cocoaControl
.size) {
1478 case QStyleHelper::SizeSmall:
1479 pi.controlSize = NSControlSizeSmall;
1481 case QStyleHelper::SizeMini:
1482 pi.controlSize = NSControlSizeMini;
1489 cocoaControls.insert(cocoaControl, bv);
1492 NSButtonType buttonType;
1493 NSBezelStyle bezelStyle;
1507NSCell *QMacStylePrivate::cocoaCell(CocoaControl cocoaControl)
const
1509 NSCell *cell = cocoaCells[cocoaControl];
1511 switch (cocoaControl.type) {
1513 cell = [[NSStepperCell alloc] init];
1515 case Button_Disclosure: {
1516 NSButtonCell *bc = [[NSButtonCell alloc] init];
1517 bc.buttonType = NSButtonTypeOnOff;
1518 bc.bezelStyle = NSBezelStyleDisclosure;
1526 switch (cocoaControl.size) {
1527 case QStyleHelper::SizeSmall:
1528 cell.controlSize = NSControlSizeSmall;
1530 case QStyleHelper::SizeMini:
1531 cell.controlSize = NSControlSizeMini;
1537 cocoaCells.insert(cocoaControl, cell);
1543void QMacStylePrivate::drawNSViewInRect(NSView *view,
const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock)
const
1545 QMacAutoReleasePool pool;
1546 QMacCGContext ctx(p);
1547 setupNSGraphicsContext(ctx, YES);
1558 view.wantsLayer = YES;
1567 view.frame = rect.toCGRect();
1569 [backingStoreNSView addSubview:view];
1576 const CGRect dirtyRect = rect.toCGRect();
1579 drawRectBlock(ctx, dirtyRect);
1581 [view drawRect:dirtyRect];
1583 [view removeFromSuperviewWithoutNeedingDisplay];
1585 restoreNSGraphicsContext(ctx);
1588void QMacStylePrivate::resolveCurrentNSView(QWindow *window)
const
1590 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1593QMacStyle *QMacStyle::create()
1595 return new QMacApperanceStyle<QMacStyle>;
1598QMacStyle::QMacStyle()
1599 : QCommonStyle(*
new QMacStylePrivate)
1601 QMacAutoReleasePool pool;
1603 static QMacNotificationObserver scrollbarStyleObserver(nil,
1604 NSPreferredScrollerStyleDidChangeNotification, []() {
1606 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1608 QEvent event(QEvent::StyleChange);
1609 for (
const auto &o : QMacStylePrivate::scrollBars)
1610 QCoreApplication::sendEvent(o, &event);
1614QMacStyle::~QMacStyle()
1618void QMacStyle::handleThemeChange()
1621 for (NSView *b : d->cocoaControls)
1623 d->cocoaControls.clear();
1626int QMacStyle::pixelMetric(PixelMetric metric,
const QStyleOption *opt)
const
1628 Q_D(
const QMacStyle);
1629 const int controlSize = getControlSize(opt);
1633 case PM_TabCloseIndicatorWidth:
1634 case PM_TabCloseIndicatorHeight:
1635 ret = closeButtonSize;
1637 case PM_ToolBarIconSize:
1638 ret = proxy()->pixelMetric(PM_LargeIconSize);
1640 case PM_FocusFrameVMargin:
1641 case PM_FocusFrameHMargin:
1642 ret = qt_mac_aqua_get_metric(FocusRectOutset);
1644 case PM_DialogButtonsSeparator:
1647 case PM_DialogButtonsButtonHeight: {
1649 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1650 if (sz == QSize(-1, -1))
1655 case PM_DialogButtonsButtonWidth: {
1657 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1658 if (sz == QSize(-1, -1))
1664 case PM_MenuBarHMargin:
1668 case PM_MenuBarVMargin:
1672 case PM_MenuBarPanelWidth:
1676 case PM_MenuButtonIndicator:
1677 ret = toolButtonArrowSize;
1680 case QStyle::PM_MenuDesktopFrameWidth:
1684 case PM_CheckBoxLabelSpacing:
1685 case PM_RadioButtonLabelSpacing:
1688 if (opt->state & State_Mini)
1690 if (opt->state & State_Small)
1696 case PM_MenuScrollerHeight:
1699 case PM_DefaultFrameWidth:
1709 if (qstyleoption_cast<
const QStyleOptionComboBox *>(opt) != 0)
1714 case PM_MaximumDragDistance:
1717 case PM_ScrollBarSliderMin:
1720 case PM_SpinBoxFrameWidth:
1721 ret = qt_mac_aqua_get_metric(EditTextFrameOutset);
1723 case PM_ButtonShiftHorizontal:
1724 case PM_ButtonShiftVertical:
1727 case PM_SliderLength:
1733 case PM_SliderControlThickness:
1734 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
1735 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1736 int ticks = sl->tickPosition;
1738 if (ticks & QStyleOptionSlider::TicksAbove)
1740 if (ticks & QStyleOptionSlider::TicksBelow)
1748 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1749 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1753 thick += (space * 2) / (n + 2);
1759 case PM_SmallIconSize:
1760 ret =
int(QStyleHelper::dpiScaled(16., opt));
1763 case PM_LargeIconSize:
1764 ret =
int(QStyleHelper::dpiScaled(32., opt));
1767 case PM_IconViewIconSize:
1768 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1771 case PM_ButtonDefaultIndicator:
1774 case PM_TitleBarHeight: {
1775 NSUInteger style = NSWindowStyleMaskTitled;
1778 ret =
int([NSWindow frameRectForContentRect:NSZeroRect
1779 styleMask:style].size.height);
1781 case QStyle::PM_TabBarTabHSpace:
1782 switch (d->aquaSizeConstrain(opt)) {
1783 case QStyleHelper::SizeLarge:
1784 ret = QCommonStyle::pixelMetric(metric, opt);
1786 case QStyleHelper::SizeSmall:
1789 case QStyleHelper::SizeMini:
1792 case QStyleHelper::SizeDefault:
1793 const QStyleOptionTab *tb = qstyleoption_cast<
const QStyleOptionTab *>(opt);
1794 if (tb && tb->documentMode)
1797 ret = QCommonStyle::pixelMetric(metric, opt);
1801 case PM_TabBarTabVSpace:
1804 case PM_TabBarTabShiftHorizontal:
1805 case PM_TabBarTabShiftVertical:
1808 case PM_TabBarBaseHeight:
1811 case PM_TabBarTabOverlap:
1814 case PM_TabBarBaseOverlap:
1815 switch (d->aquaSizeConstrain(opt)) {
1816 case QStyleHelper::SizeDefault:
1817 case QStyleHelper::SizeLarge:
1820 case QStyleHelper::SizeSmall:
1823 case QStyleHelper::SizeMini:
1828 case PM_ScrollBarExtent: {
1829 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1830 ret =
static_cast<
int>([NSScroller
1831 scrollerWidthForControlSize:
static_cast<NSControlSize>(size)
1832 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1834 case PM_IndicatorHeight: {
1835 switch (d->aquaSizeConstrain(opt)) {
1836 case QStyleHelper::SizeDefault:
1837 case QStyleHelper::SizeLarge:
1838 ret = qt_mac_aqua_get_metric(CheckBoxHeight);
1840 case QStyleHelper::SizeMini:
1841 ret = qt_mac_aqua_get_metric(MiniCheckBoxHeight);
1843 case QStyleHelper::SizeSmall:
1844 ret = qt_mac_aqua_get_metric(SmallCheckBoxHeight);
1848 case PM_IndicatorWidth: {
1849 switch (d->aquaSizeConstrain(opt)) {
1850 case QStyleHelper::SizeDefault:
1851 case QStyleHelper::SizeLarge:
1852 ret = qt_mac_aqua_get_metric(CheckBoxWidth);
1854 case QStyleHelper::SizeMini:
1855 ret = qt_mac_aqua_get_metric(MiniCheckBoxWidth);
1857 case QStyleHelper::SizeSmall:
1858 ret = qt_mac_aqua_get_metric(SmallCheckBoxWidth);
1863 case PM_ExclusiveIndicatorHeight: {
1864 switch (d->aquaSizeConstrain(opt)) {
1865 case QStyleHelper::SizeDefault:
1866 case QStyleHelper::SizeLarge:
1867 ret = qt_mac_aqua_get_metric(RadioButtonHeight);
1869 case QStyleHelper::SizeMini:
1870 ret = qt_mac_aqua_get_metric(MiniRadioButtonHeight);
1872 case QStyleHelper::SizeSmall:
1873 ret = qt_mac_aqua_get_metric(SmallRadioButtonHeight);
1877 case PM_ExclusiveIndicatorWidth: {
1878 switch (d->aquaSizeConstrain(opt)) {
1879 case QStyleHelper::SizeDefault:
1880 case QStyleHelper::SizeLarge:
1881 ret = qt_mac_aqua_get_metric(RadioButtonWidth);
1883 case QStyleHelper::SizeMini:
1884 ret = qt_mac_aqua_get_metric(MiniRadioButtonWidth);
1886 case QStyleHelper::SizeSmall:
1887 ret = qt_mac_aqua_get_metric(SmallRadioButtonWidth);
1892 case PM_MenuVMargin:
1895 case PM_MenuPanelWidth:
1898 case PM_ToolTipLabelFrameWidth:
1901 case PM_SizeGripSize: {
1902 QStyleHelper::WidgetSizePolicy aSize;
1906 aSize = QStyleHelper::SizeLarge;
1907 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
1910 case PM_MdiSubWindowFrameWidth:
1913 case PM_DockWidgetFrameWidth:
1916 case PM_DockWidgetTitleMargin:
1919 case PM_DockWidgetSeparatorExtent:
1922 case PM_ToolBarHandleExtent:
1925 case PM_ToolBarItemMargin:
1928 case PM_ToolBarItemSpacing:
1931 case PM_SplitterWidth:
1934 case PM_LayoutLeftMargin:
1935 case PM_LayoutTopMargin:
1936 case PM_LayoutRightMargin:
1937 case PM_LayoutBottomMargin:
1939 if (opt->state & State_Window) {
1941
1942
1943
1944
1945
1962
1963
1968 case PM_LayoutHorizontalSpacing:
1969 case PM_LayoutVerticalSpacing:
1971 case PM_MenuHMargin:
1974 case PM_ToolBarExtensionExtent:
1977 case PM_ToolBarFrameWidth:
1980 case PM_ScrollView_ScrollBarOverlap:
1981 ret = styleHint(SH_ScrollBar_Transient, opt,
nullptr)
1982 ? pixelMetric(PM_ScrollBarExtent, opt)
1985 case PM_PushButtonFocusFrameRadius:
1988 case PM_CheckBoxFocusFrameRadius:
1991 case PM_SearchFieldFocusFrameRadius:
1992 case PM_ComboBoxFocusFrameRadius:
1993 if (qt_apple_runningWithLiquidGlass())
1998 case PM_RadioButtonFocusFrameRadius:
2001 case PM_SliderFocusFrameRadius:
2008 case PM_DialFocusFrameRadius:
2009 case PM_SpinBoxFocusFrameRadius:
2010 case PM_TextAreaFocusFrameRadius:
2011 case PM_TextFieldFocusFrameRadius:
2012 ret = qt_apple_runningWithLiquidGlass() ? 6 : 0;
2015 ret = QCommonStyle::pixelMetric(metric, opt);
2031int QMacStyle::styleHint(StyleHint sh,
const QStyleOption *opt, QStyleHintReturn *hret)
const
2033 QMacAutoReleasePool pool;
2037 case SH_Slider_SnapToValue:
2038 case SH_PrintDialog_RightAlignButtons:
2039 case SH_FontDialog_SelectAssociatedText:
2040 case SH_MenuBar_MouseTracking:
2041 case SH_Menu_MouseTracking:
2042 case SH_ComboBox_ListMouseTracking:
2043 case SH_MainWindow_SpaceBelowMenuBar:
2044 case SH_ItemView_ChangeHighlightOnFocus:
2047 case SH_ToolBox_SelectedPageTitleBold:
2050 case SH_DialogButtonBox_ButtonsHaveIcons:
2053 case SH_Menu_SelectionWrap:
2056 case SH_Menu_KeyboardSearch:
2059 case SH_Menu_SpaceActivatesItem:
2062 case SH_Slider_AbsoluteSetButtons:
2063 ret = Qt::LeftButton|Qt::MiddleButton;
2065 case SH_Slider_PageSetButtons:
2068 case SH_ScrollBar_ContextMenu:
2071 case SH_TitleBar_AutoRaise:
2074 case SH_Menu_AllowActiveAndDisabled:
2077 case SH_Menu_SubMenuPopupDelay:
2080 case SH_Menu_SubMenuUniDirection:
2083 case SH_Menu_SubMenuSloppySelectOtherActions:
2086 case SH_Menu_SubMenuResetWhenReenteringParent:
2089 case SH_Menu_SubMenuDontStartSloppyOnLeave:
2093 case SH_ScrollBar_LeftClickAbsolutePosition: {
2094 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2095 bool result = [defaults boolForKey:@
"AppleScrollerPagingBehavior"];
2101 case SH_TabBar_PreferNoArrows:
2105
2106
2107
2108
2109 case SH_GroupBox_TextLabelVerticalAlignment:
2112 case SH_ScrollView_FrameOnlyAroundContents:
2113 ret = QCommonStyle::styleHint(sh, opt, hret);
2115 case SH_Menu_FillScreenWithScroll:
2118 case SH_Menu_Scrollable:
2121 case SH_RichText_FullWidthSelection:
2124 case SH_BlinkCursorWhenTextSelected:
2127 case SH_Slider_StopMouseOverSlider:
2130 case SH_ListViewExpand_SelectMouseType:
2131 ret = QEvent::MouseButtonRelease;
2133 case SH_TabBar_SelectMouseType:
2134 if (
const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2135 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2137 ret = QEvent::MouseButtonRelease;
2140 case SH_ComboBox_Popup:
2141 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt))
2142 ret = !cmb->editable;
2146 case SH_Workspace_FillSpaceOnMaximize:
2149 case SH_Widget_ShareActivation:
2152 case SH_Header_ArrowAlignment:
2153 ret = Qt::AlignRight;
2155 case SH_TabBar_Alignment: {
2172 ret = Qt::AlignCenter;
2174 case SH_UnderlineShortcut:
2177 case SH_ToolTipLabel_Opacity:
2180 case SH_Button_FocusPolicy:
2183 case SH_EtchDisabledText:
2186 case SH_FocusFrame_Mask: {
2188 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2189 const uchar fillR = 192, fillG = 191, fillB = 190;
2192 QSize pixmapSize = opt->rect.size();
2193 if (!pixmapSize.isEmpty()) {
2194 QPixmap pix(pixmapSize);
2195 pix.fill(QColor(fillR, fillG, fillB));
2196 QPainter pix_paint(&pix);
2197 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2199 img = pix.toImage();
2202 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2203 const qsizetype sbpl = img.bytesPerLine();
2204 const int w = sbpl/4, h = img.height();
2206 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2207 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2208 const qsizetype dbpl = img_mask.bytesPerLine();
2210 for (
int y = 0; y < h; ++y) {
2211 srow = sptr+((y*sbpl)/4);
2212 drow = dptr+((y*dbpl)/4);
2213 for (
int x = 0; x < w; ++x) {
2214 const int redDiff = qRed(*srow) - fillR;
2215 const int greenDiff = qGreen(*srow) - fillG;
2216 const int blueDiff = qBlue(*srow) - fillB;
2217 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2218 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2222 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2223 mask->region = QRegion(qmask);
2226 case SH_TitleBar_NoBorder:
2229 case SH_RubberBand_Mask:
2232 case SH_ComboBox_LayoutDirection:
2233 ret = Qt::LeftToRight;
2235 case SH_ItemView_EllipsisLocation:
2236 ret = Qt::AlignHCenter;
2238 case SH_ItemView_ShowDecorationSelected:
2241 case SH_TitleBar_ModifyNotification:
2244 case SH_ScrollBar_RollBetweenButtons:
2247 case SH_WindowFrame_Mask:
2250 case SH_TabBar_ElideMode:
2251 ret = Qt::ElideRight;
2262 case SH_FormLayoutFormAlignment:
2263 ret = Qt::AlignHCenter | Qt::AlignTop;
2265 case SH_FormLayoutLabelAlignment:
2266 ret = Qt::AlignRight;
2271 case SH_MessageBox_TextInteractionFlags:
2272 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2274 case SH_SpellCheckUnderlineStyle:
2275 ret = QTextCharFormat::DashUnderline;
2277 case SH_MessageBox_CenterButtons:
2280 case SH_MenuBar_AltKeyNavigation:
2283 case SH_ItemView_MovementWithoutUpdatingSelection:
2286 case SH_FocusFrame_AboveWidget:
2292 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2295 case SH_Menu_FlashTriggeredItem:
2298 case SH_Menu_FadeOutOnHide:
2301 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2304 case SH_TabBar_CloseButtonPosition:
2305 ret = QStyleOptionTabBarBase::LeftSide;
2307 case SH_DockWidget_ButtonsHaveFrame:
2310 case SH_ScrollBar_Transient:
2316 case SH_TitleBar_ShowToolTipsOnButtons:
2320 case SH_ComboBox_AllowWheelScrolling:
2323 case SH_SpinBox_ButtonsInsideFrame:
2326 case SH_Table_GridLineColor:
2327 ret =
int(qt_mac_toQColor(NSColor.gridColor).rgba());
2330 ret = QCommonStyle::styleHint(sh, opt, hret);
2336QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode,
const QPixmap &pixmap,
2337 const QStyleOption *opt)
const
2340 case QIcon::Disabled: {
2341 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2342 int imgh = img.height();
2343 int imgw = img.width();
2345 for (
int y = 0; y < imgh; ++y) {
2346 for (
int x = 0; x < imgw; ++x) {
2347 pixel = img.pixel(x, y);
2348 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2349 qAlpha(pixel) / 2));
2352 return QPixmap::fromImage(img);
2357 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2361QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap,
const QStyleOption *opt)
const
2368 static bool recursionGuard =
false;
2371 return QCommonStyle::standardPixmap(standardPixmap, opt);
2373 recursionGuard =
true;
2374 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2375 recursionGuard =
false;
2377 switch (standardPixmap) {
2381 case SP_MessageBoxCritical:
2382 case SP_MessageBoxQuestion:
2383 case SP_MessageBoxInformation:
2384 case SP_MessageBoxWarning:
2388 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2391void QMacStyle::drawPrimitive(PrimitiveElement pe,
const QStyleOption *opt, QPainter *p)
const
2393 Q_D(
const QMacStyle);
2395 QMacCGContext cg(p);
2396 d->resolveCurrentNSView(opt->window);
2399 case PE_IndicatorArrowUp:
2400 case PE_IndicatorArrowDown:
2401 case PE_IndicatorArrowRight:
2402 case PE_IndicatorArrowLeft: {
2404 p->setRenderHint(QPainter::Antialiasing);
2405 const int xOffset = 1;
2406 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2407 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2417 QTransform transform;
2418 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2422 case PE_IndicatorArrowDown:
2424 case PE_IndicatorArrowUp:
2425 transform.rotate(180);
2427 case PE_IndicatorArrowLeft:
2428 transform.rotate(90);
2430 case PE_IndicatorArrowRight:
2431 transform.rotate(-90);
2434 p->setTransform(transform);
2436 path.moveTo(-halfSize, -halfSize * 0.5);
2437 path.lineTo(0.0, halfSize * 0.5);
2438 path.lineTo(halfSize, -halfSize * 0.5);
2440 const QPen arrowPen(opt->palette.text(), penWidth,
2441 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2442 p->strokePath(path, arrowPen);
2445 case PE_FrameTabBarBase:
2446 if (
const QStyleOptionTabBarBase *tbb
2447 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2448 if (tbb->documentMode) {
2450 drawTabBase(p, tbb);
2454 QRegion region(tbb->rect);
2455 region -= tbb->tabBarRect;
2457 p->setClipRegion(region);
2458 QStyleOptionTabWidgetFrame twf;
2459 twf.QStyleOption::operator=(*tbb);
2460 twf.shape = tbb->shape;
2461 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2462 case QMacStylePrivate::North:
2463 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2465 case QMacStylePrivate::South:
2466 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2468 case QMacStylePrivate::West:
2469 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2471 case QMacStylePrivate::East:
2472 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2475 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2479 case PE_PanelTipLabel:
2480 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2482 case PE_FrameGroupBox:
2483 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2484 if (groupBox->features & QStyleOptionFrame::Flat) {
2485 QCommonStyle::drawPrimitive(pe, groupBox, p);
2489 case PE_FrameTabWidget:
2491 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2492 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
2506 auto adjustedRect = opt->rect;
2507 bool needTranslation =
false;
2508 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
2521 adjustedRect.adjust(0, 0, 6, 6);
2522 needTranslation =
true;
2524 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2529 QMacAutoReleasePool pool;
2530 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2531 CGContextScaleCTM(ctx, 1, -1);
2532 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
2533 || [box isMemberOfClass:QDarkNSBox.
class]) {
2534 [box drawRect:rect];
2536 if (needTranslation)
2537 CGContextTranslateCTM(ctx, -3.0, 5.0);
2538 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2543 case PE_IndicatorToolBarSeparator: {
2545 if (opt->state & State_Horizontal) {
2546 int xpoint = opt->rect.center().x();
2547 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2548 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2550 int ypoint = opt->rect.center().y();
2551 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2552 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2554 QPainterPathStroker theStroker;
2555 theStroker.setCapStyle(Qt::FlatCap);
2556 theStroker.setDashPattern(QList<qreal>() << 1 << 2);
2557 path = theStroker.createStroke(path);
2558 const auto dark = isDarkMode() ? opt->palette.dark().color().darker()
2559 : QColor(0, 0, 0, 119);
2560 p->fillPath(path, dark);
2563 case PE_FrameWindow:
2574 case PE_IndicatorDockWidgetResizeHandle: {
2577 if (opt->state & State_Horizontal) {
2578 p->setPen(QColor(160, 160, 160));
2579 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2581 p->setPen(QColor(145, 145, 145));
2582 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2586 case PE_IndicatorToolBarHandle: {
2589 int x = opt->rect.x() + 6;
2590 int y = opt->rect.y() + 7;
2591 static const int RectHeight = 2;
2592 if (opt->state & State_Horizontal) {
2593 while (y < opt->rect.height() - RectHeight - 5) {
2595 path.addEllipse(x, y, RectHeight, RectHeight);
2599 while (x < opt->rect.width() - RectHeight - 5) {
2601 path.addEllipse(x, y, RectHeight, RectHeight);
2605 p->setPen(Qt::NoPen);
2606 QColor dark = opt->palette.dark().color().darker();
2607 dark.setAlphaF(0.50);
2608 p->fillPath(path, dark);
2613 case PE_IndicatorHeaderArrow:
2614 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2616 if (header->sortIndicator != QStyleOptionHeader::None)
2617 proxy()->drawPrimitive(
2618 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2619 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
2622 case PE_IndicatorMenuCheckMark: {
2624 if (opt->state & State_On)
2625 pc = opt->palette.highlightedText().color();
2627 pc = opt->palette.text().color();
2629 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
2630 static_cast<CGFloat>(pc.greenF()),
2631 static_cast<CGFloat>(pc.blueF()),
2632 static_cast<CGFloat>(pc.alphaF()));
2638 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2639 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2640 kCTFontUIFontMenuItemMark;
2644 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2645 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2647 CGContextSaveGState(cg);
2648 CGContextSetShouldSmoothFonts(cg, NO);
2651 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2652 (opt->state & State_Small) ? 1.0 :
2655 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2656 CGContextScaleCTM(cg, 1, -1);
2658 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2662 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2663 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
2664 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2665 Q_STATIC_ASSERT((
sizeof(values) /
sizeof(values[0])) == numValues);
2666 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
2667 numValues, NULL, NULL);
2669 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
2670 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2672 CTLineDraw((CTLineRef)line, cg);
2675 CGContextRestoreGState(cg);
2677 case PE_IndicatorItemViewItemCheck:
2678 case PE_IndicatorRadioButton:
2679 case PE_IndicatorCheckBox: {
2680 const bool isEnabled = opt->state & State_Enabled;
2681 const bool isPressed = opt->state & State_Sunken;
2682 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2683 const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
2684 const auto cs = d->effectiveAquaSizeConstrain(opt);
2685 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
2686 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
2687 tb.enabled = isEnabled;
2688 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2689 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2690 [tb highlight:isPressed];
2691 const auto vOffset = [=] {
2693 if (cs == QStyleHelper::SizeMini)
2694 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
2696 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2698 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2699 QMacAutoReleasePool pool;
2700 CGContextTranslateCTM(ctx, 0, vOffset);
2701 [tb.cell drawInteriorWithFrame:rect inView:tb];
2704 case PE_FrameFocusRect:
2707 case PE_IndicatorBranch: {
2708 if (!(opt->state & State_Children))
2710 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
2711 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
2712 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2714 bool viewHasFocus =
false;
2715 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2717 d->setupNSGraphicsContext(cg, NO);
2719 QRect qtRect = opt->rect.adjusted(DisclosureOffset, 0, -DisclosureOffset, 0);
2720 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2721 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2722 CGContextScaleCTM(cg, 1, -1);
2723 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2725 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2727 d->restoreNSGraphicsContext(cg);
2731 const QPen oldPen = p->pen();
2732 QPen penCpy = p->pen();
2734 penCpy.setColor(opt->palette.dark().color());
2736 p->drawRect(opt->rect);
2739 case PE_PanelLineEdit:
2740 case PE_FrameLineEdit:
2741 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
2742 if (frame->state & State_Sunken) {
2743 const bool isEnabled = opt->state & State_Enabled;
2744 const bool isReadOnly = opt->state & State_ReadOnly;
2745 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2746 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2747 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
2748 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
2749 tf.enabled = isEnabled;
2750 tf.editable = !isReadOnly;
2752 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2753 tf.frame = opt->rect.toCGRect();
2754 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
2755 QMacAutoReleasePool pool;
2756 if (!isDarkMode()) {
2761 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2765 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
2766 tf.drawsBackground = YES;
2767 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2768 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2769 green:bgColor.greenF()
2770 blue:bgColor.blueF()
2771 alpha:bgColor.alphaF()];
2772 if (bgColor.alpha() != 255) {
2779 CGRect fixedRect = rect;
2780 if (qt_apple_runningWithLiquidGlass()) {
2785 fixedRect = CGRectInset(rect, 1., 1.);
2787 [tf.cell drawWithFrame:fixedRect inView:tf];
2790 QCommonStyle::drawPrimitive(pe, opt, p);
2794 case PE_PanelScrollAreaCorner: {
2795 const QBrush brush(opt->palette.brush(QPalette::Base));
2796 p->fillRect(opt->rect, brush);
2797 p->setPen(QPen(QColor(217, 217, 217)));
2798 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2799 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2801 case PE_FrameStatusBarItem:
2829 case PE_PanelStatusBar: {
2830 p->fillRect(opt->rect, opt->palette.window());
2833 if (qt_macWindowMainWindow(opt->window))
2834 p->setPen(titlebarSeparatorLineActive);
2836 p->setPen(titlebarSeparatorLineInactive);
2837 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2841 case PE_PanelMenu: {
2843 p->fillRect(opt->rect, Qt::transparent);
2844 p->setPen(Qt::transparent);
2845 p->setBrush(opt->palette.window());
2846 p->setRenderHint(QPainter::Antialiasing,
true);
2847 const QPainterPath path = d->windowPanelPath(opt->rect);
2853 QCommonStyle::drawPrimitive(pe, opt, p);
2860 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2861 int imgh = img.height();
2862 int imgw = img.width();
2865 for (
int y = 0; y < imgh; ++y) {
2866 for (
int x = 0; x < imgw; ++x) {
2867 pixel = img.pixel(x, y);
2869 QColor hsvColor(pixel);
2870 hsvColor.getHsv(&h, &s, &v);
2871 s = qMin(100, s * 2);
2873 hsvColor.setHsv(h, s, v);
2874 pixel = hsvColor.rgb();
2875 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2878 return QPixmap::fromImage(img);
2881void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg,
bool reverse,
bool vertical,
const CGRect &rect)
const
2884 CGContextTranslateCTM(cg, rect.size.height, 0);
2885 CGContextRotateCTM(cg,
M_PI_2);
2887 if (vertical != reverse) {
2888 CGContextTranslateCTM(cg, rect.size.width, 0);
2889 CGContextScaleCTM(cg, -1, 1);
2893void QMacStyle::drawControl(ControlElement ce,
const QStyleOption *opt, QPainter *p)
const
2895 Q_D(
const QMacStyle);
2897 const QMacAutoReleasePool pool;
2899 QMacCGContext cg(p);
2900 d->resolveCurrentNSView(opt->window);
2903 case CE_HeaderSection:
2904 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2905 State flags = header->state;
2906 QRect ir = header->rect;
2907 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2908 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2909 p->setPen(QPen(header->palette.dark(), 1.0));
2910 if (header->orientation == Qt::Horizontal)
2911 p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
2912 ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
2914 p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
2915 ir.right() - headerSectionSeparatorInset, ir.bottom()));
2919 case CE_HeaderLabel:
2920 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2922 QRect textr = header->rect;
2923 if (!header->icon.isNull()) {
2924 QIcon::Mode mode = QIcon::Disabled;
2925 if (opt->state & State_Enabled)
2926 mode = QIcon::Normal;
2927 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2928 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2929 opt->window->devicePixelRatio(), mode);
2931 QRect pixr = header->rect;
2932 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2933 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
2934 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2937 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2938 header->state & State_Enabled, header->text, QPalette::ButtonText);
2942 case CE_ToolButtonLabel:
2943 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
2944 QStyleOptionToolButton myTb = *tb;
2945 myTb.state &= ~State_AutoRaise;
2946#ifndef QT_NO_ACCESSIBILITY
2947 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2948 QRect cr = tb->rect;
2951 bool needText =
false;
2953 bool down = tb->state & (State_Sunken | State_On);
2955 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
2956 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2962 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2963 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2964 if (tb->icon.isNull() && !tb->text.isEmpty())
2965 tbstyle = Qt::ToolButtonTextOnly;
2968 case Qt::ToolButtonTextOnly: {
2970 alignment = Qt::AlignCenter;
2972 case Qt::ToolButtonIconOnly:
2973 case Qt::ToolButtonTextBesideIcon:
2974 case Qt::ToolButtonTextUnderIcon: {
2976 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2978 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2980 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2981 opt->window->devicePixelRatio(), iconMode,
2985 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
2987 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
2988 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
2989 cr.adjust(0, pr.bottom(), 0, -3);
2990 alignment |= Qt::AlignCenter;
2992 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
2993 cr.adjust(pr.right(), 0, 0, 0);
2994 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
2997 if (opt->state & State_Sunken) {
2998 pr.translate(shiftX, shiftY);
2999 pixmap = darkenPixmap(pixmap);
3001 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3009 QPalette pal = tb->palette;
3010 QPalette::ColorRole role = QPalette::NoRole;
3011 if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
3012 alignment |= Qt::TextHideMnemonic;
3014 cr.translate(shiftX, shiftY);
3015 if (tbstyle == Qt::ToolButtonTextOnly
3016 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3017 QPen pen = p->pen();
3018 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3019 light.setAlphaF(0.375f);
3021 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3023 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3025 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3026 role = QPalette::HighlightedText;
3029 proxy()->drawItemText(p, cr, alignment, pal,
3030 tb->state & State_Enabled, tb->text, role);
3033 QCommonStyle::drawControl(ce, &myTb, p);
3038 QCommonStyle::drawControl(ce, &myTb, p);
3042 case CE_ToolBoxTabShape:
3043 QCommonStyle::drawControl(ce, opt, p);
3045 case CE_PushButtonBevel:
3046 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3047 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3050 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3051 QCommonStyle::drawControl(ce, opt, p);
3055 const bool hasFocus = btn->state & State_HasFocus;
3056 const bool isActive = btn->state & State_Active;
3060 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3061 && isActive && hasFocus)
3062 d->autoDefaultButton = btn->styleObject;
3063 else if (d->autoDefaultButton == btn->styleObject)
3064 d->autoDefaultButton =
nullptr;
3066 const bool isEnabled = btn->state & State_Enabled;
3067 const bool isPressed = btn->state & State_Sunken;
3068 const bool isHighlighted = isActive &&
3069 ((btn->state & State_On)
3070 || (btn->features & QStyleOptionButton::DefaultButton)
3071 || (btn->features & QStyleOptionButton::AutoDefaultButton
3072 && d->autoDefaultButton == btn->styleObject));
3073 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3074 const auto ct = cocoaControlType(btn);
3075 const auto cs = d->effectiveAquaSizeConstrain(btn);
3076 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3077 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3081 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3082 pb.frame = frameRect.toCGRect();
3084 pb.enabled = isEnabled;
3085 [pb highlight:isPressed];
3086 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3087 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3088 QMacAutoReleasePool pool;
3089 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3093 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3096 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
3097 const auto ir = frameRect.toRect();
3098 int arrowYOffset = 0;
3099 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3101 QStyleOption arrowOpt = *opt;
3103 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
3107 case CE_PushButtonLabel:
3108 if (
const QStyleOptionButton *b = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3109 QStyleOptionButton btn(*b);
3114 const bool isEnabled = btn.state & State_Enabled;
3115 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3116 const bool hasIcon = !btn.icon.isNull();
3117 const bool hasText = !btn.text.isEmpty();
3118 const bool isActive = btn.state & State_Active;
3119 const bool isPressed = btn.state & State_Sunken;
3121 const auto ct = cocoaControlType(&btn);
3123 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
3125 || (isActive && isEnabled
3126 && ((btn.state & State_On)
3127 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3128 || d->autoDefaultButton == btn.styleObject)))
3129 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3132 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3133 QCommonStyle::drawControl(ce, &btn, p);
3135 QRect freeContentRect = btn.rect;
3136 QRect textRect = itemTextRect(
3137 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3139 textRect.moveTo(11, textRect.top());
3143 int contentW = textRect.width();
3145 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3146 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3147 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3148 mode = QIcon::Active;
3150 QIcon::State state = QIcon::Off;
3151 if (btn.state & State_On)
3153 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3155 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3156 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3157 contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
3158 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3159 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3160 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3161 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3162 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3163 int newOffset = iconDestRect.x() + iconDestRect.width()
3164 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
3165 textRect.adjust(newOffset, 0, newOffset, 0);
3169 textRect = visualRect(btn.direction, freeContentRect, textRect);
3170 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3171 isEnabled, btn.text, QPalette::ButtonText);
3176 case CE_ComboBoxLabel:
3177 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3178 auto comboCopy = *cb;
3179 comboCopy.direction = Qt::LeftToRight;
3181 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
3184 case CE_TabBarTabShape:
3185 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3186 if (tabOpt->documentMode) {
3188 bool isUnified =
false;
3195 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3196 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3202 const bool isActive = tabOpt->state & State_Active;
3203 const bool isEnabled = tabOpt->state & State_Enabled;
3204 const bool isPressed = tabOpt->state & State_Sunken;
3205 const bool isSelected = tabOpt->state & State_Selected;
3206 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3207 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3208 || tabDirection == QMacStylePrivate::West;
3210 QStyleOptionTab::TabPosition tp = tabOpt->position;
3211 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3212 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3213 if (tp == QStyleOptionTab::Beginning)
3214 tp = QStyleOptionTab::End;
3215 else if (tp == QStyleOptionTab::End)
3216 tp = QStyleOptionTab::Beginning;
3218 if (sp == QStyleOptionTab::NextIsSelected)
3219 sp = QStyleOptionTab::PreviousIsSelected;
3220 else if (sp == QStyleOptionTab::PreviousIsSelected)
3221 sp = QStyleOptionTab::NextIsSelected;
3236 const auto cs = d->effectiveAquaSizeConstrain(opt);
3238 const bool needsInactiveHack = (!isActive && isSelected);
3239 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3240 QMacStylePrivate::Button_PushButton :
3241 QMacStylePrivate::Button_PopupButton;
3242 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
3243 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3244 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3246 auto vOffset = isPopupButton ? 1 : 2;
3247 if (tabDirection == QMacStylePrivate::East)
3249 const auto outerAdjust = isPopupButton ? 1 : 4;
3250 const auto innerAdjust = isPopupButton ? 20 : 10;
3251 QRectF frameRect = tabOpt->rect;
3253 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3255 frameRect = frameRect.translated(0, vOffset);
3257 case QStyleOptionTab::Beginning:
3259 if (!isSelected && tabDirection == QMacStylePrivate::West)
3260 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3262 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3264 case QStyleOptionTab::Middle:
3265 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3267 case QStyleOptionTab::End:
3269 if (isSelected || tabDirection == QMacStylePrivate::West)
3270 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3272 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3274 case QStyleOptionTab::OnlyOneTab:
3275 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3278 pb.frame = frameRect.toCGRect();
3280 pb.enabled = isEnabled;
3281 [pb highlight:isPressed];
3283 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3285 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3286 QMacAutoReleasePool pool;
3287 CGContextClipToRect(ctx, opt->rect.toCGRect());
3288 if (!isSelected || needsInactiveHack) {
3290 if (!verticalTabs && tp == QStyleOptionTab::End) {
3291 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3292 CGContextScaleCTM(ctx, -1, 1);
3293 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3294 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3295 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3296 CGContextScaleCTM(ctx, 1, -1);
3297 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3298 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3299 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3300 CGContextScaleCTM(ctx, 1, -1);
3301 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3307 if (tabDirection == QMacStylePrivate::West) {
3308 CGContextTranslateCTM(ctx, 0, frameRect.right());
3309 CGContextRotateCTM(ctx, -
M_PI_2);
3310 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3311 }
else if (tabDirection == QMacStylePrivate::East) {
3312 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3313 CGContextRotateCTM(ctx,
M_PI_2);
3318 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3319 NSPopUpButtonCell *pbCell = nil;
3320 if (isPopupButton) {
3321 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3322 oldPosition = pbCell.arrowPosition;
3323 pbCell.arrowPosition = NSPopUpNoArrow;
3326 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3329 pbCell.arrowPosition = oldPosition;
3332 if (needsInactiveHack) {
3334 const qreal pixelRatio = p->device()->devicePixelRatioF();
3335 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3336 tabPixmap.setDevicePixelRatio(pixelRatio);
3337 tabPixmap.fill(Qt::transparent);
3338 QPainter tabPainter(&tabPixmap);
3339 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3340 QMacAutoReleasePool pool;
3341 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3342 drawBezelBlock(ctx, r);
3347 const qreal inactiveGray = 0.898;
3348 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3349 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3350 for (
int l = 0; l < tabPixmap.height(); ++l) {
3351 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3352 for (
int i = 0; i < tabPixmap.width(); ++i) {
3353 if (qAlpha(line[i]) == 255) {
3354 line[i] = inactiveGrayRGB;
3355 }
else if (qAlpha(line[i]) > 128) {
3356 const int g = qRound(inactiveGray * qRed(line[i]));
3357 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3363 p->drawImage(opt->rect, tabPixmap);
3365 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3368 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3369 && tp != QStyleOptionTab::End
3370 && tp != QStyleOptionTab::OnlyOneTab) {
3371 static const QPen separatorPen(Qt::black, 1.0);
3373 p->setOpacity(isEnabled ? 0.105 : 0.06);
3374 p->setPen(separatorPen);
3375 if (tabDirection == QMacStylePrivate::West) {
3376 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3377 opt->rect.right() - 0.5, opt->rect.bottom()));
3378 }
else if (tabDirection == QMacStylePrivate::East) {
3379 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3380 opt->rect.right() - 0.5, opt->rect.bottom()));
3382 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3383 opt->rect.right(), opt->rect.bottom() - 0.5));
3389 case CE_TabBarTabLabel:
3390 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3391 QStyleOptionTab myTab = *tab;
3392 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3393 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3394 || tabDirection == QMacStylePrivate::West;
3401 const bool nonDefaultFont =
false;
3408 if (myTab.documentMode && isDarkMode()) {
3409 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3410 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3413 int heightOffset = 0;
3416 }
else if (nonDefaultFont) {
3417 if (p->fontMetrics().height() == myTab.rect.height())
3420 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3422 QCommonStyle::drawControl(ce, &myTab, p);
3425 case CE_DockWidgetTitle:
3426 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
3427 const bool isVertical = dwOpt->verticalTitleBar;
3428 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3431 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3433 p->translate(-effectiveRect.left(), -effectiveRect.top());
3437 p->fillRect(effectiveRect, opt->palette.window());
3440 p->setPen(opt->palette.dark().color());
3441 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3443 if (!dwOpt->title.isEmpty()) {
3444 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3446 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3447 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3451 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3452 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3453 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3458 case CE_FocusFrame: {
3481 case CE_MenuEmptyArea:
3485 case CE_MenuHMargin:
3486 case CE_MenuVMargin:
3487 case CE_MenuTearoff:
3488 case CE_MenuScroller:
3489 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3490 const bool active = mi->state & State_Selected;
3492 p->fillRect(mi->rect, mi->palette.highlight());
3494 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3496 if (ce == CE_MenuTearoff) {
3497 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3498 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3499 mi->rect.x() + mi->rect.width() - 4,
3500 mi->rect.y() + mi->rect.height() / 2 - 1);
3501 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3502 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3503 mi->rect.x() + mi->rect.width() - 4,
3504 mi->rect.y() + mi->rect.height() / 2);
3505 }
else if (ce == CE_MenuScroller) {
3506 const QSize scrollerSize = QSize(10, 8);
3507 const int scrollerVOffset = 5;
3508 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3509 const int right = left + scrollerSize.width();
3512 if (opt->state & State_DownArrow) {
3513 bottom = mi->rect.y() + scrollerVOffset;
3514 top = bottom + scrollerSize.height();
3516 bottom = mi->rect.bottom() - scrollerVOffset;
3517 top = bottom - scrollerSize.height();
3520 p->setRenderHint(QPainter::Antialiasing);
3522 path.moveTo(left, bottom);
3523 path.lineTo(right, bottom);
3524 path.lineTo((left + right) / 2, top);
3525 p->fillPath(path, opt->palette.buttonText());
3527 }
else if (ce != CE_MenuItem) {
3531 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3532 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3533 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3534 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3538 const int maxpmw = mi->maxIconWidth;
3539 const bool enabled = mi->state & State_Enabled;
3541 int xpos = mi->rect.x() + 18;
3542 int checkcol = maxpmw;
3544 p->setPen(mi->palette.text().color());
3546 p->setPen(mi->palette.highlightedText().color());
3548 p->setPen(mi->palette.buttonText().color());
3551 QStyleOption checkmarkOpt;
3554 const int mw = checkcol + macItemFrame;
3555 const int mh = mi->rect.height() + macItemFrame;
3556 const int xp = mi->rect.x() + macItemFrame;
3557 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3559 checkmarkOpt.state.setFlag(State_On, active);
3560 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3561 if (widgetSize == QStyleHelper::SizeMini)
3562 checkmarkOpt.state |= State_Mini;
3563 else if (widgetSize == QStyleHelper::SizeSmall)
3564 checkmarkOpt.state |= State_Small;
3567 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3568 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3570 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3572 if (!mi->icon.isNull()) {
3573 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
3576 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3577 QSize iconSize(smallIconSize, smallIconSize);
3583 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3584 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3585 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3586 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3587 QRect pmr(0, 0, pixw, pixh);
3588 pmr.moveCenter(cr.center());
3589 p->drawPixmap(pmr.topLeft(), pixmap);
3593 QString s = mi->text;
3594 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3595 | Qt::TextSingleLine | Qt::AlignAbsolute;
3596 int yPos = mi->rect.y();
3597 if (widgetSize == QStyleHelper::SizeMini)
3600 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3601 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3603 QString rightMarginText;
3605 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
3608 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
3609 if (tabIndex >= 0) {
3611 rightMarginText = s.mid(tabIndex + 1);
3612 s = s.left(tabIndex);
3616 if (!rightMarginText.isEmpty()) {
3618 int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
3620 xp -= macItemHMargin + macItemFrame + 3;
3621 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3625 const int xm = macItemFrame + maxpmw + macItemHMargin;
3626 QFont myFont = mi->font;
3632 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3637 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3638 Q_ASSERT(fontEngine);
3639 if (fontEngine->type() == QFontEngine::Multi) {
3640 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
3641 Q_ASSERT(fontEngine);
3643 if (fontEngine->type() == QFontEngine::Mac) {
3644 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3647 const auto pc = p->pen().color();
3648 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3653 s = qt_mac_removeMnemonics(s);
3655 QMacCGContext cgCtx(p);
3656 d->setupNSGraphicsContext(cgCtx, YES);
3662 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3663 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3664 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3666 d->restoreNSGraphicsContext(cgCtx);
3669 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3670 mi->rect.height(), text_flags, s);
3676 case CE_MenuBarItem:
3677 case CE_MenuBarEmptyArea:
3678 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3679 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3680 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3681 p->fillRect(mi->rect, bg);
3683 if (ce != CE_MenuBarItem)
3686 if (!mi->icon.isNull()) {
3687 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3688 drawItemPixmap(p, mi->rect,
3689 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3690 | Qt::TextSingleLine,
3691 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3692 opt->window->devicePixelRatio(),
3693 (mi->state & State_Enabled) ? QIcon::Normal
3694 : QIcon::Disabled));
3696 drawItemText(p, mi->rect,
3697 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3698 | Qt::TextSingleLine,
3699 mi->palette, mi->state & State_Enabled,
3700 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3704 case CE_ProgressBarLabel:
3705 case CE_ProgressBarContents:
3707 case CE_ProgressBarGroove:
3708 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
3709 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3710 const bool inverted = pb->invertedAppearance;
3711 bool reverse = pb->direction == Qt::RightToLeft;
3715 QRect rect = pb->rect;
3716 const CGRect cgRect = rect.toCGRect();
3718 const auto aquaSize = d->aquaSizeConstrain(opt);
3721 QIndeterminateProgressIndicator *ipi = nil;
3723 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3724 if (isIndeterminate) {
3743 d->setupNSGraphicsContext(cg, NO);
3744 d->setupVerticalInvertedXform(cg, reverse,
false, cgRect);
3745 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3746 d->restoreNSGraphicsContext(cg);
3753 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
3754 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3755 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3756 QMacAutoReleasePool pool;
3757 d->setupVerticalInvertedXform(ctx, reverse,
false, rect);
3758 pi.minValue = pb->minimum;
3759 pi.maxValue = pb->maximum;
3760 pi.doubleValue = pb->progress;
3799 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3800 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3802 const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
3803 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
3804 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
3805 sv.frame = opt->rect.toCGRect();
3806 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3807 QMacAutoReleasePool pool;
3808 [sv drawDividerInRect:rect];
3811 QPen oldPen = p->pen();
3812 p->setPen(opt->palette.dark().color());
3813 if (opt->state & QStyle::State_Horizontal)
3814 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3816 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3821 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
3822 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
3823 if (!rubber->opaque) {
3826 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3827 fillColor.setHsvF(0, 0, 0.53, 0.25);
3828 if (opt->rect.width() * opt->rect.height() <= 3) {
3829 p->fillRect(opt->rect, strokeColor);
3831 QPen oldPen = p->pen();
3832 QBrush oldBrush = p->brush();
3833 QPen pen(strokeColor);
3835 p->setBrush(fillColor);
3836 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3837 if (adjusted.isValid())
3838 p->drawRect(adjusted);
3840 p->setBrush(oldBrush);
3843 p->fillRect(opt->rect, fillColor);
3848 const bool isDarkMode = QT_PREPEND_NAMESPACE(
QQC2_NAMESPACE::isDarkMode());
3882 QLinearGradient linearGrad;
3883 if (opt->state & State_Horizontal)
3884 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3886 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3888 QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
3889 QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
3891 linearGrad.setColorAt(0, mainWindowGradientBegin);
3892 linearGrad.setColorAt(1, mainWindowGradientEnd);
3893 p->fillRect(opt->rect, linearGrad);
3896 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3897 if (opt->state & State_Horizontal) {
3898 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3899 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3900 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3901 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3903 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3904 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3905 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3906 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3912 QCommonStyle::drawControl(ce, opt, p);
3919 if (dir == Qt::RightToLeft) {
3920 rect->adjust(-right, top, -left, bottom);
3922 rect->adjust(left, top, right, bottom);
3926QRect QMacStyle::subElementRect(SubElement sr,
const QStyleOption *opt)
const
3928 Q_D(
const QMacStyle);
3930 const int controlSize = getControlSize(opt);
3933 case SE_ItemViewItemText:
3934 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
3935 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
3937 rect = QCommonStyle::subElementRect(sr, opt);
3938 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3939 rect.adjust(-fw, 0, 0, 0);
3942 case SE_ToolBoxTabContents:
3943 rect = QCommonStyle::subElementRect(sr, opt);
3945 case SE_PushButtonContents:
3946 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3955 const auto ct = cocoaControlType(btn);
3956 const auto cs = d->effectiveAquaSizeConstrain(btn);
3957 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3958 auto frameRect = cw.adjustedControlFrame(btn->rect);
3959 frameRect -= cw.titleMargins();
3960 rect = frameRect.toRect();
3963 case SE_HeaderLabel: {
3964 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3965 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3966 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3967 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3969 if (header->sortIndicator != QStyleOptionHeader::None) {
3970 if (opt->state & State_Horizontal)
3971 rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
3973 rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
3976 rect = visualRect(opt->direction, opt->rect, rect);
3979 case SE_HeaderArrow: {
3980 int h = opt->rect.height();
3981 int w = opt->rect.width();
3982 int x = opt->rect.x();
3983 int y = opt->rect.y();
3984 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3986 if (opt->state & State_Horizontal) {
3987 rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
3988 headerSectionArrowHeight, h - margin * 2 - 5);
3990 rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
3991 w - margin * 2 - 5, headerSectionArrowHeight);
3993 rect = visualRect(opt->direction, opt->rect, rect);
3996 case SE_ProgressBarGroove:
4000 case SE_ProgressBarLabel:
4002 case SE_ProgressBarContents:
4005 case SE_TreeViewDisclosureItem: {
4008 rect.setLeft(rect.left() + 2 + DisclosureOffset);
4011 case SE_TabWidgetLeftCorner:
4012 if (
const QStyleOptionTabWidgetFrame *twf
4013 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4014 switch (twf->shape) {
4015 case QStyleOptionTab::RoundedNorth:
4016 case QStyleOptionTab::TriangularNorth:
4017 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4019 case QStyleOptionTab::RoundedSouth:
4020 case QStyleOptionTab::TriangularSouth:
4021 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4022 twf->leftCornerWidgetSize);
4027 rect = visualRect(twf->direction, twf->rect, rect);
4030 case SE_TabWidgetRightCorner:
4031 if (
const QStyleOptionTabWidgetFrame *twf
4032 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4033 switch (twf->shape) {
4034 case QStyleOptionTab::RoundedNorth:
4035 case QStyleOptionTab::TriangularNorth:
4036 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4037 twf->rightCornerWidgetSize);
4039 case QStyleOptionTab::RoundedSouth:
4040 case QStyleOptionTab::TriangularSouth:
4041 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4042 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4043 twf->rightCornerWidgetSize);
4048 rect = visualRect(twf->direction, twf->rect, rect);
4051 case SE_TabWidgetTabContents:
4052 rect = QCommonStyle::subElementRect(sr, opt);
4053 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4054 if (twf->lineWidth != 0) {
4055 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4056 case QMacStylePrivate::North:
4057 rect.adjust(+1, +14, -1, -1);
4059 case QMacStylePrivate::South:
4060 rect.adjust(+1, +1, -1, -14);
4062 case QMacStylePrivate::West:
4063 rect.adjust(+14, +1, -1, -1);
4065 case QMacStylePrivate::East:
4066 rect.adjust(+1, +1, -14, -1);
4071 case SE_TabBarTabText:
4072 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4073 QRect dummyIconRect;
4074 d->tabLayout(tab, &rect, &dummyIconRect);
4077 case SE_TabBarTabLeftButton:
4078 case SE_TabBarTabRightButton:
4079 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4080 bool selected = tab->state & State_Selected;
4081 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4082 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4085 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4086 || tab->shape == QStyleOptionTab::RoundedWest
4087 || tab->shape == QStyleOptionTab::TriangularEast
4088 || tab->shape == QStyleOptionTab::TriangularWest;
4090 QRect tr = tab->rect;
4091 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4092 verticalShift = -verticalShift;
4094 qSwap(horizontalShift, verticalShift);
4095 horizontalShift *= -1;
4096 verticalShift *= -1;
4098 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4099 horizontalShift = -horizontalShift;
4101 tr.adjust(0, 0, horizontalShift, verticalShift);
4104 tr.setBottom(tr.bottom() - verticalShift);
4105 tr.setRight(tr.right() - horizontalShift);
4108 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4109 int w = size.width();
4110 int h = size.height();
4111 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4112 int midWidth = ((tr.width() - w) / 2);
4114 bool atTheTop =
true;
4115 switch (tab->shape) {
4116 case QStyleOptionTab::RoundedWest:
4117 case QStyleOptionTab::TriangularWest:
4118 atTheTop = (sr == SE_TabBarTabLeftButton);
4120 case QStyleOptionTab::RoundedEast:
4121 case QStyleOptionTab::TriangularEast:
4122 atTheTop = (sr == SE_TabBarTabRightButton);
4125 if (sr == SE_TabBarTabLeftButton)
4126 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4128 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4129 rect = visualRect(tab->direction, tab->rect, rect);
4133 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4135 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4139 case SE_LineEditContents: {
4141 int leftPadding = 4;
4142 int rightPadding = 4;
4144 int bottomPadding = 0;
4146 if (opt->state & QStyle::State_Small) {
4148 }
else if (opt->state & QStyle::State_Mini) {
4152 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4153 opt->rect.height() - topPadding - bottomPadding);
4155 case SE_CheckBoxLayoutItem:
4157 if (controlSize == QStyleHelper::SizeLarge) {
4158 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4159 }
else if (controlSize == QStyleHelper::SizeSmall) {
4160 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4162 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4165 case SE_SearchFieldLayoutItem:
4166 if (qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4167 if (qt_apple_runningWithLiquidGlass()) {
4169 opt->rect.adjusted(2, 4, -2, -4),
4170 opt->rect.adjusted(2, 3, -2, -2),
4171 opt->rect.adjusted(2, 3, -2, -2));
4174 opt->rect.adjusted(2, 6, -2, -6),
4175 opt->rect.adjusted(2, 3, -2, -2),
4176 opt->rect.adjusted(2, 3, -2, -2));
4180 case SE_ComboBoxLayoutItem:
4181 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4190 if (combo->editable) {
4191 if (qt_apple_runningWithLiquidGlass()) {
4193 opt->rect.adjusted(4, 4, -4, -4),
4194 opt->rect.adjusted(4, 4, -5, -7),
4195 opt->rect.adjusted(5, 4, -4, -6));
4198 opt->rect.adjusted(5, 6, -6, -7),
4199 opt->rect.adjusted(4, 4, -5, -7),
4200 opt->rect.adjusted(5, 4, -4, -6));
4203 if (qt_apple_runningWithLiquidGlass()) {
4205 opt->rect.adjusted(4, 4, -4, -4),
4206 opt->rect.adjusted(6, 7, -6, -5),
4207 opt->rect.adjusted(9, 5, -5, -7));
4210 opt->rect.adjusted(6, 4, -7, -7),
4211 opt->rect.adjusted(6, 7, -6, -5),
4212 opt->rect.adjusted(9, 5, -5, -7));
4217 case SE_LabelLayoutItem:
4219 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4221 case SE_ProgressBarLayoutItem:
4222 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4223 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4226 if (isIndeterminate) {
4227 rect.adjust(1, 2, -1, -2);
4229 rect.adjust(1, 1, -1, -2);
4233 case SE_PushButtonLayoutItem:
4235 if (
const QStyleOptionButton *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4236 if ((buttonOpt->features & QStyleOptionButton::Flat))
4239 if (qt_apple_runningWithLiquidGlass()) {
4241 opt->rect.adjusted(2, 5, -2, -7),
4242 opt->rect.adjusted(6, 6, -6, -6),
4243 opt->rect.adjusted(6, 5, -6, -6));
4246 opt->rect.adjusted(7, 5, -7, -7),
4247 opt->rect.adjusted(6, 6, -6, -6),
4248 opt->rect.adjusted(6, 5, -6, -6));
4251 case SE_SpinBoxLayoutItem:
4253 opt->rect.adjusted(2, 3, -2, -2),
4254 opt->rect.adjusted(2, 3, -2, -2),
4255 opt->rect.adjusted(2, 3, -2, -2));
4257 case SE_RadioButtonLayoutItem:
4259 opt->rect.adjusted(2, 2, -3, -2),
4260 opt->rect.adjusted(2, 2, -3, -2),
4261 opt->rect.adjusted(1, 2, -3, -2));
4263 case SE_SliderLayoutItem:
4264 if (
const QStyleOptionSlider *sliderOpt
4265 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4267 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4268 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4269 rect.adjust(3, 3, -3, -3);
4271 rect.adjust(3, 0, -3, 0);
4275 case SE_ScrollBarLayoutItem:
4276 if (qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4279 case SE_FrameLayoutItem:
4295 case SE_GroupBoxLayoutItem:
4297 if (
const QStyleOptionGroupBox *groupBoxOpt =
4298 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4300
4301
4302
4303
4304 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4305 | QStyle::SC_GroupBoxLabel)) {
4307 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4308 delta =
SIZE(8, 4, 4);
4310 delta =
SIZE(15, 12, 12);
4312 rect.setTop(rect.top() + delta);
4315 rect.setBottom(rect.bottom() - 1);
4317 case SE_TabWidgetLayoutItem:
4318 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4319 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4321
4322
4323
4324
4325 rect = tabWidgetOpt->rect;
4326 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4327 rect.setTop(rect.top() +
SIZE(6 , 3 , 2 ));
4330 case SE_DockWidgetCloseButton:
4331 case SE_DockWidgetFloatButton:
4332 case SE_DockWidgetTitleBarText:
4333 case SE_DockWidgetIcon: {
4334 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
4335 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
4336 QRect srect = opt->rect;
4338 const QStyleOptionDockWidget *dwOpt
4339 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4340 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4341 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4343 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4347 if (verticalTitleBar)
4348 srect = srect.transposed();
4351 int right = srect.right();
4352 int left = srect.left();
4356 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4357 opt).actualSize(QSize(iconSize, iconSize));
4358 sz += QSize(buttonMargin, buttonMargin);
4359 if (verticalTitleBar)
4360 sz = sz.transposed();
4361 closeRect = QRect(left,
4362 srect.center().y() - sz.height()/2,
4363 sz.width(), sz.height());
4364 left = closeRect.right() + 1;
4366 if (sr == SE_DockWidgetCloseButton) {
4373 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4374 opt).actualSize(QSize(iconSize, iconSize));
4375 sz += QSize(buttonMargin, buttonMargin);
4376 if (verticalTitleBar)
4377 sz = sz.transposed();
4378 floatRect = QRect(left,
4379 srect.center().y() - sz.height()/2,
4380 sz.width(), sz.height());
4381 left = floatRect.right() + 1;
4383 if (sr == SE_DockWidgetFloatButton) {
4403 if (sr == SE_DockWidgetIcon) {
4408 QRect textRect = QRect(left, srect.top(),
4409 right - left, srect.height());
4410 if (sr == SE_DockWidgetTitleBarText) {
4416 if (verticalTitleBar) {
4417 rect = QRect(srect.left() + rect.top() - srect.top(),
4418 srect.top() + srect.right() - rect.right(),
4419 rect.height(), rect.width());
4421 rect = visualRect(opt->direction, srect, rect);
4426 rect = QCommonStyle::subElementRect(sr, opt);
4432void QMacStylePrivate::drawToolbarButtonArrow(
const QStyleOption *opt, QPainter *p)
const
4434 Q_Q(
const QMacStyle);
4435 QStyleOption arrowOpt = *opt;
4436 arrowOpt.rect = QRect(opt->rect.right() - (toolButtonArrowSize + toolButtonArrowMargin),
4437 opt->rect.bottom() - (toolButtonArrowSize + toolButtonArrowMargin),
4438 toolButtonArrowSize,
4439 toolButtonArrowSize);
4440 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4443void QMacStylePrivate::setupNSGraphicsContext(CGContextRef cg,
bool flipped)
const
4445 CGContextSaveGState(cg);
4446 [NSGraphicsContext saveGraphicsState];
4448 [NSGraphicsContext setCurrentContext:
4449 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4452void QMacStylePrivate::restoreNSGraphicsContext(CGContextRef cg)
const
4454 [NSGraphicsContext restoreGraphicsState];
4455 CGContextRestoreGState(cg);
4458void QMacStyle::drawComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt, QPainter *p)
const
4460 Q_D(
const QMacStyle);
4462 QMacCGContext cg(p);
4463 d->resolveCurrentNSView(opt->window);
4467 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4469 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4470 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4471 if (!drawTrack && !drawKnob)
4474 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4476 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
4477 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4479 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4480 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4482 const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
4485 bool wasActive =
false;
4486 CGFloat opacity = 0.0;
4487 CGFloat expandScale = 1.0;
4488 CGFloat expandOffset = 0.0;
4489 bool shouldExpand =
false;
4491 if (QObject *styleObject = opt->styleObject) {
4492 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
4493 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
4494 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
4495 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
4496 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
4497 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
4501 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4504 oldPos != sb->sliderPosition ||
4505 oldMin != sb->minimum ||
4506 oldMax != sb->maximum ||
4507 oldRect != sb->rect ||
4508 oldState != sb->state ||
4509 oldActiveControls != sb->activeSubControls) {
4515 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
4516 styleObject->setProperty(
"_q_stylemin", sb->minimum);
4517 styleObject->setProperty(
"_q_stylemax", sb->maximum);
4518 styleObject->setProperty(
"_q_stylerect", sb->rect);
4519 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
4520 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
4548 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4566 d->setupNSGraphicsContext(cg, NO );
4568 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
4569 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
4570 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
4572 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
4573 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4577 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4579 scroller.knobStyle = NSScrollerKnobStyleDefault;
4582 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4584 if (!setupScroller(scroller, sb))
4588 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
4589 CGContextSetAlpha(cg, opacity);
4594 if (!isTransient || opt->activeSubControls || wasActive) {
4595 CGRect trackRect = scroller.bounds;
4597 trackRect.origin.y += expandOffset;
4599 trackRect.origin.x += expandOffset;
4600 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4610 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4611 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4613 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4614 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4615 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4616 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4617 const CGFloat knobRadius = knobWidth / 2.0;
4620 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4622 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4623 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
4624 CGContextAddPath(cg, knobPath);
4625 CGContextSetAlpha(cg, 0.5);
4626 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4627 CGContextSetFillColorWithColor(cg, knobColor);
4628 CGContextFillPath(cg);
4630 [scroller drawKnob];
4632 if (!isTransient && opt->state & State_Sunken) {
4637 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4638 [scroller drawKnob];
4644 CGContextEndTransparencyLayer(cg);
4646 d->restoreNSGraphicsContext(cg);
4650 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4651 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4652 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
4653 const auto cs = d->effectiveAquaSizeConstrain(opt);
4654 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4655 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
4656 if (!setupSlider(slider, sl))
4659 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4660 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4661 const bool drawKnob = sl->subControls & SC_SliderHandle;
4662 const bool drawBar = sl->subControls & SC_SliderGroove;
4663 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4664 const bool isPressed = sl->state & State_Sunken;
4667 if (isPressed && drawKnob) {
4668 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4669 pressPoint.x = CGRectGetMidX(knobRect);
4670 pressPoint.y = CGRectGetMidY(knobRect);
4671 [slider.cell startTrackingAt:pressPoint inView:slider];
4674 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef,
const CGRect &) {
4677 NSSliderCell *cell = slider.cell;
4680 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4686 [cell drawBarInside:barRect flipped:!isHorizontal];
4689 if (drawBar && hasTicks && drawTicks) {
4690 if (!hasDoubleTicks) {
4691 [cell drawTickMarks];
4693 if (sl->orientation == Qt::Horizontal) {
4694 slider.tickMarkPosition = NSTickMarkPositionAbove;
4695 [slider layoutSubtreeIfNeeded];
4696 [cell drawTickMarks];
4697 slider.tickMarkPosition = NSTickMarkPositionBelow;
4698 [slider layoutSubtreeIfNeeded];
4699 [cell drawTickMarks];
4701 slider.tickMarkPosition = NSTickMarkPositionLeading;
4702 [slider layoutSubtreeIfNeeded];
4703 [cell drawTickMarks];
4704 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4705 [slider layoutSubtreeIfNeeded];
4706 [cell drawTickMarks];
4715 if (isPressed && drawKnob)
4716 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4720 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
4721 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4722 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4723 QStyleOptionFrame frame;
4724 static_cast<QStyleOption &>(frame) = *opt;
4725 frame.rect = lineEditRect;
4726 frame.state |= State_Sunken;
4727 frame.lineWidth = 1;
4728 frame.midLineWidth = 0;
4729 frame.features = QStyleOptionFrame::None;
4730 frame.frameShape = QStyleOptionFrame::Box;
4731 drawPrimitive(PE_FrameLineEdit, &frame, p);
4733 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4734 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4735 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
4737 d->setupNSGraphicsContext(cg, NO);
4739 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4740 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
4741 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
4742 cell.enabled = (sb->state & State_Enabled);
4743 const auto controlSize = cell.controlSize;
4744 if (qt_apple_runningWithLiquidGlass())
4745 cell.controlSize = NSControlSizeMini;
4747 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4749 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4750 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4751 const CGFloat x = CGRectGetMidX(newRect);
4752 const CGFloat y = upPressed ? -3 : 3;
4753 const CGPoint pressPoint = CGPointMake(x, y);
4756 if (upPressed || downPressed)
4757 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4759 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4761 if (upPressed || downPressed)
4762 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4764 d->restoreNSGraphicsContext(cg);
4765 if (qt_apple_runningWithLiquidGlass())
4766 cell.controlSize = controlSize;
4771 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4772 const bool isEnabled = combo->state & State_Enabled;
4773 const bool isPressed = combo->state & State_Sunken;
4775 const auto ct = cocoaControlType(combo);
4776 const auto cs = d->effectiveAquaSizeConstrain(combo);
4777 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4778 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4779 cc.enabled = isEnabled;
4780 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4781 if (cw.type == QMacStylePrivate::Button_PopupButton) {
4783 auto *pb =
static_cast<NSPopUpButton *>(cc);
4785 if (cw.size == QStyleHelper::SizeSmall) {
4786 frameRect = frameRect.translated(0, 1);
4787 }
else if (cw.size == QStyleHelper::SizeMini) {
4789 frameRect = frameRect.translated(2, -0.5);
4791 pb.frame = frameRect.toCGRect();
4792 [pb highlight:isPressed];
4793 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4794 QMacAutoReleasePool pool;
4795 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4797 }
else if (cw.type == QMacStylePrivate::ComboBox) {
4799 auto *cb =
static_cast<NSComboBox *>(cc);
4800 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4801 cb.frame = frameRect.toCGRect();
4804 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4805 cell.highlighted = isPressed;
4810 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4812 QMacAutoReleasePool pool;
4813 [cb.cell drawWithFrame:r inView:cb];
4818 case CC_SearchField:
4819 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4820 const bool isEnabled = sf->state & State_Enabled;
4822 const auto cs = d->effectiveAquaSizeConstrain(sf);
4823 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
4824 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4825 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4827 searchField.enabled = isEnabled;
4834 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4835 if (
__builtin_available(macOS 26, *)) {
4836 NSButtonCell *btn = cell.searchButtonCell;
4837 NSImageSymbolConfiguration *imgCfg =
4838 [NSImageSymbolConfiguration configurationWithPointSize:11
4839 weight:NSFontWeightMedium
4840 scale:NSImageSymbolScaleMedium];
4841 btn.image = [btn.image imageWithSymbolConfiguration:imgCfg];
4842 [btn.image setTemplate:YES];
4843 btn.imageScaling = NSImageScaleNone;
4847 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4849 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4850 if (
__builtin_available(macOS 26, *)) {
4851 const auto oneDevicePx = 1.0 / p->device()->devicePixelRatioF();
4852 frameRect = frameRect.adjusted(+oneDevicePx, -oneDevicePx, -oneDevicePx, +oneDevicePx);
4856 searchField.frame = frameRect.toCGRect();
4858 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4860 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4861 [cell drawWithFrame:rect inView:searchField];
4862 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4864 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4865 [cell drawWithFrame:rect inView:searchField];
4868 [cell setStringValue:sf->text.toNSString()];
4869 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4870 [cell drawWithFrame:r inView:searchField];
4876 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4877 const bool isActive = (titlebar->state & State_Active)
4878 && (titlebar->titleBarState & State_Active);
4880 p->fillRect(opt->rect, Qt::transparent);
4881 p->setRenderHint(QPainter::Antialiasing);
4882 p->setClipRect(opt->rect, Qt::IntersectClip);
4886 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4887 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4888 p->fillPath(outerFramePath, opt->palette.dark());
4890 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4891 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4892 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4893 p->fillPath(innerFramePath, opt->palette.button());
4895 if (titlebar->subControls & (SC_TitleBarCloseButton
4896 | SC_TitleBarMaxButton
4897 | SC_TitleBarMinButton
4898 | SC_TitleBarNormalButton)) {
4899 const bool isHovered = (titlebar->state & State_MouseOver);
4900 static const SubControl buttons[] = {
4901 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4903 for (
const auto sc : buttons) {
4904 const auto ct = d->windowButtonCocoaControl(sc);
4905 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4906 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4907 wb.enabled = (sc & titlebar->subControls) && isActive;
4908 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4909 Q_UNUSED(isHovered);
4911 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4912 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4913 QMacAutoReleasePool pool;
4914 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4915 [wbCell drawWithFrame:rect inView:wb];
4920 if (titlebar->subControls & SC_TitleBarLabel) {
4921 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4922 if (!titlebar->icon.isNull()) {
4923 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4924 const auto iconSize = QSize(iconExtent, iconExtent);
4925 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4927 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4928 p->drawPixmap(iconPos, tr.y(),
4929 titlebar->icon.pixmap(iconSize,
4930 opt->window->devicePixelRatio(),
4934 if (!titlebar->text.isEmpty())
4935 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4940 if (
const QStyleOptionGroupBox *gb
4941 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4943 QStyleOptionGroupBox groupBox(*gb);
4944 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4946 groupBox.state |= QStyle::State_Mini;
4948 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4954 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4969 if (
const QStyleOptionToolButton *tb
4970 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4971#ifndef QT_NO_ACCESSIBILITY
4972 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4973 if (tb->subControls & SC_ToolButtonMenu) {
4974 QStyleOption arrowOpt = *tb;
4975 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4976 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4977 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4978 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4979 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4980 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4981 d->drawToolbarButtonArrow(tb, p);
4983 if (tb->state & State_On) {
4984 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4987 isKey = [view.window isKeyWindow];
4989 QBrush brush(brushForToolButton(isKey));
4991 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4992 p->setRenderHint(QPainter::Antialiasing);
4993 p->fillPath(path, brush);
4995 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4999 auto bflags = tb->state;
5000 if (tb->subControls & SC_ToolButton)
5001 bflags |= State_Sunken;
5002 auto mflags = tb->state;
5003 if (tb->subControls & SC_ToolButtonMenu)
5004 mflags |= State_Sunken;
5006 if (tb->subControls & SC_ToolButton) {
5007 if (bflags & (State_Sunken | State_On | State_Raised)) {
5008 const bool isEnabled = tb->state & State_Enabled;
5009 const bool isPressed = tb->state & State_Sunken;
5010 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5011 const auto ct = QMacStylePrivate::Button_PushButton;
5012 const auto cs = d->effectiveAquaSizeConstrain(opt);
5013 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5014 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5015 pb.bezelStyle = NSBezelStyleShadowlessSquare;
5016 pb.frame = opt->rect.toCGRect();
5017 pb.buttonType = NSButtonTypePushOnPushOff;
5018 pb.enabled = isEnabled;
5019 [pb highlight:isPressed];
5020 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5021 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
5022 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5023 QMacAutoReleasePool pool;
5024 [pb.cell drawBezelWithFrame:rect inView:pb];
5029 if (tb->subControls & SC_ToolButtonMenu) {
5030 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
5031 QStyleOption arrowOpt = *tb;
5032 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
5033 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
5034 toolButtonArrowSize,
5035 toolButtonArrowSize);
5036 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
5037 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
5038 d->drawToolbarButtonArrow(tb, p);
5040 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
5041 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
5042 QStyleOptionToolButton label = *tb;
5043 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5044 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
5049 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
5050 QStyleHelper::drawDial(dial, p);
5053 QCommonStyle::drawComplexControl(cc, opt, p);
5058QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt,
const QPoint &pt)
const
5060 Q_D(
const QMacStyle);
5062 SubControl sc = QStyle::SC_None;
5066 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5067 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5068 if (!cmb->editable && sc != QStyle::SC_None)
5069 sc = SC_ComboBoxArrow;
5073 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5074 if (!sl->rect.contains(pt))
5077 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5078 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5079 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5080 const auto cs = d->effectiveAquaSizeConstrain(opt);
5081 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5082 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5083 if (!setupSlider(slider, sl))
5086 NSSliderCell *cell = slider.cell;
5087 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5088 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5089 if (knobRect.contains(pt)) {
5090 sc = SC_SliderHandle;
5091 }
else if (barRect.contains(pt)) {
5092 sc = SC_SliderGroove;
5093 }
else if (hasTicks) {
5094 sc = SC_SliderTickmarks;
5099 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5100 if (!sb->rect.contains(pt)) {
5105 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5106 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5107 const auto cs = d->effectiveAquaSizeConstrain(opt);
5108 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5109 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5110 if (!setupScroller(scroller, sb)) {
5118 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5120 const bool isReverse = sb->direction == Qt::RightToLeft;
5121 if (pt.x() < knobRect.left())
5122 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5123 else if (pt.x() > knobRect.right())
5124 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5126 sc = SC_ScrollBarSlider;
5128 if (pt.y() < knobRect.top())
5129 sc = SC_ScrollBarSubPage;
5130 else if (pt.y() > knobRect.bottom())
5131 sc = SC_ScrollBarAddPage;
5133 sc = SC_ScrollBarSlider;
5137 case CC_SearchField:
5138 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5139 if (!sf->rect.contains(pt))
5142 const auto cs = d->effectiveAquaSizeConstrain(sf);
5143 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5144 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5145 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5147 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5148 const CGRect bounds = searchField.bounds;
5150 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5151 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5152 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5154 const QPointF localPt = pt - sf->rect.topLeft();
5156 if (cancelRect.contains(localPt))
5157 sc = SC_SearchFieldClear;
5158 else if (searchIconRect.contains(localPt))
5159 sc = SC_SearchFieldSearch;
5160 else if (textFieldRect.contains(localPt))
5161 sc = SC_SearchFieldEditField;
5163 sc = SC_SearchFieldPopup;
5169 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5175QRect QMacStyle::subControlRect(ComplexControl cc,
const QStyleOptionComplex *opt, SubControl sc)
const
5177 Q_D(
const QMacStyle);
5183 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5184 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5185 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5187 NSScrollerPart part = NSScrollerNoPart;
5188 if (sc == SC_ScrollBarSlider) {
5189 part = NSScrollerKnob;
5190 }
else if (sc == SC_ScrollBarGroove) {
5191 part = NSScrollerKnobSlot;
5192 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5193 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5194 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5195 part = NSScrollerDecrementPage;
5197 part = NSScrollerIncrementPage;
5201 if (part != NSScrollerNoPart) {
5202 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5203 const auto cs = d->effectiveAquaSizeConstrain(opt);
5204 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5205 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5206 if (setupScroller(scroller, sb))
5207 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5212 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5213 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5214 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5215 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5216 const auto cs = d->effectiveAquaSizeConstrain(opt);
5217 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5218 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5219 if (!setupSlider(slider, sl))
5222 NSSliderCell *cell = slider.cell;
5223 if (sc == SC_SliderHandle) {
5224 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5225 }
else if (sc == SC_SliderGroove) {
5226 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5227 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5228 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5230 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5232 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5243 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5249 if (sc == SC_TitleBarLabel) {
5250 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5251 qreal labelHeight = titlebar->fontMetrics.height();
5253 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5254 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5255 if (!titlebar->icon.isNull()) {
5256 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5257 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5258 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5261 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5262 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5263 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5264 labelWidth, labelHeight);
5266 const auto currentButton = d->windowButtonCocoaControl(sc);
5267 if (currentButton == QMacStylePrivate::NoControl)
5270 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5272 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5273 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5274 QStyleHelper::SizeLarge);
5275 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5276 if (ct == currentButton)
5277 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5279 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5282 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5283 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5288 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5289 const auto ct = cocoaControlType(combo);
5290 const auto cs = d->effectiveAquaSizeConstrain(combo);
5291 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5299 case QStyleHelper::SizeLarge:
5300 if (qt_apple_runningWithLiquidGlass())
5301 editRect = combo->rect.adjusted(15, 7, -25, -7);
5303 editRect = combo->rect.adjusted(15, 7, -25, -9);
5305 case QStyleHelper::SizeSmall:
5306 if (combo->editable)
5307 editRect = combo->rect.adjusted(15, 6, -22, -9);
5309 editRect = combo->rect.adjusted(15, 8, -22, -6);
5312 if (combo->editable)
5313 editRect = combo->rect.adjusted(15, 6, -20, -7);
5315 editRect = combo->rect.adjusted(15, 5, -22, -6);
5320 case SC_ComboBoxEditField:{
5321 ret = editRect.toAlignedRect();
5323 case SC_ComboBoxArrow:{
5324 ret = editRect.toAlignedRect();
5325 ret.setX(ret.x() + ret.width());
5326 ret.setWidth(combo->rect.right() - ret.right());
5328 case SC_ComboBoxListBoxPopup:{
5329 if (combo->editable) {
5330 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5331 const int comboTop = combo->rect.top();
5332 ret = QRect(qRound(inner.origin.x),
5334 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5335 editRect.bottom() - comboTop + 2);
5337 ret = QRect(combo->rect.x() + 4 - 11,
5338 combo->rect.y() + 1,
5339 editRect.width() + 10 + 11,
5349 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5350 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5351 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5352 bool hasNoText = !checkable && groupBox->text.isEmpty();
5354 case SC_GroupBoxLabel:
5355 case SC_GroupBoxCheckBox: {
5357 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5358 const bool fontIsSet =
false;
5361 const int margin = flat || hasNoText ? 0 : 9;
5362 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5364 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5365 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5366 const int tw = qCeil(s.width());
5367 const int h = qCeil(fm.height());
5370 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5372 if (flat && checkable)
5373 labelRect.moveLeft(labelRect.left() + 4);
5374 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5375 bool rtl = groupBox->direction == Qt::RightToLeft;
5376 if (sc == SC_GroupBoxLabel) {
5378 int newSum = indicatorWidth + 1;
5379 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5380 labelRect.moveLeft(newLeft);
5382 labelRect.moveTop(labelRect.top() + 3);
5384 labelRect.moveTop(labelRect.top() + 4);
5386 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5387 labelRect.moveLeft(newLeft);
5388 labelRect.moveTop(labelRect.top() + 3);
5390 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5391 labelRect.moveLeft(newLeft);
5392 labelRect.moveTop(labelRect.top() + 4);
5397 if (sc == SC_GroupBoxCheckBox) {
5398 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5399 int top = flat ? ret.top() + 1 : ret.top() + 5;
5400 ret.setRect(left, top,
5401 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5405 case SC_GroupBoxContents:
5406 case SC_GroupBoxFrame: {
5407 QFontMetrics fm = groupBox->fontMetrics;
5413 yOffset = -qCeil(QFontMetricsF(fm).height());
5414 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5415 if (sc == SC_GroupBoxContents) {
5417 ret.adjust(3, -5, -3, -4);
5419 ret.adjust(3, 3, -3, -4);
5424 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5430 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5431 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5432 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5438 case QStyleHelper::SizeLarge:
5444 case QStyleHelper::SizeSmall:
5450 case QStyleHelper::SizeMini:
5462 case SC_SpinBoxDown: {
5463 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5467 const int x = spin->rect.width() - spinner_w;
5468 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5470 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5471 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5472 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5473 ret = QRectF::fromCGRect(outRect).toRect();
5477 ret.setHeight(ret.height() / 2);
5479 case SC_SpinBoxDown:
5480 ret.setY(ret.y() + ret.height() / 2);
5488 ret.translate(0, adjust_y);
5489 ret = visualRect(spin->direction, spin->rect, ret);
5492 case SC_SpinBoxEditField:
5493 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5494 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5495 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5496 ret = visualRect(spin->direction, spin->rect, ret);
5500 ret = QCommonStyle::subControlRect(cc, spin, sc);
5506 ret = QCommonStyle::subControlRect(cc, opt, sc);
5507 if (sc == SC_ToolButtonMenu) {
5508#ifndef QT_NO_ACCESSIBILITY
5509 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5510 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
5512 ret.adjust(-1, 0, 0, 0);
5515 case CC_SearchField:
5516 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5517 const auto cs = d->effectiveAquaSizeConstrain(sf);
5518 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5522 case QStyleHelper::SizeLarge:
5523 editRect = sf->rect.adjusted(16, 0, -22, 0);
5525 case QStyleHelper::SizeSmall:
5526 editRect = sf->rect.adjusted(16, 5, -22, -7);
5529 editRect = sf->rect.adjusted(16, 5, -18, -7);
5533 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5534 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5535 const CGRect bounds = searchField.bounds;
5538 case SC_SearchFieldEditField:{
5539 ret = editRect.toAlignedRect();
5540 ret.setX(ret.x() + QMacStylePrivate::PushButtonContentPadding);
5543 case SC_SearchFieldClear: {
5544 const CGRect r = [cell cancelButtonRectForBounds:bounds];
5545 ret = QRectF::fromCGRect(r).toRect();
5546 ret.translate(0, -1);
5547 ret = visualRect(sf->direction, sf->rect, ret);
5548 ret.adjust(-3, -3, 3, 3);
5551 case SC_SearchFieldSearch: {
5552 const CGRect r = [cell searchButtonRectForBounds:bounds];
5553 ret = QRectF::fromCGRect(r).toRect();
5554 ret.translate(0, -1);
5555 ret = visualRect(sf->direction, sf->rect, ret);
5556 ret.adjust(-3, -3, 3, 3);
5559 case SC_SearchFieldPopup: {
5560 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5561 const int searchTop = sf->rect.top();
5562 ret = QRect(qRound(inner.origin.x),
5564 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5565 editRect.bottom() - searchTop + 2);
5574 ret = QCommonStyle::subControlRect(cc, opt, sc);
5580QSize QMacStyle::sizeFromContents(ContentsType ct,
const QStyleOption *opt,
const QSize &csz)
const
5582 Q_D(
const QMacStyle);
5585 bool useAquaGuideline =
true;
5589 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5590 if (vopt->subControls == SC_SpinBoxFrame) {
5591 const QSize minimumSize(20, 24);
5592 if (sz.width() < minimumSize.width())
5593 sz.setWidth(minimumSize.width());
5594 if (sz.height() < minimumSize.height())
5595 sz.setHeight(minimumSize.height());
5597 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5598 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5599 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5603 case QStyle::CT_TabWidget:
5606 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
5635
5636
5638 if (
const QStyleOptionTabWidgetFrame *twf
5639 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5641 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5642 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5644 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5645 if (tabDirection == QMacStylePrivate::North
5646 || tabDirection == QMacStylePrivate::South) {
5647 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5649 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5654 case QStyle::CT_TabBarTab:
5655 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5658 const bool differentFont =
false;
5659 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5660 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5661 || tabDirection == QMacStylePrivate::West;
5663 sz = sz.transposed();
5665 int defaultTabHeight;
5666 const auto cs = d->effectiveAquaSizeConstrain(opt);
5668 case QStyleHelper::SizeLarge:
5669 if (tab->documentMode)
5670 defaultTabHeight = 24;
5672 defaultTabHeight = 21;
5674 case QStyleHelper::SizeSmall:
5675 defaultTabHeight = 18;
5677 case QStyleHelper::SizeMini:
5678 defaultTabHeight = 16;
5684 const bool widthSet = !differentFont && tab->icon.isNull();
5686 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5687 sz.rwidth() = textSize.width();
5688 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5690 sz.rheight() = qMax(defaultTabHeight, sz.height());
5692 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5695 sz = sz.transposed();
5697 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5698 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5700 int widgetWidth = 0;
5701 int widgetHeight = 0;
5703 if (tab->leftButtonSize.isValid()) {
5705 widgetWidth += tab->leftButtonSize.width();
5706 widgetHeight += tab->leftButtonSize.height();
5708 if (tab->rightButtonSize.isValid()) {
5710 widgetWidth += tab->rightButtonSize.width();
5711 widgetHeight += tab->rightButtonSize.height();
5715 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5716 sz.setHeight(sz.height() + widgetHeight + padding);
5719 sz.setWidth(sz.width() + widgetWidth + padding);
5720 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5725 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5727 if (sz.width() < 10)
5729 if (sz.height() < 20)
5733 int leftPadding = 4;
5734 int rightPadding = 4;
5736 int bottomPadding = 0;
5738 if (opt->state & QStyle::State_Small) {
5740 }
else if (opt->state & QStyle::State_Mini) {
5744 sz.rwidth() += leftPadding + rightPadding;
5745 sz.rheight() += topPadding + bottomPadding;
5748 case QStyle::CT_PushButton: {
5749 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5750 if (btn->features & QStyleOptionButton::CommandLinkButton)
5751 return QCommonStyle::sizeFromContents(ct, opt, sz);
5758 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5760 if (macsz.width() != -1)
5761 sz.setWidth(macsz.width());
5763 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
5765 if (controlSize != QStyleHelper::SizeMini)
5767 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5768 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5769 else if (controlSize == QStyleHelper::SizeMini)
5772 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5775 case QStyle::CT_MenuItem:
5776 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5777 int maxpmw = mi->maxIconWidth;
5779 int h = sz.height();
5785 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5787 h = qt_mac_aqua_get_metric(MenuSeparatorHeight);
5789 h = mi->fontMetrics.height() + 2;
5790 if (!mi->icon.isNull()) {
5799 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5800 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5804 if (mi->text.contains(QLatin1Char(
'\t')))
5806 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5825 case CT_MenuBarItem:
5832 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5833 if (tb->features & QStyleOptionToolButton::Menu)
5834 sz.rwidth() += toolButtonArrowMargin;
5837 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5838 const int controlSize = getControlSize(opt);
5841 if (sz.width() < 10)
5844 if (!cb->editable) {
5847 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset;
5849 if (controlSize == QStyleHelper::SizeLarge) {
5851 }
else if (controlSize == QStyleHelper::SizeSmall) {
5861 if (controlSize == QStyleHelper::SizeMini)
5864 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5869 case CT_SearchField:
5870 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5871 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5872 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5873 if (sf->subControls == SC_SearchFieldFrame) {
5874 const int controlSize = getControlSize(opt);
5878 if (controlSize == QStyleHelper::SizeLarge) {
5882 }
else if (controlSize == QStyleHelper::SizeSmall) {
5893 if (sz.width() < 60)
5896 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5897 sz.rwidth() += totalIconsSize;
5900 }
else if (sf->subControls == SC_SearchFieldClear) {
5902 }
else if (sf->subControls == SC_SearchFieldSearch) {
5903 return searchButton;
5908 if (proxy() ==
this) {
5911 QStyleHintReturnMask menuMask;
5912 QStyleOption myOption = *opt;
5913 myOption.rect.setSize(sz);
5914 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5915 sz = menuMask.region.boundingRect().size();
5918 case CT_HeaderSection:{
5919 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5920 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5921 if (header->text.contains(QLatin1Char(
'\n')))
5922 useAquaGuideline =
false;
5926 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5927 const int minimumWidth = 24;
5928 const int absoluteHeight = 14;
5929 if (slider->orientation == Qt::Horizontal) {
5930 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5931 sz.setHeight(absoluteHeight);
5933 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5934 sz.setWidth(absoluteHeight);
5938 case CT_ItemViewItem:
5939 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5940 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5941 sz.setHeight(sz.height() + 2);
5945 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5948 if (useAquaGuideline && ct != CT_PushButton) {
5951 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5952 if (macsz.width() != -1)
5953 sz.setWidth(macsz.width());
5954 if (macsz.height() != -1)
5955 sz.setHeight(macsz.height());
5961 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5962 if (combo->editable) {
5963 const auto widgetSize = d->aquaSizeConstrain(opt);
5964 QMacStylePrivate::CocoaControl cw;
5965 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
5966 cw.size = widgetSize;
5967 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5968 sz.rwidth() -= qRound(diffRect.size.width);
5969 sz.rheight() -= qRound(diffRect.size.height);
5975QFont QMacStyle::font(QStyle::ControlElement element,
const QStyle::State state)
const
5977 QFont font = QCommonStyle::font(element, state);
5979 if (state & QStyle::State_Small) {
5980 font.setPixelSize(11);
5981 }
else if (state & QStyle::State_Mini) {
5982 font.setPixelSize(9);
5988QMargins QMacStyle::ninePatchMargins(QStyle::ComplexControl cc,
const QStyleOptionComplex *opt,
const QSize &imageSize)
const
5994 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5995 margins = QMargins(10, 0, arrow.width() + 1, -1);
5998 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
6005void QMacStyle::drawItemText(QPainter *p,
const QRect &r,
int flags,
const QPalette &pal,
6006 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
6008 if(flags & Qt::TextShowMnemonic)
6009 flags |= Qt::TextHideMnemonic;
6010 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6013QIcon QMacStyle::standardIcon(StandardPixmap standardIcon,
const QStyleOption *opt)
const
6015 switch (standardIcon) {
6017 return QCommonStyle::standardIcon(standardIcon, opt);
6018 case SP_ToolBarHorizontalExtensionButton:
6019 case SP_ToolBarVerticalExtensionButton: {
6020 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
6021 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6022 QPixmap pix2(pixmap.height(), pixmap.width());
6023 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
6024 pix2.fill(Qt::transparent);
6026 p.translate(pix2.width(), 0);
6028 p.drawPixmap(0, 0, pixmap);