192static bool isDarkMode() {
return qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; }
232#ifndef QT_NO_ACCESSIBILITY
239 return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
241 return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
269static bool setupScroller(NSScroller *scroller,
const QStyleOptionSlider *sb)
271 const qreal length = sb->maximum - sb->minimum + sb->pageStep;
272 if (qFuzzyIsNull(length))
274 const qreal proportion = sb->pageStep / length;
275 const qreal range = qreal(sb->maximum - sb->minimum);
276 qreal value = range ? qreal(sb->sliderValue - sb->minimum) / range : 0;
277 if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
280 scroller.frame = sb->rect.toCGRect();
281 scroller.floatValue = value;
282 scroller.knobProportion = proportion;
286static bool setupSlider(NSSlider *slider,
const QStyleOptionSlider *sl)
288 if (sl->minimum >= sl->maximum)
294 [slider initWithFrame:sl->rect.toCGRect()];
296 slider.minValue = sl->minimum;
297 slider.maxValue = sl->maximum;
298 slider.intValue = sl->sliderPosition;
299 slider.enabled = sl->state & QStyle::State_Enabled;
300 if (sl->tickPosition != QStyleOptionSlider::NoTicks) {
302 int interval = sl->tickInterval;
304 interval = sl->pageStep;
306 interval = sl->singleStep;
310 slider.numberOfTickMarks = 1 + ((sl->maximum - sl->minimum) / interval);
312 const bool ticksAbove = sl->tickPosition == QStyleOptionSlider::TicksAbove;
313 if (sl->orientation == Qt::Horizontal)
314 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
316 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
318 slider.numberOfTickMarks = 0;
323 [slider layoutSubtreeIfNeeded];
325 if (sl->state & QStyle::State_Sunken) {
326 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
328 pressPoint.x = CGRectGetMidX(knobRect);
329 pressPoint.y = CGRectGetMidY(knobRect);
330 [slider.cell startTrackingAt:pressPoint inView:slider];
338 const auto tabDirection = QMacStylePrivate::tabDirection(shape);
339 if (QMacStylePrivate::verticalTabs(tabDirection)) {
340 int newX, newY, newRot;
341 if (tabDirection == QMacStylePrivate::East) {
342 newX = tabRect.width();
347 newY = tabRect.y() + tabRect.height();
350 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
351 QTransform transform;
352 transform.translate(newX, newY);
353 transform.rotate(newRot);
354 p->setTransform(transform,
true);
359void drawTabShape(QPainter *p,
const QStyleOptionTab *tabOpt,
bool isUnified,
int tabOverlap)
361 QRect rect = tabOpt->rect;
362 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
363 rect = rect.adjusted(-tabOverlap, 0, 0, 0);
365 rect = rect.adjusted(0, -tabOverlap, 0, 0);
367 p->translate(rect.x(), rect.y());
370 const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
372 const int width = tabRect.width();
373 const int height = tabRect.height();
374 const bool active = (tabOpt->state & QStyle::State_Active);
375 const bool selected = (tabOpt->state & QStyle::State_Selected);
377 const QRect bodyRect(1, 2, width - 2, height - 3);
378 const QRect topLineRect(1, 0, width - 2, 1);
379 const QRect bottomLineRect(1, height - 1, width - 2, 1);
382 if (tabOpt->documentMode && isUnified) {
384 p->setCompositionMode(QPainter::CompositionMode_Source);
385 p->fillRect(tabRect, QColor(Qt::transparent));
388 p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
390 p->fillRect(topLineRect, tabBarTabLineSelected());
392 p->fillRect(bodyRect, tabBarTabBackgroundSelected());
396 const bool hover = (tabOpt->state & QStyle::State_MouseOver);
399 p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
401 p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
406 const QRect leftLineRect(0, 1, 1, height - 2);
407 const QRect rightLineRect(width - 1, 1, 1, height - 2);
408 const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
409 p->fillRect(leftLineRect, separatorLineColor);
410 p->fillRect(rightLineRect, separatorLineColor);
421 const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
422 const int width = tabRect.width();
423 const int height = tabRect.height();
424 const bool active = (tbb->state & QStyle::State_Active);
427 const QRect bodyRect(0, 1, width, height - 1);
428 const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
429 p->fillRect(bodyRect, bodyColor);
432 const QRect topLineRect(0, 0, width, 1);
433 const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
434 p->fillRect(topLineRect, topLineColor);
437 const QRect bottomLineRect(0, height - 1, width, 1);
438 bool isDocument =
false;
441 const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
442 p->fillRect(bottomLineRect, bottomLineColor);
447 const auto wsp = QStyleHelper::widgetSizePolicy(option);
448 if (wsp == QStyleHelper::SizeDefault)
449 return QStyleHelper::SizeLarge;
456 QString returnText(original.size(), QChar());
459 int l = original.length();
461 if (original.at(currPos) == QLatin1Char(
'&')) {
466 }
else if (original.at(currPos) == QLatin1Char(
'(') && l >= 4 &&
467 original.at(currPos + 1) == QLatin1Char(
'&') &&
468 original.at(currPos + 2) != QLatin1Char(
'&') &&
469 original.at(currPos + 3) == QLatin1Char(
')')) {
472 while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
479 returnText[finalDest] = original.at(currPos);
484 returnText.truncate(finalDest);
490 if (window->handle()) {
491 if (NSWindow *nswindow =
static_cast<NSWindow*>(
492 QGuiApplication::platformNativeInterface()->
493 nativeResourceForWindow(QByteArrayLiteral(
"nswindow"),
494 const_cast<QWindow *>(window)))) {
495 return [nswindow isMainWindow];
501#define LargeSmallMini(option, large, small, mini)
502 (option->state & QStyle::State_Small) ? small : ((option->state & QStyle::State_Mini) ? mini : large)
505
506
512
513
608 QSize szHint, QStyleHelper::WidgetSizePolicy sz)
611 if (sz != QStyleHelper::SizeSmall && sz != QStyleHelper::SizeLarge && sz != QStyleHelper::SizeMini) {
612 qDebug(
"Not sure how to return this...");
625 Q_ASSERT(ct != QStyle::CT_CustomBase);
672 case QStyle::CT_PushButton: {
675 QString buttonText = qt_mac_removeMnemonics(btn->text);
676 if (buttonText.contains(QLatin1Char(
'\n')))
678 else if (sz == QStyleHelper::SizeLarge)
680 else if (sz == QStyleHelper::SizeSmall)
682 else if (sz == QStyleHelper::SizeMini)
685 if (!btn->icon.isNull()){
689 if (ret.height() < btn->iconSize.height())
692 else if (buttonText == QLatin1String(
"OK") || buttonText == QLatin1String(
"Cancel")){
705 if (sz == QStyleHelper::SizeLarge)
707 else if (sz == QStyleHelper::SizeSmall)
709 else if (sz == QStyleHelper::SizeMini)
716 case QStyle::CT_SizeGrip:
718 if (sz == QStyleHelper::SizeLarge || sz == QStyleHelper::SizeSmall) {
719 int s = sz == QStyleHelper::SizeSmall ? 16 : 22;
725 ret = QSize(width, s);
728 case QStyle::CT_ComboBox:
730 case QStyleHelper::SizeLarge:
733 case QStyleHelper::SizeSmall:
736 case QStyleHelper::SizeMini:
743 case QStyle::CT_ToolButton:
744 if (sz == QStyleHelper::SizeSmall) {
745 int width = 0, height = 0;
746 if (szHint == QSize(-1, -1)) {
772 width = szHint.width();
773 height = szHint.height();
776 width = szHint.width();
777 height = szHint.height();
779 width = qMax(20, width + 5);
780 height = qMax(20, height + 5);
781 ret = QSize(width, height);
784 case QStyle::CT_Slider: {
786 const QStyleOptionSlider *sld = qstyleoption_cast<
const QStyleOptionSlider *>(opt);
789 if (sz == QStyleHelper::SizeLarge) {
790 if (sld->orientation == Qt::Horizontal) {
792 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
796 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
799 }
else if (sz == QStyleHelper::SizeSmall) {
800 if (sld->orientation == Qt::Horizontal) {
802 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
806 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
809 }
else if (sz == QStyleHelper::SizeMini) {
810 if (sld->orientation == Qt::Horizontal) {
812 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
816 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
828 if (sld->orientation == Qt::Horizontal)
865 case QStyle::CT_HeaderSection:
871 case QStyle::CT_MenuBar:
872 if (sz == QStyleHelper::SizeLarge) {
873 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
878 if (ret.height() <= 0)
891 static const qreal CornerPointOffset = 5.5;
892 static const qreal CornerControlOffset = 2.1;
896 path.moveTo(r.left(), r.top() + CornerPointOffset);
897 path.cubicTo(r.left(), r.top() + CornerControlOffset,
898 r.left() + CornerControlOffset, r.top(),
899 r.left() + CornerPointOffset, r.top());
901 path.lineTo(r.right() - CornerPointOffset, r.top());
902 path.cubicTo(r.right() - CornerControlOffset, r.top(),
903 r.right(), r.top() + CornerControlOffset,
904 r.right(), r.top() + CornerPointOffset);
906 path.lineTo(r.right(), r.bottom() - CornerPointOffset);
907 path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
908 r.right() - CornerControlOffset, r.bottom(),
909 r.right() - CornerPointOffset, r.bottom());
911 path.lineTo(r.left() + CornerPointOffset, r.bottom());
912 path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
913 r.left(), r.bottom() - CornerControlOffset,
914 r.left(), r.bottom() - CornerPointOffset);
915 path.lineTo(r.left(), r.top() + CornerPointOffset);
922 struct WindowButtons {
923 QStyle::SubControl sc;
927 static const WindowButtons buttons[] = {
928 { QStyle::SC_TitleBarCloseButton, QMacStylePrivate::Button_WindowClose },
929 { QStyle::SC_TitleBarMinButton, QMacStylePrivate::Button_WindowMiniaturize },
930 { QStyle::SC_TitleBarMaxButton, QMacStylePrivate::Button_WindowZoom }
933 for (
const auto &wb : buttons)
945 QRect tr = opt->rect;
946 const bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
947 || opt->shape == QStyleOptionTab::RoundedWest
948 || opt->shape == QStyleOptionTab::TriangularEast
949 || opt->shape == QStyleOptionTab::TriangularWest;
951 tr.setRect(0, 0, tr.height(), tr.width());
953 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
954 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
955 const int hpadding = 4;
956 const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
957 if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
958 verticalShift = -verticalShift;
959 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
962 if (!opt->leftButtonSize.isEmpty()) {
963 const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
964 tr.setLeft(tr.left() + 4 + buttonSize);
966 if (opt->rightButtonSize.isEmpty())
967 tr.setRight(tr.right() - 4 - buttonSize);
970 if (!opt->rightButtonSize.isEmpty()) {
971 const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
972 tr.setRight(tr.right() - 4 - buttonSize);
974 if (opt->leftButtonSize.isEmpty())
975 tr.setLeft(tr.left() + 4 + buttonSize);
979 if (!opt->icon.isNull()) {
980 QSize iconSize = opt->iconSize;
981 if (!iconSize.isValid()) {
982 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
983 iconSize = QSize(iconExtent, iconExtent);
985 QSize tabIconSize = opt->icon.actualSize(iconSize,
986 (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
987 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
989 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
991 const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2 - hpadding;
993 if (opt->documentMode) {
995 const int textWidth =
996 opt->fontMetrics.boundingRect(tr, Qt::AlignCenter | Qt::TextShowMnemonic, opt->text).width();
997 *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
998 tr.center().y() - tabIconSize.height() / 2,
999 tabIconSize.width(), tabIconSize.height());
1001 *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
1002 tabIconSize.width(), tabIconSize.height());
1005 *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
1007 tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
1008 tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
1012 tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
1020 case QStyleOptionTab::RoundedSouth:
1021 case QStyleOptionTab::TriangularSouth:
1023 case QStyleOptionTab::RoundedNorth:
1024 case QStyleOptionTab::TriangularNorth:
1026 case QStyleOptionTab::RoundedWest:
1027 case QStyleOptionTab::TriangularWest:
1029 case QStyleOptionTab::RoundedEast:
1030 case QStyleOptionTab::TriangularEast:
1037 return (direction == QMacStylePrivate::East
1038 || direction == QMacStylePrivate::West);
1042 QStyle::ContentsType ct,
1043 QSize szHint, QSize *insz)
const
1045 QStyleHelper::WidgetSizePolicy sz = aquaSizeConstrain(option, ct, szHint, insz);
1046 if (sz == QStyleHelper::SizeDefault)
1047 return QStyleHelper::SizeLarge;
1055 return QStyleHelper::SizeLarge;
1057 if (option->state & QStyle::State_Small)
1058 return QStyleHelper::SizeSmall;
1059 if (option->state & QStyle::State_Mini)
1060 return QStyleHelper::SizeMini;
1062 return QStyleHelper::SizeLarge;
1068 return ((cw
.type << 2) | cw.size) ^ seed;
1083 return other.type == type && other.size == size;
1094 return QSizeF(-1, pushButtonDefaultHeight[size]);
1098 return QSizeF(-1, popupButtonDefaultHeight[size]);
1101 return QSizeF(-1, comboBoxDefaultHeight[size]);
1109 const auto frameSize = defaultFrameSize();
1111 frameRect = rect.adjusted(3, 1, -3, -1)
1112 .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
1115 frameRect = QRectF(rect.topLeft(),
1116 QSizeF(rect.width(), frameSize.height()));
1117 if (size == QStyleHelper::SizeSmall)
1118 frameRect = frameRect.translated(0, 1.5);
1119 else if (size == QStyleHelper::SizeMini)
1120 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
1123 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1124 QSizeF(rect.width(), frameSize.height()));
1125 frameRect = frameRect.translated(rect.topLeft());
1127 if (size == QStyleHelper::SizeLarge)
1128 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1129 else if (size == QStyleHelper::SizeSmall)
1130 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1131 else if (size == QStyleHelper::SizeMini)
1132 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1134 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1144 if (size == QStyleHelper::SizeLarge) {
1145 if (qt_apple_runningWithLiquidGlass())
1146 return QMarginsF(10, 5, 10, 5);
1148 return QMarginsF(12, 5, 12, 7);
1150 if (size == QStyleHelper::SizeSmall)
1151 return QMarginsF(12, 4, 12, 9);
1152 if (size == QStyleHelper::SizeMini)
1153 return QMarginsF(10, 1, 10, 2);
1157 if (size == QStyleHelper::SizeLarge)
1158 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1159 if (size == QStyleHelper::SizeSmall)
1160 return QMarginsF(7.5, 2, 20.5, 4);
1161 if (size == QStyleHelper::SizeMini)
1162 return QMarginsF(4.5, 0, 16.5, 2);
1166 return QMarginsF(6, 1, 6, 2);
1174 case Button_CheckBox:
1175 *buttonType = NSButtonTypeSwitch;
1176 *bezelStyle = NSBezelStyleRegularSquare;
1178 case Button_Disclosure:
1179 *buttonType = NSButtonTypeOnOff;
1180 *bezelStyle = NSBezelStyleDisclosure;
1182 case Button_RadioButton:
1183 *buttonType = NSButtonTypeRadio;
1184 *bezelStyle = NSBezelStyleRegularSquare;
1186 case Button_SquareButton:
1187 *buttonType = NSButtonTypePushOnPushOff;
1188 *bezelStyle = NSBezelStyleShadowlessSquare;
1190 case Button_PushButton:
1191 *buttonType = NSButtonTypePushOnPushOff;
1192 *bezelStyle = NSBezelStyleRounded;
1203 if (
const auto *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
1204 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
1208 const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge];
1209 const bool isSquare = (btn->features & QStyleOptionButton::Flat)
1210 || (btn->rect.height() > maxNonSquareHeight);
1217 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
1218 if (combo->editable)
1228
1229
1230
1233 CGRect innerBounds = outerBounds;
1238 switch (cocoaWidget.size) {
1239 case QStyleHelper::SizeSmall:
1240 innerBounds.origin.x += 3;
1241 innerBounds.origin.y += 3;
1242 innerBounds.size.width -= 6;
1243 innerBounds.size.height -= 7;
1245 case QStyleHelper::SizeMini:
1246 innerBounds.origin.x += 2;
1247 innerBounds.origin.y += 2;
1248 innerBounds.size.width -= 5;
1249 innerBounds.size.height -= 6;
1251 case QStyleHelper::SizeLarge:
1252 case QStyleHelper::SizeDefault:
1253 innerBounds.origin.x += 2;
1254 innerBounds.origin.y += 2;
1255 innerBounds.size.width -= 5;
1256 innerBounds.size.height -= 6;
1259 switch (cocoaWidget.size) {
1260 case QStyleHelper::SizeSmall:
1261 innerBounds.origin.x += 3;
1262 innerBounds.origin.y += 3;
1263 innerBounds.size.width -= 7;
1264 innerBounds.size.height -= 8;
1266 case QStyleHelper::SizeMini:
1267 innerBounds.origin.x += 3;
1268 innerBounds.origin.y += 3;
1269 innerBounds.size.width -= 4;
1270 innerBounds.size.height -= 8;
1272 case QStyleHelper::SizeLarge:
1273 case QStyleHelper::SizeDefault:
1274 innerBounds.origin.x += 3;
1275 innerBounds.origin.y += 2;
1276 innerBounds.size.width -= 6;
1277 innerBounds.size.height -= 8;
1285
1286
1287
1290 QRectF ret = outerBounds;
1293 case QStyleHelper::SizeLarge:
1294 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1297 case QStyleHelper::SizeSmall:
1298 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1301 case QStyleHelper::SizeMini:
1302 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1303 ret.setHeight(10.5);
1310 case QStyleHelper::SizeLarge:
1311 ret.adjust(10, 1, -23, -4);
1313 case QStyleHelper::SizeSmall:
1314 ret.adjust(10, 4, -20, -3);
1316 case QStyleHelper::SizeMini:
1317 ret.adjust(9, 0, -19, 0);
1330 if (
auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
1331 smallSystemFont = *ssf;
1332 if (
auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
1333 miniSystemFont = *msf;
1338 QMacAutoReleasePool pool;
1339 for (NSView *b : cocoaControls)
1341 for (NSCell *cell : cocoaCells)
1347 if (cocoaControl.type == QMacStylePrivate::NoControl
1348 || cocoaControl.size == QStyleHelper::SizeDefault)
1352 if (
__builtin_available(macOS 10.14, *)) {
1360 NSView *bv = cocoaControls.value(cocoaControl, nil);
1362 switch (cocoaControl
.type) {
1364 NSBox *box = [[NSBox alloc] init];
1367 box.titlePosition = NSNoTitle;
1371 bv = [[QDarkNSBox alloc] init];
1378 NSButton *bc = [[NSButton alloc] init];
1386 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1388 if (cocoaControl.type == Button_PullDown)
1396 const NSWindowButton button = [=] {
1397 switch (cocoaControl
.type) {
1398 case Button_WindowClose:
1399 return NSWindowCloseButton;
1400 case Button_WindowMiniaturize:
1401 return NSWindowMiniaturizeButton;
1402 case Button_WindowZoom:
1403 return NSWindowZoomButton;
1409 const auto styleMask = NSWindowStyleMaskTitled
1410 | NSWindowStyleMaskClosable
1411 | NSWindowStyleMaskMiniaturizable
1412 | NSWindowStyleMaskResizable;
1413 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1418 bv = [[NSSearchField alloc] init];
1421 bv = [[NSComboBox alloc] init];
1423 case ProgressIndicator_Determinate:
1424 bv = [[NSProgressIndicator alloc] init];
1426 case ProgressIndicator_Indeterminate:
1427 bv = [[QIndeterminateProgressIndicator alloc] init];
1429 case Scroller_Horizontal:
1430 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1432 case Scroller_Vertical:
1435 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1437 case Slider_Horizontal:
1438 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1440 case Slider_Vertical:
1443 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1445 case SplitView_Horizontal:
1446 bv = [[NSSplitView alloc] init];
1448 case SplitView_Vertical:
1449 bv = [[QVerticalSplitView alloc] init];
1452 bv = [[NSTextField alloc] init];
1458 if ([bv isKindOfClass:[NSControl
class]]) {
1459 auto *ctrl =
static_cast<NSControl *>(bv);
1460 switch (cocoaControl.size) {
1461 case QStyleHelper::SizeSmall:
1462 ctrl.controlSize = NSControlSizeSmall;
1464 case QStyleHelper::SizeMini:
1465 ctrl.controlSize = NSControlSizeMini;
1472 auto *pi =
static_cast<NSProgressIndicator *>(bv);
1474 switch (cocoaControl.size) {
1475 case QStyleHelper::SizeSmall:
1476 pi.controlSize = NSControlSizeSmall;
1478 case QStyleHelper::SizeMini:
1479 pi.controlSize = NSControlSizeMini;
1486 cocoaControls.insert(cocoaControl, bv);
1489 NSButtonType buttonType;
1490 NSBezelStyle bezelStyle;
1506 NSCell *cell = cocoaCells[cocoaControl];
1508 switch (cocoaControl
.type) {
1510 cell = [[NSStepperCell alloc] init];
1513 NSButtonCell *bc = [[NSButtonCell alloc] init];
1514 bc.buttonType = NSButtonTypeOnOff;
1515 bc.bezelStyle = NSBezelStyleDisclosure;
1523 switch (cocoaControl.size) {
1524 case QStyleHelper::SizeSmall:
1525 cell.controlSize = NSControlSizeSmall;
1527 case QStyleHelper::SizeMini:
1528 cell.controlSize = NSControlSizeMini;
1534 cocoaCells.insert(cocoaControl, cell);
1540void QMacStylePrivate::drawNSViewInRect(NSView *view,
const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock)
const
1542 QMacAutoReleasePool pool;
1543 QMacCGContext ctx(p);
1544 setupNSGraphicsContext(ctx, YES);
1555 view.wantsLayer = YES;
1564 view.frame = rect.toCGRect();
1566 [backingStoreNSView addSubview:view];
1573 const CGRect dirtyRect = rect.toCGRect();
1576 drawRectBlock(ctx, dirtyRect);
1578 [view drawRect:dirtyRect];
1580 [view removeFromSuperviewWithoutNeedingDisplay];
1582 restoreNSGraphicsContext(ctx);
1587 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1592 return new QMacApperanceStyle<QMacStyle, QStyleOption, QStyleOptionComplex>;
1596 : QCommonStyle(*
new QMacStylePrivate)
1598 QMacAutoReleasePool pool;
1600 static QMacNotificationObserver scrollbarStyleObserver(nil,
1601 NSPreferredScrollerStyleDidChangeNotification, []() {
1603 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1605 QEvent event(QEvent::StyleChange);
1606 for (
const auto &o : QMacStylePrivate::scrollBars)
1607 QCoreApplication::sendEvent(o, &event);
1618 for (NSView *b : d->cocoaControls)
1620 d->cocoaControls.clear();
1625 Q_D(
const QMacStyle);
1626 const int controlSize = getControlSize(opt);
1630 case PM_TabCloseIndicatorWidth:
1631 case PM_TabCloseIndicatorHeight:
1634 case PM_ToolBarIconSize:
1635 ret = proxy()->pixelMetric(PM_LargeIconSize);
1637 case PM_FocusFrameVMargin:
1638 case PM_FocusFrameHMargin:
1641 case PM_DialogButtonsSeparator:
1644 case PM_DialogButtonsButtonHeight: {
1646 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1647 if (sz == QSize(-1, -1))
1652 case PM_DialogButtonsButtonWidth: {
1654 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1655 if (sz == QSize(-1, -1))
1661 case PM_MenuBarHMargin:
1665 case PM_MenuBarVMargin:
1669 case PM_MenuBarPanelWidth:
1673 case PM_MenuButtonIndicator:
1677 case QStyle::PM_MenuDesktopFrameWidth:
1681 case PM_CheckBoxLabelSpacing:
1682 case PM_RadioButtonLabelSpacing:
1685 if (opt->state & State_Mini)
1687 if (opt->state & State_Small)
1693 case PM_MenuScrollerHeight:
1696 case PM_DefaultFrameWidth:
1706 if (qstyleoption_cast<
const QStyleOptionComboBox *>(opt) != 0)
1711 case PM_MaximumDragDistance:
1714 case PM_ScrollBarSliderMin:
1717 case PM_SpinBoxFrameWidth:
1720 case PM_ButtonShiftHorizontal:
1721 case PM_ButtonShiftVertical:
1724 case PM_SliderLength:
1730 case PM_SliderControlThickness:
1731 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
1732 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1733 int ticks = sl->tickPosition;
1735 if (ticks & QStyleOptionSlider::TicksAbove)
1737 if (ticks & QStyleOptionSlider::TicksBelow)
1745 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1746 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1750 thick += (space * 2) / (n + 2);
1756 case PM_SmallIconSize:
1757 ret =
int(QStyleHelper::dpiScaled(16., opt));
1760 case PM_LargeIconSize:
1761 ret =
int(QStyleHelper::dpiScaled(32., opt));
1764 case PM_IconViewIconSize:
1765 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1768 case PM_ButtonDefaultIndicator:
1771 case PM_TitleBarHeight: {
1772 NSUInteger style = NSWindowStyleMaskTitled;
1775 ret =
int([NSWindow frameRectForContentRect:NSZeroRect
1776 styleMask:style].size.height);
1778 case QStyle::PM_TabBarTabHSpace:
1779 switch (d->aquaSizeConstrain(opt)) {
1780 case QStyleHelper::SizeLarge:
1781 ret = QCommonStyle::pixelMetric(metric, opt);
1783 case QStyleHelper::SizeSmall:
1786 case QStyleHelper::SizeMini:
1789 case QStyleHelper::SizeDefault:
1790 const QStyleOptionTab *tb = qstyleoption_cast<
const QStyleOptionTab *>(opt);
1791 if (tb && tb->documentMode)
1794 ret = QCommonStyle::pixelMetric(metric, opt);
1798 case PM_TabBarTabVSpace:
1801 case PM_TabBarTabShiftHorizontal:
1802 case PM_TabBarTabShiftVertical:
1805 case PM_TabBarBaseHeight:
1808 case PM_TabBarTabOverlap:
1811 case PM_TabBarBaseOverlap:
1812 switch (d->aquaSizeConstrain(opt)) {
1813 case QStyleHelper::SizeDefault:
1814 case QStyleHelper::SizeLarge:
1817 case QStyleHelper::SizeSmall:
1820 case QStyleHelper::SizeMini:
1825 case PM_ScrollBarExtent: {
1826 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1827 ret =
static_cast<
int>([NSScroller
1828 scrollerWidthForControlSize:
static_cast<NSControlSize>(size)
1829 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1831 case PM_IndicatorHeight: {
1832 switch (d->aquaSizeConstrain(opt)) {
1833 case QStyleHelper::SizeDefault:
1834 case QStyleHelper::SizeLarge:
1837 case QStyleHelper::SizeMini:
1840 case QStyleHelper::SizeSmall:
1845 case PM_IndicatorWidth: {
1846 switch (d->aquaSizeConstrain(opt)) {
1847 case QStyleHelper::SizeDefault:
1848 case QStyleHelper::SizeLarge:
1851 case QStyleHelper::SizeMini:
1854 case QStyleHelper::SizeSmall:
1860 case PM_ExclusiveIndicatorHeight: {
1861 switch (d->aquaSizeConstrain(opt)) {
1862 case QStyleHelper::SizeDefault:
1863 case QStyleHelper::SizeLarge:
1866 case QStyleHelper::SizeMini:
1869 case QStyleHelper::SizeSmall:
1874 case PM_ExclusiveIndicatorWidth: {
1875 switch (d->aquaSizeConstrain(opt)) {
1876 case QStyleHelper::SizeDefault:
1877 case QStyleHelper::SizeLarge:
1880 case QStyleHelper::SizeMini:
1883 case QStyleHelper::SizeSmall:
1889 case PM_MenuVMargin:
1892 case PM_MenuPanelWidth:
1895 case PM_ToolTipLabelFrameWidth:
1898 case PM_SizeGripSize: {
1899 QStyleHelper::WidgetSizePolicy aSize;
1903 aSize = QStyleHelper::SizeLarge;
1904 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
1907 case PM_MdiSubWindowFrameWidth:
1910 case PM_DockWidgetFrameWidth:
1913 case PM_DockWidgetTitleMargin:
1916 case PM_DockWidgetSeparatorExtent:
1919 case PM_ToolBarHandleExtent:
1922 case PM_ToolBarItemMargin:
1925 case PM_ToolBarItemSpacing:
1928 case PM_SplitterWidth:
1931 case PM_LayoutLeftMargin:
1932 case PM_LayoutTopMargin:
1933 case PM_LayoutRightMargin:
1934 case PM_LayoutBottomMargin:
1936 if (opt->state & State_Window) {
1938
1939
1940
1941
1942
1959
1960
1965 case PM_LayoutHorizontalSpacing:
1966 case PM_LayoutVerticalSpacing:
1968 case PM_MenuHMargin:
1971 case PM_ToolBarExtensionExtent:
1974 case PM_ToolBarFrameWidth:
1977 case PM_ScrollView_ScrollBarOverlap:
1978 ret = styleHint(SH_ScrollBar_Transient, opt,
nullptr)
1979 ? pixelMetric(PM_ScrollBarExtent, opt)
1982 case PM_PushButtonFocusFrameRadius:
1985 case PM_CheckBoxFocusFrameRadius:
1988 case PM_SearchFieldFocusFrameRadius:
1989 case PM_ComboBoxFocusFrameRadius:
1990 if (qt_apple_runningWithLiquidGlass())
1995 case PM_RadioButtonFocusFrameRadius:
1998 case PM_SliderFocusFrameRadius:
2005 case PM_DialFocusFrameRadius:
2006 case PM_SpinBoxFocusFrameRadius:
2007 case PM_TextAreaFocusFrameRadius:
2008 case PM_TextFieldFocusFrameRadius:
2009 ret = qt_apple_runningWithLiquidGlass() ? 6 : 0;
2012 ret = QCommonStyle::pixelMetric(metric, opt);
2028int QMacStyle::
styleHint(StyleHint sh,
const QStyleOption *opt, QStyleHintReturn *hret)
const
2030 QMacAutoReleasePool pool;
2034 case SH_Slider_SnapToValue:
2035 case SH_PrintDialog_RightAlignButtons:
2036 case SH_FontDialog_SelectAssociatedText:
2037 case SH_MenuBar_MouseTracking:
2038 case SH_Menu_MouseTracking:
2039 case SH_ComboBox_ListMouseTracking:
2040 case SH_MainWindow_SpaceBelowMenuBar:
2041 case SH_ItemView_ChangeHighlightOnFocus:
2044 case SH_ToolBox_SelectedPageTitleBold:
2047 case SH_DialogButtonBox_ButtonsHaveIcons:
2050 case SH_Menu_SelectionWrap:
2053 case SH_Menu_KeyboardSearch:
2056 case SH_Menu_SpaceActivatesItem:
2059 case SH_Slider_AbsoluteSetButtons:
2060 ret = Qt::LeftButton|Qt::MiddleButton;
2062 case SH_Slider_PageSetButtons:
2065 case SH_ScrollBar_ContextMenu:
2068 case SH_TitleBar_AutoRaise:
2071 case SH_Menu_AllowActiveAndDisabled:
2074 case SH_Menu_SubMenuPopupDelay:
2077 case SH_Menu_SubMenuUniDirection:
2080 case SH_Menu_SubMenuSloppySelectOtherActions:
2083 case SH_Menu_SubMenuResetWhenReenteringParent:
2086 case SH_Menu_SubMenuDontStartSloppyOnLeave:
2090 case SH_ScrollBar_LeftClickAbsolutePosition: {
2091 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2092 bool result = [defaults boolForKey:@
"AppleScrollerPagingBehavior"];
2098 case SH_TabBar_PreferNoArrows:
2102
2103
2104
2105
2106 case SH_GroupBox_TextLabelVerticalAlignment:
2109 case SH_ScrollView_FrameOnlyAroundContents:
2110 ret = QCommonStyle::styleHint(sh, opt, hret);
2112 case SH_Menu_FillScreenWithScroll:
2115 case SH_Menu_Scrollable:
2118 case SH_RichText_FullWidthSelection:
2121 case SH_BlinkCursorWhenTextSelected:
2124 case SH_Slider_StopMouseOverSlider:
2127 case SH_ListViewExpand_SelectMouseType:
2128 ret = QEvent::MouseButtonRelease;
2130 case SH_TabBar_SelectMouseType:
2131 if (
const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2132 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2134 ret = QEvent::MouseButtonRelease;
2137 case SH_ComboBox_Popup:
2138 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt))
2139 ret = !cmb->editable;
2143 case SH_Workspace_FillSpaceOnMaximize:
2146 case SH_Widget_ShareActivation:
2149 case SH_Header_ArrowAlignment:
2150 ret = Qt::AlignRight;
2152 case SH_TabBar_Alignment: {
2169 ret = Qt::AlignCenter;
2171 case SH_UnderlineShortcut:
2174 case SH_ToolTipLabel_Opacity:
2177 case SH_Button_FocusPolicy:
2180 case SH_EtchDisabledText:
2183 case SH_FocusFrame_Mask: {
2185 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2186 const uchar fillR = 192, fillG = 191, fillB = 190;
2189 QSize pixmapSize = opt->rect.size();
2190 if (!pixmapSize.isEmpty()) {
2191 QPixmap pix(pixmapSize);
2192 pix.fill(QColor(fillR, fillG, fillB));
2193 QPainter pix_paint(&pix);
2194 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2196 img = pix.toImage();
2199 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2200 const qsizetype sbpl = img.bytesPerLine();
2201 const int w = sbpl/4, h = img.height();
2203 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2204 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2205 const qsizetype dbpl = img_mask.bytesPerLine();
2207 for (
int y = 0; y < h; ++y) {
2208 srow = sptr+((y*sbpl)/4);
2209 drow = dptr+((y*dbpl)/4);
2210 for (
int x = 0; x < w; ++x) {
2211 const int redDiff = qRed(*srow) - fillR;
2212 const int greenDiff = qGreen(*srow) - fillG;
2213 const int blueDiff = qBlue(*srow) - fillB;
2214 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2215 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2219 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2220 mask->region = QRegion(qmask);
2223 case SH_TitleBar_NoBorder:
2226 case SH_RubberBand_Mask:
2229 case SH_ComboBox_LayoutDirection:
2230 ret = Qt::LeftToRight;
2232 case SH_ItemView_EllipsisLocation:
2233 ret = Qt::AlignHCenter;
2235 case SH_ItemView_ShowDecorationSelected:
2238 case SH_TitleBar_ModifyNotification:
2241 case SH_ScrollBar_RollBetweenButtons:
2244 case SH_WindowFrame_Mask:
2247 case SH_TabBar_ElideMode:
2248 ret = Qt::ElideRight;
2259 case SH_FormLayoutFormAlignment:
2260 ret = Qt::AlignHCenter | Qt::AlignTop;
2262 case SH_FormLayoutLabelAlignment:
2263 ret = Qt::AlignRight;
2268 case SH_MessageBox_TextInteractionFlags:
2269 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2271 case SH_SpellCheckUnderlineStyle:
2272 ret = QTextCharFormat::DashUnderline;
2274 case SH_MessageBox_CenterButtons:
2277 case SH_MenuBar_AltKeyNavigation:
2280 case SH_ItemView_MovementWithoutUpdatingSelection:
2283 case SH_FocusFrame_AboveWidget:
2289 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2292 case SH_Menu_FlashTriggeredItem:
2295 case SH_Menu_FadeOutOnHide:
2298 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2301 case SH_TabBar_CloseButtonPosition:
2302 ret = QStyleOptionTabBarBase::LeftSide;
2304 case SH_DockWidget_ButtonsHaveFrame:
2307 case SH_ScrollBar_Transient:
2313 case SH_TitleBar_ShowToolTipsOnButtons:
2317 case SH_ComboBox_AllowWheelScrolling:
2320 case SH_SpinBox_ButtonsInsideFrame:
2323 case SH_Table_GridLineColor:
2324 ret =
int(qt_mac_toQColor(NSColor.gridColor).rgba());
2327 ret = QCommonStyle::styleHint(sh, opt, hret);
2334 const QStyleOption *opt)
const
2337 case QIcon::Disabled: {
2338 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2339 int imgh = img.height();
2340 int imgw = img.width();
2342 for (
int y = 0; y < imgh; ++y) {
2343 for (
int x = 0; x < imgw; ++x) {
2344 pixel = img.pixel(x, y);
2345 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2346 qAlpha(pixel) / 2));
2349 return QPixmap::fromImage(img);
2354 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2365 static bool recursionGuard =
false;
2368 return QCommonStyle::standardPixmap(standardPixmap, opt);
2370 recursionGuard =
true;
2371 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2372 recursionGuard =
false;
2374 switch (standardPixmap) {
2378 case SP_MessageBoxCritical:
2379 case SP_MessageBoxQuestion:
2380 case SP_MessageBoxInformation:
2381 case SP_MessageBoxWarning:
2385 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2390 Q_D(
const QMacStyle);
2392 QMacCGContext cg(p);
2393 d->resolveCurrentNSView(opt->window);
2396 case PE_IndicatorArrowUp:
2397 case PE_IndicatorArrowDown:
2398 case PE_IndicatorArrowRight:
2399 case PE_IndicatorArrowLeft: {
2401 p->setRenderHint(QPainter::Antialiasing);
2402 const int xOffset = 1;
2403 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2404 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2414 QTransform transform;
2415 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2419 case PE_IndicatorArrowDown:
2421 case PE_IndicatorArrowUp:
2422 transform.rotate(180);
2424 case PE_IndicatorArrowLeft:
2425 transform.rotate(90);
2427 case PE_IndicatorArrowRight:
2428 transform.rotate(-90);
2431 p->setTransform(transform);
2433 path.moveTo(-halfSize, -halfSize * 0.5);
2434 path.lineTo(0.0, halfSize * 0.5);
2435 path.lineTo(halfSize, -halfSize * 0.5);
2437 const QPen arrowPen(opt->palette.text(), penWidth,
2438 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2439 p->strokePath(path, arrowPen);
2442 case PE_FrameTabBarBase:
2443 if (
const QStyleOptionTabBarBase *tbb
2444 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2445 if (tbb->documentMode) {
2447 drawTabBase(p, tbb);
2451 QRegion region(tbb->rect);
2452 region -= tbb->tabBarRect;
2454 p->setClipRegion(region);
2455 QStyleOptionTabWidgetFrame twf;
2456 twf.QStyleOption::operator=(*tbb);
2457 twf.shape = tbb->shape;
2458 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2459 case QMacStylePrivate::North:
2460 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2462 case QMacStylePrivate::South:
2463 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2465 case QMacStylePrivate::West:
2466 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2468 case QMacStylePrivate::East:
2469 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2472 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2476 case PE_PanelTipLabel:
2477 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2479 case PE_FrameGroupBox:
2480 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2481 if (groupBox->features & QStyleOptionFrame::Flat) {
2482 QCommonStyle::drawPrimitive(pe, groupBox, p);
2486 case PE_FrameTabWidget:
2488 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2489 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
2503 auto adjustedRect = opt->rect;
2504 bool needTranslation =
false;
2505 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
2518 adjustedRect.adjust(0, 0, 6, 6);
2519 needTranslation =
true;
2521 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2526 QMacAutoReleasePool pool;
2527 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2528 CGContextScaleCTM(ctx, 1, -1);
2529 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
2530 || [box isMemberOfClass:QDarkNSBox.
class]) {
2531 [box drawRect:rect];
2533 if (needTranslation)
2534 CGContextTranslateCTM(ctx, -3.0, 5.0);
2535 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2540 case PE_IndicatorToolBarSeparator: {
2542 if (opt->state & State_Horizontal) {
2543 int xpoint = opt->rect.center().x();
2544 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2545 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2547 int ypoint = opt->rect.center().y();
2548 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2549 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2551 QPainterPathStroker theStroker;
2552 theStroker.setCapStyle(Qt::FlatCap);
2553 theStroker.setDashPattern(QList<qreal>() << 1 << 2);
2554 path = theStroker.createStroke(path);
2555 const auto dark =
isDarkMode() ? opt->palette.dark().color().darker()
2556 : QColor(0, 0, 0, 119);
2557 p->fillPath(path, dark);
2560 case PE_FrameWindow:
2571 case PE_IndicatorDockWidgetResizeHandle: {
2574 if (opt->state & State_Horizontal) {
2575 p->setPen(QColor(160, 160, 160));
2576 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2578 p->setPen(QColor(145, 145, 145));
2579 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2583 case PE_IndicatorToolBarHandle: {
2586 int x = opt->rect.x() + 6;
2587 int y = opt->rect.y() + 7;
2588 static const int RectHeight = 2;
2589 if (opt->state & State_Horizontal) {
2590 while (y < opt->rect.height() - RectHeight - 5) {
2592 path.addEllipse(x, y, RectHeight, RectHeight);
2596 while (x < opt->rect.width() - RectHeight - 5) {
2598 path.addEllipse(x, y, RectHeight, RectHeight);
2602 p->setPen(Qt::NoPen);
2603 QColor dark = opt->palette.dark().color().darker();
2604 dark.setAlphaF(0.50);
2605 p->fillPath(path, dark);
2610 case PE_IndicatorHeaderArrow:
2611 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2613 if (header->sortIndicator != QStyleOptionHeader::None)
2614 proxy()->drawPrimitive(
2615 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2616 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
2619 case PE_IndicatorMenuCheckMark: {
2621 if (opt->state & State_On)
2622 pc = opt->palette.highlightedText().color();
2624 pc = opt->palette.text().color();
2626 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
2627 static_cast<CGFloat>(pc.greenF()),
2628 static_cast<CGFloat>(pc.blueF()),
2629 static_cast<CGFloat>(pc.alphaF()));
2635 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2636 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2637 kCTFontUIFontMenuItemMark;
2641 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2642 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2644 CGContextSaveGState(cg);
2645 CGContextSetShouldSmoothFonts(cg, NO);
2648 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2649 (opt->state & State_Small) ? 1.0 :
2652 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2653 CGContextScaleCTM(cg, 1, -1);
2655 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2659 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2660 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
2661 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2662 Q_STATIC_ASSERT((
sizeof(values) /
sizeof(values[0])) == numValues);
2663 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
2664 numValues, NULL, NULL);
2666 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
2667 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2669 CTLineDraw((CTLineRef)line, cg);
2672 CGContextRestoreGState(cg);
2674 case PE_IndicatorItemViewItemCheck:
2675 case PE_IndicatorRadioButton:
2676 case PE_IndicatorCheckBox: {
2677 const bool isEnabled = opt->state & State_Enabled;
2678 const bool isPressed = opt->state & State_Sunken;
2679 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2681 const auto cs = d->effectiveAquaSizeConstrain(opt);
2683 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
2684 tb.enabled = isEnabled;
2685 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2686 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2687 [tb highlight:isPressed];
2688 const auto vOffset = [=] {
2690 if (cs == QStyleHelper::SizeMini)
2693 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2695 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2696 QMacAutoReleasePool pool;
2697 CGContextTranslateCTM(ctx, 0, vOffset);
2698 [tb.cell drawInteriorWithFrame:rect inView:tb];
2701 case PE_FrameFocusRect:
2704 case PE_IndicatorBranch: {
2705 if (!(opt->state & State_Children))
2707 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
2708 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
2709 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2711 bool viewHasFocus =
false;
2712 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2714 d->setupNSGraphicsContext(cg, NO);
2717 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2718 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2719 CGContextScaleCTM(cg, 1, -1);
2720 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2722 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2724 d->restoreNSGraphicsContext(cg);
2728 const QPen oldPen = p->pen();
2729 QPen penCpy = p->pen();
2731 penCpy.setColor(opt->palette.dark().color());
2733 p->drawRect(opt->rect);
2736 case PE_PanelLineEdit:
2737 case PE_FrameLineEdit:
2738 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
2739 if (frame->state & State_Sunken) {
2740 const bool isEnabled = opt->state & State_Enabled;
2741 const bool isReadOnly = opt->state & State_ReadOnly;
2742 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2743 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2745 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
2746 tf.enabled = isEnabled;
2747 tf.editable = !isReadOnly;
2749 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2750 tf.frame = opt->rect.toCGRect();
2751 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
2752 QMacAutoReleasePool pool;
2753 if (!isDarkMode()) {
2758 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2762 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
2763 tf.drawsBackground = YES;
2764 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2765 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2766 green:bgColor.greenF()
2767 blue:bgColor.blueF()
2768 alpha:bgColor.alphaF()];
2769 if (bgColor.alpha() != 255) {
2776 CGRect fixedRect = rect;
2777 if (qt_apple_runningWithLiquidGlass()) {
2782 fixedRect = CGRectInset(rect, 1., 1.);
2784 [tf.cell drawWithFrame:fixedRect inView:tf];
2787 QCommonStyle::drawPrimitive(pe, opt, p);
2791 case PE_PanelScrollAreaCorner: {
2792 const QBrush brush(opt->palette.brush(QPalette::Base));
2793 p->fillRect(opt->rect, brush);
2794 p->setPen(QPen(QColor(217, 217, 217)));
2795 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2796 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2798 case PE_FrameStatusBarItem:
2826 case PE_PanelStatusBar: {
2827 p->fillRect(opt->rect, opt->palette.window());
2830 if (qt_macWindowMainWindow(opt->window))
2831 p->setPen(titlebarSeparatorLineActive);
2833 p->setPen(titlebarSeparatorLineInactive);
2834 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2838 case PE_PanelMenu: {
2840 p->fillRect(opt->rect, Qt::transparent);
2841 p->setPen(Qt::transparent);
2842 p->setBrush(opt->palette.window());
2843 p->setRenderHint(QPainter::Antialiasing,
true);
2844 const QPainterPath path = d->windowPanelPath(opt->rect);
2850 QCommonStyle::drawPrimitive(pe, opt, p);
2857 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2858 int imgh = img.height();
2859 int imgw = img.width();
2862 for (
int y = 0; y < imgh; ++y) {
2863 for (
int x = 0; x < imgw; ++x) {
2864 pixel = img.pixel(x, y);
2866 QColor hsvColor(pixel);
2867 hsvColor.getHsv(&h, &s, &v);
2868 s = qMin(100, s * 2);
2870 hsvColor.setHsv(h, s, v);
2871 pixel = hsvColor.rgb();
2872 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2875 return QPixmap::fromImage(img);
2881 CGContextTranslateCTM(cg, rect.size.height, 0);
2882 CGContextRotateCTM(cg,
M_PI_2);
2884 if (vertical != reverse) {
2885 CGContextTranslateCTM(cg, rect.size.width, 0);
2886 CGContextScaleCTM(cg, -1, 1);
2892 Q_D(
const QMacStyle);
2894 const QMacAutoReleasePool pool;
2896 QMacCGContext cg(p);
2897 d->resolveCurrentNSView(opt->window);
2900 case CE_HeaderSection:
2901 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2902 State flags = header->state;
2903 QRect ir = header->rect;
2904 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2905 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2906 p->setPen(QPen(header->palette.dark(), 1.0));
2907 if (header->orientation == Qt::Horizontal)
2916 case CE_HeaderLabel:
2917 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2919 QRect textr = header->rect;
2920 if (!header->icon.isNull()) {
2921 QIcon::Mode mode = QIcon::Disabled;
2922 if (opt->state & State_Enabled)
2923 mode = QIcon::Normal;
2924 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2925 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2926 opt->window->devicePixelRatio(), mode);
2928 QRect pixr = header->rect;
2929 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2930 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
2931 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2934 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2935 header->state & State_Enabled, header->text, QPalette::ButtonText);
2939 case CE_ToolButtonLabel:
2940 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
2941 QStyleOptionToolButton myTb = *tb;
2942 myTb.state &= ~State_AutoRaise;
2943#ifndef QT_NO_ACCESSIBILITY
2944 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2945 QRect cr = tb->rect;
2948 bool needText =
false;
2950 bool down = tb->state & (State_Sunken | State_On);
2952 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
2953 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2959 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2960 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2961 if (tb->icon.isNull() && !tb->text.isEmpty())
2962 tbstyle = Qt::ToolButtonTextOnly;
2965 case Qt::ToolButtonTextOnly: {
2967 alignment = Qt::AlignCenter;
2969 case Qt::ToolButtonIconOnly:
2970 case Qt::ToolButtonTextBesideIcon:
2971 case Qt::ToolButtonTextUnderIcon: {
2973 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2975 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2977 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2978 opt->window->devicePixelRatio(), iconMode,
2982 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
2984 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
2985 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
2986 cr.adjust(0, pr.bottom(), 0, -3);
2987 alignment |= Qt::AlignCenter;
2989 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
2990 cr.adjust(pr.right(), 0, 0, 0);
2991 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
2994 if (opt->state & State_Sunken) {
2995 pr.translate(shiftX, shiftY);
2996 pixmap = darkenPixmap(pixmap);
2998 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3006 QPalette pal = tb->palette;
3007 QPalette::ColorRole role = QPalette::NoRole;
3008 if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
3009 alignment |= Qt::TextHideMnemonic;
3011 cr.translate(shiftX, shiftY);
3012 if (tbstyle == Qt::ToolButtonTextOnly
3013 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3014 QPen pen = p->pen();
3015 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3016 light.setAlphaF(0.375f);
3018 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3020 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3022 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3023 role = QPalette::HighlightedText;
3026 proxy()->drawItemText(p, cr, alignment, pal,
3027 tb->state & State_Enabled, tb->text, role);
3030 QCommonStyle::drawControl(ce, &myTb, p);
3035 QCommonStyle::drawControl(ce, &myTb, p);
3039 case CE_ToolBoxTabShape:
3040 QCommonStyle::drawControl(ce, opt, p);
3042 case CE_PushButtonBevel:
3044 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3047 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3048 QCommonStyle::drawControl(ce, opt, p);
3052 const bool hasFocus = btn->state & State_HasFocus;
3053 const bool isActive = btn->state & State_Active;
3057 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3058 && isActive && hasFocus)
3059 d->autoDefaultButton = btn->styleObject;
3060 else if (d->autoDefaultButton == btn->styleObject)
3061 d->autoDefaultButton =
nullptr;
3063 const bool isEnabled = btn->state & State_Enabled;
3064 const bool isPressed = btn->state & State_Sunken;
3065 const bool isHighlighted = isActive &&
3066 ((btn->state & State_On)
3067 || (btn->features & QStyleOptionButton::DefaultButton)
3068 || (btn->features & QStyleOptionButton::AutoDefaultButton
3069 && d->autoDefaultButton == btn->styleObject));
3070 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3071 const auto ct = cocoaControlType(btn);
3072 const auto cs = d->effectiveAquaSizeConstrain(btn);
3074 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3078 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3079 pb.frame = frameRect.toCGRect();
3081 pb.enabled = isEnabled;
3082 [pb highlight:isPressed];
3083 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3084 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3085 QMacAutoReleasePool pool;
3086 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3093 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
3094 const auto ir = frameRect.toRect();
3095 int arrowYOffset = 0;
3096 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3098 QStyleOption arrowOpt = *opt;
3100 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
3104 case CE_PushButtonLabel:
3111 const bool isEnabled = btn.state & State_Enabled;
3112 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3113 const bool hasIcon = !btn.icon.isNull();
3114 const bool hasText = !btn.text.isEmpty();
3115 const bool isActive = btn.state & State_Active;
3116 const bool isPressed = btn.state & State_Sunken;
3118 const auto ct = cocoaControlType(&btn);
3122 || (isActive && isEnabled
3123 && ((btn.state & State_On)
3124 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3125 || d->autoDefaultButton == btn.styleObject)))
3126 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3129 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3130 QCommonStyle::drawControl(ce, &btn, p);
3132 QRect freeContentRect = btn.rect;
3133 QRect textRect = itemTextRect(
3134 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3136 textRect.moveTo(11, textRect.top());
3140 int contentW = textRect.width();
3142 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3143 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3144 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3145 mode = QIcon::Active;
3147 QIcon::State state = QIcon::Off;
3148 if (btn.state & State_On)
3150 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3152 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3153 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3155 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3156 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3157 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3158 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3159 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3160 int newOffset = iconDestRect.x() + iconDestRect.width()
3162 textRect.adjust(newOffset, 0, newOffset, 0);
3166 textRect = visualRect(btn.direction, freeContentRect, textRect);
3167 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3168 isEnabled, btn.text, QPalette::ButtonText);
3173 case CE_ComboBoxLabel:
3174 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3175 auto comboCopy = *cb;
3176 comboCopy.direction = Qt::LeftToRight;
3178 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
3181 case CE_TabBarTabShape:
3182 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3183 if (tabOpt->documentMode) {
3185 bool isUnified =
false;
3192 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3193 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3199 const bool isActive = tabOpt->state & State_Active;
3200 const bool isEnabled = tabOpt->state & State_Enabled;
3201 const bool isPressed = tabOpt->state & State_Sunken;
3202 const bool isSelected = tabOpt->state & State_Selected;
3203 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3204 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3205 || tabDirection == QMacStylePrivate::West;
3207 QStyleOptionTab::TabPosition tp = tabOpt->position;
3208 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3209 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3210 if (tp == QStyleOptionTab::Beginning)
3211 tp = QStyleOptionTab::End;
3212 else if (tp == QStyleOptionTab::End)
3213 tp = QStyleOptionTab::Beginning;
3215 if (sp == QStyleOptionTab::NextIsSelected)
3216 sp = QStyleOptionTab::PreviousIsSelected;
3217 else if (sp == QStyleOptionTab::PreviousIsSelected)
3218 sp = QStyleOptionTab::NextIsSelected;
3233 const auto cs = d->effectiveAquaSizeConstrain(opt);
3235 const bool needsInactiveHack = (!isActive && isSelected);
3236 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3237 QMacStylePrivate::Button_PushButton :
3238 QMacStylePrivate::Button_PopupButton;
3241 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3243 auto vOffset = isPopupButton ? 1 : 2;
3244 if (tabDirection == QMacStylePrivate::East)
3246 const auto outerAdjust = isPopupButton ? 1 : 4;
3247 const auto innerAdjust = isPopupButton ? 20 : 10;
3248 QRectF frameRect = tabOpt->rect;
3250 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3252 frameRect = frameRect.translated(0, vOffset);
3254 case QStyleOptionTab::Beginning:
3256 if (!isSelected && tabDirection == QMacStylePrivate::West)
3257 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3259 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3261 case QStyleOptionTab::Middle:
3262 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3264 case QStyleOptionTab::End:
3266 if (isSelected || tabDirection == QMacStylePrivate::West)
3267 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3269 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3271 case QStyleOptionTab::OnlyOneTab:
3272 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3275 pb.frame = frameRect.toCGRect();
3277 pb.enabled = isEnabled;
3278 [pb highlight:isPressed];
3280 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3282 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3283 QMacAutoReleasePool pool;
3284 CGContextClipToRect(ctx, opt->rect.toCGRect());
3285 if (!isSelected || needsInactiveHack) {
3287 if (!verticalTabs && tp == QStyleOptionTab::End) {
3288 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3289 CGContextScaleCTM(ctx, -1, 1);
3290 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3291 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3292 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3293 CGContextScaleCTM(ctx, 1, -1);
3294 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3295 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3296 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3297 CGContextScaleCTM(ctx, 1, -1);
3298 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3304 if (tabDirection == QMacStylePrivate::West) {
3305 CGContextTranslateCTM(ctx, 0, frameRect.right());
3306 CGContextRotateCTM(ctx, -
M_PI_2);
3307 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3308 }
else if (tabDirection == QMacStylePrivate::East) {
3309 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3310 CGContextRotateCTM(ctx,
M_PI_2);
3315 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3316 NSPopUpButtonCell *pbCell = nil;
3317 if (isPopupButton) {
3318 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3319 oldPosition = pbCell.arrowPosition;
3320 pbCell.arrowPosition = NSPopUpNoArrow;
3323 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3326 pbCell.arrowPosition = oldPosition;
3329 if (needsInactiveHack) {
3331 const qreal pixelRatio = p->device()->devicePixelRatioF();
3332 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3333 tabPixmap.setDevicePixelRatio(pixelRatio);
3334 tabPixmap.fill(Qt::transparent);
3335 QPainter tabPainter(&tabPixmap);
3336 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3337 QMacAutoReleasePool pool;
3338 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3339 drawBezelBlock(ctx, r);
3344 const qreal inactiveGray = 0.898;
3345 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3346 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3347 for (
int l = 0; l < tabPixmap.height(); ++l) {
3348 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3349 for (
int i = 0; i < tabPixmap.width(); ++i) {
3350 if (qAlpha(line[i]) == 255) {
3351 line[i] = inactiveGrayRGB;
3352 }
else if (qAlpha(line[i]) > 128) {
3353 const int g = qRound(inactiveGray * qRed(line[i]));
3354 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3360 p->drawImage(opt->rect, tabPixmap);
3362 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3365 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3366 && tp != QStyleOptionTab::End
3367 && tp != QStyleOptionTab::OnlyOneTab) {
3368 static const QPen separatorPen(Qt::black, 1.0);
3370 p->setOpacity(isEnabled ? 0.105 : 0.06);
3371 p->setPen(separatorPen);
3372 if (tabDirection == QMacStylePrivate::West) {
3373 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3374 opt->rect.right() - 0.5, opt->rect.bottom()));
3375 }
else if (tabDirection == QMacStylePrivate::East) {
3376 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3377 opt->rect.right() - 0.5, opt->rect.bottom()));
3379 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3380 opt->rect.right(), opt->rect.bottom() - 0.5));
3386 case CE_TabBarTabLabel:
3387 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3388 QStyleOptionTab myTab = *tab;
3389 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3390 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3391 || tabDirection == QMacStylePrivate::West;
3398 const bool nonDefaultFont =
false;
3406 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3407 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3410 int heightOffset = 0;
3413 }
else if (nonDefaultFont) {
3414 if (p->fontMetrics().height() == myTab.rect.height())
3417 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3419 QCommonStyle::drawControl(ce, &myTab, p);
3422 case CE_DockWidgetTitle:
3423 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
3424 const bool isVertical = dwOpt->verticalTitleBar;
3425 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3428 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3430 p->translate(-effectiveRect.left(), -effectiveRect.top());
3434 p->fillRect(effectiveRect, opt->palette.window());
3437 p->setPen(opt->palette.dark().color());
3438 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3440 if (!dwOpt->title.isEmpty()) {
3441 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3443 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3444 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3448 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3449 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3450 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3455 case CE_FocusFrame: {
3478 case CE_MenuEmptyArea:
3482 case CE_MenuHMargin:
3483 case CE_MenuVMargin:
3484 case CE_MenuTearoff:
3485 case CE_MenuScroller:
3486 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3487 const bool active = mi->state & State_Selected;
3489 p->fillRect(mi->rect, mi->palette.highlight());
3491 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3493 if (ce == CE_MenuTearoff) {
3494 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3495 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3496 mi->rect.x() + mi->rect.width() - 4,
3497 mi->rect.y() + mi->rect.height() / 2 - 1);
3498 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3499 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3500 mi->rect.x() + mi->rect.width() - 4,
3501 mi->rect.y() + mi->rect.height() / 2);
3502 }
else if (ce == CE_MenuScroller) {
3503 const QSize scrollerSize = QSize(10, 8);
3504 const int scrollerVOffset = 5;
3505 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3506 const int right = left + scrollerSize.width();
3509 if (opt->state & State_DownArrow) {
3510 bottom = mi->rect.y() + scrollerVOffset;
3511 top = bottom + scrollerSize.height();
3513 bottom = mi->rect.bottom() - scrollerVOffset;
3514 top = bottom - scrollerSize.height();
3517 p->setRenderHint(QPainter::Antialiasing);
3519 path.moveTo(left, bottom);
3520 path.lineTo(right, bottom);
3521 path.lineTo((left + right) / 2, top);
3522 p->fillPath(path, opt->palette.buttonText());
3524 }
else if (ce != CE_MenuItem) {
3528 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3529 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3530 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3531 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3535 const int maxpmw = mi->maxIconWidth;
3536 const bool enabled = mi->state & State_Enabled;
3538 int xpos = mi->rect.x() + 18;
3539 int checkcol = maxpmw;
3541 p->setPen(mi->palette.text().color());
3543 p->setPen(mi->palette.highlightedText().color());
3545 p->setPen(mi->palette.buttonText().color());
3548 QStyleOption checkmarkOpt;
3554 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3556 checkmarkOpt.state.setFlag(State_On, active);
3557 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3558 if (widgetSize == QStyleHelper::SizeMini)
3559 checkmarkOpt.state |= State_Mini;
3560 else if (widgetSize == QStyleHelper::SizeSmall)
3561 checkmarkOpt.state |= State_Small;
3564 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3565 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3567 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3569 if (!mi->icon.isNull()) {
3570 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
3573 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3574 QSize iconSize(smallIconSize, smallIconSize);
3580 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3581 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3582 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3583 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3584 QRect pmr(0, 0, pixw, pixh);
3585 pmr.moveCenter(cr.center());
3586 p->drawPixmap(pmr.topLeft(), pixmap);
3590 QString s = mi->text;
3591 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3592 | Qt::TextSingleLine | Qt::AlignAbsolute;
3593 int yPos = mi->rect.y();
3594 if (widgetSize == QStyleHelper::SizeMini)
3597 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3598 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3600 QString rightMarginText;
3602 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
3605 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
3606 if (tabIndex >= 0) {
3608 rightMarginText = s.mid(tabIndex + 1);
3609 s = s.left(tabIndex);
3613 if (!rightMarginText.isEmpty()) {
3618 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3623 QFont myFont = mi->font;
3629 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3634 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3635 Q_ASSERT(fontEngine);
3636 if (fontEngine->type() == QFontEngine::Multi) {
3637 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
3638 Q_ASSERT(fontEngine);
3640 if (fontEngine->type() == QFontEngine::Mac) {
3641 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3644 const auto pc = p->pen().color();
3645 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3650 s = qt_mac_removeMnemonics(s);
3652 QMacCGContext cgCtx(p);
3653 d->setupNSGraphicsContext(cgCtx, YES);
3659 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3660 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3661 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3663 d->restoreNSGraphicsContext(cgCtx);
3666 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3667 mi->rect.height(), text_flags, s);
3673 case CE_MenuBarItem:
3674 case CE_MenuBarEmptyArea:
3675 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3676 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3677 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3678 p->fillRect(mi->rect, bg);
3680 if (ce != CE_MenuBarItem)
3683 if (!mi->icon.isNull()) {
3684 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3685 drawItemPixmap(p, mi->rect,
3686 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3687 | Qt::TextSingleLine,
3688 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3689 opt->window->devicePixelRatio(),
3690 (mi->state & State_Enabled) ? QIcon::Normal
3691 : QIcon::Disabled));
3693 drawItemText(p, mi->rect,
3694 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3695 | Qt::TextSingleLine,
3696 mi->palette, mi->state & State_Enabled,
3697 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3701 case CE_ProgressBarLabel:
3702 case CE_ProgressBarContents:
3704 case CE_ProgressBarGroove:
3705 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
3706 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3707 const bool inverted = pb->invertedAppearance;
3708 bool reverse = pb->direction == Qt::RightToLeft;
3712 QRect rect = pb->rect;
3713 const CGRect cgRect = rect.toCGRect();
3715 const auto aquaSize = d->aquaSizeConstrain(opt);
3718 QIndeterminateProgressIndicator *ipi = nil;
3720 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3721 if (isIndeterminate) {
3740 d->setupNSGraphicsContext(cg, NO);
3741 d->setupVerticalInvertedXform(cg, reverse,
false, cgRect);
3742 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3743 d->restoreNSGraphicsContext(cg);
3751 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3752 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3753 QMacAutoReleasePool pool;
3754 d->setupVerticalInvertedXform(ctx, reverse,
false, rect);
3755 pi.minValue = pb->minimum;
3756 pi.maxValue = pb->maximum;
3757 pi.doubleValue = pb->progress;
3796 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3797 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3800 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
3801 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
3802 sv.frame = opt->rect.toCGRect();
3803 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3804 QMacAutoReleasePool pool;
3805 [sv drawDividerInRect:rect];
3808 QPen oldPen = p->pen();
3809 p->setPen(opt->palette.dark().color());
3810 if (opt->state & QStyle::State_Horizontal)
3811 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3813 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3818 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
3819 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
3820 if (!rubber->opaque) {
3823 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3824 fillColor.setHsvF(0, 0, 0.53, 0.25);
3825 if (opt->rect.width() * opt->rect.height() <= 3) {
3826 p->fillRect(opt->rect, strokeColor);
3828 QPen oldPen = p->pen();
3829 QBrush oldBrush = p->brush();
3830 QPen pen(strokeColor);
3832 p->setBrush(fillColor);
3833 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3834 if (adjusted.isValid())
3835 p->drawRect(adjusted);
3837 p->setBrush(oldBrush);
3840 p->fillRect(opt->rect, fillColor);
3879 QLinearGradient linearGrad;
3880 if (opt->state & State_Horizontal)
3881 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3883 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3885 QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
3886 QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
3888 linearGrad.setColorAt(0, mainWindowGradientBegin);
3889 linearGrad.setColorAt(1, mainWindowGradientEnd);
3890 p->fillRect(opt->rect, linearGrad);
3893 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3894 if (opt->state & State_Horizontal) {
3895 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3896 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3897 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3898 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3900 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3901 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3902 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3903 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3909 QCommonStyle::drawControl(ce, opt, p);
3916 if (dir == Qt::RightToLeft) {
3917 rect->adjust(-right, top, -left, bottom);
3919 rect->adjust(left, top, right, bottom);
3925 Q_D(
const QMacStyle);
3927 const int controlSize = getControlSize(opt);
3930 case SE_ItemViewItemText:
3931 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
3932 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
3934 rect = QCommonStyle::subElementRect(sr, opt);
3935 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3936 rect.adjust(-fw, 0, 0, 0);
3939 case SE_ToolBoxTabContents:
3940 rect = QCommonStyle::subElementRect(sr, opt);
3942 case SE_PushButtonContents:
3952 const auto ct = cocoaControlType(btn);
3953 const auto cs = d->effectiveAquaSizeConstrain(btn);
3955 auto frameRect = cw.adjustedControlFrame(btn->rect);
3956 frameRect -= cw.titleMargins();
3957 rect = frameRect.toRect();
3960 case SE_HeaderLabel: {
3961 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3962 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3963 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3964 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3966 if (header->sortIndicator != QStyleOptionHeader::None) {
3967 if (opt->state & State_Horizontal)
3973 rect = visualRect(opt->direction, opt->rect, rect);
3976 case SE_HeaderArrow: {
3977 int h = opt->rect.height();
3978 int w = opt->rect.width();
3979 int x = opt->rect.x();
3980 int y = opt->rect.y();
3981 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3983 if (opt->state & State_Horizontal) {
3990 rect = visualRect(opt->direction, opt->rect, rect);
3993 case SE_ProgressBarGroove:
3997 case SE_ProgressBarLabel:
3999 case SE_ProgressBarContents:
4002 case SE_TreeViewDisclosureItem: {
4008 case SE_TabWidgetLeftCorner:
4009 if (
const QStyleOptionTabWidgetFrame *twf
4010 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4011 switch (twf->shape) {
4012 case QStyleOptionTab::RoundedNorth:
4013 case QStyleOptionTab::TriangularNorth:
4014 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4016 case QStyleOptionTab::RoundedSouth:
4017 case QStyleOptionTab::TriangularSouth:
4018 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4019 twf->leftCornerWidgetSize);
4024 rect = visualRect(twf->direction, twf->rect, rect);
4027 case SE_TabWidgetRightCorner:
4028 if (
const QStyleOptionTabWidgetFrame *twf
4029 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4030 switch (twf->shape) {
4031 case QStyleOptionTab::RoundedNorth:
4032 case QStyleOptionTab::TriangularNorth:
4033 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4034 twf->rightCornerWidgetSize);
4036 case QStyleOptionTab::RoundedSouth:
4037 case QStyleOptionTab::TriangularSouth:
4038 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4039 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4040 twf->rightCornerWidgetSize);
4045 rect = visualRect(twf->direction, twf->rect, rect);
4048 case SE_TabWidgetTabContents:
4049 rect = QCommonStyle::subElementRect(sr, opt);
4050 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4051 if (twf->lineWidth != 0) {
4052 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4053 case QMacStylePrivate::North:
4054 rect.adjust(+1, +14, -1, -1);
4056 case QMacStylePrivate::South:
4057 rect.adjust(+1, +1, -1, -14);
4059 case QMacStylePrivate::West:
4060 rect.adjust(+14, +1, -1, -1);
4062 case QMacStylePrivate::East:
4063 rect.adjust(+1, +1, -14, -1);
4068 case SE_TabBarTabText:
4069 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4070 QRect dummyIconRect;
4071 d->tabLayout(tab, &rect, &dummyIconRect);
4074 case SE_TabBarTabLeftButton:
4075 case SE_TabBarTabRightButton:
4076 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4077 bool selected = tab->state & State_Selected;
4078 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4079 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4082 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4083 || tab->shape == QStyleOptionTab::RoundedWest
4084 || tab->shape == QStyleOptionTab::TriangularEast
4085 || tab->shape == QStyleOptionTab::TriangularWest;
4087 QRect tr = tab->rect;
4088 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4089 verticalShift = -verticalShift;
4091 qSwap(horizontalShift, verticalShift);
4092 horizontalShift *= -1;
4093 verticalShift *= -1;
4095 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4096 horizontalShift = -horizontalShift;
4098 tr.adjust(0, 0, horizontalShift, verticalShift);
4101 tr.setBottom(tr.bottom() - verticalShift);
4102 tr.setRight(tr.right() - horizontalShift);
4105 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4106 int w = size.width();
4107 int h = size.height();
4108 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4109 int midWidth = ((tr.width() - w) / 2);
4111 bool atTheTop =
true;
4112 switch (tab->shape) {
4113 case QStyleOptionTab::RoundedWest:
4114 case QStyleOptionTab::TriangularWest:
4115 atTheTop = (sr == SE_TabBarTabLeftButton);
4117 case QStyleOptionTab::RoundedEast:
4118 case QStyleOptionTab::TriangularEast:
4119 atTheTop = (sr == SE_TabBarTabRightButton);
4122 if (sr == SE_TabBarTabLeftButton)
4123 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4125 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4126 rect = visualRect(tab->direction, tab->rect, rect);
4130 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4132 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4136 case SE_LineEditContents: {
4138 int leftPadding = 4;
4139 int rightPadding = 4;
4141 int bottomPadding = 0;
4143 if (opt->state & QStyle::State_Small) {
4145 }
else if (opt->state & QStyle::State_Mini) {
4149 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4150 opt->rect.height() - topPadding - bottomPadding);
4152 case SE_CheckBoxLayoutItem:
4154 if (controlSize == QStyleHelper::SizeLarge) {
4155 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4156 }
else if (controlSize == QStyleHelper::SizeSmall) {
4157 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4159 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4162 case SE_SearchFieldLayoutItem:
4163 if (qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4164 if (qt_apple_runningWithLiquidGlass()) {
4166 opt->rect.adjusted(2, 4, -2, -4),
4167 opt->rect.adjusted(2, 3, -2, -2),
4168 opt->rect.adjusted(2, 3, -2, -2));
4171 opt->rect.adjusted(2, 6, -2, -6),
4172 opt->rect.adjusted(2, 3, -2, -2),
4173 opt->rect.adjusted(2, 3, -2, -2));
4177 case SE_ComboBoxLayoutItem:
4178 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4187 if (combo->editable) {
4188 if (qt_apple_runningWithLiquidGlass()) {
4190 opt->rect.adjusted(4, 4, -4, -4),
4191 opt->rect.adjusted(4, 4, -5, -7),
4192 opt->rect.adjusted(5, 4, -4, -6));
4195 opt->rect.adjusted(5, 6, -6, -7),
4196 opt->rect.adjusted(4, 4, -5, -7),
4197 opt->rect.adjusted(5, 4, -4, -6));
4200 if (qt_apple_runningWithLiquidGlass()) {
4202 opt->rect.adjusted(4, 4, -4, -4),
4203 opt->rect.adjusted(6, 7, -6, -5),
4204 opt->rect.adjusted(9, 5, -5, -7));
4207 opt->rect.adjusted(6, 4, -7, -7),
4208 opt->rect.adjusted(6, 7, -6, -5),
4209 opt->rect.adjusted(9, 5, -5, -7));
4214 case SE_LabelLayoutItem:
4216 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4218 case SE_ProgressBarLayoutItem:
4219 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4220 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4223 if (isIndeterminate) {
4224 rect.adjust(1, 2, -1, -2);
4226 rect.adjust(1, 1, -1, -2);
4230 case SE_PushButtonLayoutItem:
4233 if ((buttonOpt->features & QStyleOptionButton::Flat))
4236 if (qt_apple_runningWithLiquidGlass()) {
4238 opt->rect.adjusted(2, 5, -2, -7),
4239 opt->rect.adjusted(6, 6, -6, -6),
4240 opt->rect.adjusted(6, 5, -6, -6));
4243 opt->rect.adjusted(7, 5, -7, -7),
4244 opt->rect.adjusted(6, 6, -6, -6),
4245 opt->rect.adjusted(6, 5, -6, -6));
4248 case SE_SpinBoxLayoutItem:
4250 opt->rect.adjusted(2, 3, -2, -2),
4251 opt->rect.adjusted(2, 3, -2, -2),
4252 opt->rect.adjusted(2, 3, -2, -2));
4254 case SE_RadioButtonLayoutItem:
4256 opt->rect.adjusted(2, 2, -3, -2),
4257 opt->rect.adjusted(2, 2, -3, -2),
4258 opt->rect.adjusted(1, 2, -3, -2));
4260 case SE_SliderLayoutItem:
4261 if (
const QStyleOptionSlider *sliderOpt
4262 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4264 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4265 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4266 rect.adjust(3, 3, -3, -3);
4268 rect.adjust(3, 0, -3, 0);
4272 case SE_ScrollBarLayoutItem:
4273 if (qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4276 case SE_FrameLayoutItem:
4292 case SE_GroupBoxLayoutItem:
4294 if (
const QStyleOptionGroupBox *groupBoxOpt =
4295 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4297
4298
4299
4300
4301 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4302 | QStyle::SC_GroupBoxLabel)) {
4304 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4305 delta =
SIZE(8, 4, 4);
4307 delta =
SIZE(15, 12, 12);
4309 rect.setTop(rect.top() + delta);
4312 rect.setBottom(rect.bottom() - 1);
4314 case SE_TabWidgetLayoutItem:
4315 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4316 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4318
4319
4320
4321
4322 rect = tabWidgetOpt->rect;
4323 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4324 rect.setTop(rect.top() +
SIZE(6 , 3 , 2 ));
4327 case SE_DockWidgetCloseButton:
4328 case SE_DockWidgetFloatButton:
4329 case SE_DockWidgetTitleBarText:
4330 case SE_DockWidgetIcon: {
4331 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
4332 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
4333 QRect srect = opt->rect;
4335 const QStyleOptionDockWidget *dwOpt
4336 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4337 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4338 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4340 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4344 if (verticalTitleBar)
4345 srect = srect.transposed();
4348 int right = srect.right();
4349 int left = srect.left();
4353 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4354 opt).actualSize(QSize(iconSize, iconSize));
4355 sz += QSize(buttonMargin, buttonMargin);
4356 if (verticalTitleBar)
4357 sz = sz.transposed();
4358 closeRect = QRect(left,
4359 srect.center().y() - sz.height()/2,
4360 sz.width(), sz.height());
4361 left = closeRect.right() + 1;
4363 if (sr == SE_DockWidgetCloseButton) {
4370 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4371 opt).actualSize(QSize(iconSize, iconSize));
4372 sz += QSize(buttonMargin, buttonMargin);
4373 if (verticalTitleBar)
4374 sz = sz.transposed();
4375 floatRect = QRect(left,
4376 srect.center().y() - sz.height()/2,
4377 sz.width(), sz.height());
4378 left = floatRect.right() + 1;
4380 if (sr == SE_DockWidgetFloatButton) {
4400 if (sr == SE_DockWidgetIcon) {
4405 QRect textRect = QRect(left, srect.top(),
4406 right - left, srect.height());
4407 if (sr == SE_DockWidgetTitleBarText) {
4413 if (verticalTitleBar) {
4414 rect = QRect(srect.left() + rect.top() - srect.top(),
4415 srect.top() + srect.right() - rect.right(),
4416 rect.height(), rect.width());
4418 rect = visualRect(opt->direction, srect, rect);
4423 rect = QCommonStyle::subElementRect(sr, opt);
4431 Q_Q(
const QMacStyle);
4432 QStyleOption arrowOpt = *opt;
4437 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4442 CGContextSaveGState(cg);
4443 [NSGraphicsContext saveGraphicsState];
4445 [NSGraphicsContext setCurrentContext:
4446 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4451 [NSGraphicsContext restoreGraphicsState];
4452 CGContextRestoreGState(cg);
4457 Q_D(
const QMacStyle);
4459 QMacCGContext cg(p);
4460 d->resolveCurrentNSView(opt->window);
4464 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4466 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4467 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4468 if (!drawTrack && !drawKnob)
4471 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4473 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
4474 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4476 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4477 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4479 const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
4482 bool wasActive =
false;
4483 CGFloat opacity = 0.0;
4484 CGFloat expandScale = 1.0;
4485 CGFloat expandOffset = 0.0;
4486 bool shouldExpand =
false;
4488 if (QObject *styleObject = opt->styleObject) {
4489 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
4490 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
4491 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
4492 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
4493 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
4494 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
4498 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4501 oldPos != sb->sliderPosition ||
4502 oldMin != sb->minimum ||
4503 oldMax != sb->maximum ||
4504 oldRect != sb->rect ||
4505 oldState != sb->state ||
4506 oldActiveControls != sb->activeSubControls) {
4512 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
4513 styleObject->setProperty(
"_q_stylemin", sb->minimum);
4514 styleObject->setProperty(
"_q_stylemax", sb->maximum);
4515 styleObject->setProperty(
"_q_stylerect", sb->rect);
4516 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
4517 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
4545 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4563 d->setupNSGraphicsContext(cg, NO );
4567 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
4569 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
4570 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4574 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4576 scroller.knobStyle = NSScrollerKnobStyleDefault;
4579 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4581 if (!setupScroller(scroller, sb))
4585 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
4586 CGContextSetAlpha(cg, opacity);
4591 if (!isTransient || opt->activeSubControls || wasActive) {
4592 CGRect trackRect = scroller.bounds;
4594 trackRect.origin.y += expandOffset;
4596 trackRect.origin.x += expandOffset;
4597 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4607 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4608 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4610 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4611 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4612 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4613 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4614 const CGFloat knobRadius = knobWidth / 2.0;
4617 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4619 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4620 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
4621 CGContextAddPath(cg, knobPath);
4622 CGContextSetAlpha(cg, 0.5);
4623 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4624 CGContextSetFillColorWithColor(cg, knobColor);
4625 CGContextFillPath(cg);
4627 [scroller drawKnob];
4629 if (!isTransient && opt->state & State_Sunken) {
4634 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4635 [scroller drawKnob];
4641 CGContextEndTransparencyLayer(cg);
4643 d->restoreNSGraphicsContext(cg);
4647 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4648 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4650 const auto cs = d->effectiveAquaSizeConstrain(opt);
4652 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
4653 if (!setupSlider(slider, sl))
4656 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4657 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4658 const bool drawKnob = sl->subControls & SC_SliderHandle;
4659 const bool drawBar = sl->subControls & SC_SliderGroove;
4660 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4661 const bool isPressed = sl->state & State_Sunken;
4664 if (isPressed && drawKnob) {
4665 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4666 pressPoint.x = CGRectGetMidX(knobRect);
4667 pressPoint.y = CGRectGetMidY(knobRect);
4668 [slider.cell startTrackingAt:pressPoint inView:slider];
4671 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef,
const CGRect &) {
4674 NSSliderCell *cell = slider.cell;
4677 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4683 [cell drawBarInside:barRect flipped:!isHorizontal];
4686 if (drawBar && hasTicks && drawTicks) {
4687 if (!hasDoubleTicks) {
4688 [cell drawTickMarks];
4690 if (sl->orientation == Qt::Horizontal) {
4691 slider.tickMarkPosition = NSTickMarkPositionAbove;
4692 [slider layoutSubtreeIfNeeded];
4693 [cell drawTickMarks];
4694 slider.tickMarkPosition = NSTickMarkPositionBelow;
4695 [slider layoutSubtreeIfNeeded];
4696 [cell drawTickMarks];
4698 slider.tickMarkPosition = NSTickMarkPositionLeading;
4699 [slider layoutSubtreeIfNeeded];
4700 [cell drawTickMarks];
4701 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4702 [slider layoutSubtreeIfNeeded];
4703 [cell drawTickMarks];
4712 if (isPressed && drawKnob)
4713 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4717 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
4718 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4719 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4720 QStyleOptionFrame frame;
4721 static_cast<QStyleOption &>(frame) = *opt;
4722 frame.rect = lineEditRect;
4723 frame.state |= State_Sunken;
4724 frame.lineWidth = 1;
4725 frame.midLineWidth = 0;
4726 frame.features = QStyleOptionFrame::None;
4727 frame.frameShape = QStyleOptionFrame::Box;
4728 drawPrimitive(PE_FrameLineEdit, &frame, p);
4730 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4731 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4732 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
4734 d->setupNSGraphicsContext(cg, NO);
4736 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4738 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
4739 cell.enabled = (sb->state & State_Enabled);
4740 const auto controlSize = cell.controlSize;
4741 if (qt_apple_runningWithLiquidGlass())
4742 cell.controlSize = NSControlSizeMini;
4744 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4746 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4747 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4748 const CGFloat x = CGRectGetMidX(newRect);
4749 const CGFloat y = upPressed ? -3 : 3;
4750 const CGPoint pressPoint = CGPointMake(x, y);
4753 if (upPressed || downPressed)
4754 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4756 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4758 if (upPressed || downPressed)
4759 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4761 d->restoreNSGraphicsContext(cg);
4762 if (qt_apple_runningWithLiquidGlass())
4763 cell.controlSize = controlSize;
4768 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4769 const bool isEnabled = combo->state & State_Enabled;
4770 const bool isPressed = combo->state & State_Sunken;
4772 const auto ct = cocoaControlType(combo);
4773 const auto cs = d->effectiveAquaSizeConstrain(combo);
4775 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4776 cc.enabled = isEnabled;
4777 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4780 auto *pb =
static_cast<NSPopUpButton *>(cc);
4782 if (cw.size == QStyleHelper::SizeSmall) {
4783 frameRect = frameRect.translated(0, 1);
4784 }
else if (cw.size == QStyleHelper::SizeMini) {
4786 frameRect = frameRect.translated(2, -0.5);
4788 pb.frame = frameRect.toCGRect();
4789 [pb highlight:isPressed];
4790 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4791 QMacAutoReleasePool pool;
4792 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4796 auto *cb =
static_cast<NSComboBox *>(cc);
4797 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4798 cb.frame = frameRect.toCGRect();
4801 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4802 cell.highlighted = isPressed;
4807 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4809 QMacAutoReleasePool pool;
4810 [cb.cell drawWithFrame:r inView:cb];
4815 case CC_SearchField:
4816 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4817 const bool isEnabled = sf->state & State_Enabled;
4819 const auto cs = d->effectiveAquaSizeConstrain(sf);
4821 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4822 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4824 searchField.enabled = isEnabled;
4831 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4832 if (
__builtin_available(macOS 26, *)) {
4833 NSButtonCell *btn = cell.searchButtonCell;
4834 NSImageSymbolConfiguration *imgCfg =
4835 [NSImageSymbolConfiguration configurationWithPointSize:11
4836 weight:NSFontWeightMedium
4837 scale:NSImageSymbolScaleMedium];
4838 btn.image = [btn.image imageWithSymbolConfiguration:imgCfg];
4839 [btn.image setTemplate:YES];
4840 btn.imageScaling = NSImageScaleNone;
4844 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4846 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4847 if (
__builtin_available(macOS 26, *)) {
4848 const auto oneDevicePx = 1.0 / p->device()->devicePixelRatioF();
4849 frameRect = frameRect.adjusted(+oneDevicePx, -oneDevicePx, -oneDevicePx, +oneDevicePx);
4853 searchField.frame = frameRect.toCGRect();
4855 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4857 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4858 [cell drawWithFrame:rect inView:searchField];
4859 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4861 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4862 [cell drawWithFrame:rect inView:searchField];
4865 [cell setStringValue:sf->text.toNSString()];
4866 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4867 [cell drawWithFrame:r inView:searchField];
4873 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4874 const bool isActive = (titlebar->state & State_Active)
4875 && (titlebar->titleBarState & State_Active);
4877 p->fillRect(opt->rect, Qt::transparent);
4878 p->setRenderHint(QPainter::Antialiasing);
4879 p->setClipRect(opt->rect, Qt::IntersectClip);
4883 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4884 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4885 p->fillPath(outerFramePath, opt->palette.dark());
4887 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4888 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4889 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4890 p->fillPath(innerFramePath, opt->palette.button());
4892 if (titlebar->subControls & (SC_TitleBarCloseButton
4893 | SC_TitleBarMaxButton
4894 | SC_TitleBarMinButton
4895 | SC_TitleBarNormalButton)) {
4896 const bool isHovered = (titlebar->state & State_MouseOver);
4897 static const SubControl buttons[] = {
4898 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4900 for (
const auto sc : buttons) {
4901 const auto ct = d->windowButtonCocoaControl(sc);
4902 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4903 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4904 wb.enabled = (sc & titlebar->subControls) && isActive;
4905 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4906 Q_UNUSED(isHovered);
4908 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4909 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4910 QMacAutoReleasePool pool;
4911 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4912 [wbCell drawWithFrame:rect inView:wb];
4917 if (titlebar->subControls & SC_TitleBarLabel) {
4918 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4919 if (!titlebar->icon.isNull()) {
4920 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4921 const auto iconSize = QSize(iconExtent, iconExtent);
4922 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4924 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4925 p->drawPixmap(iconPos, tr.y(),
4926 titlebar->icon.pixmap(iconSize,
4927 opt->window->devicePixelRatio(),
4931 if (!titlebar->text.isEmpty())
4932 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4937 if (
const QStyleOptionGroupBox *gb
4938 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4940 QStyleOptionGroupBox groupBox(*gb);
4941 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4943 groupBox.state |= QStyle::State_Mini;
4945 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4951 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4966 if (
const QStyleOptionToolButton *tb
4967 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4968#ifndef QT_NO_ACCESSIBILITY
4969 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4970 if (tb->subControls & SC_ToolButtonMenu) {
4971 QStyleOption arrowOpt = *tb;
4972 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4973 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4974 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4975 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4976 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4977 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4978 d->drawToolbarButtonArrow(tb, p);
4980 if (tb->state & State_On) {
4981 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4984 isKey = [view.window isKeyWindow];
4988 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4989 p->setRenderHint(QPainter::Antialiasing);
4990 p->fillPath(path, brush);
4992 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4996 auto bflags = tb->state;
4997 if (tb->subControls & SC_ToolButton)
4998 bflags |= State_Sunken;
4999 auto mflags = tb->state;
5000 if (tb->subControls & SC_ToolButtonMenu)
5001 mflags |= State_Sunken;
5003 if (tb->subControls & SC_ToolButton) {
5004 if (bflags & (State_Sunken | State_On | State_Raised)) {
5005 const bool isEnabled = tb->state & State_Enabled;
5006 const bool isPressed = tb->state & State_Sunken;
5007 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5009 const auto cs = d->effectiveAquaSizeConstrain(opt);
5011 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5012 pb.bezelStyle = NSBezelStyleShadowlessSquare;
5013 pb.frame = opt->rect.toCGRect();
5014 pb.buttonType = NSButtonTypePushOnPushOff;
5015 pb.enabled = isEnabled;
5016 [pb highlight:isPressed];
5017 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5018 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
5019 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5020 QMacAutoReleasePool pool;
5021 [pb.cell drawBezelWithFrame:rect inView:pb];
5026 if (tb->subControls & SC_ToolButtonMenu) {
5027 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
5028 QStyleOption arrowOpt = *tb;
5033 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
5034 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
5035 d->drawToolbarButtonArrow(tb, p);
5037 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
5038 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
5039 QStyleOptionToolButton label = *tb;
5040 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5041 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
5046 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
5047 QStyleHelper::drawDial(dial, p);
5050 QCommonStyle::drawComplexControl(cc, opt, p);
5057 Q_D(
const QMacStyle);
5059 SubControl sc = QStyle::SC_None;
5063 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5064 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5065 if (!cmb->editable && sc != QStyle::SC_None)
5066 sc = SC_ComboBoxArrow;
5070 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5071 if (!sl->rect.contains(pt))
5074 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5075 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5077 const auto cs = d->effectiveAquaSizeConstrain(opt);
5079 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5080 if (!setupSlider(slider, sl))
5083 NSSliderCell *cell = slider.cell;
5084 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5085 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5086 if (knobRect.contains(pt)) {
5087 sc = SC_SliderHandle;
5088 }
else if (barRect.contains(pt)) {
5089 sc = SC_SliderGroove;
5090 }
else if (hasTicks) {
5091 sc = SC_SliderTickmarks;
5096 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5097 if (!sb->rect.contains(pt)) {
5102 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5104 const auto cs = d->effectiveAquaSizeConstrain(opt);
5106 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5107 if (!setupScroller(scroller, sb)) {
5115 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5117 const bool isReverse = sb->direction == Qt::RightToLeft;
5118 if (pt.x() < knobRect.left())
5119 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5120 else if (pt.x() > knobRect.right())
5121 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5123 sc = SC_ScrollBarSlider;
5125 if (pt.y() < knobRect.top())
5126 sc = SC_ScrollBarSubPage;
5127 else if (pt.y() > knobRect.bottom())
5128 sc = SC_ScrollBarAddPage;
5130 sc = SC_ScrollBarSlider;
5134 case CC_SearchField:
5135 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5136 if (!sf->rect.contains(pt))
5139 const auto cs = d->effectiveAquaSizeConstrain(sf);
5141 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5142 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5144 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5145 const CGRect bounds = searchField.bounds;
5147 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5148 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5149 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5151 const QPointF localPt = pt - sf->rect.topLeft();
5153 if (cancelRect.contains(localPt))
5154 sc = SC_SearchFieldClear;
5155 else if (searchIconRect.contains(localPt))
5156 sc = SC_SearchFieldSearch;
5157 else if (textFieldRect.contains(localPt))
5158 sc = SC_SearchFieldEditField;
5160 sc = SC_SearchFieldPopup;
5166 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5174 Q_D(
const QMacStyle);
5180 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5181 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5182 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5184 NSScrollerPart part = NSScrollerNoPart;
5185 if (sc == SC_ScrollBarSlider) {
5186 part = NSScrollerKnob;
5187 }
else if (sc == SC_ScrollBarGroove) {
5188 part = NSScrollerKnobSlot;
5189 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5190 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5191 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5192 part = NSScrollerDecrementPage;
5194 part = NSScrollerIncrementPage;
5198 if (part != NSScrollerNoPart) {
5200 const auto cs = d->effectiveAquaSizeConstrain(opt);
5202 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5203 if (setupScroller(scroller, sb))
5204 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5209 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5210 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5211 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5213 const auto cs = d->effectiveAquaSizeConstrain(opt);
5215 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5216 if (!setupSlider(slider, sl))
5219 NSSliderCell *cell = slider.cell;
5220 if (sc == SC_SliderHandle) {
5221 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5222 }
else if (sc == SC_SliderGroove) {
5223 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5224 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5225 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5227 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5229 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5240 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5246 if (sc == SC_TitleBarLabel) {
5247 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5248 qreal labelHeight = titlebar->fontMetrics.height();
5250 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5251 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5252 if (!titlebar->icon.isNull()) {
5253 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5254 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5255 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5258 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5259 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5260 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5261 labelWidth, labelHeight);
5263 const auto currentButton = d->windowButtonCocoaControl(sc);
5267 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5270 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5271 QStyleHelper::SizeLarge);
5272 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5273 if (ct == currentButton)
5274 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5276 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5279 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5280 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5285 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5286 const auto ct = cocoaControlType(combo);
5287 const auto cs = d->effectiveAquaSizeConstrain(combo);
5296 case QStyleHelper::SizeLarge:
5297 if (qt_apple_runningWithLiquidGlass())
5298 editRect = combo->rect.adjusted(15, 7, -25, -7);
5300 editRect = combo->rect.adjusted(15, 7, -25, -9);
5302 case QStyleHelper::SizeSmall:
5303 if (combo->editable)
5304 editRect = combo->rect.adjusted(15, 6, -22, -9);
5306 editRect = combo->rect.adjusted(15, 8, -22, -6);
5309 if (combo->editable)
5310 editRect = combo->rect.adjusted(15, 6, -20, -7);
5312 editRect = combo->rect.adjusted(15, 5, -22, -6);
5317 case SC_ComboBoxEditField:{
5318 ret = editRect.toAlignedRect();
5320 case SC_ComboBoxArrow:{
5321 ret = editRect.toAlignedRect();
5322 ret.setX(ret.x() + ret.width());
5323 ret.setWidth(combo->rect.right() - ret.right());
5325 case SC_ComboBoxListBoxPopup:{
5326 if (combo->editable) {
5327 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5328 const int comboTop = combo->rect.top();
5329 ret = QRect(qRound(inner.origin.x),
5331 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5332 editRect.bottom() - comboTop + 2);
5334 ret = QRect(combo->rect.x() + 4 - 11,
5335 combo->rect.y() + 1,
5336 editRect.width() + 10 + 11,
5346 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5347 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5348 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5349 bool hasNoText = !checkable && groupBox->text.isEmpty();
5351 case SC_GroupBoxLabel:
5352 case SC_GroupBoxCheckBox: {
5354 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5355 const bool fontIsSet =
false;
5358 const int margin = flat || hasNoText ? 0 : 9;
5359 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5361 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5362 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5363 const int tw = qCeil(s.width());
5364 const int h = qCeil(fm.height());
5367 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5369 if (flat && checkable)
5370 labelRect.moveLeft(labelRect.left() + 4);
5371 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5372 bool rtl = groupBox->direction == Qt::RightToLeft;
5373 if (sc == SC_GroupBoxLabel) {
5375 int newSum = indicatorWidth + 1;
5376 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5377 labelRect.moveLeft(newLeft);
5379 labelRect.moveTop(labelRect.top() + 3);
5381 labelRect.moveTop(labelRect.top() + 4);
5383 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5384 labelRect.moveLeft(newLeft);
5385 labelRect.moveTop(labelRect.top() + 3);
5387 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5388 labelRect.moveLeft(newLeft);
5389 labelRect.moveTop(labelRect.top() + 4);
5394 if (sc == SC_GroupBoxCheckBox) {
5395 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5396 int top = flat ? ret.top() + 1 : ret.top() + 5;
5397 ret.setRect(left, top,
5398 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5402 case SC_GroupBoxContents:
5403 case SC_GroupBoxFrame: {
5404 QFontMetrics fm = groupBox->fontMetrics;
5410 yOffset = -qCeil(QFontMetricsF(fm).height());
5411 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5412 if (sc == SC_GroupBoxContents) {
5414 ret.adjust(3, -5, -3, -4);
5416 ret.adjust(3, 3, -3, -4);
5421 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5427 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5428 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5429 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5435 case QStyleHelper::SizeLarge:
5441 case QStyleHelper::SizeSmall:
5447 case QStyleHelper::SizeMini:
5459 case SC_SpinBoxDown: {
5460 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5464 const int x = spin->rect.width() - spinner_w;
5465 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5468 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5469 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5470 ret = QRectF::fromCGRect(outRect).toRect();
5474 ret.setHeight(ret.height() / 2);
5476 case SC_SpinBoxDown:
5477 ret.setY(ret.y() + ret.height() / 2);
5485 ret.translate(0, adjust_y);
5486 ret = visualRect(spin->direction, spin->rect, ret);
5489 case SC_SpinBoxEditField:
5490 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5491 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5492 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5493 ret = visualRect(spin->direction, spin->rect, ret);
5497 ret = QCommonStyle::subControlRect(cc, spin, sc);
5503 ret = QCommonStyle::subControlRect(cc, opt, sc);
5504 if (sc == SC_ToolButtonMenu) {
5505#ifndef QT_NO_ACCESSIBILITY
5506 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5509 ret.adjust(-1, 0, 0, 0);
5512 case CC_SearchField:
5513 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5514 const auto cs = d->effectiveAquaSizeConstrain(sf);
5519 case QStyleHelper::SizeLarge:
5520 editRect = sf->rect.adjusted(16, 0, -22, 0);
5522 case QStyleHelper::SizeSmall:
5523 editRect = sf->rect.adjusted(16, 5, -22, -7);
5526 editRect = sf->rect.adjusted(16, 5, -18, -7);
5530 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5531 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5532 const CGRect bounds = searchField.bounds;
5535 case SC_SearchFieldEditField:{
5536 ret = editRect.toAlignedRect();
5540 case SC_SearchFieldClear: {
5541 const CGRect r = [cell cancelButtonRectForBounds:bounds];
5542 ret = QRectF::fromCGRect(r).toRect();
5543 ret.translate(0, -1);
5544 ret = visualRect(sf->direction, sf->rect, ret);
5545 ret.adjust(-3, -3, 3, 3);
5548 case SC_SearchFieldSearch: {
5549 const CGRect r = [cell searchButtonRectForBounds:bounds];
5550 ret = QRectF::fromCGRect(r).toRect();
5551 ret.translate(0, -1);
5552 ret = visualRect(sf->direction, sf->rect, ret);
5553 ret.adjust(-3, -3, 3, 3);
5556 case SC_SearchFieldPopup: {
5557 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5558 const int searchTop = sf->rect.top();
5559 ret = QRect(qRound(inner.origin.x),
5561 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5562 editRect.bottom() - searchTop + 2);
5571 ret = QCommonStyle::subControlRect(cc, opt, sc);
5579 Q_D(
const QMacStyle);
5582 bool useAquaGuideline =
true;
5586 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5587 if (vopt->subControls == SC_SpinBoxFrame) {
5588 const QSize minimumSize(20, 24);
5589 if (sz.width() < minimumSize.width())
5590 sz.setWidth(minimumSize.width());
5591 if (sz.height() < minimumSize.height())
5592 sz.setHeight(minimumSize.height());
5594 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5595 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5596 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5600 case QStyle::CT_TabWidget:
5603 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5605
5606
5607
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
5635 if (
const QStyleOptionTabWidgetFrame *twf
5636 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5638 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5639 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5641 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5642 if (tabDirection == QMacStylePrivate::North
5643 || tabDirection == QMacStylePrivate::South) {
5644 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5646 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5651 case QStyle::CT_TabBarTab:
5652 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5655 const bool differentFont =
false;
5656 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5657 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5658 || tabDirection == QMacStylePrivate::West;
5660 sz = sz.transposed();
5662 int defaultTabHeight;
5663 const auto cs = d->effectiveAquaSizeConstrain(opt);
5665 case QStyleHelper::SizeLarge:
5666 if (tab->documentMode)
5667 defaultTabHeight = 24;
5669 defaultTabHeight = 21;
5671 case QStyleHelper::SizeSmall:
5672 defaultTabHeight = 18;
5674 case QStyleHelper::SizeMini:
5675 defaultTabHeight = 16;
5681 const bool widthSet = !differentFont && tab->icon.isNull();
5683 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5684 sz.rwidth() = textSize.width();
5685 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5687 sz.rheight() = qMax(defaultTabHeight, sz.height());
5689 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5692 sz = sz.transposed();
5694 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5695 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5697 int widgetWidth = 0;
5698 int widgetHeight = 0;
5700 if (tab->leftButtonSize.isValid()) {
5702 widgetWidth += tab->leftButtonSize.width();
5703 widgetHeight += tab->leftButtonSize.height();
5705 if (tab->rightButtonSize.isValid()) {
5707 widgetWidth += tab->rightButtonSize.width();
5708 widgetHeight += tab->rightButtonSize.height();
5712 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5713 sz.setHeight(sz.height() + widgetHeight + padding);
5716 sz.setWidth(sz.width() + widgetWidth + padding);
5717 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5722 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5724 if (sz.width() < 10)
5726 if (sz.height() < 20)
5730 int leftPadding = 4;
5731 int rightPadding = 4;
5733 int bottomPadding = 0;
5735 if (opt->state & QStyle::State_Small) {
5737 }
else if (opt->state & QStyle::State_Mini) {
5741 sz.rwidth() += leftPadding + rightPadding;
5742 sz.rheight() += topPadding + bottomPadding;
5745 case QStyle::CT_PushButton: {
5746 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5747 if (btn->features & QStyleOptionButton::CommandLinkButton)
5748 return QCommonStyle::sizeFromContents(ct, opt, sz);
5755 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5757 if (macsz.width() != -1)
5758 sz.setWidth(macsz.width());
5762 if (controlSize != QStyleHelper::SizeMini)
5764 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5765 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5766 else if (controlSize == QStyleHelper::SizeMini)
5769 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5772 case QStyle::CT_MenuItem:
5773 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5774 int maxpmw = mi->maxIconWidth;
5776 int h = sz.height();
5782 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5786 h = mi->fontMetrics.height() + 2;
5787 if (!mi->icon.isNull()) {
5796 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5797 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5801 if (mi->text.contains(QLatin1Char(
'\t')))
5803 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5822 case CT_MenuBarItem:
5829 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5830 if (tb->features & QStyleOptionToolButton::Menu)
5834 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5835 const int controlSize = getControlSize(opt);
5838 if (sz.width() < 10)
5841 if (!cb->editable) {
5846 if (controlSize == QStyleHelper::SizeLarge) {
5848 }
else if (controlSize == QStyleHelper::SizeSmall) {
5858 if (controlSize == QStyleHelper::SizeMini)
5861 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5866 case CT_SearchField:
5867 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5868 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5869 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5870 if (sf->subControls == SC_SearchFieldFrame) {
5871 const int controlSize = getControlSize(opt);
5875 if (controlSize == QStyleHelper::SizeLarge) {
5879 }
else if (controlSize == QStyleHelper::SizeSmall) {
5890 if (sz.width() < 60)
5893 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5894 sz.rwidth() += totalIconsSize;
5897 }
else if (sf->subControls == SC_SearchFieldClear) {
5899 }
else if (sf->subControls == SC_SearchFieldSearch) {
5900 return searchButton;
5905 if (proxy() ==
this) {
5908 QStyleHintReturnMask menuMask;
5909 QStyleOption myOption = *opt;
5910 myOption.rect.setSize(sz);
5911 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5912 sz = menuMask.region.boundingRect().size();
5915 case CT_HeaderSection:{
5916 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5917 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5918 if (header->text.contains(QLatin1Char(
'\n')))
5919 useAquaGuideline =
false;
5923 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5924 const int minimumWidth = 24;
5925 const int absoluteHeight = 14;
5926 if (slider->orientation == Qt::Horizontal) {
5927 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5928 sz.setHeight(absoluteHeight);
5930 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5931 sz.setWidth(absoluteHeight);
5935 case CT_ItemViewItem:
5936 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5937 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5938 sz.setHeight(sz.height() + 2);
5942 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5945 if (useAquaGuideline && ct != CT_PushButton) {
5948 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5949 if (macsz.width() != -1)
5950 sz.setWidth(macsz.width());
5951 if (macsz.height() != -1)
5952 sz.setHeight(macsz.height());
5958 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5959 if (combo->editable) {
5960 const auto widgetSize = d->aquaSizeConstrain(opt);
5963 cw.size = widgetSize;
5964 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5965 sz.rwidth() -= qRound(diffRect.size.width);
5966 sz.rheight() -= qRound(diffRect.size.height);
5974 QFont font = QCommonStyle::font(element, state);
5976 if (state & QStyle::State_Small) {
5977 font.setPixelSize(11);
5978 }
else if (state & QStyle::State_Mini) {
5979 font.setPixelSize(9);
5991 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5992 margins = QMargins(10, 0, arrow.width() + 1, -1);
5995 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
6003 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
6005 if(flags & Qt::TextShowMnemonic)
6006 flags |= Qt::TextHideMnemonic;
6007 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6012 switch (standardIcon) {
6014 return QCommonStyle::standardIcon(standardIcon, opt);
6015 case SP_ToolBarHorizontalExtensionButton:
6016 case SP_ToolBarVerticalExtensionButton: {
6017 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
6018 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6019 QPixmap pix2(pixmap.height(), pixmap.width());
6020 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
6021 pix2.fill(Qt::transparent);
6023 p.translate(pix2.width(), 0);
6025 p.drawPixmap(0, 0, pixmap);