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)
1358 NSView *bv = cocoaControls.value(cocoaControl, nil);
1360 switch (cocoaControl
.type) {
1362 NSBox *box = [[NSBox alloc] init];
1365 box.titlePosition = NSNoTitle;
1369 bv = [[QDarkNSBox alloc] init];
1376 NSButton *bc = [[NSButton alloc] init];
1384 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1386 if (cocoaControl.type == Button_PullDown)
1394 const NSWindowButton button = [=] {
1395 switch (cocoaControl
.type) {
1396 case Button_WindowClose:
1397 return NSWindowCloseButton;
1398 case Button_WindowMiniaturize:
1399 return NSWindowMiniaturizeButton;
1400 case Button_WindowZoom:
1401 return NSWindowZoomButton;
1407 const auto styleMask = NSWindowStyleMaskTitled
1408 | NSWindowStyleMaskClosable
1409 | NSWindowStyleMaskMiniaturizable
1410 | NSWindowStyleMaskResizable;
1411 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1416 bv = [[NSSearchField alloc] init];
1419 bv = [[NSComboBox alloc] init];
1421 case ProgressIndicator_Determinate:
1422 bv = [[NSProgressIndicator alloc] init];
1424 case ProgressIndicator_Indeterminate:
1425 bv = [[QIndeterminateProgressIndicator alloc] init];
1427 case Scroller_Horizontal:
1428 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1430 case Scroller_Vertical:
1433 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1435 case Slider_Horizontal:
1436 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1438 case Slider_Vertical:
1441 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1443 case SplitView_Horizontal:
1444 bv = [[NSSplitView alloc] init];
1446 case SplitView_Vertical:
1447 bv = [[QVerticalSplitView alloc] init];
1450 bv = [[NSTextField alloc] init];
1456 if ([bv isKindOfClass:[NSControl
class]]) {
1457 auto *ctrl =
static_cast<NSControl *>(bv);
1458 switch (cocoaControl.size) {
1459 case QStyleHelper::SizeSmall:
1460 ctrl.controlSize = NSControlSizeSmall;
1462 case QStyleHelper::SizeMini:
1463 ctrl.controlSize = NSControlSizeMini;
1470 auto *pi =
static_cast<NSProgressIndicator *>(bv);
1472 switch (cocoaControl.size) {
1473 case QStyleHelper::SizeSmall:
1474 pi.controlSize = NSControlSizeSmall;
1476 case QStyleHelper::SizeMini:
1477 pi.controlSize = NSControlSizeMini;
1484 cocoaControls.insert(cocoaControl, bv);
1487 NSButtonType buttonType;
1488 NSBezelStyle bezelStyle;
1504 NSCell *cell = cocoaCells[cocoaControl];
1506 switch (cocoaControl
.type) {
1508 cell = [[NSStepperCell alloc] init];
1511 NSButtonCell *bc = [[NSButtonCell alloc] init];
1512 bc.buttonType = NSButtonTypeOnOff;
1513 bc.bezelStyle = NSBezelStyleDisclosure;
1521 switch (cocoaControl.size) {
1522 case QStyleHelper::SizeSmall:
1523 cell.controlSize = NSControlSizeSmall;
1525 case QStyleHelper::SizeMini:
1526 cell.controlSize = NSControlSizeMini;
1532 cocoaCells.insert(cocoaControl, cell);
1538void QMacStylePrivate::drawNSViewInRect(NSView *view,
const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock)
const
1540 QMacAutoReleasePool pool;
1541 QMacCGContext ctx(p);
1542 setupNSGraphicsContext(ctx, YES);
1553 view.wantsLayer = YES;
1562 view.frame = rect.toCGRect();
1564 [backingStoreNSView addSubview:view];
1571 const CGRect dirtyRect = rect.toCGRect();
1574 drawRectBlock(ctx, dirtyRect);
1576 [view drawRect:dirtyRect];
1578 [view removeFromSuperviewWithoutNeedingDisplay];
1580 restoreNSGraphicsContext(ctx);
1585 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1590 return new QMacApperanceStyle<QMacStyle, QStyleOption, QStyleOptionComplex>;
1594 : QCommonStyle(*
new QMacStylePrivate)
1596 QMacAutoReleasePool pool;
1598 static QMacNotificationObserver scrollbarStyleObserver(nil,
1599 NSPreferredScrollerStyleDidChangeNotification, []() {
1601 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1603 QEvent event(QEvent::StyleChange);
1604 for (
const auto &o : QMacStylePrivate::scrollBars)
1605 QCoreApplication::sendEvent(o, &event);
1616 for (NSView *b : d->cocoaControls)
1618 d->cocoaControls.clear();
1623 Q_D(
const QMacStyle);
1624 const int controlSize = getControlSize(opt);
1628 case PM_TabCloseIndicatorWidth:
1629 case PM_TabCloseIndicatorHeight:
1632 case PM_ToolBarIconSize:
1633 ret = proxy()->pixelMetric(PM_LargeIconSize);
1635 case PM_FocusFrameVMargin:
1636 case PM_FocusFrameHMargin:
1639 case PM_DialogButtonsSeparator:
1642 case PM_DialogButtonsButtonHeight: {
1644 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1645 if (sz == QSize(-1, -1))
1650 case PM_DialogButtonsButtonWidth: {
1652 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1653 if (sz == QSize(-1, -1))
1659 case PM_MenuBarHMargin:
1663 case PM_MenuBarVMargin:
1667 case PM_MenuBarPanelWidth:
1671 case PM_MenuButtonIndicator:
1675 case QStyle::PM_MenuDesktopFrameWidth:
1679 case PM_CheckBoxLabelSpacing:
1680 case PM_RadioButtonLabelSpacing:
1683 if (opt->state & State_Mini)
1685 if (opt->state & State_Small)
1691 case PM_MenuScrollerHeight:
1694 case PM_DefaultFrameWidth:
1704 if (qstyleoption_cast<
const QStyleOptionComboBox *>(opt) != 0)
1709 case PM_MaximumDragDistance:
1712 case PM_ScrollBarSliderMin:
1715 case PM_SpinBoxFrameWidth:
1718 case PM_ButtonShiftHorizontal:
1719 case PM_ButtonShiftVertical:
1722 case PM_SliderLength:
1728 case PM_SliderControlThickness:
1729 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
1730 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1731 int ticks = sl->tickPosition;
1733 if (ticks & QStyleOptionSlider::TicksAbove)
1735 if (ticks & QStyleOptionSlider::TicksBelow)
1743 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1744 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1748 thick += (space * 2) / (n + 2);
1754 case PM_SmallIconSize:
1755 ret =
int(QStyleHelper::dpiScaled(16., opt));
1758 case PM_LargeIconSize:
1759 ret =
int(QStyleHelper::dpiScaled(32., opt));
1762 case PM_IconViewIconSize:
1763 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1766 case PM_ButtonDefaultIndicator:
1769 case PM_TitleBarHeight: {
1770 NSUInteger style = NSWindowStyleMaskTitled;
1773 ret =
int([NSWindow frameRectForContentRect:NSZeroRect
1774 styleMask:style].size.height);
1776 case QStyle::PM_TabBarTabHSpace:
1777 switch (d->aquaSizeConstrain(opt)) {
1778 case QStyleHelper::SizeLarge:
1779 ret = QCommonStyle::pixelMetric(metric, opt);
1781 case QStyleHelper::SizeSmall:
1784 case QStyleHelper::SizeMini:
1787 case QStyleHelper::SizeDefault:
1788 const QStyleOptionTab *tb = qstyleoption_cast<
const QStyleOptionTab *>(opt);
1789 if (tb && tb->documentMode)
1792 ret = QCommonStyle::pixelMetric(metric, opt);
1796 case PM_TabBarTabVSpace:
1799 case PM_TabBarTabShiftHorizontal:
1800 case PM_TabBarTabShiftVertical:
1803 case PM_TabBarBaseHeight:
1806 case PM_TabBarTabOverlap:
1809 case PM_TabBarBaseOverlap:
1810 switch (d->aquaSizeConstrain(opt)) {
1811 case QStyleHelper::SizeDefault:
1812 case QStyleHelper::SizeLarge:
1815 case QStyleHelper::SizeSmall:
1818 case QStyleHelper::SizeMini:
1823 case PM_ScrollBarExtent: {
1824 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1825 ret =
static_cast<
int>([NSScroller
1826 scrollerWidthForControlSize:
static_cast<NSControlSize>(size)
1827 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1829 case PM_IndicatorHeight: {
1830 switch (d->aquaSizeConstrain(opt)) {
1831 case QStyleHelper::SizeDefault:
1832 case QStyleHelper::SizeLarge:
1835 case QStyleHelper::SizeMini:
1838 case QStyleHelper::SizeSmall:
1843 case PM_IndicatorWidth: {
1844 switch (d->aquaSizeConstrain(opt)) {
1845 case QStyleHelper::SizeDefault:
1846 case QStyleHelper::SizeLarge:
1849 case QStyleHelper::SizeMini:
1852 case QStyleHelper::SizeSmall:
1858 case PM_ExclusiveIndicatorHeight: {
1859 switch (d->aquaSizeConstrain(opt)) {
1860 case QStyleHelper::SizeDefault:
1861 case QStyleHelper::SizeLarge:
1864 case QStyleHelper::SizeMini:
1867 case QStyleHelper::SizeSmall:
1872 case PM_ExclusiveIndicatorWidth: {
1873 switch (d->aquaSizeConstrain(opt)) {
1874 case QStyleHelper::SizeDefault:
1875 case QStyleHelper::SizeLarge:
1878 case QStyleHelper::SizeMini:
1881 case QStyleHelper::SizeSmall:
1887 case PM_MenuVMargin:
1890 case PM_MenuPanelWidth:
1893 case PM_ToolTipLabelFrameWidth:
1896 case PM_SizeGripSize: {
1897 QStyleHelper::WidgetSizePolicy aSize;
1901 aSize = QStyleHelper::SizeLarge;
1902 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
1905 case PM_MdiSubWindowFrameWidth:
1908 case PM_DockWidgetFrameWidth:
1911 case PM_DockWidgetTitleMargin:
1914 case PM_DockWidgetSeparatorExtent:
1917 case PM_ToolBarHandleExtent:
1920 case PM_ToolBarItemMargin:
1923 case PM_ToolBarItemSpacing:
1926 case PM_SplitterWidth:
1929 case PM_LayoutLeftMargin:
1930 case PM_LayoutTopMargin:
1931 case PM_LayoutRightMargin:
1932 case PM_LayoutBottomMargin:
1934 if (opt->state & State_Window) {
1936
1937
1938
1939
1940
1957
1958
1963 case PM_LayoutHorizontalSpacing:
1964 case PM_LayoutVerticalSpacing:
1966 case PM_MenuHMargin:
1969 case PM_ToolBarExtensionExtent:
1972 case PM_ToolBarFrameWidth:
1975 case PM_ScrollView_ScrollBarOverlap:
1976 ret = styleHint(SH_ScrollBar_Transient, opt,
nullptr)
1977 ? pixelMetric(PM_ScrollBarExtent, opt)
1980 case PM_PushButtonFocusFrameRadius:
1983 case PM_CheckBoxFocusFrameRadius:
1986 case PM_SearchFieldFocusFrameRadius:
1987 case PM_ComboBoxFocusFrameRadius:
1988 if (qt_apple_runningWithLiquidGlass())
1993 case PM_RadioButtonFocusFrameRadius:
1996 case PM_SliderFocusFrameRadius:
2003 case PM_DialFocusFrameRadius:
2004 case PM_SpinBoxFocusFrameRadius:
2005 case PM_TextAreaFocusFrameRadius:
2006 case PM_TextFieldFocusFrameRadius:
2007 ret = qt_apple_runningWithLiquidGlass() ? 6 : 0;
2010 ret = QCommonStyle::pixelMetric(metric, opt);
2026int QMacStyle::
styleHint(StyleHint sh,
const QStyleOption *opt, QStyleHintReturn *hret)
const
2028 QMacAutoReleasePool pool;
2032 case SH_Slider_SnapToValue:
2033 case SH_PrintDialog_RightAlignButtons:
2034 case SH_FontDialog_SelectAssociatedText:
2035 case SH_MenuBar_MouseTracking:
2036 case SH_Menu_MouseTracking:
2037 case SH_ComboBox_ListMouseTracking:
2038 case SH_MainWindow_SpaceBelowMenuBar:
2039 case SH_ItemView_ChangeHighlightOnFocus:
2042 case SH_ToolBox_SelectedPageTitleBold:
2045 case SH_DialogButtonBox_ButtonsHaveIcons:
2048 case SH_Menu_SelectionWrap:
2051 case SH_Menu_KeyboardSearch:
2054 case SH_Menu_SpaceActivatesItem:
2057 case SH_Slider_AbsoluteSetButtons:
2058 ret = Qt::LeftButton|Qt::MiddleButton;
2060 case SH_Slider_PageSetButtons:
2063 case SH_ScrollBar_ContextMenu:
2066 case SH_TitleBar_AutoRaise:
2069 case SH_Menu_AllowActiveAndDisabled:
2072 case SH_Menu_SubMenuPopupDelay:
2075 case SH_Menu_SubMenuUniDirection:
2078 case SH_Menu_SubMenuSloppySelectOtherActions:
2081 case SH_Menu_SubMenuResetWhenReenteringParent:
2084 case SH_Menu_SubMenuDontStartSloppyOnLeave:
2088 case SH_ScrollBar_LeftClickAbsolutePosition: {
2089 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2090 bool result = [defaults boolForKey:@
"AppleScrollerPagingBehavior"];
2096 case SH_TabBar_PreferNoArrows:
2100
2101
2102
2103
2104 case SH_GroupBox_TextLabelVerticalAlignment:
2107 case SH_ScrollView_FrameOnlyAroundContents:
2108 ret = QCommonStyle::styleHint(sh, opt, hret);
2110 case SH_Menu_FillScreenWithScroll:
2113 case SH_Menu_Scrollable:
2116 case SH_RichText_FullWidthSelection:
2119 case SH_BlinkCursorWhenTextSelected:
2122 case SH_Slider_StopMouseOverSlider:
2125 case SH_ListViewExpand_SelectMouseType:
2126 ret = QEvent::MouseButtonRelease;
2128 case SH_TabBar_SelectMouseType:
2129 if (
const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2130 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2132 ret = QEvent::MouseButtonRelease;
2135 case SH_ComboBox_Popup:
2136 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt))
2137 ret = !cmb->editable;
2141 case SH_Workspace_FillSpaceOnMaximize:
2144 case SH_Widget_ShareActivation:
2147 case SH_Header_ArrowAlignment:
2148 ret = Qt::AlignRight;
2150 case SH_TabBar_Alignment: {
2167 ret = Qt::AlignCenter;
2169 case SH_UnderlineShortcut:
2172 case SH_ToolTipLabel_Opacity:
2175 case SH_Button_FocusPolicy:
2178 case SH_EtchDisabledText:
2181 case SH_FocusFrame_Mask: {
2183 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2184 const uchar fillR = 192, fillG = 191, fillB = 190;
2187 QSize pixmapSize = opt->rect.size();
2188 if (!pixmapSize.isEmpty()) {
2189 QPixmap pix(pixmapSize);
2190 pix.fill(QColor(fillR, fillG, fillB));
2191 QPainter pix_paint(&pix);
2192 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2194 img = pix.toImage();
2197 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2198 const qsizetype sbpl = img.bytesPerLine();
2199 const int w = sbpl/4, h = img.height();
2201 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2202 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2203 const qsizetype dbpl = img_mask.bytesPerLine();
2205 for (
int y = 0; y < h; ++y) {
2206 srow = sptr+((y*sbpl)/4);
2207 drow = dptr+((y*dbpl)/4);
2208 for (
int x = 0; x < w; ++x) {
2209 const int redDiff = qRed(*srow) - fillR;
2210 const int greenDiff = qGreen(*srow) - fillG;
2211 const int blueDiff = qBlue(*srow) - fillB;
2212 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2213 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2217 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2218 mask->region = QRegion(qmask);
2221 case SH_TitleBar_NoBorder:
2224 case SH_RubberBand_Mask:
2227 case SH_ComboBox_LayoutDirection:
2228 ret = Qt::LeftToRight;
2230 case SH_ItemView_EllipsisLocation:
2231 ret = Qt::AlignHCenter;
2233 case SH_ItemView_ShowDecorationSelected:
2236 case SH_TitleBar_ModifyNotification:
2239 case SH_ScrollBar_RollBetweenButtons:
2242 case SH_WindowFrame_Mask:
2245 case SH_TabBar_ElideMode:
2246 ret = Qt::ElideRight;
2257 case SH_FormLayoutFormAlignment:
2258 ret = Qt::AlignHCenter | Qt::AlignTop;
2260 case SH_FormLayoutLabelAlignment:
2261 ret = Qt::AlignRight;
2266 case SH_MessageBox_TextInteractionFlags:
2267 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2269 case SH_SpellCheckUnderlineStyle:
2270 ret = QTextCharFormat::DashUnderline;
2272 case SH_MessageBox_CenterButtons:
2275 case SH_MenuBar_AltKeyNavigation:
2278 case SH_ItemView_MovementWithoutUpdatingSelection:
2281 case SH_FocusFrame_AboveWidget:
2287 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2290 case SH_Menu_FlashTriggeredItem:
2293 case SH_Menu_FadeOutOnHide:
2296 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2299 case SH_TabBar_CloseButtonPosition:
2300 ret = QStyleOptionTabBarBase::LeftSide;
2302 case SH_DockWidget_ButtonsHaveFrame:
2305 case SH_ScrollBar_Transient:
2311 case SH_TitleBar_ShowToolTipsOnButtons:
2315 case SH_ComboBox_AllowWheelScrolling:
2318 case SH_SpinBox_ButtonsInsideFrame:
2321 case SH_Table_GridLineColor:
2322 ret =
int(qt_mac_toQColor(NSColor.gridColor).rgba());
2325 ret = QCommonStyle::styleHint(sh, opt, hret);
2332 const QStyleOption *opt)
const
2335 case QIcon::Disabled: {
2336 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2337 int imgh = img.height();
2338 int imgw = img.width();
2340 for (
int y = 0; y < imgh; ++y) {
2341 for (
int x = 0; x < imgw; ++x) {
2342 pixel = img.pixel(x, y);
2343 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2344 qAlpha(pixel) / 2));
2347 return QPixmap::fromImage(img);
2352 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2363 static bool recursionGuard =
false;
2366 return QCommonStyle::standardPixmap(standardPixmap, opt);
2368 recursionGuard =
true;
2369 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2370 recursionGuard =
false;
2372 switch (standardPixmap) {
2376 case SP_MessageBoxCritical:
2377 case SP_MessageBoxQuestion:
2378 case SP_MessageBoxInformation:
2379 case SP_MessageBoxWarning:
2383 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2388 Q_D(
const QMacStyle);
2390 QMacCGContext cg(p);
2391 d->resolveCurrentNSView(opt->window);
2394 case PE_IndicatorArrowUp:
2395 case PE_IndicatorArrowDown:
2396 case PE_IndicatorArrowRight:
2397 case PE_IndicatorArrowLeft: {
2399 p->setRenderHint(QPainter::Antialiasing);
2400 const int xOffset = 1;
2401 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2402 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2412 QTransform transform;
2413 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2417 case PE_IndicatorArrowDown:
2419 case PE_IndicatorArrowUp:
2420 transform.rotate(180);
2422 case PE_IndicatorArrowLeft:
2423 transform.rotate(90);
2425 case PE_IndicatorArrowRight:
2426 transform.rotate(-90);
2429 p->setTransform(transform);
2431 path.moveTo(-halfSize, -halfSize * 0.5);
2432 path.lineTo(0.0, halfSize * 0.5);
2433 path.lineTo(halfSize, -halfSize * 0.5);
2435 const QPen arrowPen(opt->palette.text(), penWidth,
2436 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2437 p->strokePath(path, arrowPen);
2440 case PE_FrameTabBarBase:
2441 if (
const QStyleOptionTabBarBase *tbb
2442 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2443 if (tbb->documentMode) {
2445 drawTabBase(p, tbb);
2449 QRegion region(tbb->rect);
2450 region -= tbb->tabBarRect;
2452 p->setClipRegion(region);
2453 QStyleOptionTabWidgetFrame twf;
2454 twf.QStyleOption::operator=(*tbb);
2455 twf.shape = tbb->shape;
2456 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2457 case QMacStylePrivate::North:
2458 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2460 case QMacStylePrivate::South:
2461 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2463 case QMacStylePrivate::West:
2464 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2466 case QMacStylePrivate::East:
2467 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2470 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2474 case PE_PanelTipLabel:
2475 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2477 case PE_FrameGroupBox:
2478 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2479 if (groupBox->features & QStyleOptionFrame::Flat) {
2480 QCommonStyle::drawPrimitive(pe, groupBox, p);
2484 case PE_FrameTabWidget:
2486 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2487 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
2501 auto adjustedRect = opt->rect;
2502 bool needTranslation =
false;
2515 adjustedRect.adjust(0, 0, 6, 6);
2516 needTranslation =
true;
2518 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2523 QMacAutoReleasePool pool;
2524 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2525 CGContextScaleCTM(ctx, 1, -1);
2526 if ([box isMemberOfClass:QDarkNSBox.
class]) {
2527 [box drawRect:rect];
2529 if (needTranslation)
2530 CGContextTranslateCTM(ctx, -3.0, 5.0);
2531 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2536 case PE_IndicatorToolBarSeparator: {
2538 if (opt->state & State_Horizontal) {
2539 int xpoint = opt->rect.center().x();
2540 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2541 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2543 int ypoint = opt->rect.center().y();
2544 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2545 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2547 QPainterPathStroker theStroker;
2548 theStroker.setCapStyle(Qt::FlatCap);
2549 theStroker.setDashPattern(QList<qreal>() << 1 << 2);
2550 path = theStroker.createStroke(path);
2551 const auto dark =
isDarkMode() ? opt->palette.dark().color().darker()
2552 : QColor(0, 0, 0, 119);
2553 p->fillPath(path, dark);
2556 case PE_FrameWindow:
2567 case PE_IndicatorDockWidgetResizeHandle: {
2570 if (opt->state & State_Horizontal) {
2571 p->setPen(QColor(160, 160, 160));
2572 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2574 p->setPen(QColor(145, 145, 145));
2575 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2579 case PE_IndicatorToolBarHandle: {
2582 int x = opt->rect.x() + 6;
2583 int y = opt->rect.y() + 7;
2584 static const int RectHeight = 2;
2585 if (opt->state & State_Horizontal) {
2586 while (y < opt->rect.height() - RectHeight - 5) {
2588 path.addEllipse(x, y, RectHeight, RectHeight);
2592 while (x < opt->rect.width() - RectHeight - 5) {
2594 path.addEllipse(x, y, RectHeight, RectHeight);
2598 p->setPen(Qt::NoPen);
2599 QColor dark = opt->palette.dark().color().darker();
2600 dark.setAlphaF(0.50);
2601 p->fillPath(path, dark);
2606 case PE_IndicatorHeaderArrow:
2607 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2609 if (header->sortIndicator != QStyleOptionHeader::None)
2610 proxy()->drawPrimitive(
2611 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2612 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
2615 case PE_IndicatorMenuCheckMark: {
2617 if (opt->state & State_On)
2618 pc = opt->palette.highlightedText().color();
2620 pc = opt->palette.text().color();
2622 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
2623 static_cast<CGFloat>(pc.greenF()),
2624 static_cast<CGFloat>(pc.blueF()),
2625 static_cast<CGFloat>(pc.alphaF()));
2631 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2632 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2633 kCTFontUIFontMenuItemMark;
2637 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2638 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2640 CGContextSaveGState(cg);
2641 CGContextSetShouldSmoothFonts(cg, NO);
2644 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2645 (opt->state & State_Small) ? 1.0 :
2648 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2649 CGContextScaleCTM(cg, 1, -1);
2651 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2655 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2656 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
2657 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2658 Q_STATIC_ASSERT((
sizeof(values) /
sizeof(values[0])) == numValues);
2659 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
2660 numValues, NULL, NULL);
2662 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
2663 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2665 CTLineDraw((CTLineRef)line, cg);
2668 CGContextRestoreGState(cg);
2670 case PE_IndicatorItemViewItemCheck:
2671 case PE_IndicatorRadioButton:
2672 case PE_IndicatorCheckBox: {
2673 const bool isEnabled = opt->state & State_Enabled;
2674 const bool isPressed = opt->state & State_Sunken;
2675 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2677 const auto cs = d->effectiveAquaSizeConstrain(opt);
2679 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
2680 tb.enabled = isEnabled;
2681 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2682 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2683 [tb highlight:isPressed];
2684 const auto vOffset = [=] {
2686 if (cs == QStyleHelper::SizeMini)
2689 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2691 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2692 QMacAutoReleasePool pool;
2693 CGContextTranslateCTM(ctx, 0, vOffset);
2694 [tb.cell drawInteriorWithFrame:rect inView:tb];
2697 case PE_FrameFocusRect:
2700 case PE_IndicatorBranch: {
2701 if (!(opt->state & State_Children))
2703 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
2704 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
2705 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2707 bool viewHasFocus =
false;
2708 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2710 d->setupNSGraphicsContext(cg, NO);
2713 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2714 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2715 CGContextScaleCTM(cg, 1, -1);
2716 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2718 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2720 d->restoreNSGraphicsContext(cg);
2724 const QPen oldPen = p->pen();
2725 QPen penCpy = p->pen();
2727 penCpy.setColor(opt->palette.dark().color());
2729 p->drawRect(opt->rect);
2732 case PE_PanelLineEdit:
2733 case PE_FrameLineEdit:
2734 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
2735 if (frame->state & State_Sunken) {
2736 const bool isEnabled = opt->state & State_Enabled;
2737 const bool isReadOnly = opt->state & State_ReadOnly;
2738 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2739 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2741 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
2742 tf.enabled = isEnabled;
2743 tf.editable = !isReadOnly;
2745 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2746 tf.frame = opt->rect.toCGRect();
2747 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
2748 QMacAutoReleasePool pool;
2749 if (!isDarkMode()) {
2754 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2758 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
2759 tf.drawsBackground = YES;
2760 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2761 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2762 green:bgColor.greenF()
2763 blue:bgColor.blueF()
2764 alpha:bgColor.alphaF()];
2765 if (bgColor.alpha() != 255) {
2772 CGRect fixedRect = rect;
2773 if (qt_apple_runningWithLiquidGlass()) {
2778 fixedRect = CGRectInset(rect, 1., 1.);
2780 [tf.cell drawWithFrame:fixedRect inView:tf];
2783 QCommonStyle::drawPrimitive(pe, opt, p);
2787 case PE_PanelScrollAreaCorner: {
2788 const QBrush brush(opt->palette.brush(QPalette::Base));
2789 p->fillRect(opt->rect, brush);
2790 p->setPen(QPen(QColor(217, 217, 217)));
2791 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2792 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2794 case PE_FrameStatusBarItem:
2822 case PE_PanelStatusBar: {
2823 p->fillRect(opt->rect, opt->palette.window());
2826 if (qt_macWindowMainWindow(opt->window))
2827 p->setPen(titlebarSeparatorLineActive);
2829 p->setPen(titlebarSeparatorLineInactive);
2830 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2834 case PE_PanelMenu: {
2836 p->fillRect(opt->rect, Qt::transparent);
2837 p->setPen(Qt::transparent);
2838 p->setBrush(opt->palette.window());
2839 p->setRenderHint(QPainter::Antialiasing,
true);
2840 const QPainterPath path = d->windowPanelPath(opt->rect);
2846 QCommonStyle::drawPrimitive(pe, opt, p);
2853 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2854 int imgh = img.height();
2855 int imgw = img.width();
2858 for (
int y = 0; y < imgh; ++y) {
2859 for (
int x = 0; x < imgw; ++x) {
2860 pixel = img.pixel(x, y);
2862 QColor hsvColor(pixel);
2863 hsvColor.getHsv(&h, &s, &v);
2864 s = qMin(100, s * 2);
2866 hsvColor.setHsv(h, s, v);
2867 pixel = hsvColor.rgb();
2868 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2871 return QPixmap::fromImage(img);
2877 CGContextTranslateCTM(cg, rect.size.height, 0);
2878 CGContextRotateCTM(cg,
M_PI_2);
2880 if (vertical != reverse) {
2881 CGContextTranslateCTM(cg, rect.size.width, 0);
2882 CGContextScaleCTM(cg, -1, 1);
2888 Q_D(
const QMacStyle);
2890 const QMacAutoReleasePool pool;
2892 QMacCGContext cg(p);
2893 d->resolveCurrentNSView(opt->window);
2896 case CE_HeaderSection:
2897 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2898 State flags = header->state;
2899 QRect ir = header->rect;
2900 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2901 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2902 p->setPen(QPen(header->palette.dark(), 1.0));
2903 if (header->orientation == Qt::Horizontal)
2912 case CE_HeaderLabel:
2913 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2915 QRect textr = header->rect;
2916 if (!header->icon.isNull()) {
2917 QIcon::Mode mode = QIcon::Disabled;
2918 if (opt->state & State_Enabled)
2919 mode = QIcon::Normal;
2920 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2921 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2922 opt->window->devicePixelRatio(), mode);
2924 QRect pixr = header->rect;
2925 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2926 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
2927 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2930 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2931 header->state & State_Enabled, header->text, QPalette::ButtonText);
2935 case CE_ToolButtonLabel:
2936 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
2937 QStyleOptionToolButton myTb = *tb;
2938 myTb.state &= ~State_AutoRaise;
2939#ifndef QT_NO_ACCESSIBILITY
2940 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2941 QRect cr = tb->rect;
2944 bool needText =
false;
2946 bool down = tb->state & (State_Sunken | State_On);
2948 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
2949 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2955 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2956 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2957 if (tb->icon.isNull() && !tb->text.isEmpty())
2958 tbstyle = Qt::ToolButtonTextOnly;
2961 case Qt::ToolButtonTextOnly: {
2963 alignment = Qt::AlignCenter;
2965 case Qt::ToolButtonIconOnly:
2966 case Qt::ToolButtonTextBesideIcon:
2967 case Qt::ToolButtonTextUnderIcon: {
2969 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2971 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2973 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2974 opt->window->devicePixelRatio(), iconMode,
2978 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
2980 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
2981 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
2982 cr.adjust(0, pr.bottom(), 0, -3);
2983 alignment |= Qt::AlignCenter;
2985 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
2986 cr.adjust(pr.right(), 0, 0, 0);
2987 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
2990 if (opt->state & State_Sunken) {
2991 pr.translate(shiftX, shiftY);
2992 pixmap = darkenPixmap(pixmap);
2994 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3002 QPalette pal = tb->palette;
3003 QPalette::ColorRole role = QPalette::NoRole;
3004 if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
3005 alignment |= Qt::TextHideMnemonic;
3007 cr.translate(shiftX, shiftY);
3008 if (tbstyle == Qt::ToolButtonTextOnly
3009 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3010 QPen pen = p->pen();
3011 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3012 light.setAlphaF(0.375f);
3014 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3016 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3018 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3019 role = QPalette::HighlightedText;
3022 proxy()->drawItemText(p, cr, alignment, pal,
3023 tb->state & State_Enabled, tb->text, role);
3026 QCommonStyle::drawControl(ce, &myTb, p);
3031 QCommonStyle::drawControl(ce, &myTb, p);
3035 case CE_ToolBoxTabShape:
3036 QCommonStyle::drawControl(ce, opt, p);
3038 case CE_PushButtonBevel:
3040 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3043 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3044 QCommonStyle::drawControl(ce, opt, p);
3048 const bool hasFocus = btn->state & State_HasFocus;
3049 const bool isActive = btn->state & State_Active;
3053 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3054 && isActive && hasFocus)
3055 d->autoDefaultButton = btn->styleObject;
3056 else if (d->autoDefaultButton == btn->styleObject)
3057 d->autoDefaultButton =
nullptr;
3059 const bool isEnabled = btn->state & State_Enabled;
3060 const bool isPressed = btn->state & State_Sunken;
3061 const bool isHighlighted = isActive &&
3062 ((btn->state & State_On)
3063 || (btn->features & QStyleOptionButton::DefaultButton)
3064 || (btn->features & QStyleOptionButton::AutoDefaultButton
3065 && d->autoDefaultButton == btn->styleObject));
3066 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3067 const auto ct = cocoaControlType(btn);
3068 const auto cs = d->effectiveAquaSizeConstrain(btn);
3070 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3074 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3075 pb.frame = frameRect.toCGRect();
3077 pb.enabled = isEnabled;
3078 [pb highlight:isPressed];
3079 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3080 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3081 QMacAutoReleasePool pool;
3082 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3089 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
3090 const auto ir = frameRect.toRect();
3091 int arrowYOffset = 0;
3092 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3094 QStyleOption arrowOpt = *opt;
3096 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
3100 case CE_PushButtonLabel:
3107 const bool isEnabled = btn.state & State_Enabled;
3108 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3109 const bool hasIcon = !btn.icon.isNull();
3110 const bool hasText = !btn.text.isEmpty();
3111 const bool isActive = btn.state & State_Active;
3112 const bool isPressed = btn.state & State_Sunken;
3114 const auto ct = cocoaControlType(&btn);
3118 || (isActive && isEnabled
3119 && ((btn.state & State_On)
3120 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3121 || d->autoDefaultButton == btn.styleObject)))
3122 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3125 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3126 QCommonStyle::drawControl(ce, &btn, p);
3128 QRect freeContentRect = btn.rect;
3129 QRect textRect = itemTextRect(
3130 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3132 textRect.moveTo(11, textRect.top());
3136 int contentW = textRect.width();
3138 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3139 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3140 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3141 mode = QIcon::Active;
3143 QIcon::State state = QIcon::Off;
3144 if (btn.state & State_On)
3146 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3148 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3149 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3151 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3152 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3153 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3154 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3155 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3156 int newOffset = iconDestRect.x() + iconDestRect.width()
3158 textRect.adjust(newOffset, 0, newOffset, 0);
3162 textRect = visualRect(btn.direction, freeContentRect, textRect);
3163 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3164 isEnabled, btn.text, QPalette::ButtonText);
3169 case CE_ComboBoxLabel:
3170 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3171 auto comboCopy = *cb;
3172 comboCopy.direction = Qt::LeftToRight;
3174 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
3177 case CE_TabBarTabShape:
3178 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3179 if (tabOpt->documentMode) {
3181 bool isUnified =
false;
3188 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3189 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3195 const bool isActive = tabOpt->state & State_Active;
3196 const bool isEnabled = tabOpt->state & State_Enabled;
3197 const bool isPressed = tabOpt->state & State_Sunken;
3198 const bool isSelected = tabOpt->state & State_Selected;
3199 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3200 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3201 || tabDirection == QMacStylePrivate::West;
3203 QStyleOptionTab::TabPosition tp = tabOpt->position;
3204 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3205 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3206 if (tp == QStyleOptionTab::Beginning)
3207 tp = QStyleOptionTab::End;
3208 else if (tp == QStyleOptionTab::End)
3209 tp = QStyleOptionTab::Beginning;
3211 if (sp == QStyleOptionTab::NextIsSelected)
3212 sp = QStyleOptionTab::PreviousIsSelected;
3213 else if (sp == QStyleOptionTab::PreviousIsSelected)
3214 sp = QStyleOptionTab::NextIsSelected;
3229 const auto cs = d->effectiveAquaSizeConstrain(opt);
3231 const bool needsInactiveHack = (!isActive && isSelected);
3232 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3233 QMacStylePrivate::Button_PushButton :
3234 QMacStylePrivate::Button_PopupButton;
3237 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3239 auto vOffset = isPopupButton ? 1 : 2;
3240 if (tabDirection == QMacStylePrivate::East)
3242 const auto outerAdjust = isPopupButton ? 1 : 4;
3243 const auto innerAdjust = isPopupButton ? 20 : 10;
3244 QRectF frameRect = tabOpt->rect;
3246 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3248 frameRect = frameRect.translated(0, vOffset);
3250 case QStyleOptionTab::Beginning:
3252 if (!isSelected && tabDirection == QMacStylePrivate::West)
3253 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3255 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3257 case QStyleOptionTab::Middle:
3258 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3260 case QStyleOptionTab::End:
3262 if (isSelected || tabDirection == QMacStylePrivate::West)
3263 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3265 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3267 case QStyleOptionTab::OnlyOneTab:
3268 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3271 pb.frame = frameRect.toCGRect();
3273 pb.enabled = isEnabled;
3274 [pb highlight:isPressed];
3276 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3278 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3279 QMacAutoReleasePool pool;
3280 CGContextClipToRect(ctx, opt->rect.toCGRect());
3281 if (!isSelected || needsInactiveHack) {
3283 if (!verticalTabs && tp == QStyleOptionTab::End) {
3284 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3285 CGContextScaleCTM(ctx, -1, 1);
3286 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3287 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3288 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3289 CGContextScaleCTM(ctx, 1, -1);
3290 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3291 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3292 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3293 CGContextScaleCTM(ctx, 1, -1);
3294 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3300 if (tabDirection == QMacStylePrivate::West) {
3301 CGContextTranslateCTM(ctx, 0, frameRect.right());
3302 CGContextRotateCTM(ctx, -
M_PI_2);
3303 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3304 }
else if (tabDirection == QMacStylePrivate::East) {
3305 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3306 CGContextRotateCTM(ctx,
M_PI_2);
3311 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3312 NSPopUpButtonCell *pbCell = nil;
3313 if (isPopupButton) {
3314 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3315 oldPosition = pbCell.arrowPosition;
3316 pbCell.arrowPosition = NSPopUpNoArrow;
3319 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3322 pbCell.arrowPosition = oldPosition;
3325 if (needsInactiveHack) {
3327 const qreal pixelRatio = p->device()->devicePixelRatioF();
3328 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3329 tabPixmap.setDevicePixelRatio(pixelRatio);
3330 tabPixmap.fill(Qt::transparent);
3331 QPainter tabPainter(&tabPixmap);
3332 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3333 QMacAutoReleasePool pool;
3334 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3335 drawBezelBlock(ctx, r);
3340 const qreal inactiveGray = 0.898;
3341 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3342 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3343 for (
int l = 0; l < tabPixmap.height(); ++l) {
3344 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3345 for (
int i = 0; i < tabPixmap.width(); ++i) {
3346 if (qAlpha(line[i]) == 255) {
3347 line[i] = inactiveGrayRGB;
3348 }
else if (qAlpha(line[i]) > 128) {
3349 const int g = qRound(inactiveGray * qRed(line[i]));
3350 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3356 p->drawImage(opt->rect, tabPixmap);
3358 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3361 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3362 && tp != QStyleOptionTab::End
3363 && tp != QStyleOptionTab::OnlyOneTab) {
3364 static const QPen separatorPen(Qt::black, 1.0);
3366 p->setOpacity(isEnabled ? 0.105 : 0.06);
3367 p->setPen(separatorPen);
3368 if (tabDirection == QMacStylePrivate::West) {
3369 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3370 opt->rect.right() - 0.5, opt->rect.bottom()));
3371 }
else if (tabDirection == QMacStylePrivate::East) {
3372 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3373 opt->rect.right() - 0.5, opt->rect.bottom()));
3375 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3376 opt->rect.right(), opt->rect.bottom() - 0.5));
3382 case CE_TabBarTabLabel:
3383 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3384 QStyleOptionTab myTab = *tab;
3385 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3386 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3387 || tabDirection == QMacStylePrivate::West;
3394 const bool nonDefaultFont =
false;
3402 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3403 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3406 int heightOffset = 0;
3409 }
else if (nonDefaultFont) {
3410 if (p->fontMetrics().height() == myTab.rect.height())
3413 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3415 QCommonStyle::drawControl(ce, &myTab, p);
3418 case CE_DockWidgetTitle:
3419 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
3420 const bool isVertical = dwOpt->verticalTitleBar;
3421 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3424 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3426 p->translate(-effectiveRect.left(), -effectiveRect.top());
3430 p->fillRect(effectiveRect, opt->palette.window());
3433 p->setPen(opt->palette.dark().color());
3434 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3436 if (!dwOpt->title.isEmpty()) {
3437 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3439 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3440 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3444 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3445 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3446 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3451 case CE_FocusFrame: {
3474 case CE_MenuEmptyArea:
3478 case CE_MenuHMargin:
3479 case CE_MenuVMargin:
3480 case CE_MenuTearoff:
3481 case CE_MenuScroller:
3482 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3483 const bool active = mi->state & State_Selected;
3485 p->fillRect(mi->rect, mi->palette.highlight());
3487 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3489 if (ce == CE_MenuTearoff) {
3490 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3491 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3492 mi->rect.x() + mi->rect.width() - 4,
3493 mi->rect.y() + mi->rect.height() / 2 - 1);
3494 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3495 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3496 mi->rect.x() + mi->rect.width() - 4,
3497 mi->rect.y() + mi->rect.height() / 2);
3498 }
else if (ce == CE_MenuScroller) {
3499 const QSize scrollerSize = QSize(10, 8);
3500 const int scrollerVOffset = 5;
3501 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3502 const int right = left + scrollerSize.width();
3505 if (opt->state & State_DownArrow) {
3506 bottom = mi->rect.y() + scrollerVOffset;
3507 top = bottom + scrollerSize.height();
3509 bottom = mi->rect.bottom() - scrollerVOffset;
3510 top = bottom - scrollerSize.height();
3513 p->setRenderHint(QPainter::Antialiasing);
3515 path.moveTo(left, bottom);
3516 path.lineTo(right, bottom);
3517 path.lineTo((left + right) / 2, top);
3518 p->fillPath(path, opt->palette.buttonText());
3520 }
else if (ce != CE_MenuItem) {
3524 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3525 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3526 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3527 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3531 const int maxpmw = mi->maxIconWidth;
3532 const bool enabled = mi->state & State_Enabled;
3534 int xpos = mi->rect.x() + 18;
3535 int checkcol = maxpmw;
3537 p->setPen(mi->palette.text().color());
3539 p->setPen(mi->palette.highlightedText().color());
3541 p->setPen(mi->palette.buttonText().color());
3544 QStyleOption checkmarkOpt;
3550 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3552 checkmarkOpt.state.setFlag(State_On, active);
3553 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3554 if (widgetSize == QStyleHelper::SizeMini)
3555 checkmarkOpt.state |= State_Mini;
3556 else if (widgetSize == QStyleHelper::SizeSmall)
3557 checkmarkOpt.state |= State_Small;
3560 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3561 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3563 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3565 if (!mi->icon.isNull()) {
3566 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
3569 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3570 QSize iconSize(smallIconSize, smallIconSize);
3576 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3577 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3578 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3579 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3580 QRect pmr(0, 0, pixw, pixh);
3581 pmr.moveCenter(cr.center());
3582 p->drawPixmap(pmr.topLeft(), pixmap);
3586 QString s = mi->text;
3587 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3588 | Qt::TextSingleLine | Qt::AlignAbsolute;
3589 int yPos = mi->rect.y();
3590 if (widgetSize == QStyleHelper::SizeMini)
3593 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3594 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3596 QString rightMarginText;
3598 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
3601 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
3602 if (tabIndex >= 0) {
3604 rightMarginText = s.mid(tabIndex + 1);
3605 s = s.left(tabIndex);
3609 if (!rightMarginText.isEmpty()) {
3614 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3619 QFont myFont = mi->font;
3625 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3630 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3631 Q_ASSERT(fontEngine);
3632 if (fontEngine->type() == QFontEngine::Multi) {
3633 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
3634 Q_ASSERT(fontEngine);
3636 if (fontEngine->type() == QFontEngine::Mac) {
3637 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3640 const auto pc = p->pen().color();
3641 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3646 s = qt_mac_removeMnemonics(s);
3648 QMacCGContext cgCtx(p);
3649 d->setupNSGraphicsContext(cgCtx, YES);
3655 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3656 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3657 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3659 d->restoreNSGraphicsContext(cgCtx);
3662 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3663 mi->rect.height(), text_flags, s);
3669 case CE_MenuBarItem:
3670 case CE_MenuBarEmptyArea:
3671 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3672 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3673 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3674 p->fillRect(mi->rect, bg);
3676 if (ce != CE_MenuBarItem)
3679 if (!mi->icon.isNull()) {
3680 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3681 drawItemPixmap(p, mi->rect,
3682 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3683 | Qt::TextSingleLine,
3684 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3685 opt->window->devicePixelRatio(),
3686 (mi->state & State_Enabled) ? QIcon::Normal
3687 : QIcon::Disabled));
3689 drawItemText(p, mi->rect,
3690 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3691 | Qt::TextSingleLine,
3692 mi->palette, mi->state & State_Enabled,
3693 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3697 case CE_ProgressBarLabel:
3698 case CE_ProgressBarContents:
3700 case CE_ProgressBarGroove:
3701 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
3702 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3703 const bool inverted = pb->invertedAppearance;
3704 bool reverse = pb->direction == Qt::RightToLeft;
3708 QRect rect = pb->rect;
3709 const CGRect cgRect = rect.toCGRect();
3711 const auto aquaSize = d->aquaSizeConstrain(opt);
3714 QIndeterminateProgressIndicator *ipi = nil;
3716 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3717 if (isIndeterminate) {
3736 d->setupNSGraphicsContext(cg, NO);
3737 d->setupVerticalInvertedXform(cg, reverse,
false, cgRect);
3738 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3739 d->restoreNSGraphicsContext(cg);
3747 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3748 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3749 QMacAutoReleasePool pool;
3750 d->setupVerticalInvertedXform(ctx, reverse,
false, rect);
3751 pi.minValue = pb->minimum;
3752 pi.maxValue = pb->maximum;
3753 pi.doubleValue = pb->progress;
3792 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3793 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3796 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
3797 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
3798 sv.frame = opt->rect.toCGRect();
3799 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3800 QMacAutoReleasePool pool;
3801 [sv drawDividerInRect:rect];
3804 QPen oldPen = p->pen();
3805 p->setPen(opt->palette.dark().color());
3806 if (opt->state & QStyle::State_Horizontal)
3807 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3809 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3814 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
3815 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
3816 if (!rubber->opaque) {
3819 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3820 fillColor.setHsvF(0, 0, 0.53, 0.25);
3821 if (opt->rect.width() * opt->rect.height() <= 3) {
3822 p->fillRect(opt->rect, strokeColor);
3824 QPen oldPen = p->pen();
3825 QBrush oldBrush = p->brush();
3826 QPen pen(strokeColor);
3828 p->setBrush(fillColor);
3829 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3830 if (adjusted.isValid())
3831 p->drawRect(adjusted);
3833 p->setBrush(oldBrush);
3836 p->fillRect(opt->rect, fillColor);
3875 QLinearGradient linearGrad;
3876 if (opt->state & State_Horizontal)
3877 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3879 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3881 QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
3882 QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
3884 linearGrad.setColorAt(0, mainWindowGradientBegin);
3885 linearGrad.setColorAt(1, mainWindowGradientEnd);
3886 p->fillRect(opt->rect, linearGrad);
3889 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3890 if (opt->state & State_Horizontal) {
3891 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3892 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3893 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3894 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3896 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3897 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3898 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3899 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3905 QCommonStyle::drawControl(ce, opt, p);
3912 if (dir == Qt::RightToLeft) {
3913 rect->adjust(-right, top, -left, bottom);
3915 rect->adjust(left, top, right, bottom);
3921 Q_D(
const QMacStyle);
3923 const int controlSize = getControlSize(opt);
3926 case SE_ItemViewItemText:
3927 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
3928 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
3930 rect = QCommonStyle::subElementRect(sr, opt);
3931 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3932 rect.adjust(-fw, 0, 0, 0);
3935 case SE_ToolBoxTabContents:
3936 rect = QCommonStyle::subElementRect(sr, opt);
3938 case SE_PushButtonContents:
3948 const auto ct = cocoaControlType(btn);
3949 const auto cs = d->effectiveAquaSizeConstrain(btn);
3951 auto frameRect = cw.adjustedControlFrame(btn->rect);
3952 frameRect -= cw.titleMargins();
3953 rect = frameRect.toRect();
3956 case SE_HeaderLabel: {
3957 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3958 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3959 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3960 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3962 if (header->sortIndicator != QStyleOptionHeader::None) {
3963 if (opt->state & State_Horizontal)
3969 rect = visualRect(opt->direction, opt->rect, rect);
3972 case SE_HeaderArrow: {
3973 int h = opt->rect.height();
3974 int w = opt->rect.width();
3975 int x = opt->rect.x();
3976 int y = opt->rect.y();
3977 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3979 if (opt->state & State_Horizontal) {
3986 rect = visualRect(opt->direction, opt->rect, rect);
3989 case SE_ProgressBarGroove:
3993 case SE_ProgressBarLabel:
3995 case SE_ProgressBarContents:
3998 case SE_TreeViewDisclosureItem: {
4004 case SE_TabWidgetLeftCorner:
4005 if (
const QStyleOptionTabWidgetFrame *twf
4006 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4007 switch (twf->shape) {
4008 case QStyleOptionTab::RoundedNorth:
4009 case QStyleOptionTab::TriangularNorth:
4010 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4012 case QStyleOptionTab::RoundedSouth:
4013 case QStyleOptionTab::TriangularSouth:
4014 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4015 twf->leftCornerWidgetSize);
4020 rect = visualRect(twf->direction, twf->rect, rect);
4023 case SE_TabWidgetRightCorner:
4024 if (
const QStyleOptionTabWidgetFrame *twf
4025 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4026 switch (twf->shape) {
4027 case QStyleOptionTab::RoundedNorth:
4028 case QStyleOptionTab::TriangularNorth:
4029 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4030 twf->rightCornerWidgetSize);
4032 case QStyleOptionTab::RoundedSouth:
4033 case QStyleOptionTab::TriangularSouth:
4034 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4035 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4036 twf->rightCornerWidgetSize);
4041 rect = visualRect(twf->direction, twf->rect, rect);
4044 case SE_TabWidgetTabContents:
4045 rect = QCommonStyle::subElementRect(sr, opt);
4046 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4047 if (twf->lineWidth != 0) {
4048 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4049 case QMacStylePrivate::North:
4050 rect.adjust(+1, +14, -1, -1);
4052 case QMacStylePrivate::South:
4053 rect.adjust(+1, +1, -1, -14);
4055 case QMacStylePrivate::West:
4056 rect.adjust(+14, +1, -1, -1);
4058 case QMacStylePrivate::East:
4059 rect.adjust(+1, +1, -14, -1);
4064 case SE_TabBarTabText:
4065 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4066 QRect dummyIconRect;
4067 d->tabLayout(tab, &rect, &dummyIconRect);
4070 case SE_TabBarTabLeftButton:
4071 case SE_TabBarTabRightButton:
4072 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4073 bool selected = tab->state & State_Selected;
4074 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4075 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4078 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4079 || tab->shape == QStyleOptionTab::RoundedWest
4080 || tab->shape == QStyleOptionTab::TriangularEast
4081 || tab->shape == QStyleOptionTab::TriangularWest;
4083 QRect tr = tab->rect;
4084 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4085 verticalShift = -verticalShift;
4087 qSwap(horizontalShift, verticalShift);
4088 horizontalShift *= -1;
4089 verticalShift *= -1;
4091 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4092 horizontalShift = -horizontalShift;
4094 tr.adjust(0, 0, horizontalShift, verticalShift);
4097 tr.setBottom(tr.bottom() - verticalShift);
4098 tr.setRight(tr.right() - horizontalShift);
4101 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4102 int w = size.width();
4103 int h = size.height();
4104 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4105 int midWidth = ((tr.width() - w) / 2);
4107 bool atTheTop =
true;
4108 switch (tab->shape) {
4109 case QStyleOptionTab::RoundedWest:
4110 case QStyleOptionTab::TriangularWest:
4111 atTheTop = (sr == SE_TabBarTabLeftButton);
4113 case QStyleOptionTab::RoundedEast:
4114 case QStyleOptionTab::TriangularEast:
4115 atTheTop = (sr == SE_TabBarTabRightButton);
4118 if (sr == SE_TabBarTabLeftButton)
4119 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4121 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4122 rect = visualRect(tab->direction, tab->rect, rect);
4126 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4128 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4132 case SE_LineEditContents: {
4134 int leftPadding = 4;
4135 int rightPadding = 4;
4137 int bottomPadding = 0;
4139 if (opt->state & QStyle::State_Small) {
4141 }
else if (opt->state & QStyle::State_Mini) {
4145 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4146 opt->rect.height() - topPadding - bottomPadding);
4148 case SE_CheckBoxLayoutItem:
4150 if (controlSize == QStyleHelper::SizeLarge) {
4151 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4152 }
else if (controlSize == QStyleHelper::SizeSmall) {
4153 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4155 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4158 case SE_SearchFieldLayoutItem:
4159 if (qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4160 if (qt_apple_runningWithLiquidGlass()) {
4162 opt->rect.adjusted(2, 4, -2, -4),
4163 opt->rect.adjusted(2, 3, -2, -2),
4164 opt->rect.adjusted(2, 3, -2, -2));
4167 opt->rect.adjusted(2, 6, -2, -6),
4168 opt->rect.adjusted(2, 3, -2, -2),
4169 opt->rect.adjusted(2, 3, -2, -2));
4173 case SE_ComboBoxLayoutItem:
4174 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4183 if (combo->editable) {
4184 if (qt_apple_runningWithLiquidGlass()) {
4186 opt->rect.adjusted(4, 4, -4, -4),
4187 opt->rect.adjusted(4, 4, -5, -7),
4188 opt->rect.adjusted(5, 4, -4, -6));
4191 opt->rect.adjusted(5, 6, -6, -7),
4192 opt->rect.adjusted(4, 4, -5, -7),
4193 opt->rect.adjusted(5, 4, -4, -6));
4196 if (qt_apple_runningWithLiquidGlass()) {
4198 opt->rect.adjusted(4, 4, -4, -4),
4199 opt->rect.adjusted(6, 7, -6, -5),
4200 opt->rect.adjusted(9, 5, -5, -7));
4203 opt->rect.adjusted(6, 4, -7, -7),
4204 opt->rect.adjusted(6, 7, -6, -5),
4205 opt->rect.adjusted(9, 5, -5, -7));
4210 case SE_LabelLayoutItem:
4212 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4214 case SE_ProgressBarLayoutItem:
4215 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4216 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4219 if (isIndeterminate) {
4220 rect.adjust(1, 2, -1, -2);
4222 rect.adjust(1, 1, -1, -2);
4226 case SE_PushButtonLayoutItem:
4229 if ((buttonOpt->features & QStyleOptionButton::Flat))
4232 if (qt_apple_runningWithLiquidGlass()) {
4234 opt->rect.adjusted(2, 5, -2, -7),
4235 opt->rect.adjusted(6, 6, -6, -6),
4236 opt->rect.adjusted(6, 5, -6, -6));
4239 opt->rect.adjusted(7, 5, -7, -7),
4240 opt->rect.adjusted(6, 6, -6, -6),
4241 opt->rect.adjusted(6, 5, -6, -6));
4244 case SE_SpinBoxLayoutItem:
4246 opt->rect.adjusted(2, 3, -2, -2),
4247 opt->rect.adjusted(2, 3, -2, -2),
4248 opt->rect.adjusted(2, 3, -2, -2));
4250 case SE_RadioButtonLayoutItem:
4252 opt->rect.adjusted(2, 2, -3, -2),
4253 opt->rect.adjusted(2, 2, -3, -2),
4254 opt->rect.adjusted(1, 2, -3, -2));
4256 case SE_SliderLayoutItem:
4257 if (
const QStyleOptionSlider *sliderOpt
4258 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4260 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4261 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4262 rect.adjust(3, 3, -3, -3);
4264 rect.adjust(3, 0, -3, 0);
4268 case SE_ScrollBarLayoutItem:
4269 if (qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4272 case SE_FrameLayoutItem:
4288 case SE_GroupBoxLayoutItem:
4290 if (
const QStyleOptionGroupBox *groupBoxOpt =
4291 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4293
4294
4295
4296
4297 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4298 | QStyle::SC_GroupBoxLabel)) {
4300 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4301 delta =
SIZE(8, 4, 4);
4303 delta =
SIZE(15, 12, 12);
4305 rect.setTop(rect.top() + delta);
4308 rect.setBottom(rect.bottom() - 1);
4310 case SE_TabWidgetLayoutItem:
4311 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4312 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4314
4315
4316
4317
4318 rect = tabWidgetOpt->rect;
4319 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4320 rect.setTop(rect.top() +
SIZE(6 , 3 , 2 ));
4323 case SE_DockWidgetCloseButton:
4324 case SE_DockWidgetFloatButton:
4325 case SE_DockWidgetTitleBarText:
4326 case SE_DockWidgetIcon: {
4327 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
4328 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
4329 QRect srect = opt->rect;
4331 const QStyleOptionDockWidget *dwOpt
4332 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4333 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4334 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4336 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4340 if (verticalTitleBar)
4341 srect = srect.transposed();
4344 int right = srect.right();
4345 int left = srect.left();
4349 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4350 opt).actualSize(QSize(iconSize, iconSize));
4351 sz += QSize(buttonMargin, buttonMargin);
4352 if (verticalTitleBar)
4353 sz = sz.transposed();
4354 closeRect = QRect(left,
4355 srect.center().y() - sz.height()/2,
4356 sz.width(), sz.height());
4357 left = closeRect.right() + 1;
4359 if (sr == SE_DockWidgetCloseButton) {
4366 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4367 opt).actualSize(QSize(iconSize, iconSize));
4368 sz += QSize(buttonMargin, buttonMargin);
4369 if (verticalTitleBar)
4370 sz = sz.transposed();
4371 floatRect = QRect(left,
4372 srect.center().y() - sz.height()/2,
4373 sz.width(), sz.height());
4374 left = floatRect.right() + 1;
4376 if (sr == SE_DockWidgetFloatButton) {
4396 if (sr == SE_DockWidgetIcon) {
4401 QRect textRect = QRect(left, srect.top(),
4402 right - left, srect.height());
4403 if (sr == SE_DockWidgetTitleBarText) {
4409 if (verticalTitleBar) {
4410 rect = QRect(srect.left() + rect.top() - srect.top(),
4411 srect.top() + srect.right() - rect.right(),
4412 rect.height(), rect.width());
4414 rect = visualRect(opt->direction, srect, rect);
4419 rect = QCommonStyle::subElementRect(sr, opt);
4427 Q_Q(
const QMacStyle);
4428 QStyleOption arrowOpt = *opt;
4433 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4438 CGContextSaveGState(cg);
4439 [NSGraphicsContext saveGraphicsState];
4441 [NSGraphicsContext setCurrentContext:
4442 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4447 [NSGraphicsContext restoreGraphicsState];
4448 CGContextRestoreGState(cg);
4453 Q_D(
const QMacStyle);
4455 QMacCGContext cg(p);
4456 d->resolveCurrentNSView(opt->window);
4460 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4462 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4463 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4464 if (!drawTrack && !drawKnob)
4467 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4469 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
4470 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4472 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4473 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4475 const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
4478 bool wasActive =
false;
4479 CGFloat opacity = 0.0;
4480 CGFloat expandScale = 1.0;
4481 CGFloat expandOffset = 0.0;
4482 bool shouldExpand =
false;
4484 if (QObject *styleObject = opt->styleObject) {
4485 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
4486 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
4487 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
4488 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
4489 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
4490 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
4494 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4497 oldPos != sb->sliderPosition ||
4498 oldMin != sb->minimum ||
4499 oldMax != sb->maximum ||
4500 oldRect != sb->rect ||
4501 oldState != sb->state ||
4502 oldActiveControls != sb->activeSubControls) {
4508 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
4509 styleObject->setProperty(
"_q_stylemin", sb->minimum);
4510 styleObject->setProperty(
"_q_stylemax", sb->maximum);
4511 styleObject->setProperty(
"_q_stylerect", sb->rect);
4512 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
4513 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
4541 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4559 d->setupNSGraphicsContext(cg, NO );
4563 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
4565 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
4566 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4570 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4572 scroller.knobStyle = NSScrollerKnobStyleDefault;
4575 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4577 if (!setupScroller(scroller, sb))
4581 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
4582 CGContextSetAlpha(cg, opacity);
4587 if (!isTransient || opt->activeSubControls || wasActive) {
4588 CGRect trackRect = scroller.bounds;
4590 trackRect.origin.y += expandOffset;
4592 trackRect.origin.x += expandOffset;
4593 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4603 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4604 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4606 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4607 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4608 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4609 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4610 const CGFloat knobRadius = knobWidth / 2.0;
4613 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4615 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4616 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
4617 CGContextAddPath(cg, knobPath);
4618 CGContextSetAlpha(cg, 0.5);
4619 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4620 CGContextSetFillColorWithColor(cg, knobColor);
4621 CGContextFillPath(cg);
4623 [scroller drawKnob];
4625 if (!isTransient && opt->state & State_Sunken) {
4630 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4631 [scroller drawKnob];
4637 CGContextEndTransparencyLayer(cg);
4639 d->restoreNSGraphicsContext(cg);
4643 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4644 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4646 const auto cs = d->effectiveAquaSizeConstrain(opt);
4648 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
4649 if (!setupSlider(slider, sl))
4652 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4653 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4654 const bool drawKnob = sl->subControls & SC_SliderHandle;
4655 const bool drawBar = sl->subControls & SC_SliderGroove;
4656 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4657 const bool isPressed = sl->state & State_Sunken;
4660 if (isPressed && drawKnob) {
4661 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4662 pressPoint.x = CGRectGetMidX(knobRect);
4663 pressPoint.y = CGRectGetMidY(knobRect);
4664 [slider.cell startTrackingAt:pressPoint inView:slider];
4667 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef,
const CGRect &) {
4670 NSSliderCell *cell = slider.cell;
4673 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4679 [cell drawBarInside:barRect flipped:!isHorizontal];
4682 if (drawBar && hasTicks && drawTicks) {
4683 if (!hasDoubleTicks) {
4684 [cell drawTickMarks];
4686 if (sl->orientation == Qt::Horizontal) {
4687 slider.tickMarkPosition = NSTickMarkPositionAbove;
4688 [slider layoutSubtreeIfNeeded];
4689 [cell drawTickMarks];
4690 slider.tickMarkPosition = NSTickMarkPositionBelow;
4691 [slider layoutSubtreeIfNeeded];
4692 [cell drawTickMarks];
4694 slider.tickMarkPosition = NSTickMarkPositionLeading;
4695 [slider layoutSubtreeIfNeeded];
4696 [cell drawTickMarks];
4697 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4698 [slider layoutSubtreeIfNeeded];
4699 [cell drawTickMarks];
4708 if (isPressed && drawKnob)
4709 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4713 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
4714 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4715 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4716 QStyleOptionFrame frame;
4717 static_cast<QStyleOption &>(frame) = *opt;
4718 frame.rect = lineEditRect;
4719 frame.state |= State_Sunken;
4720 frame.lineWidth = 1;
4721 frame.midLineWidth = 0;
4722 frame.features = QStyleOptionFrame::None;
4723 frame.frameShape = QStyleOptionFrame::Box;
4724 drawPrimitive(PE_FrameLineEdit, &frame, p);
4726 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4727 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4728 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
4730 d->setupNSGraphicsContext(cg, NO);
4732 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4734 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
4735 cell.enabled = (sb->state & State_Enabled);
4736 const auto controlSize = cell.controlSize;
4737 if (qt_apple_runningWithLiquidGlass())
4738 cell.controlSize = NSControlSizeMini;
4740 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4742 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4743 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4744 const CGFloat x = CGRectGetMidX(newRect);
4745 const CGFloat y = upPressed ? -3 : 3;
4746 const CGPoint pressPoint = CGPointMake(x, y);
4749 if (upPressed || downPressed)
4750 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4752 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4754 if (upPressed || downPressed)
4755 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4757 d->restoreNSGraphicsContext(cg);
4758 if (qt_apple_runningWithLiquidGlass())
4759 cell.controlSize = controlSize;
4764 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4765 const bool isEnabled = combo->state & State_Enabled;
4766 const bool isPressed = combo->state & State_Sunken;
4768 const auto ct = cocoaControlType(combo);
4769 const auto cs = d->effectiveAquaSizeConstrain(combo);
4771 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4772 cc.enabled = isEnabled;
4773 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4776 auto *pb =
static_cast<NSPopUpButton *>(cc);
4778 if (cw.size == QStyleHelper::SizeSmall) {
4779 frameRect = frameRect.translated(0, 1);
4780 }
else if (cw.size == QStyleHelper::SizeMini) {
4782 frameRect = frameRect.translated(2, -0.5);
4784 pb.frame = frameRect.toCGRect();
4785 [pb highlight:isPressed];
4786 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4787 QMacAutoReleasePool pool;
4788 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4792 auto *cb =
static_cast<NSComboBox *>(cc);
4793 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4794 cb.frame = frameRect.toCGRect();
4797 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4798 cell.highlighted = isPressed;
4803 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4805 QMacAutoReleasePool pool;
4806 [cb.cell drawWithFrame:r inView:cb];
4811 case CC_SearchField:
4812 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4813 const bool isEnabled = sf->state & State_Enabled;
4815 const auto cs = d->effectiveAquaSizeConstrain(sf);
4817 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4818 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4820 searchField.enabled = isEnabled;
4827 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4828 if (
__builtin_available(macOS 26, *)) {
4829 NSButtonCell *btn = cell.searchButtonCell;
4830 NSImageSymbolConfiguration *imgCfg =
4831 [NSImageSymbolConfiguration configurationWithPointSize:11
4832 weight:NSFontWeightMedium
4833 scale:NSImageSymbolScaleMedium];
4834 btn.image = [btn.image imageWithSymbolConfiguration:imgCfg];
4835 [btn.image setTemplate:YES];
4836 btn.imageScaling = NSImageScaleNone;
4840 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4842 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4843 if (
__builtin_available(macOS 26, *)) {
4844 const auto oneDevicePx = 1.0 / p->device()->devicePixelRatioF();
4845 frameRect = frameRect.adjusted(+oneDevicePx, -oneDevicePx, -oneDevicePx, +oneDevicePx);
4849 searchField.frame = frameRect.toCGRect();
4851 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4853 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4854 [cell drawWithFrame:rect inView:searchField];
4855 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4857 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4858 [cell drawWithFrame:rect inView:searchField];
4861 [cell setStringValue:sf->text.toNSString()];
4862 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4863 [cell drawWithFrame:r inView:searchField];
4869 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4870 const bool isActive = (titlebar->state & State_Active)
4871 && (titlebar->titleBarState & State_Active);
4873 p->fillRect(opt->rect, Qt::transparent);
4874 p->setRenderHint(QPainter::Antialiasing);
4875 p->setClipRect(opt->rect, Qt::IntersectClip);
4879 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4880 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4881 p->fillPath(outerFramePath, opt->palette.dark());
4883 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4884 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4885 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4886 p->fillPath(innerFramePath, opt->palette.button());
4888 if (titlebar->subControls & (SC_TitleBarCloseButton
4889 | SC_TitleBarMaxButton
4890 | SC_TitleBarMinButton
4891 | SC_TitleBarNormalButton)) {
4892 const bool isHovered = (titlebar->state & State_MouseOver);
4893 static const SubControl buttons[] = {
4894 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4896 for (
const auto sc : buttons) {
4897 const auto ct = d->windowButtonCocoaControl(sc);
4898 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4899 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4900 wb.enabled = (sc & titlebar->subControls) && isActive;
4901 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4902 Q_UNUSED(isHovered);
4904 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4905 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4906 QMacAutoReleasePool pool;
4907 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4908 [wbCell drawWithFrame:rect inView:wb];
4913 if (titlebar->subControls & SC_TitleBarLabel) {
4914 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4915 if (!titlebar->icon.isNull()) {
4916 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4917 const auto iconSize = QSize(iconExtent, iconExtent);
4918 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4920 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4921 p->drawPixmap(iconPos, tr.y(),
4922 titlebar->icon.pixmap(iconSize,
4923 opt->window->devicePixelRatio(),
4927 if (!titlebar->text.isEmpty())
4928 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4933 if (
const QStyleOptionGroupBox *gb
4934 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4936 QStyleOptionGroupBox groupBox(*gb);
4937 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4939 groupBox.state |= QStyle::State_Mini;
4941 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4947 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4962 if (
const QStyleOptionToolButton *tb
4963 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4964#ifndef QT_NO_ACCESSIBILITY
4965 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4966 if (tb->subControls & SC_ToolButtonMenu) {
4967 QStyleOption arrowOpt = *tb;
4968 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4969 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4970 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4971 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4972 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4973 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4974 d->drawToolbarButtonArrow(tb, p);
4976 if (tb->state & State_On) {
4977 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4980 isKey = [view.window isKeyWindow];
4984 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4985 p->setRenderHint(QPainter::Antialiasing);
4986 p->fillPath(path, brush);
4988 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4992 auto bflags = tb->state;
4993 if (tb->subControls & SC_ToolButton)
4994 bflags |= State_Sunken;
4995 auto mflags = tb->state;
4996 if (tb->subControls & SC_ToolButtonMenu)
4997 mflags |= State_Sunken;
4999 if (tb->subControls & SC_ToolButton) {
5000 if (bflags & (State_Sunken | State_On | State_Raised)) {
5001 const bool isEnabled = tb->state & State_Enabled;
5002 const bool isPressed = tb->state & State_Sunken;
5003 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5005 const auto cs = d->effectiveAquaSizeConstrain(opt);
5007 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5008 pb.bezelStyle = NSBezelStyleShadowlessSquare;
5009 pb.frame = opt->rect.toCGRect();
5010 pb.buttonType = NSButtonTypePushOnPushOff;
5011 pb.enabled = isEnabled;
5012 [pb highlight:isPressed];
5013 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5014 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
5015 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5016 QMacAutoReleasePool pool;
5017 [pb.cell drawBezelWithFrame:rect inView:pb];
5022 if (tb->subControls & SC_ToolButtonMenu) {
5023 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
5024 QStyleOption arrowOpt = *tb;
5029 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
5030 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
5031 d->drawToolbarButtonArrow(tb, p);
5033 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
5034 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
5035 QStyleOptionToolButton label = *tb;
5036 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5037 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
5042 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
5043 QStyleHelper::drawDial(dial, p);
5046 QCommonStyle::drawComplexControl(cc, opt, p);
5053 Q_D(
const QMacStyle);
5055 SubControl sc = QStyle::SC_None;
5059 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5060 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5061 if (!cmb->editable && sc != QStyle::SC_None)
5062 sc = SC_ComboBoxArrow;
5066 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5067 if (!sl->rect.contains(pt))
5070 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5071 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5073 const auto cs = d->effectiveAquaSizeConstrain(opt);
5075 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5076 if (!setupSlider(slider, sl))
5079 NSSliderCell *cell = slider.cell;
5080 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5081 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5082 if (knobRect.contains(pt)) {
5083 sc = SC_SliderHandle;
5084 }
else if (barRect.contains(pt)) {
5085 sc = SC_SliderGroove;
5086 }
else if (hasTicks) {
5087 sc = SC_SliderTickmarks;
5092 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5093 if (!sb->rect.contains(pt)) {
5098 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5100 const auto cs = d->effectiveAquaSizeConstrain(opt);
5102 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5103 if (!setupScroller(scroller, sb)) {
5111 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5113 const bool isReverse = sb->direction == Qt::RightToLeft;
5114 if (pt.x() < knobRect.left())
5115 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5116 else if (pt.x() > knobRect.right())
5117 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5119 sc = SC_ScrollBarSlider;
5121 if (pt.y() < knobRect.top())
5122 sc = SC_ScrollBarSubPage;
5123 else if (pt.y() > knobRect.bottom())
5124 sc = SC_ScrollBarAddPage;
5126 sc = SC_ScrollBarSlider;
5130 case CC_SearchField:
5131 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5132 if (!sf->rect.contains(pt))
5135 const auto cs = d->effectiveAquaSizeConstrain(sf);
5137 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5138 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5140 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5141 const CGRect bounds = searchField.bounds;
5143 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5144 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5145 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5147 const QPointF localPt = pt - sf->rect.topLeft();
5149 if (cancelRect.contains(localPt))
5150 sc = SC_SearchFieldClear;
5151 else if (searchIconRect.contains(localPt))
5152 sc = SC_SearchFieldSearch;
5153 else if (textFieldRect.contains(localPt))
5154 sc = SC_SearchFieldEditField;
5156 sc = SC_SearchFieldPopup;
5162 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5170 Q_D(
const QMacStyle);
5176 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5177 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5178 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5180 NSScrollerPart part = NSScrollerNoPart;
5181 if (sc == SC_ScrollBarSlider) {
5182 part = NSScrollerKnob;
5183 }
else if (sc == SC_ScrollBarGroove) {
5184 part = NSScrollerKnobSlot;
5185 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5186 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5187 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5188 part = NSScrollerDecrementPage;
5190 part = NSScrollerIncrementPage;
5194 if (part != NSScrollerNoPart) {
5196 const auto cs = d->effectiveAquaSizeConstrain(opt);
5198 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5199 if (setupScroller(scroller, sb))
5200 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5205 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5206 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5207 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5209 const auto cs = d->effectiveAquaSizeConstrain(opt);
5211 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5212 if (!setupSlider(slider, sl))
5215 NSSliderCell *cell = slider.cell;
5216 if (sc == SC_SliderHandle) {
5217 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5218 }
else if (sc == SC_SliderGroove) {
5219 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5220 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5221 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5223 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5225 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5236 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5242 if (sc == SC_TitleBarLabel) {
5243 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5244 qreal labelHeight = titlebar->fontMetrics.height();
5246 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5247 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5248 if (!titlebar->icon.isNull()) {
5249 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5250 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5251 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5254 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5255 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5256 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5257 labelWidth, labelHeight);
5259 const auto currentButton = d->windowButtonCocoaControl(sc);
5263 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5266 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5267 QStyleHelper::SizeLarge);
5268 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5269 if (ct == currentButton)
5270 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5272 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5275 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5276 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5281 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5282 const auto ct = cocoaControlType(combo);
5283 const auto cs = d->effectiveAquaSizeConstrain(combo);
5292 case QStyleHelper::SizeLarge:
5293 if (qt_apple_runningWithLiquidGlass())
5294 editRect = combo->rect.adjusted(15, 7, -25, -7);
5296 editRect = combo->rect.adjusted(15, 7, -25, -9);
5298 case QStyleHelper::SizeSmall:
5299 if (combo->editable)
5300 editRect = combo->rect.adjusted(15, 6, -22, -9);
5302 editRect = combo->rect.adjusted(15, 8, -22, -6);
5305 if (combo->editable)
5306 editRect = combo->rect.adjusted(15, 6, -20, -7);
5308 editRect = combo->rect.adjusted(15, 5, -22, -6);
5313 case SC_ComboBoxEditField:{
5314 ret = editRect.toAlignedRect();
5316 case SC_ComboBoxArrow:{
5317 ret = editRect.toAlignedRect();
5318 ret.setX(ret.x() + ret.width());
5319 ret.setWidth(combo->rect.right() - ret.right());
5321 case SC_ComboBoxListBoxPopup:{
5322 if (combo->editable) {
5323 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5324 const int comboTop = combo->rect.top();
5325 ret = QRect(qRound(inner.origin.x),
5327 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5328 editRect.bottom() - comboTop + 2);
5330 ret = QRect(combo->rect.x() + 4 - 11,
5331 combo->rect.y() + 1,
5332 editRect.width() + 10 + 11,
5342 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5343 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5344 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5345 bool hasNoText = !checkable && groupBox->text.isEmpty();
5347 case SC_GroupBoxLabel:
5348 case SC_GroupBoxCheckBox: {
5350 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5351 const bool fontIsSet =
false;
5354 const int margin = flat || hasNoText ? 0 : 9;
5355 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5357 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5358 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5359 const int tw = qCeil(s.width());
5360 const int h = qCeil(fm.height());
5363 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5365 if (flat && checkable)
5366 labelRect.moveLeft(labelRect.left() + 4);
5367 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5368 bool rtl = groupBox->direction == Qt::RightToLeft;
5369 if (sc == SC_GroupBoxLabel) {
5371 int newSum = indicatorWidth + 1;
5372 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5373 labelRect.moveLeft(newLeft);
5375 labelRect.moveTop(labelRect.top() + 3);
5377 labelRect.moveTop(labelRect.top() + 4);
5379 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5380 labelRect.moveLeft(newLeft);
5381 labelRect.moveTop(labelRect.top() + 3);
5383 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5384 labelRect.moveLeft(newLeft);
5385 labelRect.moveTop(labelRect.top() + 4);
5390 if (sc == SC_GroupBoxCheckBox) {
5391 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5392 int top = flat ? ret.top() + 1 : ret.top() + 5;
5393 ret.setRect(left, top,
5394 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5398 case SC_GroupBoxContents:
5399 case SC_GroupBoxFrame: {
5400 QFontMetrics fm = groupBox->fontMetrics;
5406 yOffset = -qCeil(QFontMetricsF(fm).height());
5407 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5408 if (sc == SC_GroupBoxContents) {
5410 ret.adjust(3, -5, -3, -4);
5412 ret.adjust(3, 3, -3, -4);
5417 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5423 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5424 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5425 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5431 case QStyleHelper::SizeLarge:
5437 case QStyleHelper::SizeSmall:
5443 case QStyleHelper::SizeMini:
5455 case SC_SpinBoxDown: {
5456 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5460 const int x = spin->rect.width() - spinner_w;
5461 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5464 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5465 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5466 ret = QRectF::fromCGRect(outRect).toRect();
5470 ret.setHeight(ret.height() / 2);
5472 case SC_SpinBoxDown:
5473 ret.setY(ret.y() + ret.height() / 2);
5481 ret.translate(0, adjust_y);
5482 ret = visualRect(spin->direction, spin->rect, ret);
5485 case SC_SpinBoxEditField:
5486 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5487 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5488 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5489 ret = visualRect(spin->direction, spin->rect, ret);
5493 ret = QCommonStyle::subControlRect(cc, spin, sc);
5499 ret = QCommonStyle::subControlRect(cc, opt, sc);
5500 if (sc == SC_ToolButtonMenu) {
5501#ifndef QT_NO_ACCESSIBILITY
5502 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5505 ret.adjust(-1, 0, 0, 0);
5508 case CC_SearchField:
5509 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5510 const auto cs = d->effectiveAquaSizeConstrain(sf);
5515 case QStyleHelper::SizeLarge:
5516 editRect = sf->rect.adjusted(16, 0, -22, 0);
5518 case QStyleHelper::SizeSmall:
5519 editRect = sf->rect.adjusted(16, 5, -22, -7);
5522 editRect = sf->rect.adjusted(16, 5, -18, -7);
5526 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5527 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5528 const CGRect bounds = searchField.bounds;
5531 case SC_SearchFieldEditField:{
5532 ret = editRect.toAlignedRect();
5536 case SC_SearchFieldClear: {
5537 const CGRect r = [cell cancelButtonRectForBounds:bounds];
5538 ret = QRectF::fromCGRect(r).toRect();
5539 ret.translate(0, -1);
5540 ret = visualRect(sf->direction, sf->rect, ret);
5541 ret.adjust(-3, -3, 3, 3);
5544 case SC_SearchFieldSearch: {
5545 const CGRect r = [cell searchButtonRectForBounds:bounds];
5546 ret = QRectF::fromCGRect(r).toRect();
5547 ret.translate(0, -1);
5548 ret = visualRect(sf->direction, sf->rect, ret);
5549 ret.adjust(-3, -3, 3, 3);
5552 case SC_SearchFieldPopup: {
5553 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5554 const int searchTop = sf->rect.top();
5555 ret = QRect(qRound(inner.origin.x),
5557 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5558 editRect.bottom() - searchTop + 2);
5567 ret = QCommonStyle::subControlRect(cc, opt, sc);
5575 Q_D(
const QMacStyle);
5578 bool useAquaGuideline =
true;
5582 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5583 if (vopt->subControls == SC_SpinBoxFrame) {
5584 const QSize minimumSize(20, 24);
5585 if (sz.width() < minimumSize.width())
5586 sz.setWidth(minimumSize.width());
5587 if (sz.height() < minimumSize.height())
5588 sz.setHeight(minimumSize.height());
5590 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5591 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5592 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5596 case QStyle::CT_TabWidget:
5599 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5601
5602
5603
5604
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
5631 if (
const QStyleOptionTabWidgetFrame *twf
5632 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5634 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5635 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5637 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5638 if (tabDirection == QMacStylePrivate::North
5639 || tabDirection == QMacStylePrivate::South) {
5640 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5642 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5647 case QStyle::CT_TabBarTab:
5648 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5651 const bool differentFont =
false;
5652 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5653 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5654 || tabDirection == QMacStylePrivate::West;
5656 sz = sz.transposed();
5658 int defaultTabHeight;
5659 const auto cs = d->effectiveAquaSizeConstrain(opt);
5661 case QStyleHelper::SizeLarge:
5662 if (tab->documentMode)
5663 defaultTabHeight = 24;
5665 defaultTabHeight = 21;
5667 case QStyleHelper::SizeSmall:
5668 defaultTabHeight = 18;
5670 case QStyleHelper::SizeMini:
5671 defaultTabHeight = 16;
5677 const bool widthSet = !differentFont && tab->icon.isNull();
5679 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5680 sz.rwidth() = textSize.width();
5681 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5683 sz.rheight() = qMax(defaultTabHeight, sz.height());
5685 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5688 sz = sz.transposed();
5690 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5691 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5693 int widgetWidth = 0;
5694 int widgetHeight = 0;
5696 if (tab->leftButtonSize.isValid()) {
5698 widgetWidth += tab->leftButtonSize.width();
5699 widgetHeight += tab->leftButtonSize.height();
5701 if (tab->rightButtonSize.isValid()) {
5703 widgetWidth += tab->rightButtonSize.width();
5704 widgetHeight += tab->rightButtonSize.height();
5708 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5709 sz.setHeight(sz.height() + widgetHeight + padding);
5712 sz.setWidth(sz.width() + widgetWidth + padding);
5713 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5718 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5720 if (sz.width() < 10)
5722 if (sz.height() < 20)
5726 int leftPadding = 4;
5727 int rightPadding = 4;
5729 int bottomPadding = 0;
5731 if (opt->state & QStyle::State_Small) {
5733 }
else if (opt->state & QStyle::State_Mini) {
5737 sz.rwidth() += leftPadding + rightPadding;
5738 sz.rheight() += topPadding + bottomPadding;
5741 case QStyle::CT_PushButton: {
5742 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5743 if (btn->features & QStyleOptionButton::CommandLinkButton)
5744 return QCommonStyle::sizeFromContents(ct, opt, sz);
5751 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5753 if (macsz.width() != -1)
5754 sz.setWidth(macsz.width());
5758 if (controlSize != QStyleHelper::SizeMini)
5760 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5761 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5762 else if (controlSize == QStyleHelper::SizeMini)
5765 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5768 case QStyle::CT_MenuItem:
5769 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5770 int maxpmw = mi->maxIconWidth;
5772 int h = sz.height();
5778 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5782 h = mi->fontMetrics.height() + 2;
5783 if (!mi->icon.isNull()) {
5792 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5793 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5797 if (mi->text.contains(QLatin1Char(
'\t')))
5799 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5818 case CT_MenuBarItem:
5825 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5826 if (tb->features & QStyleOptionToolButton::Menu)
5830 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5831 const int controlSize = getControlSize(opt);
5834 if (sz.width() < 10)
5837 if (!cb->editable) {
5842 if (controlSize == QStyleHelper::SizeLarge) {
5844 }
else if (controlSize == QStyleHelper::SizeSmall) {
5854 if (controlSize == QStyleHelper::SizeMini)
5857 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5862 case CT_SearchField:
5863 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5864 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5865 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5866 if (sf->subControls == SC_SearchFieldFrame) {
5867 const int controlSize = getControlSize(opt);
5871 if (controlSize == QStyleHelper::SizeLarge) {
5875 }
else if (controlSize == QStyleHelper::SizeSmall) {
5886 if (sz.width() < 60)
5889 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5890 sz.rwidth() += totalIconsSize;
5893 }
else if (sf->subControls == SC_SearchFieldClear) {
5895 }
else if (sf->subControls == SC_SearchFieldSearch) {
5896 return searchButton;
5901 if (proxy() ==
this) {
5904 QStyleHintReturnMask menuMask;
5905 QStyleOption myOption = *opt;
5906 myOption.rect.setSize(sz);
5907 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5908 sz = menuMask.region.boundingRect().size();
5911 case CT_HeaderSection:{
5912 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5913 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5914 if (header->text.contains(QLatin1Char(
'\n')))
5915 useAquaGuideline =
false;
5919 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5920 const int minimumWidth = 24;
5921 const int absoluteHeight = 14;
5922 if (slider->orientation == Qt::Horizontal) {
5923 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5924 sz.setHeight(absoluteHeight);
5926 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5927 sz.setWidth(absoluteHeight);
5931 case CT_ItemViewItem:
5932 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5933 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5934 sz.setHeight(sz.height() + 2);
5938 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5941 if (useAquaGuideline && ct != CT_PushButton) {
5944 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5945 if (macsz.width() != -1)
5946 sz.setWidth(macsz.width());
5947 if (macsz.height() != -1)
5948 sz.setHeight(macsz.height());
5954 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5955 if (combo->editable) {
5956 const auto widgetSize = d->aquaSizeConstrain(opt);
5959 cw.size = widgetSize;
5960 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5961 sz.rwidth() -= qRound(diffRect.size.width);
5962 sz.rheight() -= qRound(diffRect.size.height);
5970 QFont font = QCommonStyle::font(element, state);
5972 if (state & QStyle::State_Small) {
5973 font.setPixelSize(11);
5974 }
else if (state & QStyle::State_Mini) {
5975 font.setPixelSize(9);
5987 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5988 margins = QMargins(10, 0, arrow.width() + 1, -1);
5991 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
5999 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
6001 if(flags & Qt::TextShowMnemonic)
6002 flags |= Qt::TextHideMnemonic;
6003 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6008 switch (standardIcon) {
6010 return QCommonStyle::standardIcon(standardIcon, opt);
6011 case SP_ToolBarHorizontalExtensionButton:
6012 case SP_ToolBarVerticalExtensionButton: {
6013 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
6014 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6015 QPixmap pix2(pixmap.height(), pixmap.width());
6016 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
6017 pix2.fill(Qt::transparent);
6019 p.translate(pix2.width(), 0);
6021 p.drawPixmap(0, 0, pixmap);