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;
1078 return other.type == type && other.size == size;
1089 return QSizeF(-1, pushButtonDefaultHeight[size]);
1093 return QSizeF(-1, popupButtonDefaultHeight[size]);
1096 return QSizeF(-1, comboBoxDefaultHeight[size]);
1104 const auto frameSize = defaultFrameSize();
1106 frameRect = rect.adjusted(3, 1, -3, -1)
1107 .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
1110 frameRect = QRectF(rect.topLeft(),
1111 QSizeF(rect.width(), frameSize.height()));
1112 if (size == QStyleHelper::SizeSmall)
1113 frameRect = frameRect.translated(0, 1.5);
1114 else if (size == QStyleHelper::SizeMini)
1115 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
1118 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1119 QSizeF(rect.width(), frameSize.height()));
1120 frameRect = frameRect.translated(rect.topLeft());
1122 if (size == QStyleHelper::SizeLarge)
1123 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1124 else if (size == QStyleHelper::SizeSmall)
1125 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1126 else if (size == QStyleHelper::SizeMini)
1127 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1129 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1139 if (size == QStyleHelper::SizeLarge) {
1140 if (qt_apple_runningWithLiquidGlass())
1141 return QMarginsF(10, 5, 10, 5);
1143 return QMarginsF(12, 5, 12, 7);
1145 if (size == QStyleHelper::SizeSmall)
1146 return QMarginsF(12, 4, 12, 9);
1147 if (size == QStyleHelper::SizeMini)
1148 return QMarginsF(10, 1, 10, 2);
1152 if (size == QStyleHelper::SizeLarge)
1153 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1154 if (size == QStyleHelper::SizeSmall)
1155 return QMarginsF(7.5, 2, 20.5, 4);
1156 if (size == QStyleHelper::SizeMini)
1157 return QMarginsF(4.5, 0, 16.5, 2);
1161 return QMarginsF(6, 1, 6, 2);
1169 case Button_CheckBox:
1170 *buttonType = NSButtonTypeSwitch;
1171 *bezelStyle = NSBezelStyleRegularSquare;
1173 case Button_Disclosure:
1174 *buttonType = NSButtonTypeOnOff;
1175 *bezelStyle = NSBezelStyleDisclosure;
1177 case Button_RadioButton:
1178 *buttonType = NSButtonTypeRadio;
1179 *bezelStyle = NSBezelStyleRegularSquare;
1181 case Button_SquareButton:
1182 *buttonType = NSButtonTypePushOnPushOff;
1183 *bezelStyle = NSBezelStyleShadowlessSquare;
1185 case Button_PushButton:
1186 *buttonType = NSButtonTypePushOnPushOff;
1187 *bezelStyle = NSBezelStyleRounded;
1198 if (
const auto *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
1199 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
1203 const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge];
1204 const bool isSquare = (btn->features & QStyleOptionButton::Flat)
1205 || (btn->rect.height() > maxNonSquareHeight);
1212 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
1213 if (combo->editable)
1223
1224
1225
1228 CGRect innerBounds = outerBounds;
1233 switch (cocoaWidget.size) {
1234 case QStyleHelper::SizeSmall:
1235 innerBounds.origin.x += 3;
1236 innerBounds.origin.y += 3;
1237 innerBounds.size.width -= 6;
1238 innerBounds.size.height -= 7;
1240 case QStyleHelper::SizeMini:
1241 innerBounds.origin.x += 2;
1242 innerBounds.origin.y += 2;
1243 innerBounds.size.width -= 5;
1244 innerBounds.size.height -= 6;
1246 case QStyleHelper::SizeLarge:
1247 case QStyleHelper::SizeDefault:
1248 innerBounds.origin.x += 2;
1249 innerBounds.origin.y += 2;
1250 innerBounds.size.width -= 5;
1251 innerBounds.size.height -= 6;
1254 switch (cocoaWidget.size) {
1255 case QStyleHelper::SizeSmall:
1256 innerBounds.origin.x += 3;
1257 innerBounds.origin.y += 3;
1258 innerBounds.size.width -= 7;
1259 innerBounds.size.height -= 8;
1261 case QStyleHelper::SizeMini:
1262 innerBounds.origin.x += 3;
1263 innerBounds.origin.y += 3;
1264 innerBounds.size.width -= 4;
1265 innerBounds.size.height -= 8;
1267 case QStyleHelper::SizeLarge:
1268 case QStyleHelper::SizeDefault:
1269 innerBounds.origin.x += 3;
1270 innerBounds.origin.y += 2;
1271 innerBounds.size.width -= 6;
1272 innerBounds.size.height -= 8;
1280
1281
1282
1285 QRectF ret = outerBounds;
1288 case QStyleHelper::SizeLarge:
1289 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1292 case QStyleHelper::SizeSmall:
1293 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1296 case QStyleHelper::SizeMini:
1297 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1298 ret.setHeight(10.5);
1305 case QStyleHelper::SizeLarge:
1306 ret.adjust(10, 1, -23, -4);
1308 case QStyleHelper::SizeSmall:
1309 ret.adjust(10, 4, -20, -3);
1311 case QStyleHelper::SizeMini:
1312 ret.adjust(9, 0, -19, 0);
1325 if (
auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
1326 smallSystemFont = *ssf;
1327 if (
auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
1328 miniSystemFont = *msf;
1333 QMacAutoReleasePool pool;
1334 for (NSView *b : cocoaControls)
1336 for (NSCell *cell : cocoaCells)
1342 if (cocoaControl.type == QMacStylePrivate::NoControl
1343 || cocoaControl.size == QStyleHelper::SizeDefault)
1353 NSView *bv = cocoaControls.value(cocoaControl, nil);
1355 switch (cocoaControl
.type) {
1357 NSBox *box = [[NSBox alloc] init];
1360 box.titlePosition = NSNoTitle;
1364 bv = [[QDarkNSBox alloc] init];
1371 NSButton *bc = [[NSButton alloc] init];
1379 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1381 if (cocoaControl.type == Button_PullDown)
1389 const NSWindowButton button = [=] {
1390 switch (cocoaControl
.type) {
1391 case Button_WindowClose:
1392 return NSWindowCloseButton;
1393 case Button_WindowMiniaturize:
1394 return NSWindowMiniaturizeButton;
1395 case Button_WindowZoom:
1396 return NSWindowZoomButton;
1402 const auto styleMask = NSWindowStyleMaskTitled
1403 | NSWindowStyleMaskClosable
1404 | NSWindowStyleMaskMiniaturizable
1405 | NSWindowStyleMaskResizable;
1406 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1411 bv = [[NSSearchField alloc] init];
1414 bv = [[NSComboBox alloc] init];
1416 case ProgressIndicator_Determinate:
1417 bv = [[NSProgressIndicator alloc] init];
1419 case ProgressIndicator_Indeterminate:
1420 bv = [[QIndeterminateProgressIndicator alloc] init];
1422 case Scroller_Horizontal:
1423 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1425 case Scroller_Vertical:
1428 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1430 case Slider_Horizontal:
1431 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1433 case Slider_Vertical:
1436 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1438 case SplitView_Horizontal:
1439 bv = [[NSSplitView alloc] init];
1441 case SplitView_Vertical:
1442 bv = [[QVerticalSplitView alloc] init];
1445 bv = [[NSTextField alloc] init];
1451 if ([bv isKindOfClass:[NSControl
class]]) {
1452 auto *ctrl =
static_cast<NSControl *>(bv);
1453 switch (cocoaControl.size) {
1454 case QStyleHelper::SizeSmall:
1455 ctrl.controlSize = NSControlSizeSmall;
1457 case QStyleHelper::SizeMini:
1458 ctrl.controlSize = NSControlSizeMini;
1465 auto *pi =
static_cast<NSProgressIndicator *>(bv);
1467 switch (cocoaControl.size) {
1468 case QStyleHelper::SizeSmall:
1469 pi.controlSize = NSControlSizeSmall;
1471 case QStyleHelper::SizeMini:
1472 pi.controlSize = NSControlSizeMini;
1479 cocoaControls.insert(cocoaControl, bv);
1482 NSButtonType buttonType;
1483 NSBezelStyle bezelStyle;
1499 NSCell *cell = cocoaCells[cocoaControl];
1501 switch (cocoaControl
.type) {
1503 cell = [[NSStepperCell alloc] init];
1506 NSButtonCell *bc = [[NSButtonCell alloc] init];
1507 bc.buttonType = NSButtonTypeOnOff;
1508 bc.bezelStyle = NSBezelStyleDisclosure;
1516 switch (cocoaControl.size) {
1517 case QStyleHelper::SizeSmall:
1518 cell.controlSize = NSControlSizeSmall;
1520 case QStyleHelper::SizeMini:
1521 cell.controlSize = NSControlSizeMini;
1527 cocoaCells.insert(cocoaControl, cell);
1533void QMacStylePrivate::drawNSViewInRect(NSView *view,
const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock)
const
1535 QMacAutoReleasePool pool;
1536 QMacCGContext ctx(p);
1537 setupNSGraphicsContext(ctx, YES);
1548 view.wantsLayer = YES;
1557 view.frame = rect.toCGRect();
1559 [backingStoreNSView addSubview:view];
1566 const CGRect dirtyRect = rect.toCGRect();
1569 drawRectBlock(ctx, dirtyRect);
1571 [view drawRect:dirtyRect];
1573 [view removeFromSuperviewWithoutNeedingDisplay];
1575 restoreNSGraphicsContext(ctx);
1580 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1585 return new QMacApperanceStyle<QMacStyle, QStyleOption, QStyleOptionComplex>;
1589 : QCommonStyle(*
new QMacStylePrivate)
1591 QMacAutoReleasePool pool;
1593 static QMacNotificationObserver scrollbarStyleObserver(nil,
1594 NSPreferredScrollerStyleDidChangeNotification, []() {
1596 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1598 QEvent event(QEvent::StyleChange);
1599 for (
const auto &o : QMacStylePrivate::scrollBars)
1600 QCoreApplication::sendEvent(o, &event);
1611 for (NSView *b : d->cocoaControls)
1613 d->cocoaControls.clear();
1618 Q_D(
const QMacStyle);
1619 const int controlSize = getControlSize(opt);
1623 case PM_TabCloseIndicatorWidth:
1624 case PM_TabCloseIndicatorHeight:
1627 case PM_ToolBarIconSize:
1628 ret = proxy()->pixelMetric(PM_LargeIconSize);
1630 case PM_FocusFrameVMargin:
1631 case PM_FocusFrameHMargin:
1634 case PM_DialogButtonsSeparator:
1637 case PM_DialogButtonsButtonHeight: {
1639 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1640 if (sz == QSize(-1, -1))
1645 case PM_DialogButtonsButtonWidth: {
1647 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1648 if (sz == QSize(-1, -1))
1654 case PM_MenuBarHMargin:
1658 case PM_MenuBarVMargin:
1662 case PM_MenuBarPanelWidth:
1666 case PM_MenuButtonIndicator:
1670 case QStyle::PM_MenuDesktopFrameWidth:
1674 case PM_CheckBoxLabelSpacing:
1675 case PM_RadioButtonLabelSpacing:
1678 if (opt->state & State_Mini)
1680 if (opt->state & State_Small)
1686 case PM_MenuScrollerHeight:
1689 case PM_DefaultFrameWidth:
1699 if (qstyleoption_cast<
const QStyleOptionComboBox *>(opt) != 0)
1704 case PM_MaximumDragDistance:
1707 case PM_ScrollBarSliderMin:
1710 case PM_SpinBoxFrameWidth:
1713 case PM_ButtonShiftHorizontal:
1714 case PM_ButtonShiftVertical:
1717 case PM_SliderLength:
1723 case PM_SliderControlThickness:
1724 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
1725 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1726 int ticks = sl->tickPosition;
1728 if (ticks & QStyleOptionSlider::TicksAbove)
1730 if (ticks & QStyleOptionSlider::TicksBelow)
1738 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1739 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1743 thick += (space * 2) / (n + 2);
1749 case PM_SmallIconSize:
1750 ret =
int(QStyleHelper::dpiScaled(16., opt));
1753 case PM_LargeIconSize:
1754 ret =
int(QStyleHelper::dpiScaled(32., opt));
1757 case PM_IconViewIconSize:
1758 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1761 case PM_ButtonDefaultIndicator:
1764 case PM_TitleBarHeight: {
1765 NSUInteger style = NSWindowStyleMaskTitled;
1768 ret =
int([NSWindow frameRectForContentRect:NSZeroRect
1769 styleMask:style].size.height);
1771 case QStyle::PM_TabBarTabHSpace:
1772 switch (d->aquaSizeConstrain(opt)) {
1773 case QStyleHelper::SizeLarge:
1774 ret = QCommonStyle::pixelMetric(metric, opt);
1776 case QStyleHelper::SizeSmall:
1779 case QStyleHelper::SizeMini:
1782 case QStyleHelper::SizeDefault:
1783 const QStyleOptionTab *tb = qstyleoption_cast<
const QStyleOptionTab *>(opt);
1784 if (tb && tb->documentMode)
1787 ret = QCommonStyle::pixelMetric(metric, opt);
1791 case PM_TabBarTabVSpace:
1794 case PM_TabBarTabShiftHorizontal:
1795 case PM_TabBarTabShiftVertical:
1798 case PM_TabBarBaseHeight:
1801 case PM_TabBarTabOverlap:
1804 case PM_TabBarBaseOverlap:
1805 switch (d->aquaSizeConstrain(opt)) {
1806 case QStyleHelper::SizeDefault:
1807 case QStyleHelper::SizeLarge:
1810 case QStyleHelper::SizeSmall:
1813 case QStyleHelper::SizeMini:
1818 case PM_ScrollBarExtent: {
1819 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1820 ret =
static_cast<
int>([NSScroller
1821 scrollerWidthForControlSize:
static_cast<NSControlSize>(size)
1822 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1824 case PM_IndicatorHeight: {
1825 switch (d->aquaSizeConstrain(opt)) {
1826 case QStyleHelper::SizeDefault:
1827 case QStyleHelper::SizeLarge:
1830 case QStyleHelper::SizeMini:
1833 case QStyleHelper::SizeSmall:
1838 case PM_IndicatorWidth: {
1839 switch (d->aquaSizeConstrain(opt)) {
1840 case QStyleHelper::SizeDefault:
1841 case QStyleHelper::SizeLarge:
1844 case QStyleHelper::SizeMini:
1847 case QStyleHelper::SizeSmall:
1853 case PM_ExclusiveIndicatorHeight: {
1854 switch (d->aquaSizeConstrain(opt)) {
1855 case QStyleHelper::SizeDefault:
1856 case QStyleHelper::SizeLarge:
1859 case QStyleHelper::SizeMini:
1862 case QStyleHelper::SizeSmall:
1867 case PM_ExclusiveIndicatorWidth: {
1868 switch (d->aquaSizeConstrain(opt)) {
1869 case QStyleHelper::SizeDefault:
1870 case QStyleHelper::SizeLarge:
1873 case QStyleHelper::SizeMini:
1876 case QStyleHelper::SizeSmall:
1882 case PM_MenuVMargin:
1885 case PM_MenuPanelWidth:
1888 case PM_ToolTipLabelFrameWidth:
1891 case PM_SizeGripSize: {
1892 QStyleHelper::WidgetSizePolicy aSize;
1896 aSize = QStyleHelper::SizeLarge;
1897 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
1900 case PM_MdiSubWindowFrameWidth:
1903 case PM_DockWidgetFrameWidth:
1906 case PM_DockWidgetTitleMargin:
1909 case PM_DockWidgetSeparatorExtent:
1912 case PM_ToolBarHandleExtent:
1915 case PM_ToolBarItemMargin:
1918 case PM_ToolBarItemSpacing:
1921 case PM_SplitterWidth:
1924 case PM_LayoutLeftMargin:
1925 case PM_LayoutTopMargin:
1926 case PM_LayoutRightMargin:
1927 case PM_LayoutBottomMargin:
1929 if (opt->state & State_Window) {
1931
1932
1933
1934
1935
1952
1953
1958 case PM_LayoutHorizontalSpacing:
1959 case PM_LayoutVerticalSpacing:
1961 case PM_MenuHMargin:
1964 case PM_ToolBarExtensionExtent:
1967 case PM_ToolBarFrameWidth:
1970 case PM_ScrollView_ScrollBarOverlap:
1971 ret = styleHint(SH_ScrollBar_Transient, opt,
nullptr)
1972 ? pixelMetric(PM_ScrollBarExtent, opt)
1975 case PM_PushButtonFocusFrameRadius:
1978 case PM_CheckBoxFocusFrameRadius:
1981 case PM_SearchFieldFocusFrameRadius:
1982 case PM_ComboBoxFocusFrameRadius:
1983 if (qt_apple_runningWithLiquidGlass())
1988 case PM_RadioButtonFocusFrameRadius:
1991 case PM_SliderFocusFrameRadius:
1998 case PM_DialFocusFrameRadius:
1999 case PM_SpinBoxFocusFrameRadius:
2000 case PM_TextAreaFocusFrameRadius:
2001 case PM_TextFieldFocusFrameRadius:
2002 ret = qt_apple_runningWithLiquidGlass() ? 6 : 0;
2005 ret = QCommonStyle::pixelMetric(metric, opt);
2021int QMacStyle::
styleHint(StyleHint sh,
const QStyleOption *opt, QStyleHintReturn *hret)
const
2023 QMacAutoReleasePool pool;
2027 case SH_Slider_SnapToValue:
2028 case SH_PrintDialog_RightAlignButtons:
2029 case SH_FontDialog_SelectAssociatedText:
2030 case SH_MenuBar_MouseTracking:
2031 case SH_Menu_MouseTracking:
2032 case SH_ComboBox_ListMouseTracking:
2033 case SH_MainWindow_SpaceBelowMenuBar:
2034 case SH_ItemView_ChangeHighlightOnFocus:
2037 case SH_ToolBox_SelectedPageTitleBold:
2040 case SH_DialogButtonBox_ButtonsHaveIcons:
2043 case SH_Menu_SelectionWrap:
2046 case SH_Menu_KeyboardSearch:
2049 case SH_Menu_SpaceActivatesItem:
2052 case SH_Slider_AbsoluteSetButtons:
2053 ret = Qt::LeftButton|Qt::MiddleButton;
2055 case SH_Slider_PageSetButtons:
2058 case SH_ScrollBar_ContextMenu:
2061 case SH_TitleBar_AutoRaise:
2064 case SH_Menu_AllowActiveAndDisabled:
2067 case SH_Menu_SubMenuPopupDelay:
2070 case SH_Menu_SubMenuUniDirection:
2073 case SH_Menu_SubMenuSloppySelectOtherActions:
2076 case SH_Menu_SubMenuResetWhenReenteringParent:
2079 case SH_Menu_SubMenuDontStartSloppyOnLeave:
2083 case SH_ScrollBar_LeftClickAbsolutePosition: {
2084 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2085 bool result = [defaults boolForKey:@
"AppleScrollerPagingBehavior"];
2091 case SH_TabBar_PreferNoArrows:
2095
2096
2097
2098
2099 case SH_GroupBox_TextLabelVerticalAlignment:
2102 case SH_ScrollView_FrameOnlyAroundContents:
2103 ret = QCommonStyle::styleHint(sh, opt, hret);
2105 case SH_Menu_FillScreenWithScroll:
2108 case SH_Menu_Scrollable:
2111 case SH_RichText_FullWidthSelection:
2114 case SH_BlinkCursorWhenTextSelected:
2117 case SH_Slider_StopMouseOverSlider:
2120 case SH_ListViewExpand_SelectMouseType:
2121 ret = QEvent::MouseButtonRelease;
2123 case SH_TabBar_SelectMouseType:
2124 if (
const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2125 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2127 ret = QEvent::MouseButtonRelease;
2130 case SH_ComboBox_Popup:
2131 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt))
2132 ret = !cmb->editable;
2136 case SH_Workspace_FillSpaceOnMaximize:
2139 case SH_Widget_ShareActivation:
2142 case SH_Header_ArrowAlignment:
2143 ret = Qt::AlignRight;
2145 case SH_TabBar_Alignment: {
2162 ret = Qt::AlignCenter;
2164 case SH_UnderlineShortcut:
2167 case SH_ToolTipLabel_Opacity:
2170 case SH_Button_FocusPolicy:
2173 case SH_EtchDisabledText:
2176 case SH_FocusFrame_Mask: {
2178 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2179 const uchar fillR = 192, fillG = 191, fillB = 190;
2182 QSize pixmapSize = opt->rect.size();
2183 if (!pixmapSize.isEmpty()) {
2184 QPixmap pix(pixmapSize);
2185 pix.fill(QColor(fillR, fillG, fillB));
2186 QPainter pix_paint(&pix);
2187 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2189 img = pix.toImage();
2192 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2193 const qsizetype sbpl = img.bytesPerLine();
2194 const int w = sbpl/4, h = img.height();
2196 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2197 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2198 const qsizetype dbpl = img_mask.bytesPerLine();
2200 for (
int y = 0; y < h; ++y) {
2201 srow = sptr+((y*sbpl)/4);
2202 drow = dptr+((y*dbpl)/4);
2203 for (
int x = 0; x < w; ++x) {
2204 const int redDiff = qRed(*srow) - fillR;
2205 const int greenDiff = qGreen(*srow) - fillG;
2206 const int blueDiff = qBlue(*srow) - fillB;
2207 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2208 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2212 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2213 mask->region = QRegion(qmask);
2216 case SH_TitleBar_NoBorder:
2219 case SH_RubberBand_Mask:
2222 case SH_ComboBox_LayoutDirection:
2223 ret = Qt::LeftToRight;
2225 case SH_ItemView_EllipsisLocation:
2226 ret = Qt::AlignHCenter;
2228 case SH_ItemView_ShowDecorationSelected:
2231 case SH_TitleBar_ModifyNotification:
2234 case SH_ScrollBar_RollBetweenButtons:
2237 case SH_WindowFrame_Mask:
2240 case SH_TabBar_ElideMode:
2241 ret = Qt::ElideRight;
2252 case SH_FormLayoutFormAlignment:
2253 ret = Qt::AlignHCenter | Qt::AlignTop;
2255 case SH_FormLayoutLabelAlignment:
2256 ret = Qt::AlignRight;
2261 case SH_MessageBox_TextInteractionFlags:
2262 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2264 case SH_SpellCheckUnderlineStyle:
2265 ret = QTextCharFormat::DashUnderline;
2267 case SH_MessageBox_CenterButtons:
2270 case SH_MenuBar_AltKeyNavigation:
2273 case SH_ItemView_MovementWithoutUpdatingSelection:
2276 case SH_FocusFrame_AboveWidget:
2282 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2285 case SH_Menu_FlashTriggeredItem:
2288 case SH_Menu_FadeOutOnHide:
2291 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2294 case SH_TabBar_CloseButtonPosition:
2295 ret = QStyleOptionTabBarBase::LeftSide;
2297 case SH_DockWidget_ButtonsHaveFrame:
2300 case SH_ScrollBar_Transient:
2306 case SH_TitleBar_ShowToolTipsOnButtons:
2310 case SH_ComboBox_AllowWheelScrolling:
2313 case SH_SpinBox_ButtonsInsideFrame:
2316 case SH_Table_GridLineColor:
2317 ret =
int(qt_mac_toQColor(NSColor.gridColor).rgba());
2320 ret = QCommonStyle::styleHint(sh, opt, hret);
2327 const QStyleOption *opt)
const
2330 case QIcon::Disabled: {
2331 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2332 int imgh = img.height();
2333 int imgw = img.width();
2335 for (
int y = 0; y < imgh; ++y) {
2336 for (
int x = 0; x < imgw; ++x) {
2337 pixel = img.pixel(x, y);
2338 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2339 qAlpha(pixel) / 2));
2342 return QPixmap::fromImage(img);
2347 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2358 static bool recursionGuard =
false;
2361 return QCommonStyle::standardPixmap(standardPixmap, opt);
2363 recursionGuard =
true;
2364 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2365 recursionGuard =
false;
2367 switch (standardPixmap) {
2371 case SP_MessageBoxCritical:
2372 case SP_MessageBoxQuestion:
2373 case SP_MessageBoxInformation:
2374 case SP_MessageBoxWarning:
2378 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2383 Q_D(
const QMacStyle);
2385 QMacCGContext cg(p);
2386 d->resolveCurrentNSView(opt->window);
2389 case PE_IndicatorArrowUp:
2390 case PE_IndicatorArrowDown:
2391 case PE_IndicatorArrowRight:
2392 case PE_IndicatorArrowLeft: {
2394 p->setRenderHint(QPainter::Antialiasing);
2395 const int xOffset = 1;
2396 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2397 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2407 QTransform transform;
2408 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2412 case PE_IndicatorArrowDown:
2414 case PE_IndicatorArrowUp:
2415 transform.rotate(180);
2417 case PE_IndicatorArrowLeft:
2418 transform.rotate(90);
2420 case PE_IndicatorArrowRight:
2421 transform.rotate(-90);
2424 p->setTransform(transform);
2426 path.moveTo(-halfSize, -halfSize * 0.5);
2427 path.lineTo(0.0, halfSize * 0.5);
2428 path.lineTo(halfSize, -halfSize * 0.5);
2430 const QPen arrowPen(opt->palette.text(), penWidth,
2431 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2432 p->strokePath(path, arrowPen);
2435 case PE_FrameTabBarBase:
2436 if (
const QStyleOptionTabBarBase *tbb
2437 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2438 if (tbb->documentMode) {
2440 drawTabBase(p, tbb);
2444 QRegion region(tbb->rect);
2445 region -= tbb->tabBarRect;
2447 p->setClipRegion(region);
2448 QStyleOptionTabWidgetFrame twf;
2449 twf.QStyleOption::operator=(*tbb);
2450 twf.shape = tbb->shape;
2451 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2452 case QMacStylePrivate::North:
2453 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2455 case QMacStylePrivate::South:
2456 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2458 case QMacStylePrivate::West:
2459 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2461 case QMacStylePrivate::East:
2462 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2465 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2469 case PE_PanelTipLabel:
2470 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2472 case PE_FrameGroupBox:
2473 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2474 if (groupBox->features & QStyleOptionFrame::Flat) {
2475 QCommonStyle::drawPrimitive(pe, groupBox, p);
2479 case PE_FrameTabWidget:
2481 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2482 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
2496 auto adjustedRect = opt->rect;
2497 bool needTranslation =
false;
2510 adjustedRect.adjust(0, 0, 6, 6);
2511 needTranslation =
true;
2513 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2518 QMacAutoReleasePool pool;
2519 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2520 CGContextScaleCTM(ctx, 1, -1);
2521 if ([box isMemberOfClass:QDarkNSBox.
class]) {
2522 [box drawRect:rect];
2524 if (needTranslation)
2525 CGContextTranslateCTM(ctx, -3.0, 5.0);
2526 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2531 case PE_IndicatorToolBarSeparator: {
2533 if (opt->state & State_Horizontal) {
2534 int xpoint = opt->rect.center().x();
2535 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2536 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2538 int ypoint = opt->rect.center().y();
2539 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2540 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2542 QPainterPathStroker theStroker;
2543 theStroker.setCapStyle(Qt::FlatCap);
2544 theStroker.setDashPattern(QList<qreal>() << 1 << 2);
2545 path = theStroker.createStroke(path);
2546 const auto dark =
isDarkMode() ? opt->palette.dark().color().darker()
2547 : QColor(0, 0, 0, 119);
2548 p->fillPath(path, dark);
2551 case PE_FrameWindow:
2562 case PE_IndicatorDockWidgetResizeHandle: {
2565 if (opt->state & State_Horizontal) {
2566 p->setPen(QColor(160, 160, 160));
2567 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2569 p->setPen(QColor(145, 145, 145));
2570 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2574 case PE_IndicatorToolBarHandle: {
2577 int x = opt->rect.x() + 6;
2578 int y = opt->rect.y() + 7;
2579 static const int RectHeight = 2;
2580 if (opt->state & State_Horizontal) {
2581 while (y < opt->rect.height() - RectHeight - 5) {
2583 path.addEllipse(x, y, RectHeight, RectHeight);
2587 while (x < opt->rect.width() - RectHeight - 5) {
2589 path.addEllipse(x, y, RectHeight, RectHeight);
2593 p->setPen(Qt::NoPen);
2594 QColor dark = opt->palette.dark().color().darker();
2595 dark.setAlphaF(0.50);
2596 p->fillPath(path, dark);
2601 case PE_IndicatorHeaderArrow:
2602 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2604 if (header->sortIndicator != QStyleOptionHeader::None)
2605 proxy()->drawPrimitive(
2606 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2607 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
2610 case PE_IndicatorMenuCheckMark: {
2612 if (opt->state & State_On)
2613 pc = opt->palette.highlightedText().color();
2615 pc = opt->palette.text().color();
2617 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
2618 static_cast<CGFloat>(pc.greenF()),
2619 static_cast<CGFloat>(pc.blueF()),
2620 static_cast<CGFloat>(pc.alphaF()));
2626 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2627 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2628 kCTFontUIFontMenuItemMark;
2632 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2633 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2635 CGContextSaveGState(cg);
2636 CGContextSetShouldSmoothFonts(cg, NO);
2639 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2640 (opt->state & State_Small) ? 1.0 :
2643 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2644 CGContextScaleCTM(cg, 1, -1);
2646 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2650 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2651 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
2652 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2653 Q_STATIC_ASSERT((
sizeof(values) /
sizeof(values[0])) == numValues);
2654 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
2655 numValues, NULL, NULL);
2657 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
2658 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2660 CTLineDraw((CTLineRef)line, cg);
2663 CGContextRestoreGState(cg);
2665 case PE_IndicatorItemViewItemCheck:
2666 case PE_IndicatorRadioButton:
2667 case PE_IndicatorCheckBox: {
2668 const bool isEnabled = opt->state & State_Enabled;
2669 const bool isPressed = opt->state & State_Sunken;
2670 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2672 const auto cs = d->effectiveAquaSizeConstrain(opt);
2674 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
2675 tb.enabled = isEnabled;
2676 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2677 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2678 [tb highlight:isPressed];
2679 const auto vOffset = [=] {
2681 if (cs == QStyleHelper::SizeMini)
2684 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2686 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2687 QMacAutoReleasePool pool;
2688 CGContextTranslateCTM(ctx, 0, vOffset);
2689 [tb.cell drawInteriorWithFrame:rect inView:tb];
2692 case PE_FrameFocusRect:
2695 case PE_IndicatorBranch: {
2696 if (!(opt->state & State_Children))
2698 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
2699 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
2700 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2702 bool viewHasFocus =
false;
2703 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2705 d->setupNSGraphicsContext(cg, NO);
2708 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2709 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2710 CGContextScaleCTM(cg, 1, -1);
2711 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2713 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2715 d->restoreNSGraphicsContext(cg);
2719 const QPen oldPen = p->pen();
2720 QPen penCpy = p->pen();
2722 penCpy.setColor(opt->palette.dark().color());
2724 p->drawRect(opt->rect);
2727 case PE_PanelLineEdit:
2728 case PE_FrameLineEdit:
2729 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
2730 if (frame->state & State_Sunken) {
2731 const bool isEnabled = opt->state & State_Enabled;
2732 const bool isReadOnly = opt->state & State_ReadOnly;
2733 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2734 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2736 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
2737 tf.enabled = isEnabled;
2738 tf.editable = !isReadOnly;
2740 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2741 tf.frame = opt->rect.toCGRect();
2742 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
2743 QMacAutoReleasePool pool;
2744 if (!isDarkMode()) {
2749 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2753 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
2754 tf.drawsBackground = YES;
2755 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2756 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2757 green:bgColor.greenF()
2758 blue:bgColor.blueF()
2759 alpha:bgColor.alphaF()];
2760 if (bgColor.alpha() != 255) {
2767 CGRect fixedRect = rect;
2768 if (qt_apple_runningWithLiquidGlass()) {
2773 fixedRect = CGRectInset(rect, 1., 1.);
2775 [tf.cell drawWithFrame:fixedRect inView:tf];
2778 QCommonStyle::drawPrimitive(pe, opt, p);
2782 case PE_PanelScrollAreaCorner: {
2783 const QBrush brush(opt->palette.brush(QPalette::Base));
2784 p->fillRect(opt->rect, brush);
2785 p->setPen(QPen(QColor(217, 217, 217)));
2786 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2787 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2789 case PE_FrameStatusBarItem:
2817 case PE_PanelStatusBar: {
2818 p->fillRect(opt->rect, opt->palette.window());
2821 if (qt_macWindowMainWindow(opt->window))
2822 p->setPen(titlebarSeparatorLineActive);
2824 p->setPen(titlebarSeparatorLineInactive);
2825 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2829 case PE_PanelMenu: {
2831 p->fillRect(opt->rect, Qt::transparent);
2832 p->setPen(Qt::transparent);
2833 p->setBrush(opt->palette.window());
2834 p->setRenderHint(QPainter::Antialiasing,
true);
2835 const QPainterPath path = d->windowPanelPath(opt->rect);
2841 QCommonStyle::drawPrimitive(pe, opt, p);
2848 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2849 int imgh = img.height();
2850 int imgw = img.width();
2853 for (
int y = 0; y < imgh; ++y) {
2854 for (
int x = 0; x < imgw; ++x) {
2855 pixel = img.pixel(x, y);
2857 QColor hsvColor(pixel);
2858 hsvColor.getHsv(&h, &s, &v);
2859 s = qMin(100, s * 2);
2861 hsvColor.setHsv(h, s, v);
2862 pixel = hsvColor.rgb();
2863 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2866 return QPixmap::fromImage(img);
2872 CGContextTranslateCTM(cg, rect.size.height, 0);
2873 CGContextRotateCTM(cg,
M_PI_2);
2875 if (vertical != reverse) {
2876 CGContextTranslateCTM(cg, rect.size.width, 0);
2877 CGContextScaleCTM(cg, -1, 1);
2883 Q_D(
const QMacStyle);
2885 const QMacAutoReleasePool pool;
2887 QMacCGContext cg(p);
2888 d->resolveCurrentNSView(opt->window);
2891 case CE_HeaderSection:
2892 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2893 State flags = header->state;
2894 QRect ir = header->rect;
2895 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2896 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2897 p->setPen(QPen(header->palette.dark(), 1.0));
2898 if (header->orientation == Qt::Horizontal)
2907 case CE_HeaderLabel:
2908 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2910 QRect textr = header->rect;
2911 if (!header->icon.isNull()) {
2912 QIcon::Mode mode = QIcon::Disabled;
2913 if (opt->state & State_Enabled)
2914 mode = QIcon::Normal;
2915 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2916 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2917 opt->window->devicePixelRatio(), mode);
2919 QRect pixr = header->rect;
2920 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2921 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
2922 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2925 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2926 header->state & State_Enabled, header->text, QPalette::ButtonText);
2930 case CE_ToolButtonLabel:
2931 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
2932 QStyleOptionToolButton myTb = *tb;
2933 myTb.state &= ~State_AutoRaise;
2934#ifndef QT_NO_ACCESSIBILITY
2935 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2936 QRect cr = tb->rect;
2939 bool needText =
false;
2941 bool down = tb->state & (State_Sunken | State_On);
2943 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
2944 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2950 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2951 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2952 if (tb->icon.isNull() && !tb->text.isEmpty())
2953 tbstyle = Qt::ToolButtonTextOnly;
2956 case Qt::ToolButtonTextOnly: {
2958 alignment = Qt::AlignCenter;
2960 case Qt::ToolButtonIconOnly:
2961 case Qt::ToolButtonTextBesideIcon:
2962 case Qt::ToolButtonTextUnderIcon: {
2964 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2966 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2968 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2969 opt->window->devicePixelRatio(), iconMode,
2973 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
2975 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
2976 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
2977 cr.adjust(0, pr.bottom(), 0, -3);
2978 alignment |= Qt::AlignCenter;
2980 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
2981 cr.adjust(pr.right(), 0, 0, 0);
2982 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
2985 if (opt->state & State_Sunken) {
2986 pr.translate(shiftX, shiftY);
2987 pixmap = darkenPixmap(pixmap);
2989 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
2997 QPalette pal = tb->palette;
2998 QPalette::ColorRole role = QPalette::NoRole;
2999 if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
3000 alignment |= Qt::TextHideMnemonic;
3002 cr.translate(shiftX, shiftY);
3003 if (tbstyle == Qt::ToolButtonTextOnly
3004 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3005 QPen pen = p->pen();
3006 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3007 light.setAlphaF(0.375f);
3009 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3011 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3013 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3014 role = QPalette::HighlightedText;
3017 proxy()->drawItemText(p, cr, alignment, pal,
3018 tb->state & State_Enabled, tb->text, role);
3021 QCommonStyle::drawControl(ce, &myTb, p);
3026 QCommonStyle::drawControl(ce, &myTb, p);
3030 case CE_ToolBoxTabShape:
3031 QCommonStyle::drawControl(ce, opt, p);
3033 case CE_PushButtonBevel:
3035 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3038 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3039 QCommonStyle::drawControl(ce, opt, p);
3043 const bool hasFocus = btn->state & State_HasFocus;
3044 const bool isActive = btn->state & State_Active;
3048 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3049 && isActive && hasFocus)
3050 d->autoDefaultButton = btn->styleObject;
3051 else if (d->autoDefaultButton == btn->styleObject)
3052 d->autoDefaultButton =
nullptr;
3054 const bool isEnabled = btn->state & State_Enabled;
3055 const bool isPressed = btn->state & State_Sunken;
3056 const bool isHighlighted = isActive &&
3057 ((btn->state & State_On)
3058 || (btn->features & QStyleOptionButton::DefaultButton)
3059 || (btn->features & QStyleOptionButton::AutoDefaultButton
3060 && d->autoDefaultButton == btn->styleObject));
3061 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3062 const auto ct = cocoaControlType(btn);
3063 const auto cs = d->effectiveAquaSizeConstrain(btn);
3065 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3069 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3070 pb.frame = frameRect.toCGRect();
3072 pb.enabled = isEnabled;
3073 [pb highlight:isPressed];
3074 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3075 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3076 QMacAutoReleasePool pool;
3077 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3084 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
3085 const auto ir = frameRect.toRect();
3086 int arrowYOffset = 0;
3087 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3089 QStyleOption arrowOpt = *opt;
3091 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
3095 case CE_PushButtonLabel:
3102 const bool isEnabled = btn.state & State_Enabled;
3103 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3104 const bool hasIcon = !btn.icon.isNull();
3105 const bool hasText = !btn.text.isEmpty();
3106 const bool isActive = btn.state & State_Active;
3107 const bool isPressed = btn.state & State_Sunken;
3109 const auto ct = cocoaControlType(&btn);
3113 || (isActive && isEnabled
3114 && ((btn.state & State_On)
3115 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3116 || d->autoDefaultButton == btn.styleObject)))
3117 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3120 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3121 QCommonStyle::drawControl(ce, &btn, p);
3123 QRect freeContentRect = btn.rect;
3124 QRect textRect = itemTextRect(
3125 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3127 textRect.moveTo(11, textRect.top());
3131 int contentW = textRect.width();
3133 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3134 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3135 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3136 mode = QIcon::Active;
3138 QIcon::State state = QIcon::Off;
3139 if (btn.state & State_On)
3141 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3143 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3144 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3146 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3147 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3148 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3149 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3150 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3151 int newOffset = iconDestRect.x() + iconDestRect.width()
3153 textRect.adjust(newOffset, 0, newOffset, 0);
3157 textRect = visualRect(btn.direction, freeContentRect, textRect);
3158 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3159 isEnabled, btn.text, QPalette::ButtonText);
3164 case CE_ComboBoxLabel:
3165 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3166 auto comboCopy = *cb;
3167 comboCopy.direction = Qt::LeftToRight;
3169 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
3172 case CE_TabBarTabShape:
3173 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3174 if (tabOpt->documentMode) {
3176 bool isUnified =
false;
3183 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3184 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3190 const bool isActive = tabOpt->state & State_Active;
3191 const bool isEnabled = tabOpt->state & State_Enabled;
3192 const bool isPressed = tabOpt->state & State_Sunken;
3193 const bool isSelected = tabOpt->state & State_Selected;
3194 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3195 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3196 || tabDirection == QMacStylePrivate::West;
3198 QStyleOptionTab::TabPosition tp = tabOpt->position;
3199 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3200 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3201 if (tp == QStyleOptionTab::Beginning)
3202 tp = QStyleOptionTab::End;
3203 else if (tp == QStyleOptionTab::End)
3204 tp = QStyleOptionTab::Beginning;
3206 if (sp == QStyleOptionTab::NextIsSelected)
3207 sp = QStyleOptionTab::PreviousIsSelected;
3208 else if (sp == QStyleOptionTab::PreviousIsSelected)
3209 sp = QStyleOptionTab::NextIsSelected;
3224 const auto cs = d->effectiveAquaSizeConstrain(opt);
3226 const bool needsInactiveHack = (!isActive && isSelected);
3227 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3228 QMacStylePrivate::Button_PushButton :
3229 QMacStylePrivate::Button_PopupButton;
3232 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3234 auto vOffset = isPopupButton ? 1 : 2;
3235 if (tabDirection == QMacStylePrivate::East)
3237 const auto outerAdjust = isPopupButton ? 1 : 4;
3238 const auto innerAdjust = isPopupButton ? 20 : 10;
3239 QRectF frameRect = tabOpt->rect;
3241 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3243 frameRect = frameRect.translated(0, vOffset);
3245 case QStyleOptionTab::Beginning:
3247 if (!isSelected && tabDirection == QMacStylePrivate::West)
3248 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3250 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3252 case QStyleOptionTab::Middle:
3253 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3255 case QStyleOptionTab::End:
3257 if (isSelected || tabDirection == QMacStylePrivate::West)
3258 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3260 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3262 case QStyleOptionTab::OnlyOneTab:
3263 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3266 pb.frame = frameRect.toCGRect();
3268 pb.enabled = isEnabled;
3269 [pb highlight:isPressed];
3271 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3273 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3274 QMacAutoReleasePool pool;
3275 CGContextClipToRect(ctx, opt->rect.toCGRect());
3276 if (!isSelected || needsInactiveHack) {
3278 if (!verticalTabs && tp == QStyleOptionTab::End) {
3279 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3280 CGContextScaleCTM(ctx, -1, 1);
3281 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3282 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3283 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3284 CGContextScaleCTM(ctx, 1, -1);
3285 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3286 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3287 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3288 CGContextScaleCTM(ctx, 1, -1);
3289 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3295 if (tabDirection == QMacStylePrivate::West) {
3296 CGContextTranslateCTM(ctx, 0, frameRect.right());
3297 CGContextRotateCTM(ctx, -
M_PI_2);
3298 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3299 }
else if (tabDirection == QMacStylePrivate::East) {
3300 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3301 CGContextRotateCTM(ctx,
M_PI_2);
3306 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3307 NSPopUpButtonCell *pbCell = nil;
3308 if (isPopupButton) {
3309 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3310 oldPosition = pbCell.arrowPosition;
3311 pbCell.arrowPosition = NSPopUpNoArrow;
3314 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3317 pbCell.arrowPosition = oldPosition;
3320 if (needsInactiveHack) {
3322 const qreal pixelRatio = p->device()->devicePixelRatioF();
3323 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3324 tabPixmap.setDevicePixelRatio(pixelRatio);
3325 tabPixmap.fill(Qt::transparent);
3326 QPainter tabPainter(&tabPixmap);
3327 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3328 QMacAutoReleasePool pool;
3329 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3330 drawBezelBlock(ctx, r);
3335 const qreal inactiveGray = 0.898;
3336 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3337 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3338 for (
int l = 0; l < tabPixmap.height(); ++l) {
3339 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3340 for (
int i = 0; i < tabPixmap.width(); ++i) {
3341 if (qAlpha(line[i]) == 255) {
3342 line[i] = inactiveGrayRGB;
3343 }
else if (qAlpha(line[i]) > 128) {
3344 const int g = qRound(inactiveGray * qRed(line[i]));
3345 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3351 p->drawImage(opt->rect, tabPixmap);
3353 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3356 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3357 && tp != QStyleOptionTab::End
3358 && tp != QStyleOptionTab::OnlyOneTab) {
3359 static const QPen separatorPen(Qt::black, 1.0);
3361 p->setOpacity(isEnabled ? 0.105 : 0.06);
3362 p->setPen(separatorPen);
3363 if (tabDirection == QMacStylePrivate::West) {
3364 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3365 opt->rect.right() - 0.5, opt->rect.bottom()));
3366 }
else if (tabDirection == QMacStylePrivate::East) {
3367 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3368 opt->rect.right() - 0.5, opt->rect.bottom()));
3370 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3371 opt->rect.right(), opt->rect.bottom() - 0.5));
3377 case CE_TabBarTabLabel:
3378 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3379 QStyleOptionTab myTab = *tab;
3380 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3381 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3382 || tabDirection == QMacStylePrivate::West;
3389 const bool nonDefaultFont =
false;
3397 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3398 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3401 int heightOffset = 0;
3404 }
else if (nonDefaultFont) {
3405 if (p->fontMetrics().height() == myTab.rect.height())
3408 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3410 QCommonStyle::drawControl(ce, &myTab, p);
3413 case CE_DockWidgetTitle:
3414 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
3415 const bool isVertical = dwOpt->verticalTitleBar;
3416 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3419 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3421 p->translate(-effectiveRect.left(), -effectiveRect.top());
3425 p->fillRect(effectiveRect, opt->palette.window());
3428 p->setPen(opt->palette.dark().color());
3429 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3431 if (!dwOpt->title.isEmpty()) {
3432 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3434 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3435 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3439 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3440 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3441 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3446 case CE_FocusFrame: {
3469 case CE_MenuEmptyArea:
3473 case CE_MenuHMargin:
3474 case CE_MenuVMargin:
3475 case CE_MenuTearoff:
3476 case CE_MenuScroller:
3477 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3478 const bool active = mi->state & State_Selected;
3480 p->fillRect(mi->rect, mi->palette.highlight());
3482 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3484 if (ce == CE_MenuTearoff) {
3485 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3486 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3487 mi->rect.x() + mi->rect.width() - 4,
3488 mi->rect.y() + mi->rect.height() / 2 - 1);
3489 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3490 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3491 mi->rect.x() + mi->rect.width() - 4,
3492 mi->rect.y() + mi->rect.height() / 2);
3493 }
else if (ce == CE_MenuScroller) {
3494 const QSize scrollerSize = QSize(10, 8);
3495 const int scrollerVOffset = 5;
3496 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3497 const int right = left + scrollerSize.width();
3500 if (opt->state & State_DownArrow) {
3501 bottom = mi->rect.y() + scrollerVOffset;
3502 top = bottom + scrollerSize.height();
3504 bottom = mi->rect.bottom() - scrollerVOffset;
3505 top = bottom - scrollerSize.height();
3508 p->setRenderHint(QPainter::Antialiasing);
3510 path.moveTo(left, bottom);
3511 path.lineTo(right, bottom);
3512 path.lineTo((left + right) / 2, top);
3513 p->fillPath(path, opt->palette.buttonText());
3515 }
else if (ce != CE_MenuItem) {
3519 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3520 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3521 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3522 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3526 const int maxpmw = mi->maxIconWidth;
3527 const bool enabled = mi->state & State_Enabled;
3529 int xpos = mi->rect.x() + 18;
3530 int checkcol = maxpmw;
3532 p->setPen(mi->palette.text().color());
3534 p->setPen(mi->palette.highlightedText().color());
3536 p->setPen(mi->palette.buttonText().color());
3539 QStyleOption checkmarkOpt;
3545 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3547 checkmarkOpt.state.setFlag(State_On, active);
3548 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3549 if (widgetSize == QStyleHelper::SizeMini)
3550 checkmarkOpt.state |= State_Mini;
3551 else if (widgetSize == QStyleHelper::SizeSmall)
3552 checkmarkOpt.state |= State_Small;
3555 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3556 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3558 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3560 if (!mi->icon.isNull()) {
3561 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
3564 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3565 QSize iconSize(smallIconSize, smallIconSize);
3571 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3572 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3573 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3574 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3575 QRect pmr(0, 0, pixw, pixh);
3576 pmr.moveCenter(cr.center());
3577 p->drawPixmap(pmr.topLeft(), pixmap);
3581 QString s = mi->text;
3582 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3583 | Qt::TextSingleLine | Qt::AlignAbsolute;
3584 int yPos = mi->rect.y();
3585 if (widgetSize == QStyleHelper::SizeMini)
3588 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3589 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3591 QString rightMarginText;
3593 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
3596 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
3597 if (tabIndex >= 0) {
3599 rightMarginText = s.mid(tabIndex + 1);
3600 s = s.left(tabIndex);
3604 if (!rightMarginText.isEmpty()) {
3609 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3614 QFont myFont = mi->font;
3620 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3625 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3626 Q_ASSERT(fontEngine);
3627 if (fontEngine->type() == QFontEngine::Multi) {
3628 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
3629 Q_ASSERT(fontEngine);
3631 if (fontEngine->type() == QFontEngine::Mac) {
3632 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3635 const auto pc = p->pen().color();
3636 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3641 s = qt_mac_removeMnemonics(s);
3643 QMacCGContext cgCtx(p);
3644 d->setupNSGraphicsContext(cgCtx, YES);
3650 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3651 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3652 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3654 d->restoreNSGraphicsContext(cgCtx);
3657 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3658 mi->rect.height(), text_flags, s);
3664 case CE_MenuBarItem:
3665 case CE_MenuBarEmptyArea:
3666 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3667 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3668 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3669 p->fillRect(mi->rect, bg);
3671 if (ce != CE_MenuBarItem)
3674 if (!mi->icon.isNull()) {
3675 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3676 drawItemPixmap(p, mi->rect,
3677 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3678 | Qt::TextSingleLine,
3679 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3680 opt->window->devicePixelRatio(),
3681 (mi->state & State_Enabled) ? QIcon::Normal
3682 : QIcon::Disabled));
3684 drawItemText(p, mi->rect,
3685 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3686 | Qt::TextSingleLine,
3687 mi->palette, mi->state & State_Enabled,
3688 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3692 case CE_ProgressBarLabel:
3693 case CE_ProgressBarContents:
3695 case CE_ProgressBarGroove:
3696 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
3697 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3698 const bool inverted = pb->invertedAppearance;
3699 bool reverse = pb->direction == Qt::RightToLeft;
3703 QRect rect = pb->rect;
3704 const CGRect cgRect = rect.toCGRect();
3706 const auto aquaSize = d->aquaSizeConstrain(opt);
3709 QIndeterminateProgressIndicator *ipi = nil;
3711 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3712 if (isIndeterminate) {
3731 d->setupNSGraphicsContext(cg, NO);
3732 d->setupVerticalInvertedXform(cg, reverse,
false, cgRect);
3733 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3734 d->restoreNSGraphicsContext(cg);
3742 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3743 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3744 QMacAutoReleasePool pool;
3745 d->setupVerticalInvertedXform(ctx, reverse,
false, rect);
3746 pi.minValue = pb->minimum;
3747 pi.maxValue = pb->maximum;
3748 pi.doubleValue = pb->progress;
3787 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3788 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3791 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
3792 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
3793 sv.frame = opt->rect.toCGRect();
3794 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3795 QMacAutoReleasePool pool;
3796 [sv drawDividerInRect:rect];
3799 QPen oldPen = p->pen();
3800 p->setPen(opt->palette.dark().color());
3801 if (opt->state & QStyle::State_Horizontal)
3802 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3804 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3809 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
3810 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
3811 if (!rubber->opaque) {
3814 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3815 fillColor.setHsvF(0, 0, 0.53, 0.25);
3816 if (opt->rect.width() * opt->rect.height() <= 3) {
3817 p->fillRect(opt->rect, strokeColor);
3819 QPen oldPen = p->pen();
3820 QBrush oldBrush = p->brush();
3821 QPen pen(strokeColor);
3823 p->setBrush(fillColor);
3824 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3825 if (adjusted.isValid())
3826 p->drawRect(adjusted);
3828 p->setBrush(oldBrush);
3831 p->fillRect(opt->rect, fillColor);
3870 QLinearGradient linearGrad;
3871 if (opt->state & State_Horizontal)
3872 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3874 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3876 QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
3877 QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
3879 linearGrad.setColorAt(0, mainWindowGradientBegin);
3880 linearGrad.setColorAt(1, mainWindowGradientEnd);
3881 p->fillRect(opt->rect, linearGrad);
3884 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3885 if (opt->state & State_Horizontal) {
3886 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3887 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3888 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3889 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3891 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3892 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3893 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3894 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3900 QCommonStyle::drawControl(ce, opt, p);
3907 if (dir == Qt::RightToLeft) {
3908 rect->adjust(-right, top, -left, bottom);
3910 rect->adjust(left, top, right, bottom);
3916 Q_D(
const QMacStyle);
3918 const int controlSize = getControlSize(opt);
3921 case SE_ItemViewItemText:
3922 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
3923 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
3925 rect = QCommonStyle::subElementRect(sr, opt);
3926 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3927 rect.adjust(-fw, 0, 0, 0);
3930 case SE_ToolBoxTabContents:
3931 rect = QCommonStyle::subElementRect(sr, opt);
3933 case SE_PushButtonContents:
3943 const auto ct = cocoaControlType(btn);
3944 const auto cs = d->effectiveAquaSizeConstrain(btn);
3946 auto frameRect = cw.adjustedControlFrame(btn->rect);
3947 frameRect -= cw.titleMargins();
3948 rect = frameRect.toRect();
3951 case SE_HeaderLabel: {
3952 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3953 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3954 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3955 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3957 if (header->sortIndicator != QStyleOptionHeader::None) {
3958 if (opt->state & State_Horizontal)
3964 rect = visualRect(opt->direction, opt->rect, rect);
3967 case SE_HeaderArrow: {
3968 int h = opt->rect.height();
3969 int w = opt->rect.width();
3970 int x = opt->rect.x();
3971 int y = opt->rect.y();
3972 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3974 if (opt->state & State_Horizontal) {
3981 rect = visualRect(opt->direction, opt->rect, rect);
3984 case SE_ProgressBarGroove:
3988 case SE_ProgressBarLabel:
3990 case SE_ProgressBarContents:
3993 case SE_TreeViewDisclosureItem: {
3999 case SE_TabWidgetLeftCorner:
4000 if (
const QStyleOptionTabWidgetFrame *twf
4001 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4002 switch (twf->shape) {
4003 case QStyleOptionTab::RoundedNorth:
4004 case QStyleOptionTab::TriangularNorth:
4005 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4007 case QStyleOptionTab::RoundedSouth:
4008 case QStyleOptionTab::TriangularSouth:
4009 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4010 twf->leftCornerWidgetSize);
4015 rect = visualRect(twf->direction, twf->rect, rect);
4018 case SE_TabWidgetRightCorner:
4019 if (
const QStyleOptionTabWidgetFrame *twf
4020 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4021 switch (twf->shape) {
4022 case QStyleOptionTab::RoundedNorth:
4023 case QStyleOptionTab::TriangularNorth:
4024 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4025 twf->rightCornerWidgetSize);
4027 case QStyleOptionTab::RoundedSouth:
4028 case QStyleOptionTab::TriangularSouth:
4029 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4030 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4031 twf->rightCornerWidgetSize);
4036 rect = visualRect(twf->direction, twf->rect, rect);
4039 case SE_TabWidgetTabContents:
4040 rect = QCommonStyle::subElementRect(sr, opt);
4041 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4042 if (twf->lineWidth != 0) {
4043 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4044 case QMacStylePrivate::North:
4045 rect.adjust(+1, +14, -1, -1);
4047 case QMacStylePrivate::South:
4048 rect.adjust(+1, +1, -1, -14);
4050 case QMacStylePrivate::West:
4051 rect.adjust(+14, +1, -1, -1);
4053 case QMacStylePrivate::East:
4054 rect.adjust(+1, +1, -14, -1);
4059 case SE_TabBarTabText:
4060 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4061 QRect dummyIconRect;
4062 d->tabLayout(tab, &rect, &dummyIconRect);
4065 case SE_TabBarTabLeftButton:
4066 case SE_TabBarTabRightButton:
4067 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4068 bool selected = tab->state & State_Selected;
4069 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4070 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4073 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4074 || tab->shape == QStyleOptionTab::RoundedWest
4075 || tab->shape == QStyleOptionTab::TriangularEast
4076 || tab->shape == QStyleOptionTab::TriangularWest;
4078 QRect tr = tab->rect;
4079 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4080 verticalShift = -verticalShift;
4082 qSwap(horizontalShift, verticalShift);
4083 horizontalShift *= -1;
4084 verticalShift *= -1;
4086 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4087 horizontalShift = -horizontalShift;
4089 tr.adjust(0, 0, horizontalShift, verticalShift);
4092 tr.setBottom(tr.bottom() - verticalShift);
4093 tr.setRight(tr.right() - horizontalShift);
4096 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4097 int w = size.width();
4098 int h = size.height();
4099 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4100 int midWidth = ((tr.width() - w) / 2);
4102 bool atTheTop =
true;
4103 switch (tab->shape) {
4104 case QStyleOptionTab::RoundedWest:
4105 case QStyleOptionTab::TriangularWest:
4106 atTheTop = (sr == SE_TabBarTabLeftButton);
4108 case QStyleOptionTab::RoundedEast:
4109 case QStyleOptionTab::TriangularEast:
4110 atTheTop = (sr == SE_TabBarTabRightButton);
4113 if (sr == SE_TabBarTabLeftButton)
4114 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4116 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4117 rect = visualRect(tab->direction, tab->rect, rect);
4121 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4123 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4127 case SE_LineEditContents: {
4129 int leftPadding = 4;
4130 int rightPadding = 4;
4132 int bottomPadding = 0;
4134 if (opt->state & QStyle::State_Small) {
4136 }
else if (opt->state & QStyle::State_Mini) {
4140 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4141 opt->rect.height() - topPadding - bottomPadding);
4143 case SE_CheckBoxLayoutItem:
4145 if (controlSize == QStyleHelper::SizeLarge) {
4146 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4147 }
else if (controlSize == QStyleHelper::SizeSmall) {
4148 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4150 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4153 case SE_SearchFieldLayoutItem:
4154 if (qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4155 if (qt_apple_runningWithLiquidGlass()) {
4157 opt->rect.adjusted(2, 4, -2, -4),
4158 opt->rect.adjusted(2, 3, -2, -2),
4159 opt->rect.adjusted(2, 3, -2, -2));
4162 opt->rect.adjusted(2, 6, -2, -6),
4163 opt->rect.adjusted(2, 3, -2, -2),
4164 opt->rect.adjusted(2, 3, -2, -2));
4168 case SE_ComboBoxLayoutItem:
4169 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4178 if (combo->editable) {
4179 if (qt_apple_runningWithLiquidGlass()) {
4181 opt->rect.adjusted(4, 4, -4, -4),
4182 opt->rect.adjusted(4, 4, -5, -7),
4183 opt->rect.adjusted(5, 4, -4, -6));
4186 opt->rect.adjusted(5, 6, -6, -7),
4187 opt->rect.adjusted(4, 4, -5, -7),
4188 opt->rect.adjusted(5, 4, -4, -6));
4191 if (qt_apple_runningWithLiquidGlass()) {
4193 opt->rect.adjusted(4, 4, -4, -4),
4194 opt->rect.adjusted(6, 7, -6, -5),
4195 opt->rect.adjusted(9, 5, -5, -7));
4198 opt->rect.adjusted(6, 4, -7, -7),
4199 opt->rect.adjusted(6, 7, -6, -5),
4200 opt->rect.adjusted(9, 5, -5, -7));
4205 case SE_LabelLayoutItem:
4207 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4209 case SE_ProgressBarLayoutItem:
4210 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4211 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4214 if (isIndeterminate) {
4215 rect.adjust(1, 2, -1, -2);
4217 rect.adjust(1, 1, -1, -2);
4221 case SE_PushButtonLayoutItem:
4224 if ((buttonOpt->features & QStyleOptionButton::Flat))
4227 if (qt_apple_runningWithLiquidGlass()) {
4229 opt->rect.adjusted(2, 5, -2, -7),
4230 opt->rect.adjusted(6, 6, -6, -6),
4231 opt->rect.adjusted(6, 5, -6, -6));
4234 opt->rect.adjusted(7, 5, -7, -7),
4235 opt->rect.adjusted(6, 6, -6, -6),
4236 opt->rect.adjusted(6, 5, -6, -6));
4239 case SE_SpinBoxLayoutItem:
4241 opt->rect.adjusted(2, 3, -2, -2),
4242 opt->rect.adjusted(2, 3, -2, -2),
4243 opt->rect.adjusted(2, 3, -2, -2));
4245 case SE_RadioButtonLayoutItem:
4247 opt->rect.adjusted(2, 2, -3, -2),
4248 opt->rect.adjusted(2, 2, -3, -2),
4249 opt->rect.adjusted(1, 2, -3, -2));
4251 case SE_SliderLayoutItem:
4252 if (
const QStyleOptionSlider *sliderOpt
4253 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4255 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4256 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4257 rect.adjust(3, 3, -3, -3);
4259 rect.adjust(3, 0, -3, 0);
4263 case SE_ScrollBarLayoutItem:
4264 if (qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4267 case SE_FrameLayoutItem:
4283 case SE_GroupBoxLayoutItem:
4285 if (
const QStyleOptionGroupBox *groupBoxOpt =
4286 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4288
4289
4290
4291
4292 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4293 | QStyle::SC_GroupBoxLabel)) {
4295 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4296 delta =
SIZE(8, 4, 4);
4298 delta =
SIZE(15, 12, 12);
4300 rect.setTop(rect.top() + delta);
4303 rect.setBottom(rect.bottom() - 1);
4305 case SE_TabWidgetLayoutItem:
4306 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4307 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4309
4310
4311
4312
4313 rect = tabWidgetOpt->rect;
4314 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4315 rect.setTop(rect.top() +
SIZE(6 , 3 , 2 ));
4318 case SE_DockWidgetCloseButton:
4319 case SE_DockWidgetFloatButton:
4320 case SE_DockWidgetTitleBarText:
4321 case SE_DockWidgetIcon: {
4322 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
4323 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
4324 QRect srect = opt->rect;
4326 const QStyleOptionDockWidget *dwOpt
4327 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4328 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4329 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4331 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4335 if (verticalTitleBar)
4336 srect = srect.transposed();
4339 int right = srect.right();
4340 int left = srect.left();
4344 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4345 opt).actualSize(QSize(iconSize, iconSize));
4346 sz += QSize(buttonMargin, buttonMargin);
4347 if (verticalTitleBar)
4348 sz = sz.transposed();
4349 closeRect = QRect(left,
4350 srect.center().y() - sz.height()/2,
4351 sz.width(), sz.height());
4352 left = closeRect.right() + 1;
4354 if (sr == SE_DockWidgetCloseButton) {
4361 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4362 opt).actualSize(QSize(iconSize, iconSize));
4363 sz += QSize(buttonMargin, buttonMargin);
4364 if (verticalTitleBar)
4365 sz = sz.transposed();
4366 floatRect = QRect(left,
4367 srect.center().y() - sz.height()/2,
4368 sz.width(), sz.height());
4369 left = floatRect.right() + 1;
4371 if (sr == SE_DockWidgetFloatButton) {
4391 if (sr == SE_DockWidgetIcon) {
4396 QRect textRect = QRect(left, srect.top(),
4397 right - left, srect.height());
4398 if (sr == SE_DockWidgetTitleBarText) {
4404 if (verticalTitleBar) {
4405 rect = QRect(srect.left() + rect.top() - srect.top(),
4406 srect.top() + srect.right() - rect.right(),
4407 rect.height(), rect.width());
4409 rect = visualRect(opt->direction, srect, rect);
4414 rect = QCommonStyle::subElementRect(sr, opt);
4422 Q_Q(
const QMacStyle);
4423 QStyleOption arrowOpt = *opt;
4428 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4433 CGContextSaveGState(cg);
4434 [NSGraphicsContext saveGraphicsState];
4436 [NSGraphicsContext setCurrentContext:
4437 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4442 [NSGraphicsContext restoreGraphicsState];
4443 CGContextRestoreGState(cg);
4448 Q_D(
const QMacStyle);
4450 QMacCGContext cg(p);
4451 d->resolveCurrentNSView(opt->window);
4455 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4457 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4458 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4459 if (!drawTrack && !drawKnob)
4462 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4464 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
4465 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4467 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4468 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4470 const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
4473 bool wasActive =
false;
4474 CGFloat opacity = 0.0;
4475 CGFloat expandScale = 1.0;
4476 CGFloat expandOffset = 0.0;
4477 bool shouldExpand =
false;
4479 if (QObject *styleObject = opt->styleObject) {
4480 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
4481 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
4482 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
4483 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
4484 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
4485 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
4489 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4492 oldPos != sb->sliderPosition ||
4493 oldMin != sb->minimum ||
4494 oldMax != sb->maximum ||
4495 oldRect != sb->rect ||
4496 oldState != sb->state ||
4497 oldActiveControls != sb->activeSubControls) {
4503 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
4504 styleObject->setProperty(
"_q_stylemin", sb->minimum);
4505 styleObject->setProperty(
"_q_stylemax", sb->maximum);
4506 styleObject->setProperty(
"_q_stylerect", sb->rect);
4507 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
4508 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
4536 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4554 d->setupNSGraphicsContext(cg, NO );
4558 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
4560 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
4561 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4565 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4567 scroller.knobStyle = NSScrollerKnobStyleDefault;
4570 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4572 if (!setupScroller(scroller, sb))
4576 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
4577 CGContextSetAlpha(cg, opacity);
4582 if (!isTransient || opt->activeSubControls || wasActive) {
4583 CGRect trackRect = scroller.bounds;
4585 trackRect.origin.y += expandOffset;
4587 trackRect.origin.x += expandOffset;
4588 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4598 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4599 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4601 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4602 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4603 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4604 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4605 const CGFloat knobRadius = knobWidth / 2.0;
4608 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4610 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4611 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
4612 CGContextAddPath(cg, knobPath);
4613 CGContextSetAlpha(cg, 0.5);
4614 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4615 CGContextSetFillColorWithColor(cg, knobColor);
4616 CGContextFillPath(cg);
4618 [scroller drawKnob];
4620 if (!isTransient && opt->state & State_Sunken) {
4625 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4626 [scroller drawKnob];
4632 CGContextEndTransparencyLayer(cg);
4634 d->restoreNSGraphicsContext(cg);
4638 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4639 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4641 const auto cs = d->effectiveAquaSizeConstrain(opt);
4643 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
4644 if (!setupSlider(slider, sl))
4647 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4648 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4649 const bool drawKnob = sl->subControls & SC_SliderHandle;
4650 const bool drawBar = sl->subControls & SC_SliderGroove;
4651 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4652 const bool isPressed = sl->state & State_Sunken;
4655 if (isPressed && drawKnob) {
4656 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4657 pressPoint.x = CGRectGetMidX(knobRect);
4658 pressPoint.y = CGRectGetMidY(knobRect);
4659 [slider.cell startTrackingAt:pressPoint inView:slider];
4662 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef,
const CGRect &) {
4665 NSSliderCell *cell = slider.cell;
4668 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4674 [cell drawBarInside:barRect flipped:!isHorizontal];
4677 if (drawBar && hasTicks && drawTicks) {
4678 if (!hasDoubleTicks) {
4679 [cell drawTickMarks];
4681 if (sl->orientation == Qt::Horizontal) {
4682 slider.tickMarkPosition = NSTickMarkPositionAbove;
4683 [slider layoutSubtreeIfNeeded];
4684 [cell drawTickMarks];
4685 slider.tickMarkPosition = NSTickMarkPositionBelow;
4686 [slider layoutSubtreeIfNeeded];
4687 [cell drawTickMarks];
4689 slider.tickMarkPosition = NSTickMarkPositionLeading;
4690 [slider layoutSubtreeIfNeeded];
4691 [cell drawTickMarks];
4692 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4693 [slider layoutSubtreeIfNeeded];
4694 [cell drawTickMarks];
4703 if (isPressed && drawKnob)
4704 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4708 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
4709 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4710 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4711 QStyleOptionFrame frame;
4712 static_cast<QStyleOption &>(frame) = *opt;
4713 frame.rect = lineEditRect;
4714 frame.state |= State_Sunken;
4715 frame.lineWidth = 1;
4716 frame.midLineWidth = 0;
4717 frame.features = QStyleOptionFrame::None;
4718 frame.frameShape = QStyleOptionFrame::Box;
4719 drawPrimitive(PE_FrameLineEdit, &frame, p);
4721 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4722 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4723 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
4725 d->setupNSGraphicsContext(cg, NO);
4727 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4729 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
4730 cell.enabled = (sb->state & State_Enabled);
4731 const auto controlSize = cell.controlSize;
4732 if (qt_apple_runningWithLiquidGlass())
4733 cell.controlSize = NSControlSizeMini;
4735 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4737 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4738 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4739 const CGFloat x = CGRectGetMidX(newRect);
4740 const CGFloat y = upPressed ? -3 : 3;
4741 const CGPoint pressPoint = CGPointMake(x, y);
4744 if (upPressed || downPressed)
4745 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4747 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4749 if (upPressed || downPressed)
4750 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4752 d->restoreNSGraphicsContext(cg);
4753 if (qt_apple_runningWithLiquidGlass())
4754 cell.controlSize = controlSize;
4759 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4760 const bool isEnabled = combo->state & State_Enabled;
4761 const bool isPressed = combo->state & State_Sunken;
4763 const auto ct = cocoaControlType(combo);
4764 const auto cs = d->effectiveAquaSizeConstrain(combo);
4766 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4767 cc.enabled = isEnabled;
4768 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4771 auto *pb =
static_cast<NSPopUpButton *>(cc);
4773 if (cw.size == QStyleHelper::SizeSmall) {
4774 frameRect = frameRect.translated(0, 1);
4775 }
else if (cw.size == QStyleHelper::SizeMini) {
4777 frameRect = frameRect.translated(2, -0.5);
4779 pb.frame = frameRect.toCGRect();
4780 [pb highlight:isPressed];
4781 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4782 QMacAutoReleasePool pool;
4783 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4787 auto *cb =
static_cast<NSComboBox *>(cc);
4788 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4789 cb.frame = frameRect.toCGRect();
4792 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4793 cell.highlighted = isPressed;
4798 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4800 QMacAutoReleasePool pool;
4801 [cb.cell drawWithFrame:r inView:cb];
4806 case CC_SearchField:
4807 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4808 const bool isEnabled = sf->state & State_Enabled;
4810 const auto cs = d->effectiveAquaSizeConstrain(sf);
4812 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4813 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4815 searchField.enabled = isEnabled;
4822 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4823 if (
__builtin_available(macOS 26, *)) {
4824 NSButtonCell *btn = cell.searchButtonCell;
4825 NSImageSymbolConfiguration *imgCfg =
4826 [NSImageSymbolConfiguration configurationWithPointSize:11
4827 weight:NSFontWeightMedium
4828 scale:NSImageSymbolScaleMedium];
4829 btn.image = [btn.image imageWithSymbolConfiguration:imgCfg];
4830 [btn.image setTemplate:YES];
4831 btn.imageScaling = NSImageScaleNone;
4835 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4837 #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
4838 if (
__builtin_available(macOS 26, *)) {
4839 const auto oneDevicePx = 1.0 / p->device()->devicePixelRatioF();
4840 frameRect = frameRect.adjusted(+oneDevicePx, -oneDevicePx, -oneDevicePx, +oneDevicePx);
4844 searchField.frame = frameRect.toCGRect();
4846 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4848 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4849 [cell drawWithFrame:rect inView:searchField];
4850 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4852 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4853 [cell drawWithFrame:rect inView:searchField];
4856 [cell setStringValue:sf->text.toNSString()];
4857 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4858 [cell drawWithFrame:r inView:searchField];
4864 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4865 const bool isActive = (titlebar->state & State_Active)
4866 && (titlebar->titleBarState & State_Active);
4868 p->fillRect(opt->rect, Qt::transparent);
4869 p->setRenderHint(QPainter::Antialiasing);
4870 p->setClipRect(opt->rect, Qt::IntersectClip);
4874 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4875 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4876 p->fillPath(outerFramePath, opt->palette.dark());
4878 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4879 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4880 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4881 p->fillPath(innerFramePath, opt->palette.button());
4883 if (titlebar->subControls & (SC_TitleBarCloseButton
4884 | SC_TitleBarMaxButton
4885 | SC_TitleBarMinButton
4886 | SC_TitleBarNormalButton)) {
4887 const bool isHovered = (titlebar->state & State_MouseOver);
4888 static const SubControl buttons[] = {
4889 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4891 for (
const auto sc : buttons) {
4892 const auto ct = d->windowButtonCocoaControl(sc);
4893 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4894 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4895 wb.enabled = (sc & titlebar->subControls) && isActive;
4896 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4897 Q_UNUSED(isHovered);
4899 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4900 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4901 QMacAutoReleasePool pool;
4902 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4903 [wbCell drawWithFrame:rect inView:wb];
4908 if (titlebar->subControls & SC_TitleBarLabel) {
4909 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4910 if (!titlebar->icon.isNull()) {
4911 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4912 const auto iconSize = QSize(iconExtent, iconExtent);
4913 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4915 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4916 p->drawPixmap(iconPos, tr.y(),
4917 titlebar->icon.pixmap(iconSize,
4918 opt->window->devicePixelRatio(),
4922 if (!titlebar->text.isEmpty())
4923 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4928 if (
const QStyleOptionGroupBox *gb
4929 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4931 QStyleOptionGroupBox groupBox(*gb);
4932 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4934 groupBox.state |= QStyle::State_Mini;
4936 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4942 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4957 if (
const QStyleOptionToolButton *tb
4958 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4959#ifndef QT_NO_ACCESSIBILITY
4960 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4961 if (tb->subControls & SC_ToolButtonMenu) {
4962 QStyleOption arrowOpt = *tb;
4963 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4964 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4965 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4966 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4967 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4968 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4969 d->drawToolbarButtonArrow(tb, p);
4971 if (tb->state & State_On) {
4972 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4975 isKey = [view.window isKeyWindow];
4979 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4980 p->setRenderHint(QPainter::Antialiasing);
4981 p->fillPath(path, brush);
4983 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4987 auto bflags = tb->state;
4988 if (tb->subControls & SC_ToolButton)
4989 bflags |= State_Sunken;
4990 auto mflags = tb->state;
4991 if (tb->subControls & SC_ToolButtonMenu)
4992 mflags |= State_Sunken;
4994 if (tb->subControls & SC_ToolButton) {
4995 if (bflags & (State_Sunken | State_On | State_Raised)) {
4996 const bool isEnabled = tb->state & State_Enabled;
4997 const bool isPressed = tb->state & State_Sunken;
4998 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5000 const auto cs = d->effectiveAquaSizeConstrain(opt);
5002 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
5003 pb.bezelStyle = NSBezelStyleShadowlessSquare;
5004 pb.frame = opt->rect.toCGRect();
5005 pb.buttonType = NSButtonTypePushOnPushOff;
5006 pb.enabled = isEnabled;
5007 [pb highlight:isPressed];
5008 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5009 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
5010 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
5011 QMacAutoReleasePool pool;
5012 [pb.cell drawBezelWithFrame:rect inView:pb];
5017 if (tb->subControls & SC_ToolButtonMenu) {
5018 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
5019 QStyleOption arrowOpt = *tb;
5024 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
5025 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
5026 d->drawToolbarButtonArrow(tb, p);
5028 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
5029 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
5030 QStyleOptionToolButton label = *tb;
5031 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5032 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
5037 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
5038 QStyleHelper::drawDial(dial, p);
5041 QCommonStyle::drawComplexControl(cc, opt, p);
5048 Q_D(
const QMacStyle);
5050 SubControl sc = QStyle::SC_None;
5054 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5055 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5056 if (!cmb->editable && sc != QStyle::SC_None)
5057 sc = SC_ComboBoxArrow;
5061 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5062 if (!sl->rect.contains(pt))
5065 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5066 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5068 const auto cs = d->effectiveAquaSizeConstrain(opt);
5070 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5071 if (!setupSlider(slider, sl))
5074 NSSliderCell *cell = slider.cell;
5075 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5076 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5077 if (knobRect.contains(pt)) {
5078 sc = SC_SliderHandle;
5079 }
else if (barRect.contains(pt)) {
5080 sc = SC_SliderGroove;
5081 }
else if (hasTicks) {
5082 sc = SC_SliderTickmarks;
5087 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5088 if (!sb->rect.contains(pt)) {
5093 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5095 const auto cs = d->effectiveAquaSizeConstrain(opt);
5097 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5098 if (!setupScroller(scroller, sb)) {
5106 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5108 const bool isReverse = sb->direction == Qt::RightToLeft;
5109 if (pt.x() < knobRect.left())
5110 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5111 else if (pt.x() > knobRect.right())
5112 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5114 sc = SC_ScrollBarSlider;
5116 if (pt.y() < knobRect.top())
5117 sc = SC_ScrollBarSubPage;
5118 else if (pt.y() > knobRect.bottom())
5119 sc = SC_ScrollBarAddPage;
5121 sc = SC_ScrollBarSlider;
5125 case CC_SearchField:
5126 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5127 if (!sf->rect.contains(pt))
5130 const auto cs = d->effectiveAquaSizeConstrain(sf);
5132 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5133 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5135 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5136 const CGRect bounds = searchField.bounds;
5138 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5139 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5140 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5142 const QPointF localPt = pt - sf->rect.topLeft();
5144 if (cancelRect.contains(localPt))
5145 sc = SC_SearchFieldClear;
5146 else if (searchIconRect.contains(localPt))
5147 sc = SC_SearchFieldSearch;
5148 else if (textFieldRect.contains(localPt))
5149 sc = SC_SearchFieldEditField;
5151 sc = SC_SearchFieldPopup;
5157 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5165 Q_D(
const QMacStyle);
5171 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5172 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5173 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5175 NSScrollerPart part = NSScrollerNoPart;
5176 if (sc == SC_ScrollBarSlider) {
5177 part = NSScrollerKnob;
5178 }
else if (sc == SC_ScrollBarGroove) {
5179 part = NSScrollerKnobSlot;
5180 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5181 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5182 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5183 part = NSScrollerDecrementPage;
5185 part = NSScrollerIncrementPage;
5189 if (part != NSScrollerNoPart) {
5191 const auto cs = d->effectiveAquaSizeConstrain(opt);
5193 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5194 if (setupScroller(scroller, sb))
5195 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5200 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5201 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5202 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5204 const auto cs = d->effectiveAquaSizeConstrain(opt);
5206 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5207 if (!setupSlider(slider, sl))
5210 NSSliderCell *cell = slider.cell;
5211 if (sc == SC_SliderHandle) {
5212 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5213 }
else if (sc == SC_SliderGroove) {
5214 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5215 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5216 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5218 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5220 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5231 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5237 if (sc == SC_TitleBarLabel) {
5238 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5239 qreal labelHeight = titlebar->fontMetrics.height();
5241 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5242 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5243 if (!titlebar->icon.isNull()) {
5244 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5245 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5246 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5249 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5250 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5251 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5252 labelWidth, labelHeight);
5254 const auto currentButton = d->windowButtonCocoaControl(sc);
5258 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5261 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5262 QStyleHelper::SizeLarge);
5263 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5264 if (ct == currentButton)
5265 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5267 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5270 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5271 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5276 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5277 const auto ct = cocoaControlType(combo);
5278 const auto cs = d->effectiveAquaSizeConstrain(combo);
5287 case QStyleHelper::SizeLarge:
5288 if (qt_apple_runningWithLiquidGlass())
5289 editRect = combo->rect.adjusted(15, 7, -25, -7);
5291 editRect = combo->rect.adjusted(15, 7, -25, -9);
5293 case QStyleHelper::SizeSmall:
5294 if (combo->editable)
5295 editRect = combo->rect.adjusted(15, 6, -22, -9);
5297 editRect = combo->rect.adjusted(15, 8, -22, -6);
5300 if (combo->editable)
5301 editRect = combo->rect.adjusted(15, 6, -20, -7);
5303 editRect = combo->rect.adjusted(15, 5, -22, -6);
5308 case SC_ComboBoxEditField:{
5309 ret = editRect.toAlignedRect();
5311 case SC_ComboBoxArrow:{
5312 ret = editRect.toAlignedRect();
5313 ret.setX(ret.x() + ret.width());
5314 ret.setWidth(combo->rect.right() - ret.right());
5316 case SC_ComboBoxListBoxPopup:{
5317 if (combo->editable) {
5318 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5319 const int comboTop = combo->rect.top();
5320 ret = QRect(qRound(inner.origin.x),
5322 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5323 editRect.bottom() - comboTop + 2);
5325 ret = QRect(combo->rect.x() + 4 - 11,
5326 combo->rect.y() + 1,
5327 editRect.width() + 10 + 11,
5337 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5338 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5339 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5340 bool hasNoText = !checkable && groupBox->text.isEmpty();
5342 case SC_GroupBoxLabel:
5343 case SC_GroupBoxCheckBox: {
5345 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5346 const bool fontIsSet =
false;
5349 const int margin = flat || hasNoText ? 0 : 9;
5350 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5352 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5353 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5354 const int tw = qCeil(s.width());
5355 const int h = qCeil(fm.height());
5358 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5360 if (flat && checkable)
5361 labelRect.moveLeft(labelRect.left() + 4);
5362 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5363 bool rtl = groupBox->direction == Qt::RightToLeft;
5364 if (sc == SC_GroupBoxLabel) {
5366 int newSum = indicatorWidth + 1;
5367 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5368 labelRect.moveLeft(newLeft);
5370 labelRect.moveTop(labelRect.top() + 3);
5372 labelRect.moveTop(labelRect.top() + 4);
5374 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5375 labelRect.moveLeft(newLeft);
5376 labelRect.moveTop(labelRect.top() + 3);
5378 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5379 labelRect.moveLeft(newLeft);
5380 labelRect.moveTop(labelRect.top() + 4);
5385 if (sc == SC_GroupBoxCheckBox) {
5386 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5387 int top = flat ? ret.top() + 1 : ret.top() + 5;
5388 ret.setRect(left, top,
5389 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5393 case SC_GroupBoxContents:
5394 case SC_GroupBoxFrame: {
5395 QFontMetrics fm = groupBox->fontMetrics;
5401 yOffset = -qCeil(QFontMetricsF(fm).height());
5402 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5403 if (sc == SC_GroupBoxContents) {
5405 ret.adjust(3, -5, -3, -4);
5407 ret.adjust(3, 3, -3, -4);
5412 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5418 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5419 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5420 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5426 case QStyleHelper::SizeLarge:
5432 case QStyleHelper::SizeSmall:
5438 case QStyleHelper::SizeMini:
5450 case SC_SpinBoxDown: {
5451 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5455 const int x = spin->rect.width() - spinner_w;
5456 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5459 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5460 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5461 ret = QRectF::fromCGRect(outRect).toRect();
5465 ret.setHeight(ret.height() / 2);
5467 case SC_SpinBoxDown:
5468 ret.setY(ret.y() + ret.height() / 2);
5476 ret.translate(0, adjust_y);
5477 ret = visualRect(spin->direction, spin->rect, ret);
5480 case SC_SpinBoxEditField:
5481 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5482 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5483 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5484 ret = visualRect(spin->direction, spin->rect, ret);
5488 ret = QCommonStyle::subControlRect(cc, spin, sc);
5494 ret = QCommonStyle::subControlRect(cc, opt, sc);
5495 if (sc == SC_ToolButtonMenu) {
5496#ifndef QT_NO_ACCESSIBILITY
5497 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5500 ret.adjust(-1, 0, 0, 0);
5503 case CC_SearchField:
5504 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5505 const auto cs = d->effectiveAquaSizeConstrain(sf);
5510 case QStyleHelper::SizeLarge:
5511 editRect = sf->rect.adjusted(16, 0, -22, 0);
5513 case QStyleHelper::SizeSmall:
5514 editRect = sf->rect.adjusted(16, 5, -22, -7);
5517 editRect = sf->rect.adjusted(16, 5, -18, -7);
5521 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5522 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5523 const CGRect bounds = searchField.bounds;
5526 case SC_SearchFieldEditField:{
5527 ret = editRect.toAlignedRect();
5531 case SC_SearchFieldClear: {
5532 const CGRect r = [cell cancelButtonRectForBounds:bounds];
5533 ret = QRectF::fromCGRect(r).toRect();
5534 ret.translate(0, -1);
5535 ret = visualRect(sf->direction, sf->rect, ret);
5536 ret.adjust(-3, -3, 3, 3);
5539 case SC_SearchFieldSearch: {
5540 const CGRect r = [cell searchButtonRectForBounds:bounds];
5541 ret = QRectF::fromCGRect(r).toRect();
5542 ret.translate(0, -1);
5543 ret = visualRect(sf->direction, sf->rect, ret);
5544 ret.adjust(-3, -3, 3, 3);
5547 case SC_SearchFieldPopup: {
5548 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5549 const int searchTop = sf->rect.top();
5550 ret = QRect(qRound(inner.origin.x),
5552 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5553 editRect.bottom() - searchTop + 2);
5562 ret = QCommonStyle::subControlRect(cc, opt, sc);
5570 Q_D(
const QMacStyle);
5573 bool useAquaGuideline =
true;
5577 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5578 if (vopt->subControls == SC_SpinBoxFrame) {
5579 const QSize minimumSize(20, 24);
5580 if (sz.width() < minimumSize.width())
5581 sz.setWidth(minimumSize.width());
5582 if (sz.height() < minimumSize.height())
5583 sz.setHeight(minimumSize.height());
5585 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5586 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5587 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5591 case QStyle::CT_TabWidget:
5594 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5596
5597
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5626 if (
const QStyleOptionTabWidgetFrame *twf
5627 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5629 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5630 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5632 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5633 if (tabDirection == QMacStylePrivate::North
5634 || tabDirection == QMacStylePrivate::South) {
5635 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5637 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5642 case QStyle::CT_TabBarTab:
5643 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5646 const bool differentFont =
false;
5647 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5648 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5649 || tabDirection == QMacStylePrivate::West;
5651 sz = sz.transposed();
5653 int defaultTabHeight;
5654 const auto cs = d->effectiveAquaSizeConstrain(opt);
5656 case QStyleHelper::SizeLarge:
5657 if (tab->documentMode)
5658 defaultTabHeight = 24;
5660 defaultTabHeight = 21;
5662 case QStyleHelper::SizeSmall:
5663 defaultTabHeight = 18;
5665 case QStyleHelper::SizeMini:
5666 defaultTabHeight = 16;
5672 const bool widthSet = !differentFont && tab->icon.isNull();
5674 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5675 sz.rwidth() = textSize.width();
5676 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5678 sz.rheight() = qMax(defaultTabHeight, sz.height());
5680 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5683 sz = sz.transposed();
5685 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5686 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5688 int widgetWidth = 0;
5689 int widgetHeight = 0;
5691 if (tab->leftButtonSize.isValid()) {
5693 widgetWidth += tab->leftButtonSize.width();
5694 widgetHeight += tab->leftButtonSize.height();
5696 if (tab->rightButtonSize.isValid()) {
5698 widgetWidth += tab->rightButtonSize.width();
5699 widgetHeight += tab->rightButtonSize.height();
5703 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5704 sz.setHeight(sz.height() + widgetHeight + padding);
5707 sz.setWidth(sz.width() + widgetWidth + padding);
5708 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5713 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5715 if (sz.width() < 10)
5717 if (sz.height() < 20)
5721 int leftPadding = 4;
5722 int rightPadding = 4;
5724 int bottomPadding = 0;
5726 if (opt->state & QStyle::State_Small) {
5728 }
else if (opt->state & QStyle::State_Mini) {
5732 sz.rwidth() += leftPadding + rightPadding;
5733 sz.rheight() += topPadding + bottomPadding;
5736 case QStyle::CT_PushButton: {
5737 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5738 if (btn->features & QStyleOptionButton::CommandLinkButton)
5739 return QCommonStyle::sizeFromContents(ct, opt, sz);
5746 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5748 if (macsz.width() != -1)
5749 sz.setWidth(macsz.width());
5753 if (controlSize != QStyleHelper::SizeMini)
5755 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5756 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5757 else if (controlSize == QStyleHelper::SizeMini)
5760 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5763 case QStyle::CT_MenuItem:
5764 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5765 int maxpmw = mi->maxIconWidth;
5767 int h = sz.height();
5773 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5777 h = mi->fontMetrics.height() + 2;
5778 if (!mi->icon.isNull()) {
5787 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5788 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5792 if (mi->text.contains(QLatin1Char(
'\t')))
5794 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5813 case CT_MenuBarItem:
5820 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5821 if (tb->features & QStyleOptionToolButton::Menu)
5825 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5826 const int controlSize = getControlSize(opt);
5829 if (sz.width() < 10)
5832 if (!cb->editable) {
5837 if (controlSize == QStyleHelper::SizeLarge) {
5839 }
else if (controlSize == QStyleHelper::SizeSmall) {
5849 if (controlSize == QStyleHelper::SizeMini)
5852 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5857 case CT_SearchField:
5858 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5859 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5860 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5861 if (sf->subControls == SC_SearchFieldFrame) {
5862 const int controlSize = getControlSize(opt);
5866 if (controlSize == QStyleHelper::SizeLarge) {
5870 }
else if (controlSize == QStyleHelper::SizeSmall) {
5881 if (sz.width() < 60)
5884 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5885 sz.rwidth() += totalIconsSize;
5888 }
else if (sf->subControls == SC_SearchFieldClear) {
5890 }
else if (sf->subControls == SC_SearchFieldSearch) {
5891 return searchButton;
5896 if (proxy() ==
this) {
5899 QStyleHintReturnMask menuMask;
5900 QStyleOption myOption = *opt;
5901 myOption.rect.setSize(sz);
5902 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5903 sz = menuMask.region.boundingRect().size();
5906 case CT_HeaderSection:{
5907 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5908 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5909 if (header->text.contains(QLatin1Char(
'\n')))
5910 useAquaGuideline =
false;
5914 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5915 const int minimumWidth = 24;
5916 const int absoluteHeight = 14;
5917 if (slider->orientation == Qt::Horizontal) {
5918 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5919 sz.setHeight(absoluteHeight);
5921 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5922 sz.setWidth(absoluteHeight);
5926 case CT_ItemViewItem:
5927 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5928 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5929 sz.setHeight(sz.height() + 2);
5933 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5936 if (useAquaGuideline && ct != CT_PushButton) {
5939 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5940 if (macsz.width() != -1)
5941 sz.setWidth(macsz.width());
5942 if (macsz.height() != -1)
5943 sz.setHeight(macsz.height());
5949 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5950 if (combo->editable) {
5951 const auto widgetSize = d->aquaSizeConstrain(opt);
5954 cw.size = widgetSize;
5955 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5956 sz.rwidth() -= qRound(diffRect.size.width);
5957 sz.rheight() -= qRound(diffRect.size.height);
5965 QFont font = QCommonStyle::font(element, state);
5967 if (state & QStyle::State_Small) {
5968 font.setPixelSize(11);
5969 }
else if (state & QStyle::State_Mini) {
5970 font.setPixelSize(9);
5982 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5983 margins = QMargins(10, 0, arrow.width() + 1, -1);
5986 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
5994 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
5996 if(flags & Qt::TextShowMnemonic)
5997 flags |= Qt::TextHideMnemonic;
5998 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6003 switch (standardIcon) {
6005 return QCommonStyle::standardIcon(standardIcon, opt);
6006 case SP_ToolBarHorizontalExtensionButton:
6007 case SP_ToolBarVerticalExtensionButton: {
6008 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
6009 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6010 QPixmap pix2(pixmap.height(), pixmap.width());
6011 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
6012 pix2.fill(Qt::transparent);
6014 p.translate(pix2.width(), 0);
6016 p.drawPixmap(0, 0, pixmap);