195static bool isDarkMode() {
return qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark; }
235#ifndef QT_NO_ACCESSIBILITY
242 return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
244 return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
275 if (qFuzzyIsNull(length))
277 const qreal proportion = sb
->pageStep / length;
280 if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
283 scroller.frame = sb->rect.toCGRect();
284 scroller.floatValue = value;
285 scroller.knobProportion = proportion;
297 [slider initWithFrame:sl->rect.toCGRect()];
316 if (sl->orientation == Qt::Horizontal)
317 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
319 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
321 slider.numberOfTickMarks = 0;
326 [slider layoutSubtreeIfNeeded];
329 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
331 pressPoint.x = CGRectGetMidX(knobRect);
332 pressPoint.y = CGRectGetMidY(knobRect);
333 [slider.cell startTrackingAt:pressPoint inView:slider];
341 const auto tabDirection = QMacStylePrivate::tabDirection(shape);
342 if (QMacStylePrivate::verticalTabs(tabDirection)) {
343 int newX, newY, newRot;
344 if (tabDirection == QMacStylePrivate::East) {
345 newX = tabRect.width();
350 newY = tabRect.y() + tabRect.height();
353 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
354 QTransform transform;
355 transform.translate(newX, newY);
356 transform.rotate(newRot);
357 p->setTransform(transform,
true);
364 QRect rect = tabOpt->rect;
365 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
366 rect = rect.adjusted(-tabOverlap, 0, 0, 0);
368 rect = rect.adjusted(0, -tabOverlap, 0, 0);
370 p->translate(rect.x(), rect.y());
373 const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
375 const int width = tabRect.width();
376 const int height = tabRect.height();
380 const QRect bodyRect(1, 2, width - 2, height - 3);
381 const QRect topLineRect(1, 0, width - 2, 1);
382 const QRect bottomLineRect(1, height - 1, width - 2, 1);
385 if (tabOpt->documentMode && isUnified) {
387 p->setCompositionMode(QPainter::CompositionMode_Source);
388 p->fillRect(tabRect, QColor(Qt::transparent));
391 p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
393 p->fillRect(topLineRect, tabBarTabLineSelected());
395 p->fillRect(bodyRect, tabBarTabBackgroundSelected());
402 p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
404 p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
409 const QRect leftLineRect(0, 1, 1, height - 2);
410 const QRect rightLineRect(width - 1, 1, 1, height - 2);
411 const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
412 p->fillRect(leftLineRect, separatorLineColor);
413 p->fillRect(rightLineRect, separatorLineColor);
424 const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
425 const int width = tabRect.width();
426 const int height = tabRect.height();
430 const QRect bodyRect(0, 1, width, height - 1);
431 const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
432 p->fillRect(bodyRect, bodyColor);
435 const QRect topLineRect(0, 0, width, 1);
436 const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
437 p->fillRect(topLineRect, topLineColor);
440 const QRect bottomLineRect(0, height - 1, width, 1);
441 bool isDocument =
false;
444 const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
445 p->fillRect(bottomLineRect, bottomLineColor);
459 QString returnText(original.size(), QChar());
462 int l = original.length();
464 if (original.at(currPos) == QLatin1Char(
'&')) {
469 }
else if (original.at(currPos) == QLatin1Char(
'(') && l >= 4 &&
470 original.at(currPos + 1) == QLatin1Char(
'&') &&
471 original.at(currPos + 2) != QLatin1Char(
'&') &&
472 original.at(currPos + 3) == QLatin1Char(
')')) {
475 while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
482 returnText[finalDest] = original.at(currPos);
487 returnText.truncate(finalDest);
493 if (window->handle()) {
494 if (NSWindow *nswindow =
static_cast<NSWindow*>(
495 QGuiApplication::platformNativeInterface()->
496 nativeResourceForWindow(QByteArrayLiteral(
"nswindow"),
497 const_cast<QWindow *>(window)))) {
498 return [nswindow isMainWindow];
504#define LargeSmallMini(option, large, small, mini)
505 (option->state & QStyle::State_Small) ? small : ((option->state & QStyle::State_Mini) ? mini : large)
508
509
515
516
615 qDebug(
"Not sure how to return this...");
894 static const qreal CornerPointOffset = 5.5;
895 static const qreal CornerControlOffset = 2.1;
899 path.moveTo(r.left(), r.top() + CornerPointOffset);
900 path.cubicTo(r.left(), r.top() + CornerControlOffset,
901 r.left() + CornerControlOffset, r.top(),
902 r.left() + CornerPointOffset, r.top());
904 path.lineTo(r.right() - CornerPointOffset, r.top());
905 path.cubicTo(r.right() - CornerControlOffset, r.top(),
906 r.right(), r.top() + CornerControlOffset,
907 r.right(), r.top() + CornerPointOffset);
909 path.lineTo(r.right(), r.bottom() - CornerPointOffset);
910 path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
911 r.right() - CornerControlOffset, r.bottom(),
912 r.right() - CornerPointOffset, r.bottom());
914 path.lineTo(r.left() + CornerPointOffset, r.bottom());
915 path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
916 r.left(), r.bottom() - CornerControlOffset,
917 r.left(), r.bottom() - CornerPointOffset);
918 path.lineTo(r.left(), r.top() + CornerPointOffset);
948 QRect tr = opt->rect;
949 const bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
950 || opt->shape == QStyleOptionTab::RoundedWest
951 || opt->shape == QStyleOptionTab::TriangularEast
952 || opt->shape == QStyleOptionTab::TriangularWest;
954 tr.setRect(0, 0, tr.height(), tr.width());
956 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
957 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
958 const int hpadding = 4;
959 const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
960 if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
961 verticalShift = -verticalShift;
962 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
965 if (!opt->leftButtonSize.isEmpty()) {
966 const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
967 tr.setLeft(tr.left() + 4 + buttonSize);
969 if (opt->rightButtonSize.isEmpty())
970 tr.setRight(tr.right() - 4 - buttonSize);
973 if (!opt->rightButtonSize.isEmpty()) {
974 const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
975 tr.setRight(tr.right() - 4 - buttonSize);
977 if (opt->leftButtonSize.isEmpty())
978 tr.setLeft(tr.left() + 4 + buttonSize);
982 if (!opt->icon.isNull()) {
983 QSize iconSize = opt->iconSize;
984 if (!iconSize.isValid()) {
985 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
986 iconSize = QSize(iconExtent, iconExtent);
988 QSize tabIconSize = opt->icon.actualSize(iconSize,
989 (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
990 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
992 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
994 const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2 - hpadding;
996 if (opt->documentMode) {
998 const int textWidth =
999 opt->fontMetrics.boundingRect(tr, Qt::AlignCenter | Qt::TextShowMnemonic, opt->text).width();
1000 *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
1001 tr.center().y() - tabIconSize.height() / 2,
1002 tabIconSize.width(), tabIconSize.height());
1004 *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
1005 tabIconSize.width(), tabIconSize.height());
1008 *iconRect =
proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
1010 tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
1011 tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
1015 tr =
proxyStyle->visualRect(opt->direction, opt->rect, tr);
1023 case QStyleOptionTab::RoundedSouth:
1024 case QStyleOptionTab::TriangularSouth:
1026 case QStyleOptionTab::RoundedNorth:
1027 case QStyleOptionTab::TriangularNorth:
1029 case QStyleOptionTab::RoundedWest:
1030 case QStyleOptionTab::TriangularWest:
1032 case QStyleOptionTab::RoundedEast:
1033 case QStyleOptionTab::TriangularEast:
1040 return (direction == QMacStylePrivate::East
1041 || direction == QMacStylePrivate::West);
1045 QStyle::ContentsType ct,
1046 QSize szHint, QSize *insz)
const
1097 return QSizeF(-1, pushButtonDefaultHeight[
size]);
1101 return QSizeF(-1, popupButtonDefaultHeight[
size]);
1104 return QSizeF(-1, comboBoxDefaultHeight[
size]);
1112 const auto frameSize = defaultFrameSize();
1114 frameRect = rect.adjusted(3, 1, -3, -1)
1115 .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
1118 frameRect = QRectF(rect.topLeft(),
1119 QSizeF(rect.width(), frameSize.height()));
1121 frameRect = frameRect.translated(0, 1.5);
1123 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
1126 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1127 QSizeF(rect.width(), frameSize.height()));
1128 frameRect = frameRect.translated(rect.topLeft());
1131 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1133 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1135 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1137 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1148 return QMarginsF(12, 5, 12, 9);
1150 return QMarginsF(12, 4, 12, 9);
1152 return QMarginsF(10, 1, 10, 2);
1157 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1159 return QMarginsF(7.5, 2, 20.5, 4);
1161 return QMarginsF(4.5, 0, 16.5, 2);
1165 return QMarginsF(6, 1, 6, 2);
1173 case Button_CheckBox:
1174 *buttonType = NSButtonTypeSwitch;
1175 *bezelStyle = NSBezelStyleRegularSquare;
1177 case Button_Disclosure:
1178 *buttonType = NSButtonTypeOnOff;
1179 *bezelStyle = NSBezelStyleDisclosure;
1181 case Button_RadioButton:
1182 *buttonType = NSButtonTypeRadio;
1183 *bezelStyle = NSBezelStyleRegularSquare;
1185 case Button_SquareButton:
1186 *buttonType = NSButtonTypePushOnPushOff;
1187 *bezelStyle = NSBezelStyleShadowlessSquare;
1189 case Button_PushButton:
1190 *buttonType = NSButtonTypePushOnPushOff;
1191 *bezelStyle = NSBezelStyleRounded;
1202 if (
const auto *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
1209 || (btn->rect.height() > maxNonSquareHeight);
1216 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
1217 if (combo->editable)
1227
1228
1229
1232 CGRect innerBounds = outerBounds;
1237 switch (cocoaWidget
.size) {
1239 innerBounds.origin.x += 3;
1240 innerBounds.origin.y += 3;
1241 innerBounds.size.width -= 6;
1242 innerBounds.size.height -= 7;
1245 innerBounds.origin.x += 2;
1246 innerBounds.origin.y += 2;
1247 innerBounds.size.width -= 5;
1248 innerBounds.size.height -= 6;
1252 innerBounds.origin.x += 2;
1253 innerBounds.origin.y += 2;
1254 innerBounds.size.width -= 5;
1255 innerBounds.size.height -= 6;
1258 switch (cocoaWidget
.size) {
1260 innerBounds.origin.x += 3;
1261 innerBounds.origin.y += 3;
1262 innerBounds.size.width -= 7;
1263 innerBounds.size.height -= 8;
1266 innerBounds.origin.x += 3;
1267 innerBounds.origin.y += 3;
1268 innerBounds.size.width -= 4;
1269 innerBounds.size.height -= 8;
1273 innerBounds.origin.x += 3;
1274 innerBounds.origin.y += 2;
1275 innerBounds.size.width -= 6;
1276 innerBounds.size.height -= 8;
1284
1285
1286
1289 QRectF ret = outerBounds;
1293 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1297 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1301 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1302 ret.setHeight(10.5);
1310 ret.adjust(10, 1, -23, -4);
1313 ret.adjust(10, 4, -20, -3);
1316 ret.adjust(9, 0, -19, 0);
1329 if (
auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
1330 smallSystemFont = *ssf;
1331 if (
auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
1332 miniSystemFont = *msf;
1337 QMacAutoReleasePool pool;
1338 for (NSView *b : cocoaControls)
1340 for (NSCell *cell : cocoaCells)
1346 if (cocoaControl.type == QMacStylePrivate::NoControl
1347 || cocoaControl.size == QStyleHelper::SizeDefault)
1351 if (
__builtin_available(macOS 10.14, *)) {
1359 NSView *bv = cocoaControls.value(cocoaControl, nil);
1361 switch (cocoaControl
.type) {
1363 NSBox *box = [[NSBox alloc] init];
1366 box.titlePosition = NSNoTitle;
1370 bv = [[QDarkNSBox alloc] init];
1377 NSButton *bc = [[NSButton alloc] init];
1385 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1387 if (cocoaControl.type == Button_PullDown)
1395 const NSWindowButton button = [=] {
1396 switch (cocoaControl
.type) {
1397 case Button_WindowClose:
1398 return NSWindowCloseButton;
1399 case Button_WindowMiniaturize:
1400 return NSWindowMiniaturizeButton;
1401 case Button_WindowZoom:
1402 return NSWindowZoomButton;
1408 const auto styleMask = NSWindowStyleMaskTitled
1409 | NSWindowStyleMaskClosable
1410 | NSWindowStyleMaskMiniaturizable
1411 | NSWindowStyleMaskResizable;
1412 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1417 bv = [[NSSearchField alloc] init];
1420 bv = [[NSComboBox alloc] init];
1422 case ProgressIndicator_Determinate:
1423 bv = [[NSProgressIndicator alloc] init];
1425 case ProgressIndicator_Indeterminate:
1426 bv = [[QIndeterminateProgressIndicator alloc] init];
1428 case Scroller_Horizontal:
1429 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1431 case Scroller_Vertical:
1434 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1436 case Slider_Horizontal:
1437 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1439 case Slider_Vertical:
1442 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1444 case SplitView_Horizontal:
1445 bv = [[NSSplitView alloc] init];
1447 case SplitView_Vertical:
1448 bv = [[QVerticalSplitView alloc] init];
1451 bv = [[NSTextField alloc] init];
1457 if ([bv isKindOfClass:[NSControl
class]]) {
1458 auto *ctrl =
static_cast<NSControl *>(bv);
1459 switch (cocoaControl
.size) {
1460 case QStyleHelper::SizeSmall:
1461 ctrl.controlSize = NSControlSizeSmall;
1463 case QStyleHelper::SizeMini:
1464 ctrl.controlSize = NSControlSizeMini;
1471 auto *pi =
static_cast<NSProgressIndicator *>(bv);
1473 switch (cocoaControl
.size) {
1474 case QStyleHelper::SizeSmall:
1475 pi.controlSize = NSControlSizeSmall;
1477 case QStyleHelper::SizeMini:
1478 pi.controlSize = NSControlSizeMini;
1485 cocoaControls.insert(cocoaControl, bv);
1488 NSButtonType buttonType;
1489 NSBezelStyle bezelStyle;
1503NSCell *QMacStylePrivate::cocoaCell(CocoaControl cocoaControl)
const
1505 NSCell *cell = cocoaCells[cocoaControl];
1507 switch (cocoaControl.type) {
1509 cell = [[NSStepperCell alloc] init];
1511 case Button_Disclosure: {
1512 NSButtonCell *bc = [[NSButtonCell alloc] init];
1513 bc.buttonType = NSButtonTypeOnOff;
1514 bc.bezelStyle = NSBezelStyleDisclosure;
1522 switch (cocoaControl.size) {
1523 case QStyleHelper::SizeSmall:
1524 cell.controlSize = NSControlSizeSmall;
1526 case QStyleHelper::SizeMini:
1527 cell.controlSize = NSControlSizeMini;
1533 cocoaCells.insert(cocoaControl, cell);
1539void QMacStylePrivate::drawNSViewInRect(NSView *view,
const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock)
const
1541 QMacAutoReleasePool pool;
1542 QMacCGContext ctx(p);
1543 setupNSGraphicsContext(ctx, YES);
1554 view.wantsLayer = YES;
1563 view.frame = rect.toCGRect();
1565 [backingStoreNSView addSubview:view];
1572 const CGRect dirtyRect = rect.toCGRect();
1575 drawRectBlock(ctx, dirtyRect);
1577 [view drawRect:dirtyRect];
1579 [view removeFromSuperviewWithoutNeedingDisplay];
1581 restoreNSGraphicsContext(ctx);
1584void QMacStylePrivate::resolveCurrentNSView(QWindow *window)
const
1586 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1589QMacStyle *QMacStyle::create()
1591 return new QMacApperanceStyle<QMacStyle>;
1594QMacStyle::QMacStyle()
1595 : QCommonStyle(*
new QMacStylePrivate)
1597 QMacAutoReleasePool pool;
1599 static QMacNotificationObserver scrollbarStyleObserver(nil,
1600 NSPreferredScrollerStyleDidChangeNotification, []() {
1602 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1604 QEvent event(QEvent::StyleChange);
1605 for (
const auto &o : QMacStylePrivate::scrollBars)
1606 QCoreApplication::sendEvent(o, &event);
1610QMacStyle::~QMacStyle()
1614void QMacStyle::handleThemeChange()
1617 for (NSView *b : d->cocoaControls)
1619 d->cocoaControls.clear();
1622int QMacStyle::pixelMetric(PixelMetric metric,
const QStyleOption *opt)
const
1624 Q_D(
const QMacStyle);
1625 const int controlSize = getControlSize(opt);
1629 case PM_TabCloseIndicatorWidth:
1630 case PM_TabCloseIndicatorHeight:
1631 ret = closeButtonSize;
1633 case PM_ToolBarIconSize:
1634 ret = proxy()->pixelMetric(PM_LargeIconSize);
1636 case PM_FocusFrameVMargin:
1637 case PM_FocusFrameHMargin:
1638 ret = qt_mac_aqua_get_metric(FocusRectOutset);
1640 case PM_DialogButtonsSeparator:
1643 case PM_DialogButtonsButtonHeight: {
1645 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1646 if (sz == QSize(-1, -1))
1651 case PM_DialogButtonsButtonWidth: {
1653 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1654 if (sz == QSize(-1, -1))
1660 case PM_MenuBarHMargin:
1664 case PM_MenuBarVMargin:
1668 case PM_MenuBarPanelWidth:
1672 case PM_MenuButtonIndicator:
1673 ret = toolButtonArrowSize;
1676 case QStyle::PM_MenuDesktopFrameWidth:
1680 case PM_CheckBoxLabelSpacing:
1681 case PM_RadioButtonLabelSpacing:
1684 if (opt->state & State_Mini)
1686 if (opt->state & State_Small)
1692 case PM_MenuScrollerHeight:
1695 case PM_DefaultFrameWidth:
1705 if (qstyleoption_cast<
const QStyleOptionComboBox *>(opt) != 0)
1710 case PM_MaximumDragDistance:
1713 case PM_ScrollBarSliderMin:
1716 case PM_SpinBoxFrameWidth:
1717 ret = qt_mac_aqua_get_metric(EditTextFrameOutset);
1719 case PM_ButtonShiftHorizontal:
1720 case PM_ButtonShiftVertical:
1723 case PM_SliderLength:
1729 case PM_SliderControlThickness:
1730 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
1731 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1732 int ticks = sl->tickPosition;
1734 if (ticks & QStyleOptionSlider::TicksAbove)
1736 if (ticks & QStyleOptionSlider::TicksBelow)
1744 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1745 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1749 thick += (space * 2) / (n + 2);
1755 case PM_SmallIconSize:
1756 ret =
int(QStyleHelper::dpiScaled(16., opt));
1759 case PM_LargeIconSize:
1760 ret =
int(QStyleHelper::dpiScaled(32., opt));
1763 case PM_IconViewIconSize:
1764 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1767 case PM_ButtonDefaultIndicator:
1770 case PM_TitleBarHeight: {
1771 NSUInteger style = NSWindowStyleMaskTitled;
1774 ret =
int([NSWindow frameRectForContentRect:NSZeroRect
1775 styleMask:style].size.height);
1777 case QStyle::PM_TabBarTabHSpace:
1778 switch (d->aquaSizeConstrain(opt)) {
1779 case QStyleHelper::SizeLarge:
1780 ret = QCommonStyle::pixelMetric(metric, opt);
1782 case QStyleHelper::SizeSmall:
1785 case QStyleHelper::SizeMini:
1788 case QStyleHelper::SizeDefault:
1789 const QStyleOptionTab *tb = qstyleoption_cast<
const QStyleOptionTab *>(opt);
1790 if (tb && tb->documentMode)
1793 ret = QCommonStyle::pixelMetric(metric, opt);
1797 case PM_TabBarTabVSpace:
1800 case PM_TabBarTabShiftHorizontal:
1801 case PM_TabBarTabShiftVertical:
1804 case PM_TabBarBaseHeight:
1807 case PM_TabBarTabOverlap:
1810 case PM_TabBarBaseOverlap:
1811 switch (d->aquaSizeConstrain(opt)) {
1812 case QStyleHelper::SizeDefault:
1813 case QStyleHelper::SizeLarge:
1816 case QStyleHelper::SizeSmall:
1819 case QStyleHelper::SizeMini:
1824 case PM_ScrollBarExtent: {
1825 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1826 ret =
static_cast<
int>([NSScroller
1827 scrollerWidthForControlSize:
static_cast<NSControlSize>(size)
1828 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1830 case PM_IndicatorHeight: {
1831 switch (d->aquaSizeConstrain(opt)) {
1832 case QStyleHelper::SizeDefault:
1833 case QStyleHelper::SizeLarge:
1834 ret = qt_mac_aqua_get_metric(CheckBoxHeight);
1836 case QStyleHelper::SizeMini:
1837 ret = qt_mac_aqua_get_metric(MiniCheckBoxHeight);
1839 case QStyleHelper::SizeSmall:
1840 ret = qt_mac_aqua_get_metric(SmallCheckBoxHeight);
1844 case PM_IndicatorWidth: {
1845 switch (d->aquaSizeConstrain(opt)) {
1846 case QStyleHelper::SizeDefault:
1847 case QStyleHelper::SizeLarge:
1848 ret = qt_mac_aqua_get_metric(CheckBoxWidth);
1850 case QStyleHelper::SizeMini:
1851 ret = qt_mac_aqua_get_metric(MiniCheckBoxWidth);
1853 case QStyleHelper::SizeSmall:
1854 ret = qt_mac_aqua_get_metric(SmallCheckBoxWidth);
1859 case PM_ExclusiveIndicatorHeight: {
1860 switch (d->aquaSizeConstrain(opt)) {
1861 case QStyleHelper::SizeDefault:
1862 case QStyleHelper::SizeLarge:
1863 ret = qt_mac_aqua_get_metric(RadioButtonHeight);
1865 case QStyleHelper::SizeMini:
1866 ret = qt_mac_aqua_get_metric(MiniRadioButtonHeight);
1868 case QStyleHelper::SizeSmall:
1869 ret = qt_mac_aqua_get_metric(SmallRadioButtonHeight);
1873 case PM_ExclusiveIndicatorWidth: {
1874 switch (d->aquaSizeConstrain(opt)) {
1875 case QStyleHelper::SizeDefault:
1876 case QStyleHelper::SizeLarge:
1877 ret = qt_mac_aqua_get_metric(RadioButtonWidth);
1879 case QStyleHelper::SizeMini:
1880 ret = qt_mac_aqua_get_metric(MiniRadioButtonWidth);
1882 case QStyleHelper::SizeSmall:
1883 ret = qt_mac_aqua_get_metric(SmallRadioButtonWidth);
1888 case PM_MenuVMargin:
1891 case PM_MenuPanelWidth:
1894 case PM_ToolTipLabelFrameWidth:
1897 case PM_SizeGripSize: {
1898 QStyleHelper::WidgetSizePolicy aSize;
1902 aSize = QStyleHelper::SizeLarge;
1903 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
1906 case PM_MdiSubWindowFrameWidth:
1909 case PM_DockWidgetFrameWidth:
1912 case PM_DockWidgetTitleMargin:
1915 case PM_DockWidgetSeparatorExtent:
1918 case PM_ToolBarHandleExtent:
1921 case PM_ToolBarItemMargin:
1924 case PM_ToolBarItemSpacing:
1927 case PM_SplitterWidth:
1930 case PM_LayoutLeftMargin:
1931 case PM_LayoutTopMargin:
1932 case PM_LayoutRightMargin:
1933 case PM_LayoutBottomMargin:
1935 if (opt->state & State_Window) {
1937
1938
1939
1940
1941
1958
1959
1964 case PM_LayoutHorizontalSpacing:
1965 case PM_LayoutVerticalSpacing:
1967 case PM_MenuHMargin:
1970 case PM_ToolBarExtensionExtent:
1973 case PM_ToolBarFrameWidth:
1976 case PM_ScrollView_ScrollBarOverlap:
1977 ret = styleHint(SH_ScrollBar_Transient, opt,
nullptr)
1978 ? pixelMetric(PM_ScrollBarExtent, opt)
1981 case PM_PushButtonFocusFrameRadius:
1984 case PM_CheckBoxFocusFrameRadius:
1987 case PM_SearchFieldFocusFrameRadius:
1988 case PM_ComboBoxFocusFrameRadius:
1991 case PM_RadioButtonFocusFrameRadius:
1994 case PM_SliderFocusFrameRadius:
2001 case PM_DialFocusFrameRadius:
2002 case PM_SpinBoxFocusFrameRadius:
2003 case PM_TextAreaFocusFrameRadius:
2004 case PM_TextFieldFocusFrameRadius:
2008 ret = QCommonStyle::pixelMetric(metric, opt);
2024int QMacStyle::styleHint(StyleHint sh,
const QStyleOption *opt, QStyleHintReturn *hret)
const
2026 QMacAutoReleasePool pool;
2030 case SH_Slider_SnapToValue:
2031 case SH_PrintDialog_RightAlignButtons:
2032 case SH_FontDialog_SelectAssociatedText:
2033 case SH_MenuBar_MouseTracking:
2034 case SH_Menu_MouseTracking:
2035 case SH_ComboBox_ListMouseTracking:
2036 case SH_MainWindow_SpaceBelowMenuBar:
2037 case SH_ItemView_ChangeHighlightOnFocus:
2040 case SH_ToolBox_SelectedPageTitleBold:
2043 case SH_DialogButtonBox_ButtonsHaveIcons:
2046 case SH_Menu_SelectionWrap:
2049 case SH_Menu_KeyboardSearch:
2052 case SH_Menu_SpaceActivatesItem:
2055 case SH_Slider_AbsoluteSetButtons:
2056 ret = Qt::LeftButton|Qt::MiddleButton;
2058 case SH_Slider_PageSetButtons:
2061 case SH_ScrollBar_ContextMenu:
2064 case SH_TitleBar_AutoRaise:
2067 case SH_Menu_AllowActiveAndDisabled:
2070 case SH_Menu_SubMenuPopupDelay:
2073 case SH_Menu_SubMenuUniDirection:
2076 case SH_Menu_SubMenuSloppySelectOtherActions:
2079 case SH_Menu_SubMenuResetWhenReenteringParent:
2082 case SH_Menu_SubMenuDontStartSloppyOnLeave:
2086 case SH_ScrollBar_LeftClickAbsolutePosition: {
2087 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2088 bool result = [defaults boolForKey:@
"AppleScrollerPagingBehavior"];
2094 case SH_TabBar_PreferNoArrows:
2098
2099
2100
2101
2102 case SH_GroupBox_TextLabelVerticalAlignment:
2105 case SH_ScrollView_FrameOnlyAroundContents:
2106 ret = QCommonStyle::styleHint(sh, opt, hret);
2108 case SH_Menu_FillScreenWithScroll:
2111 case SH_Menu_Scrollable:
2114 case SH_RichText_FullWidthSelection:
2117 case SH_BlinkCursorWhenTextSelected:
2120 case SH_Slider_StopMouseOverSlider:
2123 case SH_ListViewExpand_SelectMouseType:
2124 ret = QEvent::MouseButtonRelease;
2126 case SH_TabBar_SelectMouseType:
2127 if (
const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2128 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2130 ret = QEvent::MouseButtonRelease;
2133 case SH_ComboBox_Popup:
2134 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt))
2135 ret = !cmb->editable;
2139 case SH_Workspace_FillSpaceOnMaximize:
2142 case SH_Widget_ShareActivation:
2145 case SH_Header_ArrowAlignment:
2146 ret = Qt::AlignRight;
2148 case SH_TabBar_Alignment: {
2165 ret = Qt::AlignCenter;
2167 case SH_UnderlineShortcut:
2170 case SH_ToolTipLabel_Opacity:
2173 case SH_Button_FocusPolicy:
2176 case SH_EtchDisabledText:
2179 case SH_FocusFrame_Mask: {
2181 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2182 const uchar fillR = 192, fillG = 191, fillB = 190;
2185 QSize pixmapSize = opt->rect.size();
2186 if (!pixmapSize.isEmpty()) {
2187 QPixmap pix(pixmapSize);
2188 pix.fill(QColor(fillR, fillG, fillB));
2189 QPainter pix_paint(&pix);
2190 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2192 img = pix.toImage();
2195 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2196 const qsizetype sbpl = img.bytesPerLine();
2197 const int w = sbpl/4, h = img.height();
2199 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2200 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2201 const qsizetype dbpl = img_mask.bytesPerLine();
2203 for (
int y = 0; y < h; ++y) {
2204 srow = sptr+((y*sbpl)/4);
2205 drow = dptr+((y*dbpl)/4);
2206 for (
int x = 0; x < w; ++x) {
2207 const int redDiff = qRed(*srow) - fillR;
2208 const int greenDiff = qGreen(*srow) - fillG;
2209 const int blueDiff = qBlue(*srow) - fillB;
2210 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2211 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2215 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2216 mask->region = QRegion(qmask);
2219 case SH_TitleBar_NoBorder:
2222 case SH_RubberBand_Mask:
2225 case SH_ComboBox_LayoutDirection:
2226 ret = Qt::LeftToRight;
2228 case SH_ItemView_EllipsisLocation:
2229 ret = Qt::AlignHCenter;
2231 case SH_ItemView_ShowDecorationSelected:
2234 case SH_TitleBar_ModifyNotification:
2237 case SH_ScrollBar_RollBetweenButtons:
2240 case SH_WindowFrame_Mask:
2243 case SH_TabBar_ElideMode:
2244 ret = Qt::ElideRight;
2255 case SH_FormLayoutFormAlignment:
2256 ret = Qt::AlignHCenter | Qt::AlignTop;
2258 case SH_FormLayoutLabelAlignment:
2259 ret = Qt::AlignRight;
2264 case SH_MessageBox_TextInteractionFlags:
2265 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2267 case SH_SpellCheckUnderlineStyle:
2268 ret = QTextCharFormat::DashUnderline;
2270 case SH_MessageBox_CenterButtons:
2273 case SH_MenuBar_AltKeyNavigation:
2276 case SH_ItemView_MovementWithoutUpdatingSelection:
2279 case SH_FocusFrame_AboveWidget:
2285 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2288 case SH_Menu_FlashTriggeredItem:
2291 case SH_Menu_FadeOutOnHide:
2294 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2297 case SH_TabBar_CloseButtonPosition:
2298 ret = QStyleOptionTabBarBase::LeftSide;
2300 case SH_DockWidget_ButtonsHaveFrame:
2303 case SH_ScrollBar_Transient:
2309 case SH_TitleBar_ShowToolTipsOnButtons:
2313 case SH_ComboBox_AllowWheelScrolling:
2316 case SH_SpinBox_ButtonsInsideFrame:
2319 case SH_Table_GridLineColor:
2320 ret =
int(qt_mac_toQColor(NSColor.gridColor).rgba());
2323 ret = QCommonStyle::styleHint(sh, opt, hret);
2329QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode,
const QPixmap &pixmap,
2330 const QStyleOption *opt)
const
2333 case QIcon::Disabled: {
2334 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2335 int imgh = img.height();
2336 int imgw = img.width();
2338 for (
int y = 0; y < imgh; ++y) {
2339 for (
int x = 0; x < imgw; ++x) {
2340 pixel = img.pixel(x, y);
2341 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2342 qAlpha(pixel) / 2));
2345 return QPixmap::fromImage(img);
2350 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2354QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap,
const QStyleOption *opt)
const
2361 static bool recursionGuard =
false;
2364 return QCommonStyle::standardPixmap(standardPixmap, opt);
2366 recursionGuard =
true;
2367 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2368 recursionGuard =
false;
2370 switch (standardPixmap) {
2374 case SP_MessageBoxCritical:
2375 case SP_MessageBoxQuestion:
2376 case SP_MessageBoxInformation:
2377 case SP_MessageBoxWarning:
2381 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2384void QMacStyle::drawPrimitive(PrimitiveElement pe,
const QStyleOption *opt, QPainter *p)
const
2386 Q_D(
const QMacStyle);
2388 QMacCGContext cg(p);
2389 d->resolveCurrentNSView(opt->window);
2392 case PE_IndicatorArrowUp:
2393 case PE_IndicatorArrowDown:
2394 case PE_IndicatorArrowRight:
2395 case PE_IndicatorArrowLeft: {
2397 p->setRenderHint(QPainter::Antialiasing);
2398 const int xOffset = 1;
2399 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2400 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2410 QTransform transform;
2411 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2415 case PE_IndicatorArrowDown:
2417 case PE_IndicatorArrowUp:
2418 transform.rotate(180);
2420 case PE_IndicatorArrowLeft:
2421 transform.rotate(90);
2423 case PE_IndicatorArrowRight:
2424 transform.rotate(-90);
2427 p->setTransform(transform);
2429 path.moveTo(-halfSize, -halfSize * 0.5);
2430 path.lineTo(0.0, halfSize * 0.5);
2431 path.lineTo(halfSize, -halfSize * 0.5);
2433 const QPen arrowPen(opt->palette.text(), penWidth,
2434 Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
2435 p->strokePath(path, arrowPen);
2438 case PE_FrameTabBarBase:
2439 if (
const QStyleOptionTabBarBase *tbb
2440 = qstyleoption_cast<
const QStyleOptionTabBarBase *>(opt)) {
2441 if (tbb->documentMode) {
2443 drawTabBase(p, tbb);
2447 QRegion region(tbb->rect);
2448 region -= tbb->tabBarRect;
2450 p->setClipRegion(region);
2451 QStyleOptionTabWidgetFrame twf;
2452 twf.QStyleOption::operator=(*tbb);
2453 twf.shape = tbb->shape;
2454 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2455 case QMacStylePrivate::North:
2456 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2458 case QMacStylePrivate::South:
2459 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2461 case QMacStylePrivate::West:
2462 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2464 case QMacStylePrivate::East:
2465 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2468 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2472 case PE_PanelTipLabel:
2473 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2475 case PE_FrameGroupBox:
2476 if (
const auto *groupBox = qstyleoption_cast<
const QStyleOptionFrame *>(opt))
2477 if (groupBox->features & QStyleOptionFrame::Flat) {
2478 QCommonStyle::drawPrimitive(pe, groupBox, p);
2482 case PE_FrameTabWidget:
2484 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
2485 auto *box =
static_cast<NSBox *>(d->cocoaControl(cw));
2499 auto adjustedRect = opt->rect;
2500 bool needTranslation =
false;
2501 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
2514 adjustedRect.adjust(0, 0, 6, 6);
2515 needTranslation =
true;
2517 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2522 QMacAutoReleasePool pool;
2523 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2524 CGContextScaleCTM(ctx, 1, -1);
2525 if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
2526 || [box isMemberOfClass:QDarkNSBox.
class]) {
2527 [box drawRect:rect];
2529 if (needTranslation)
2530 CGContextTranslateCTM(ctx, -3.0, 5.0);
2531 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2536 case PE_IndicatorToolBarSeparator: {
2538 if (opt->state & State_Horizontal) {
2539 int xpoint = opt->rect.center().x();
2540 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2541 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2543 int ypoint = opt->rect.center().y();
2544 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2545 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2547 QPainterPathStroker theStroker;
2548 theStroker.setCapStyle(Qt::FlatCap);
2549 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
2550 path = theStroker.createStroke(path);
2551 const auto dark = isDarkMode() ? opt->palette.dark().color().darker()
2552 : QColor(0, 0, 0, 119);
2553 p->fillPath(path, dark);
2556 case PE_FrameWindow:
2567 case PE_IndicatorDockWidgetResizeHandle: {
2570 if (opt->state & State_Horizontal) {
2571 p->setPen(QColor(160, 160, 160));
2572 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2574 p->setPen(QColor(145, 145, 145));
2575 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2579 case PE_IndicatorToolBarHandle: {
2582 int x = opt->rect.x() + 6;
2583 int y = opt->rect.y() + 7;
2584 static const int RectHeight = 2;
2585 if (opt->state & State_Horizontal) {
2586 while (y < opt->rect.height() - RectHeight - 5) {
2588 path.addEllipse(x, y, RectHeight, RectHeight);
2592 while (x < opt->rect.width() - RectHeight - 5) {
2594 path.addEllipse(x, y, RectHeight, RectHeight);
2598 p->setPen(Qt::NoPen);
2599 QColor dark = opt->palette.dark().color().darker();
2600 dark.setAlphaF(0.50);
2601 p->fillPath(path, dark);
2606 case PE_IndicatorHeaderArrow:
2607 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2609 if (header->sortIndicator != QStyleOptionHeader::None)
2610 proxy()->drawPrimitive(
2611 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2612 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
2615 case PE_IndicatorMenuCheckMark: {
2617 if (opt->state & State_On)
2618 pc = opt->palette.highlightedText().color();
2620 pc = opt->palette.text().color();
2622 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(
static_cast<CGFloat>(pc.redF()),
2623 static_cast<CGFloat>(pc.greenF()),
2624 static_cast<CGFloat>(pc.blueF()),
2625 static_cast<CGFloat>(pc.alphaF()));
2631 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2632 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2633 kCTFontUIFontMenuItemMark;
2637 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2638 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2640 CGContextSaveGState(cg);
2641 CGContextSetShouldSmoothFonts(cg, NO);
2644 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2645 (opt->state & State_Small) ? 1.0 :
2648 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2649 CGContextScaleCTM(cg, 1, -1);
2651 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2655 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2656 static const int numValues =
sizeof(keys) /
sizeof(keys[0]);
2657 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2658 Q_STATIC_ASSERT((
sizeof(values) /
sizeof(values[0])) == numValues);
2659 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (
const void **)keys, (
const void **)values,
2660 numValues, NULL, NULL);
2662 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@
"\u2713", attributes);
2663 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2665 CTLineDraw((CTLineRef)line, cg);
2668 CGContextRestoreGState(cg);
2670 case PE_IndicatorItemViewItemCheck:
2671 case PE_IndicatorRadioButton:
2672 case PE_IndicatorCheckBox: {
2673 const bool isEnabled = opt->state & State_Enabled;
2674 const bool isPressed = opt->state & State_Sunken;
2675 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2676 const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
2677 const auto cs = d->effectiveAquaSizeConstrain(opt);
2678 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
2679 auto *tb =
static_cast<NSButton *>(d->cocoaControl(cw));
2680 tb.enabled = isEnabled;
2681 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2682 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2683 [tb highlight:isPressed];
2684 const auto vOffset = [=] {
2686 if (cs == QStyleHelper::SizeMini)
2687 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
2689 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2691 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
2692 QMacAutoReleasePool pool;
2693 CGContextTranslateCTM(ctx, 0, vOffset);
2694 [tb.cell drawInteriorWithFrame:rect inView:tb];
2697 case PE_FrameFocusRect:
2700 case PE_IndicatorBranch: {
2701 if (!(opt->state & State_Children))
2703 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
2704 NSButtonCell *triangleCell =
static_cast<NSButtonCell *>(d->cocoaCell(cw));
2705 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2707 bool viewHasFocus =
false;
2708 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2710 d->setupNSGraphicsContext(cg, NO);
2712 QRect qtRect = opt->rect.adjusted(DisclosureOffset, 0, -DisclosureOffset, 0);
2713 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2714 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2715 CGContextScaleCTM(cg, 1, -1);
2716 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2718 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2720 d->restoreNSGraphicsContext(cg);
2724 const QPen oldPen = p->pen();
2725 QPen penCpy = p->pen();
2727 penCpy.setColor(opt->palette.dark().color());
2729 p->drawRect(opt->rect);
2732 case PE_PanelLineEdit:
2733 case PE_FrameLineEdit:
2734 if (
const QStyleOptionFrame *frame = qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
2735 if (frame->state & State_Sunken) {
2736 const bool isEnabled = opt->state & State_Enabled;
2737 const bool isReadOnly = opt->state & State_ReadOnly;
2738 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2739 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2740 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
2741 auto *tf =
static_cast<NSTextField *>(d->cocoaControl(cw));
2742 tf.enabled = isEnabled;
2743 tf.editable = !isReadOnly;
2745 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2746 tf.frame = opt->rect.toCGRect();
2747 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
2748 QMacAutoReleasePool pool;
2749 if (!isDarkMode()) {
2754 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2758 if (cgContext ?
bool(CGBitmapContextGetColorSpace(cgContext)) :
false) {
2759 tf.drawsBackground = YES;
2760 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2761 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2762 green:bgColor.greenF()
2763 blue:bgColor.blueF()
2764 alpha:bgColor.alphaF()];
2765 if (bgColor.alpha() != 255) {
2772 CGRect fixedRect = rect;
2773 if (qt_apple_runningWithLiquidGlass()) {
2778 fixedRect = CGRectInset(rect, 1., 1.);
2780 [tf.cell drawWithFrame:fixedRect inView:tf];
2783 QCommonStyle::drawPrimitive(pe, opt, p);
2787 case PE_PanelScrollAreaCorner: {
2788 const QBrush brush(opt->palette.brush(QPalette::Base));
2789 p->fillRect(opt->rect, brush);
2790 p->setPen(QPen(QColor(217, 217, 217)));
2791 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2792 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2794 case PE_FrameStatusBarItem:
2822 case PE_PanelStatusBar: {
2823 p->fillRect(opt->rect, opt->palette.window());
2826 if (qt_macWindowMainWindow(opt->window))
2827 p->setPen(titlebarSeparatorLineActive);
2829 p->setPen(titlebarSeparatorLineInactive);
2830 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2834 case PE_PanelMenu: {
2836 p->fillRect(opt->rect, Qt::transparent);
2837 p->setPen(Qt::transparent);
2838 p->setBrush(opt->palette.window());
2839 p->setRenderHint(QPainter::Antialiasing,
true);
2840 const QPainterPath path = d->windowPanelPath(opt->rect);
2846 QCommonStyle::drawPrimitive(pe, opt, p);
2853 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2854 int imgh = img.height();
2855 int imgw = img.width();
2858 for (
int y = 0; y < imgh; ++y) {
2859 for (
int x = 0; x < imgw; ++x) {
2860 pixel = img.pixel(x, y);
2862 QColor hsvColor(pixel);
2863 hsvColor.getHsv(&h, &s, &v);
2864 s = qMin(100, s * 2);
2866 hsvColor.setHsv(h, s, v);
2867 pixel = hsvColor.rgb();
2868 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2871 return QPixmap::fromImage(img);
2874void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg,
bool reverse,
bool vertical,
const CGRect &rect)
const
2877 CGContextTranslateCTM(cg, rect.size.height, 0);
2878 CGContextRotateCTM(cg,
M_PI_2);
2880 if (vertical != reverse) {
2881 CGContextTranslateCTM(cg, rect.size.width, 0);
2882 CGContextScaleCTM(cg, -1, 1);
2886void QMacStyle::drawControl(ControlElement ce,
const QStyleOption *opt, QPainter *p)
const
2888 Q_D(
const QMacStyle);
2890 const QMacAutoReleasePool pool;
2892 QMacCGContext cg(p);
2893 d->resolveCurrentNSView(opt->window);
2896 case CE_HeaderSection:
2897 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2898 State flags = header->state;
2899 QRect ir = header->rect;
2900 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2901 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2902 p->setPen(QPen(header->palette.dark(), 1.0));
2903 if (header->orientation == Qt::Horizontal)
2904 p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
2905 ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
2907 p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
2908 ir.right() - headerSectionSeparatorInset, ir.bottom()));
2912 case CE_HeaderLabel:
2913 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
2915 QRect textr = header->rect;
2916 if (!header->icon.isNull()) {
2917 QIcon::Mode mode = QIcon::Disabled;
2918 if (opt->state & State_Enabled)
2919 mode = QIcon::Normal;
2920 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2921 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2922 opt->window->devicePixelRatio(), mode);
2924 QRect pixr = header->rect;
2925 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2926 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
2927 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2930 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2931 header->state & State_Enabled, header->text, QPalette::ButtonText);
2935 case CE_ToolButtonLabel:
2936 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
2937 QStyleOptionToolButton myTb = *tb;
2938 myTb.state &= ~State_AutoRaise;
2939#ifndef QT_NO_ACCESSIBILITY
2940 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2941 QRect cr = tb->rect;
2944 bool needText =
false;
2946 bool down = tb->state & (State_Sunken | State_On);
2948 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
2949 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2955 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2956 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2957 if (tb->icon.isNull() && !tb->text.isEmpty())
2958 tbstyle = Qt::ToolButtonTextOnly;
2961 case Qt::ToolButtonTextOnly: {
2963 alignment = Qt::AlignCenter;
2965 case Qt::ToolButtonIconOnly:
2966 case Qt::ToolButtonTextBesideIcon:
2967 case Qt::ToolButtonTextUnderIcon: {
2969 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2971 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2973 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2974 opt->window->devicePixelRatio(), iconMode,
2978 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
2980 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
2981 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
2982 cr.adjust(0, pr.bottom(), 0, -3);
2983 alignment |= Qt::AlignCenter;
2985 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
2986 cr.adjust(pr.right(), 0, 0, 0);
2987 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
2990 if (opt->state & State_Sunken) {
2991 pr.translate(shiftX, shiftY);
2992 pixmap = darkenPixmap(pixmap);
2994 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3002 QPalette pal = tb->palette;
3003 QPalette::ColorRole role = QPalette::NoRole;
3004 if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
3005 alignment |= Qt::TextHideMnemonic;
3007 cr.translate(shiftX, shiftY);
3008 if (tbstyle == Qt::ToolButtonTextOnly
3009 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3010 QPen pen = p->pen();
3011 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3012 light.setAlphaF(0.375f);
3014 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3016 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3018 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3019 role = QPalette::HighlightedText;
3022 proxy()->drawItemText(p, cr, alignment, pal,
3023 tb->state & State_Enabled, tb->text, role);
3026 QCommonStyle::drawControl(ce, &myTb, p);
3031 QCommonStyle::drawControl(ce, &myTb, p);
3035 case CE_ToolBoxTabShape:
3036 QCommonStyle::drawControl(ce, opt, p);
3038 case CE_PushButtonBevel:
3039 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3040 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3043 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3044 QCommonStyle::drawControl(ce, opt, p);
3048 const bool hasFocus = btn->state & State_HasFocus;
3049 const bool isActive = btn->state & State_Active;
3053 if ((btn->features & QStyleOptionButton::AutoDefaultButton)
3054 && isActive && hasFocus)
3055 d->autoDefaultButton = btn->styleObject;
3056 else if (d->autoDefaultButton == btn->styleObject)
3057 d->autoDefaultButton =
nullptr;
3059 const bool isEnabled = btn->state & State_Enabled;
3060 const bool isPressed = btn->state & State_Sunken;
3061 const bool isHighlighted = isActive &&
3062 ((btn->state & State_On)
3063 || (btn->features & QStyleOptionButton::DefaultButton)
3064 || (btn->features & QStyleOptionButton::AutoDefaultButton
3065 && d->autoDefaultButton == btn->styleObject));
3066 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3067 const auto ct = cocoaControlType(btn);
3068 const auto cs = d->effectiveAquaSizeConstrain(btn);
3069 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3070 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3074 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3075 pb.frame = frameRect.toCGRect();
3077 pb.enabled = isEnabled;
3078 [pb highlight:isPressed];
3079 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3080 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
3081 QMacAutoReleasePool pool;
3082 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3086 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3089 const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
3090 const auto ir = frameRect.toRect();
3091 int arrowYOffset = 0;
3092 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3094 QStyleOption arrowOpt = *opt;
3096 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
3100 case CE_PushButtonLabel:
3101 if (
const QStyleOptionButton *b = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3102 QStyleOptionButton btn(*b);
3107 const bool isEnabled = btn.state & State_Enabled;
3108 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3109 const bool hasIcon = !btn.icon.isNull();
3110 const bool hasText = !btn.text.isEmpty();
3111 const bool isActive = btn.state & State_Active;
3112 const bool isPressed = btn.state & State_Sunken;
3114 const auto ct = cocoaControlType(&btn);
3116 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
3118 || (isActive && isEnabled
3119 && ((btn.state & State_On)
3120 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3121 || d->autoDefaultButton == btn.styleObject)))
3122 btn.palette.setColor(QPalette::ButtonText, Qt::white);
3125 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3126 QCommonStyle::drawControl(ce, &btn, p);
3128 QRect freeContentRect = btn.rect;
3129 QRect textRect = itemTextRect(
3130 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3132 textRect.moveTo(11, textRect.top());
3136 int contentW = textRect.width();
3138 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3139 QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
3140 if (mode == QIcon::Normal && btn.state & State_HasFocus)
3141 mode = QIcon::Active;
3143 QIcon::State state = QIcon::Off;
3144 if (btn.state & State_On)
3146 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3148 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3149 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3150 contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
3151 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3152 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3153 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3154 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3155 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3156 int newOffset = iconDestRect.x() + iconDestRect.width()
3157 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
3158 textRect.adjust(newOffset, 0, newOffset, 0);
3162 textRect = visualRect(btn.direction, freeContentRect, textRect);
3163 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
3164 isEnabled, btn.text, QPalette::ButtonText);
3169 case CE_ComboBoxLabel:
3170 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
3171 auto comboCopy = *cb;
3172 comboCopy.direction = Qt::LeftToRight;
3174 QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
3177 case CE_TabBarTabShape:
3178 if (
const auto *tabOpt = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3179 if (tabOpt->documentMode) {
3181 bool isUnified =
false;
3188 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3189 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3195 const bool isActive = tabOpt->state & State_Active;
3196 const bool isEnabled = tabOpt->state & State_Enabled;
3197 const bool isPressed = tabOpt->state & State_Sunken;
3198 const bool isSelected = tabOpt->state & State_Selected;
3199 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3200 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3201 || tabDirection == QMacStylePrivate::West;
3203 QStyleOptionTab::TabPosition tp = tabOpt->position;
3204 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3205 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3206 if (tp == QStyleOptionTab::Beginning)
3207 tp = QStyleOptionTab::End;
3208 else if (tp == QStyleOptionTab::End)
3209 tp = QStyleOptionTab::Beginning;
3211 if (sp == QStyleOptionTab::NextIsSelected)
3212 sp = QStyleOptionTab::PreviousIsSelected;
3213 else if (sp == QStyleOptionTab::PreviousIsSelected)
3214 sp = QStyleOptionTab::NextIsSelected;
3229 const auto cs = d->effectiveAquaSizeConstrain(opt);
3231 const bool needsInactiveHack = (!isActive && isSelected);
3232 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3233 QMacStylePrivate::Button_PushButton :
3234 QMacStylePrivate::Button_PopupButton;
3235 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
3236 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3237 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
3239 auto vOffset = isPopupButton ? 1 : 2;
3240 if (tabDirection == QMacStylePrivate::East)
3242 const auto outerAdjust = isPopupButton ? 1 : 4;
3243 const auto innerAdjust = isPopupButton ? 20 : 10;
3244 QRectF frameRect = tabOpt->rect;
3246 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3248 frameRect = frameRect.translated(0, vOffset);
3250 case QStyleOptionTab::Beginning:
3252 if (!isSelected && tabDirection == QMacStylePrivate::West)
3253 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3255 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3257 case QStyleOptionTab::Middle:
3258 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3260 case QStyleOptionTab::End:
3262 if (isSelected || tabDirection == QMacStylePrivate::West)
3263 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3265 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3267 case QStyleOptionTab::OnlyOneTab:
3268 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3271 pb.frame = frameRect.toCGRect();
3273 pb.enabled = isEnabled;
3274 [pb highlight:isPressed];
3276 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3278 const auto drawBezelBlock = ^(CGContextRef ctx,
const CGRect &r) {
3279 QMacAutoReleasePool pool;
3280 CGContextClipToRect(ctx, opt->rect.toCGRect());
3281 if (!isSelected || needsInactiveHack) {
3283 if (!verticalTabs && tp == QStyleOptionTab::End) {
3284 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3285 CGContextScaleCTM(ctx, -1, 1);
3286 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3287 }
else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3288 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3289 CGContextScaleCTM(ctx, 1, -1);
3290 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3291 }
else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3292 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3293 CGContextScaleCTM(ctx, 1, -1);
3294 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3300 if (tabDirection == QMacStylePrivate::West) {
3301 CGContextTranslateCTM(ctx, 0, frameRect.right());
3302 CGContextRotateCTM(ctx, -
M_PI_2);
3303 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3304 }
else if (tabDirection == QMacStylePrivate::East) {
3305 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3306 CGContextRotateCTM(ctx,
M_PI_2);
3311 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3312 NSPopUpButtonCell *pbCell = nil;
3313 if (isPopupButton) {
3314 pbCell =
static_cast<NSPopUpButtonCell *>(pb.cell);
3315 oldPosition = pbCell.arrowPosition;
3316 pbCell.arrowPosition = NSPopUpNoArrow;
3319 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3322 pbCell.arrowPosition = oldPosition;
3325 if (needsInactiveHack) {
3327 const qreal pixelRatio = p->device()->devicePixelRatioF();
3328 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3329 tabPixmap.setDevicePixelRatio(pixelRatio);
3330 tabPixmap.fill(Qt::transparent);
3331 QPainter tabPainter(&tabPixmap);
3332 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx,
const CGRect &r) {
3333 QMacAutoReleasePool pool;
3334 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3335 drawBezelBlock(ctx, r);
3340 const qreal inactiveGray = 0.898;
3341 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3342 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3343 for (
int l = 0; l < tabPixmap.height(); ++l) {
3344 auto *line =
reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3345 for (
int i = 0; i < tabPixmap.width(); ++i) {
3346 if (qAlpha(line[i]) == 255) {
3347 line[i] = inactiveGrayRGB;
3348 }
else if (qAlpha(line[i]) > 128) {
3349 const int g = qRound(inactiveGray * qRed(line[i]));
3350 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3356 p->drawImage(opt->rect, tabPixmap);
3358 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3361 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3362 && tp != QStyleOptionTab::End
3363 && tp != QStyleOptionTab::OnlyOneTab) {
3364 static const QPen separatorPen(Qt::black, 1.0);
3366 p->setOpacity(isEnabled ? 0.105 : 0.06);
3367 p->setPen(separatorPen);
3368 if (tabDirection == QMacStylePrivate::West) {
3369 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3370 opt->rect.right() - 0.5, opt->rect.bottom()));
3371 }
else if (tabDirection == QMacStylePrivate::East) {
3372 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3373 opt->rect.right() - 0.5, opt->rect.bottom()));
3375 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3376 opt->rect.right(), opt->rect.bottom() - 0.5));
3382 case CE_TabBarTabLabel:
3383 if (
const auto *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
3384 QStyleOptionTab myTab = *tab;
3385 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3386 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3387 || tabDirection == QMacStylePrivate::West;
3394 const bool nonDefaultFont =
false;
3401 if (myTab.documentMode && isDarkMode()) {
3402 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3403 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3406 int heightOffset = 0;
3409 }
else if (nonDefaultFont) {
3410 if (p->fontMetrics().height() == myTab.rect.height())
3413 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3415 QCommonStyle::drawControl(ce, &myTab, p);
3418 case CE_DockWidgetTitle:
3419 if (
const auto *dwOpt = qstyleoption_cast<
const QStyleOptionDockWidget *>(opt)) {
3420 const bool isVertical = dwOpt->verticalTitleBar;
3421 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3424 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3426 p->translate(-effectiveRect.left(), -effectiveRect.top());
3430 p->fillRect(effectiveRect, opt->palette.window());
3433 p->setPen(opt->palette.dark().color());
3434 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3436 if (!dwOpt->title.isEmpty()) {
3437 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3439 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3440 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3444 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3445 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3446 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3451 case CE_FocusFrame: {
3474 case CE_MenuEmptyArea:
3478 case CE_MenuHMargin:
3479 case CE_MenuVMargin:
3480 case CE_MenuTearoff:
3481 case CE_MenuScroller:
3482 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3483 const bool active = mi->state & State_Selected;
3485 p->fillRect(mi->rect, mi->palette.highlight());
3487 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3489 if (ce == CE_MenuTearoff) {
3490 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3491 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3492 mi->rect.x() + mi->rect.width() - 4,
3493 mi->rect.y() + mi->rect.height() / 2 - 1);
3494 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3495 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3496 mi->rect.x() + mi->rect.width() - 4,
3497 mi->rect.y() + mi->rect.height() / 2);
3498 }
else if (ce == CE_MenuScroller) {
3499 const QSize scrollerSize = QSize(10, 8);
3500 const int scrollerVOffset = 5;
3501 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3502 const int right = left + scrollerSize.width();
3505 if (opt->state & State_DownArrow) {
3506 bottom = mi->rect.y() + scrollerVOffset;
3507 top = bottom + scrollerSize.height();
3509 bottom = mi->rect.bottom() - scrollerVOffset;
3510 top = bottom - scrollerSize.height();
3513 p->setRenderHint(QPainter::Antialiasing);
3515 path.moveTo(left, bottom);
3516 path.lineTo(right, bottom);
3517 path.lineTo((left + right) / 2, top);
3518 p->fillPath(path, opt->palette.buttonText());
3520 }
else if (ce != CE_MenuItem) {
3524 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3525 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3526 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3527 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3531 const int maxpmw = mi->maxIconWidth;
3532 const bool enabled = mi->state & State_Enabled;
3534 int xpos = mi->rect.x() + 18;
3535 int checkcol = maxpmw;
3537 p->setPen(mi->palette.text().color());
3539 p->setPen(mi->palette.highlightedText().color());
3541 p->setPen(mi->palette.buttonText().color());
3544 QStyleOption checkmarkOpt;
3547 const int mw = checkcol + macItemFrame;
3548 const int mh = mi->rect.height() + macItemFrame;
3549 const int xp = mi->rect.x() + macItemFrame;
3550 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3552 checkmarkOpt.state.setFlag(State_On, active);
3553 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3554 if (widgetSize == QStyleHelper::SizeMini)
3555 checkmarkOpt.state |= State_Mini;
3556 else if (widgetSize == QStyleHelper::SizeSmall)
3557 checkmarkOpt.state |= State_Small;
3560 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3561 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3563 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3565 if (!mi->icon.isNull()) {
3566 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
3569 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3570 QSize iconSize(smallIconSize, smallIconSize);
3576 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3577 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3578 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3579 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3580 QRect pmr(0, 0, pixw, pixh);
3581 pmr.moveCenter(cr.center());
3582 p->drawPixmap(pmr.topLeft(), pixmap);
3586 QString s = mi->text;
3587 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3588 | Qt::TextSingleLine | Qt::AlignAbsolute;
3589 int yPos = mi->rect.y();
3590 if (widgetSize == QStyleHelper::SizeMini)
3593 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3594 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3596 QString rightMarginText;
3598 rightMarginText = QStringLiteral(
"\u25b6\ufe0e");
3601 const int tabIndex = s.indexOf(QLatin1Char(
'\t'));
3602 if (tabIndex >= 0) {
3604 rightMarginText = s.mid(tabIndex + 1);
3605 s = s.left(tabIndex);
3609 if (!rightMarginText.isEmpty()) {
3611 int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
3613 xp -= macItemHMargin + macItemFrame + 3;
3614 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3618 const int xm = macItemFrame + maxpmw + macItemHMargin;
3619 QFont myFont = mi->font;
3625 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3630 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3631 Q_ASSERT(fontEngine);
3632 if (fontEngine->type() == QFontEngine::Multi) {
3633 fontEngine =
static_cast<
const QFontEngineMulti *>(fontEngine)->engine(0);
3634 Q_ASSERT(fontEngine);
3636 if (fontEngine->type() == QFontEngine::Mac) {
3637 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3640 const auto pc = p->pen().color();
3641 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3646 s = qt_mac_removeMnemonics(s);
3648 QMacCGContext cgCtx(p);
3649 d->setupNSGraphicsContext(cgCtx, YES);
3655 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3656 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3657 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3659 d->restoreNSGraphicsContext(cgCtx);
3662 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3663 mi->rect.height(), text_flags, s);
3669 case CE_MenuBarItem:
3670 case CE_MenuBarEmptyArea:
3671 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
3672 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3673 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3674 p->fillRect(mi->rect, bg);
3676 if (ce != CE_MenuBarItem)
3679 if (!mi->icon.isNull()) {
3680 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3681 drawItemPixmap(p, mi->rect,
3682 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3683 | Qt::TextSingleLine,
3684 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3685 opt->window->devicePixelRatio(),
3686 (mi->state & State_Enabled) ? QIcon::Normal
3687 : QIcon::Disabled));
3689 drawItemText(p, mi->rect,
3690 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
3691 | Qt::TextSingleLine,
3692 mi->palette, mi->state & State_Enabled,
3693 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3697 case CE_ProgressBarLabel:
3698 case CE_ProgressBarContents:
3700 case CE_ProgressBarGroove:
3701 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
3702 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3703 const bool inverted = pb->invertedAppearance;
3704 bool reverse = pb->direction == Qt::RightToLeft;
3708 QRect rect = pb->rect;
3709 const CGRect cgRect = rect.toCGRect();
3711 const auto aquaSize = d->aquaSizeConstrain(opt);
3714 QIndeterminateProgressIndicator *ipi = nil;
3716 ipi =
static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3717 if (isIndeterminate) {
3736 d->setupNSGraphicsContext(cg, NO);
3737 d->setupVerticalInvertedXform(cg, reverse,
false, cgRect);
3738 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3739 d->restoreNSGraphicsContext(cg);
3746 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
3747 auto *pi =
static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3748 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx,
const CGRect &rect) {
3749 QMacAutoReleasePool pool;
3750 d->setupVerticalInvertedXform(ctx, reverse,
false, rect);
3751 pi.minValue = pb->minimum;
3752 pi.maxValue = pb->maximum;
3753 pi.doubleValue = pb->progress;
3792 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3793 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3795 const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
3796 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
3797 auto *sv =
static_cast<NSSplitView *>(d->cocoaControl(cw));
3798 sv.frame = opt->rect.toCGRect();
3799 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef,
const CGRect &rect) {
3800 QMacAutoReleasePool pool;
3801 [sv drawDividerInRect:rect];
3804 QPen oldPen = p->pen();
3805 p->setPen(opt->palette.dark().color());
3806 if (opt->state & QStyle::State_Horizontal)
3807 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3809 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3814 if (
const QStyleOptionRubberBand *rubber = qstyleoption_cast<
const QStyleOptionRubberBand *>(opt)) {
3815 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
3816 if (!rubber->opaque) {
3819 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3820 fillColor.setHsvF(0, 0, 0.53, 0.25);
3821 if (opt->rect.width() * opt->rect.height() <= 3) {
3822 p->fillRect(opt->rect, strokeColor);
3824 QPen oldPen = p->pen();
3825 QBrush oldBrush = p->brush();
3826 QPen pen(strokeColor);
3828 p->setBrush(fillColor);
3829 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3830 if (adjusted.isValid())
3831 p->drawRect(adjusted);
3833 p->setBrush(oldBrush);
3836 p->fillRect(opt->rect, fillColor);
3841 const bool isDarkMode = QT_PREPEND_NAMESPACE(
QQC2_NAMESPACE::isDarkMode());
3875 QLinearGradient linearGrad;
3876 if (opt->state & State_Horizontal)
3877 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3879 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3881 QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
3882 QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
3884 linearGrad.setColorAt(0, mainWindowGradientBegin);
3885 linearGrad.setColorAt(1, mainWindowGradientEnd);
3886 p->fillRect(opt->rect, linearGrad);
3889 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3890 if (opt->state & State_Horizontal) {
3891 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3892 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3893 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3894 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3896 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3897 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3898 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3899 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3905 QCommonStyle::drawControl(ce, opt, p);
3912 if (dir == Qt::RightToLeft) {
3913 rect->adjust(-right, top, -left, bottom);
3915 rect->adjust(left, top, right, bottom);
3919QRect QMacStyle::subElementRect(SubElement sr,
const QStyleOption *opt)
const
3921 Q_D(
const QMacStyle);
3923 const int controlSize = getControlSize(opt);
3926 case SE_ItemViewItemText:
3927 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
3928 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
3930 rect = QCommonStyle::subElementRect(sr, opt);
3931 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3932 rect.adjust(-fw, 0, 0, 0);
3935 case SE_ToolBoxTabContents:
3936 rect = QCommonStyle::subElementRect(sr, opt);
3938 case SE_PushButtonContents:
3939 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
3948 const auto ct = cocoaControlType(btn);
3949 const auto cs = d->effectiveAquaSizeConstrain(btn);
3950 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3951 auto frameRect = cw.adjustedControlFrame(btn->rect);
3952 frameRect -= cw.titleMargins();
3953 rect = frameRect.toRect();
3956 case SE_HeaderLabel: {
3957 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3958 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3959 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3960 if (
const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt)) {
3962 if (header->sortIndicator != QStyleOptionHeader::None) {
3963 if (opt->state & State_Horizontal)
3964 rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
3966 rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
3969 rect = visualRect(opt->direction, opt->rect, rect);
3972 case SE_HeaderArrow: {
3973 int h = opt->rect.height();
3974 int w = opt->rect.width();
3975 int x = opt->rect.x();
3976 int y = opt->rect.y();
3977 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3979 if (opt->state & State_Horizontal) {
3980 rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
3981 headerSectionArrowHeight, h - margin * 2 - 5);
3983 rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
3984 w - margin * 2 - 5, headerSectionArrowHeight);
3986 rect = visualRect(opt->direction, opt->rect, rect);
3989 case SE_ProgressBarGroove:
3993 case SE_ProgressBarLabel:
3995 case SE_ProgressBarContents:
3998 case SE_TreeViewDisclosureItem: {
4001 rect.setLeft(rect.left() + 2 + DisclosureOffset);
4004 case SE_TabWidgetLeftCorner:
4005 if (
const QStyleOptionTabWidgetFrame *twf
4006 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4007 switch (twf->shape) {
4008 case QStyleOptionTab::RoundedNorth:
4009 case QStyleOptionTab::TriangularNorth:
4010 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4012 case QStyleOptionTab::RoundedSouth:
4013 case QStyleOptionTab::TriangularSouth:
4014 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4015 twf->leftCornerWidgetSize);
4020 rect = visualRect(twf->direction, twf->rect, rect);
4023 case SE_TabWidgetRightCorner:
4024 if (
const QStyleOptionTabWidgetFrame *twf
4025 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4026 switch (twf->shape) {
4027 case QStyleOptionTab::RoundedNorth:
4028 case QStyleOptionTab::TriangularNorth:
4029 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4030 twf->rightCornerWidgetSize);
4032 case QStyleOptionTab::RoundedSouth:
4033 case QStyleOptionTab::TriangularSouth:
4034 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4035 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4036 twf->rightCornerWidgetSize);
4041 rect = visualRect(twf->direction, twf->rect, rect);
4044 case SE_TabWidgetTabContents:
4045 rect = QCommonStyle::subElementRect(sr, opt);
4046 if (
const auto *twf = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4047 if (twf->lineWidth != 0) {
4048 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4049 case QMacStylePrivate::North:
4050 rect.adjust(+1, +14, -1, -1);
4052 case QMacStylePrivate::South:
4053 rect.adjust(+1, +1, -1, -14);
4055 case QMacStylePrivate::West:
4056 rect.adjust(+14, +1, -1, -1);
4058 case QMacStylePrivate::East:
4059 rect.adjust(+1, +1, -14, -1);
4064 case SE_TabBarTabText:
4065 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4066 QRect dummyIconRect;
4067 d->tabLayout(tab, &rect, &dummyIconRect);
4070 case SE_TabBarTabLeftButton:
4071 case SE_TabBarTabRightButton:
4072 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
4073 bool selected = tab->state & State_Selected;
4074 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4075 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4078 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4079 || tab->shape == QStyleOptionTab::RoundedWest
4080 || tab->shape == QStyleOptionTab::TriangularEast
4081 || tab->shape == QStyleOptionTab::TriangularWest;
4083 QRect tr = tab->rect;
4084 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4085 verticalShift = -verticalShift;
4087 qSwap(horizontalShift, verticalShift);
4088 horizontalShift *= -1;
4089 verticalShift *= -1;
4091 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4092 horizontalShift = -horizontalShift;
4094 tr.adjust(0, 0, horizontalShift, verticalShift);
4097 tr.setBottom(tr.bottom() - verticalShift);
4098 tr.setRight(tr.right() - horizontalShift);
4101 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4102 int w = size.width();
4103 int h = size.height();
4104 int midHeight =
static_cast<
int>(qCeil(
float(tr.height() - h) / 2));
4105 int midWidth = ((tr.width() - w) / 2);
4107 bool atTheTop =
true;
4108 switch (tab->shape) {
4109 case QStyleOptionTab::RoundedWest:
4110 case QStyleOptionTab::TriangularWest:
4111 atTheTop = (sr == SE_TabBarTabLeftButton);
4113 case QStyleOptionTab::RoundedEast:
4114 case QStyleOptionTab::TriangularEast:
4115 atTheTop = (sr == SE_TabBarTabRightButton);
4118 if (sr == SE_TabBarTabLeftButton)
4119 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4121 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4122 rect = visualRect(tab->direction, tab->rect, rect);
4126 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4128 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4132 case SE_LineEditContents: {
4134 int leftPadding = 4;
4135 int rightPadding = 4;
4137 int bottomPadding = 0;
4139 if (opt->state & QStyle::State_Small) {
4141 }
else if (opt->state & QStyle::State_Mini) {
4145 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4146 opt->rect.height() - topPadding - bottomPadding);
4148 case SE_CheckBoxLayoutItem:
4150 if (controlSize == QStyleHelper::SizeLarge) {
4151 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4152 }
else if (controlSize == QStyleHelper::SizeSmall) {
4153 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4155 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4158 case SE_SearchFieldLayoutItem:
4159 if (qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4161 opt->rect.adjusted(4, 6, -4, -7),
4162 opt->rect.adjusted(4, 7, -4, -7),
4163 opt->rect.adjusted(3, 6, -3, -6));
4166 case SE_ComboBoxLayoutItem:
4167 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4176 if (combo->editable)
4178 opt->rect.adjusted(5, 6, -6, -7),
4179 opt->rect.adjusted(4, 4, -5, -7),
4180 opt->rect.adjusted(5, 4, -4, -6));
4183 opt->rect.adjusted(6, 4, -7, -7),
4184 opt->rect.adjusted(6, 7, -6, -5),
4185 opt->rect.adjusted(9, 5, -5, -7));
4188 case SE_LabelLayoutItem:
4190 setLayoutItemMargins(+1, 0 , 0, 0 , &rect, opt->direction);
4192 case SE_ProgressBarLayoutItem:
4193 if (
const QStyleOptionProgressBar *pb = qstyleoption_cast<
const QStyleOptionProgressBar *>(opt)) {
4194 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4197 if (isIndeterminate) {
4198 rect.adjust(1, 2, -1, -2);
4200 rect.adjust(1, 1, -1, -2);
4204 case SE_PushButtonLayoutItem:
4206 if (
const QStyleOptionButton *buttonOpt = qstyleoption_cast<
const QStyleOptionButton *>(opt)) {
4207 if ((buttonOpt->features & QStyleOptionButton::Flat))
4211 opt->rect.adjusted(7, 5, -7, -7),
4212 opt->rect.adjusted(6, 6, -6, -6),
4213 opt->rect.adjusted(6, 5, -6, -6));
4215 case SE_SpinBoxLayoutItem:
4217 opt->rect.adjusted(2, 3, -2, -2),
4218 opt->rect.adjusted(2, 3, -2, -2),
4219 opt->rect.adjusted(2, 3, -2, -2));
4221 case SE_RadioButtonLayoutItem:
4223 opt->rect.adjusted(2, 2, -3, -2),
4224 opt->rect.adjusted(2, 2, -3, -2),
4225 opt->rect.adjusted(1, 2, -3, -2));
4227 case SE_SliderLayoutItem:
4228 if (
const QStyleOptionSlider *sliderOpt
4229 = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4231 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4232 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4233 rect.adjust(3, 3, -3, -3);
4235 rect.adjust(3, 0, -3, 0);
4239 case SE_ScrollBarLayoutItem:
4240 if (qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4243 case SE_FrameLayoutItem:
4259 case SE_GroupBoxLayoutItem:
4261 if (
const QStyleOptionGroupBox *groupBoxOpt =
4262 qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4264
4265
4266
4267
4268 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4269 | QStyle::SC_GroupBoxLabel)) {
4271 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4272 delta =
SIZE(8, 4, 4);
4274 delta =
SIZE(15, 12, 12);
4276 rect.setTop(rect.top() + delta);
4279 rect.setBottom(rect.bottom() - 1);
4281 case SE_TabWidgetLayoutItem:
4282 if (
const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4283 qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
4285
4286
4287
4288
4289 rect = tabWidgetOpt->rect;
4290 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4291 rect.setTop(rect.top() +
SIZE(6 , 3 , 2 ));
4294 case SE_DockWidgetCloseButton:
4295 case SE_DockWidgetFloatButton:
4296 case SE_DockWidgetTitleBarText:
4297 case SE_DockWidgetIcon: {
4298 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
4299 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
4300 QRect srect = opt->rect;
4302 const QStyleOptionDockWidget *dwOpt
4303 = qstyleoption_cast<
const QStyleOptionDockWidget*>(opt);
4304 bool canClose = dwOpt == 0 ?
true : dwOpt->closable;
4305 bool canFloat = dwOpt == 0 ?
false : dwOpt->floatable;
4307 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4311 if (verticalTitleBar)
4312 srect = srect.transposed();
4315 int right = srect.right();
4316 int left = srect.left();
4320 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
4321 opt).actualSize(QSize(iconSize, iconSize));
4322 sz += QSize(buttonMargin, buttonMargin);
4323 if (verticalTitleBar)
4324 sz = sz.transposed();
4325 closeRect = QRect(left,
4326 srect.center().y() - sz.height()/2,
4327 sz.width(), sz.height());
4328 left = closeRect.right() + 1;
4330 if (sr == SE_DockWidgetCloseButton) {
4337 QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
4338 opt).actualSize(QSize(iconSize, iconSize));
4339 sz += QSize(buttonMargin, buttonMargin);
4340 if (verticalTitleBar)
4341 sz = sz.transposed();
4342 floatRect = QRect(left,
4343 srect.center().y() - sz.height()/2,
4344 sz.width(), sz.height());
4345 left = floatRect.right() + 1;
4347 if (sr == SE_DockWidgetFloatButton) {
4367 if (sr == SE_DockWidgetIcon) {
4372 QRect textRect = QRect(left, srect.top(),
4373 right - left, srect.height());
4374 if (sr == SE_DockWidgetTitleBarText) {
4380 if (verticalTitleBar) {
4381 rect = QRect(srect.left() + rect.top() - srect.top(),
4382 srect.top() + srect.right() - rect.right(),
4383 rect.height(), rect.width());
4385 rect = visualRect(opt->direction, srect, rect);
4390 rect = QCommonStyle::subElementRect(sr, opt);
4396void QMacStylePrivate::drawToolbarButtonArrow(
const QStyleOption *opt, QPainter *p)
const
4398 Q_Q(
const QMacStyle);
4399 QStyleOption arrowOpt = *opt;
4400 arrowOpt.rect = QRect(opt->rect.right() - (toolButtonArrowSize + toolButtonArrowMargin),
4401 opt->rect.bottom() - (toolButtonArrowSize + toolButtonArrowMargin),
4402 toolButtonArrowSize,
4403 toolButtonArrowSize);
4404 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4407void QMacStylePrivate::setupNSGraphicsContext(CGContextRef cg,
bool flipped)
const
4409 CGContextSaveGState(cg);
4410 [NSGraphicsContext saveGraphicsState];
4412 [NSGraphicsContext setCurrentContext:
4413 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4416void QMacStylePrivate::restoreNSGraphicsContext(CGContextRef cg)
const
4418 [NSGraphicsContext restoreGraphicsState];
4419 CGContextRestoreGState(cg);
4422void QMacStyle::drawComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt, QPainter *p)
const
4424 Q_D(
const QMacStyle);
4426 QMacCGContext cg(p);
4427 d->resolveCurrentNSView(opt->window);
4431 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4433 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4434 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4435 if (!drawTrack && !drawKnob)
4438 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4440 if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
4441 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4443 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4444 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4446 const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
4449 bool wasActive =
false;
4450 CGFloat opacity = 0.0;
4451 CGFloat expandScale = 1.0;
4452 CGFloat expandOffset = 0.0;
4453 bool shouldExpand =
false;
4455 if (QObject *styleObject = opt->styleObject) {
4456 const int oldPos = styleObject->property(
"_q_stylepos").toInt();
4457 const int oldMin = styleObject->property(
"_q_stylemin").toInt();
4458 const int oldMax = styleObject->property(
"_q_stylemax").toInt();
4459 const QRect oldRect = styleObject->property(
"_q_stylerect").toRect();
4460 const QStyle::State oldState =
static_cast<QStyle::State>(styleObject->property(
"_q_stylestate").value<QStyle::State::Int>());
4461 const uint oldActiveControls = styleObject->property(
"_q_stylecontrols").toUInt();
4465 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4468 oldPos != sb->sliderPosition ||
4469 oldMin != sb->minimum ||
4470 oldMax != sb->maximum ||
4471 oldRect != sb->rect ||
4472 oldState != sb->state ||
4473 oldActiveControls != sb->activeSubControls) {
4479 styleObject->setProperty(
"_q_stylepos", sb->sliderPosition);
4480 styleObject->setProperty(
"_q_stylemin", sb->minimum);
4481 styleObject->setProperty(
"_q_stylemax", sb->maximum);
4482 styleObject->setProperty(
"_q_stylerect", sb->rect);
4483 styleObject->setProperty(
"_q_stylestate",
static_cast<QStyle::State::Int>(sb->state));
4484 styleObject->setProperty(
"_q_stylecontrols",
static_cast<uint>(sb->activeSubControls));
4512 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4530 d->setupNSGraphicsContext(cg, NO );
4532 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
4533 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
4534 NSScroller *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
4536 const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
4537 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4541 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4543 scroller.knobStyle = NSScrollerKnobStyleDefault;
4546 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4548 if (!setupScroller(scroller, sb))
4552 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame,
nullptr);
4553 CGContextSetAlpha(cg, opacity);
4558 if (!isTransient || opt->activeSubControls || wasActive) {
4559 CGRect trackRect = scroller.bounds;
4561 trackRect.origin.y += expandOffset;
4563 trackRect.origin.x += expandOffset;
4564 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4574 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4575 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4577 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4578 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4579 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4580 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4581 const CGFloat knobRadius = knobWidth / 2.0;
4584 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4586 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4587 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius,
nullptr);
4588 CGContextAddPath(cg, knobPath);
4589 CGContextSetAlpha(cg, 0.5);
4590 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4591 CGContextSetFillColorWithColor(cg, knobColor);
4592 CGContextFillPath(cg);
4594 [scroller drawKnob];
4596 if (!isTransient && opt->state & State_Sunken) {
4601 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4602 [scroller drawKnob];
4608 CGContextEndTransparencyLayer(cg);
4610 d->restoreNSGraphicsContext(cg);
4614 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
4615 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4616 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
4617 const auto cs = d->effectiveAquaSizeConstrain(opt);
4618 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4619 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
4620 if (!setupSlider(slider, sl))
4623 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4624 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4625 const bool drawKnob = sl->subControls & SC_SliderHandle;
4626 const bool drawBar = sl->subControls & SC_SliderGroove;
4627 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4628 const bool isPressed = sl->state & State_Sunken;
4631 if (isPressed && drawKnob) {
4632 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4633 pressPoint.x = CGRectGetMidX(knobRect);
4634 pressPoint.y = CGRectGetMidY(knobRect);
4635 [slider.cell startTrackingAt:pressPoint inView:slider];
4638 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef,
const CGRect &) {
4641 NSSliderCell *cell = slider.cell;
4644 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4650 [cell drawBarInside:barRect flipped:!isHorizontal];
4653 if (drawBar && hasTicks && drawTicks) {
4654 if (!hasDoubleTicks) {
4655 [cell drawTickMarks];
4657 if (sl->orientation == Qt::Horizontal) {
4658 slider.tickMarkPosition = NSTickMarkPositionAbove;
4659 [slider layoutSubtreeIfNeeded];
4660 [cell drawTickMarks];
4661 slider.tickMarkPosition = NSTickMarkPositionBelow;
4662 [slider layoutSubtreeIfNeeded];
4663 [cell drawTickMarks];
4665 slider.tickMarkPosition = NSTickMarkPositionLeading;
4666 [slider layoutSubtreeIfNeeded];
4667 [cell drawTickMarks];
4668 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4669 [slider layoutSubtreeIfNeeded];
4670 [cell drawTickMarks];
4679 if (isPressed && drawKnob)
4680 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4684 if (
const QStyleOptionSpinBox *sb = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
4685 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4686 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4687 QStyleOptionFrame frame;
4688 static_cast<QStyleOption &>(frame) = *opt;
4689 frame.rect = lineEditRect;
4690 frame.state |= State_Sunken;
4691 frame.lineWidth = 1;
4692 frame.midLineWidth = 0;
4693 frame.features = QStyleOptionFrame::None;
4694 frame.frameShape = QStyleOptionFrame::Box;
4695 drawPrimitive(PE_FrameLineEdit, &frame, p);
4697 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4698 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4699 | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
4701 d->setupNSGraphicsContext(cg, NO);
4703 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4704 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
4705 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
4706 cell.enabled = (sb->state & State_Enabled);
4707 const auto controlSize = cell.controlSize;
4708 if (qt_apple_runningWithLiquidGlass())
4709 cell.controlSize = NSControlSizeMini;
4711 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4713 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4714 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4715 const CGFloat x = CGRectGetMidX(newRect);
4716 const CGFloat y = upPressed ? -3 : 3;
4717 const CGPoint pressPoint = CGPointMake(x, y);
4720 if (upPressed || downPressed)
4721 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4723 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4725 if (upPressed || downPressed)
4726 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4728 d->restoreNSGraphicsContext(cg);
4729 if (qt_apple_runningWithLiquidGlass())
4730 cell.controlSize = controlSize;
4735 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4736 const bool isEnabled = combo->state & State_Enabled;
4737 const bool isPressed = combo->state & State_Sunken;
4739 const auto ct = cocoaControlType(combo);
4740 const auto cs = d->effectiveAquaSizeConstrain(combo);
4741 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4742 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4743 cc.enabled = isEnabled;
4744 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4745 if (cw.type == QMacStylePrivate::Button_PopupButton) {
4747 auto *pb =
static_cast<NSPopUpButton *>(cc);
4749 if (cw.size == QStyleHelper::SizeSmall) {
4750 frameRect = frameRect.translated(0, 1);
4751 }
else if (cw.size == QStyleHelper::SizeMini) {
4753 frameRect = frameRect.translated(2, -0.5);
4755 pb.frame = frameRect.toCGRect();
4756 [pb highlight:isPressed];
4757 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4758 QMacAutoReleasePool pool;
4759 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4761 }
else if (cw.type == QMacStylePrivate::ComboBox) {
4763 auto *cb =
static_cast<NSComboBox *>(cc);
4764 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4765 cb.frame = frameRect.toCGRect();
4768 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4769 cell.highlighted = isPressed;
4774 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4776 QMacAutoReleasePool pool;
4777 [cb.cell drawWithFrame:r inView:cb];
4782 case CC_SearchField:
4783 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4784 const bool isEnabled = sf->state & State_Enabled;
4786 const auto cs = d->effectiveAquaSizeConstrain(sf);
4787 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
4788 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4789 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4791 searchField.enabled = isEnabled;
4793 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4795 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4796 [cell drawWithFrame:rect inView:searchField];
4797 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4799 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4800 [cell drawWithFrame:rect inView:searchField];
4803 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4804 searchField.frame = frameRect.toCGRect();
4805 [cell setStringValue:sf->text.toNSString()];
4806 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4807 [cell drawWithFrame:r inView:searchField];
4813 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4814 const bool isActive = (titlebar->state & State_Active)
4815 && (titlebar->titleBarState & State_Active);
4817 p->fillRect(opt->rect, Qt::transparent);
4818 p->setRenderHint(QPainter::Antialiasing);
4819 p->setClipRect(opt->rect, Qt::IntersectClip);
4823 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4824 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4825 p->fillPath(outerFramePath, opt->palette.dark());
4827 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4828 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4829 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4830 p->fillPath(innerFramePath, opt->palette.button());
4832 if (titlebar->subControls & (SC_TitleBarCloseButton
4833 | SC_TitleBarMaxButton
4834 | SC_TitleBarMinButton
4835 | SC_TitleBarNormalButton)) {
4836 const bool isHovered = (titlebar->state & State_MouseOver);
4837 static const SubControl buttons[] = {
4838 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4840 for (
const auto sc : buttons) {
4841 const auto ct = d->windowButtonCocoaControl(sc);
4842 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4843 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4844 wb.enabled = (sc & titlebar->subControls) && isActive;
4845 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4846 Q_UNUSED(isHovered);
4848 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4849 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4850 QMacAutoReleasePool pool;
4851 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4852 [wbCell drawWithFrame:rect inView:wb];
4857 if (titlebar->subControls & SC_TitleBarLabel) {
4858 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4859 if (!titlebar->icon.isNull()) {
4860 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4861 const auto iconSize = QSize(iconExtent, iconExtent);
4862 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4864 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4865 p->drawPixmap(iconPos, tr.y(),
4866 titlebar->icon.pixmap(iconSize,
4867 opt->window->devicePixelRatio(),
4871 if (!titlebar->text.isEmpty())
4872 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4877 if (
const QStyleOptionGroupBox *gb
4878 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4880 QStyleOptionGroupBox groupBox(*gb);
4881 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4883 groupBox.state |= QStyle::State_Mini;
4885 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4891 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4906 if (
const QStyleOptionToolButton *tb
4907 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4908#ifndef QT_NO_ACCESSIBILITY
4909 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4910 if (tb->subControls & SC_ToolButtonMenu) {
4911 QStyleOption arrowOpt = *tb;
4912 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4913 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4914 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4915 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4916 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4917 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4918 d->drawToolbarButtonArrow(tb, p);
4920 if (tb->state & State_On) {
4921 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4924 isKey = [view.window isKeyWindow];
4926 QBrush brush(brushForToolButton(isKey));
4928 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4929 p->setRenderHint(QPainter::Antialiasing);
4930 p->fillPath(path, brush);
4932 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4936 auto bflags = tb->state;
4937 if (tb->subControls & SC_ToolButton)
4938 bflags |= State_Sunken;
4939 auto mflags = tb->state;
4940 if (tb->subControls & SC_ToolButtonMenu)
4941 mflags |= State_Sunken;
4943 if (tb->subControls & SC_ToolButton) {
4944 if (bflags & (State_Sunken | State_On | State_Raised)) {
4945 const bool isEnabled = tb->state & State_Enabled;
4946 const bool isPressed = tb->state & State_Sunken;
4947 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
4948 const auto ct = QMacStylePrivate::Button_PushButton;
4949 const auto cs = d->effectiveAquaSizeConstrain(opt);
4950 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4951 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4952 pb.bezelStyle = NSBezelStyleShadowlessSquare;
4953 pb.frame = opt->rect.toCGRect();
4954 pb.buttonType = NSButtonTypePushOnPushOff;
4955 pb.enabled = isEnabled;
4956 [pb highlight:isPressed];
4957 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
4958 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
4959 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4960 QMacAutoReleasePool pool;
4961 [pb.cell drawBezelWithFrame:rect inView:pb];
4966 if (tb->subControls & SC_ToolButtonMenu) {
4967 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4968 QStyleOption arrowOpt = *tb;
4969 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
4970 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
4971 toolButtonArrowSize,
4972 toolButtonArrowSize);
4973 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4974 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
4975 d->drawToolbarButtonArrow(tb, p);
4977 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
4978 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
4979 QStyleOptionToolButton label = *tb;
4980 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
4981 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
4986 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
4987 QStyleHelper::drawDial(dial, p);
4990 QCommonStyle::drawComplexControl(cc, opt, p);
4995QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt,
const QPoint &pt)
const
4997 Q_D(
const QMacStyle);
4999 SubControl sc = QStyle::SC_None;
5003 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5004 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5005 if (!cmb->editable && sc != QStyle::SC_None)
5006 sc = SC_ComboBoxArrow;
5010 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5011 if (!sl->rect.contains(pt))
5014 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5015 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5016 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5017 const auto cs = d->effectiveAquaSizeConstrain(opt);
5018 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5019 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5020 if (!setupSlider(slider, sl))
5023 NSSliderCell *cell = slider.cell;
5024 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5025 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5026 if (knobRect.contains(pt)) {
5027 sc = SC_SliderHandle;
5028 }
else if (barRect.contains(pt)) {
5029 sc = SC_SliderGroove;
5030 }
else if (hasTicks) {
5031 sc = SC_SliderTickmarks;
5036 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5037 if (!sb->rect.contains(pt)) {
5042 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5043 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5044 const auto cs = d->effectiveAquaSizeConstrain(opt);
5045 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5046 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5047 if (!setupScroller(scroller, sb)) {
5055 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5057 const bool isReverse = sb->direction == Qt::RightToLeft;
5058 if (pt.x() < knobRect.left())
5059 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5060 else if (pt.x() > knobRect.right())
5061 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5063 sc = SC_ScrollBarSlider;
5065 if (pt.y() < knobRect.top())
5066 sc = SC_ScrollBarSubPage;
5067 else if (pt.y() > knobRect.bottom())
5068 sc = SC_ScrollBarAddPage;
5070 sc = SC_ScrollBarSlider;
5074 case CC_SearchField:
5075 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5076 if (!sf->rect.contains(pt))
5079 const auto cs = d->effectiveAquaSizeConstrain(sf);
5080 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5081 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5082 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5084 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5085 const CGRect bounds = searchField.bounds;
5087 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5088 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5089 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5091 const QPointF localPt = pt - sf->rect.topLeft();
5093 if (cancelRect.contains(localPt))
5094 sc = SC_SearchFieldClear;
5095 else if (searchIconRect.contains(localPt))
5096 sc = SC_SearchFieldSearch;
5097 else if (textFieldRect.contains(localPt))
5098 sc = SC_SearchFieldEditField;
5100 sc = SC_SearchFieldPopup;
5106 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5112QRect QMacStyle::subControlRect(ComplexControl cc,
const QStyleOptionComplex *opt, SubControl sc)
const
5114 Q_D(
const QMacStyle);
5120 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5121 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5122 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5124 NSScrollerPart part = NSScrollerNoPart;
5125 if (sc == SC_ScrollBarSlider) {
5126 part = NSScrollerKnob;
5127 }
else if (sc == SC_ScrollBarGroove) {
5128 part = NSScrollerKnobSlot;
5129 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5130 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5131 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5132 part = NSScrollerDecrementPage;
5134 part = NSScrollerIncrementPage;
5138 if (part != NSScrollerNoPart) {
5139 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5140 const auto cs = d->effectiveAquaSizeConstrain(opt);
5141 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5142 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5143 if (setupScroller(scroller, sb))
5144 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5149 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5150 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5151 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5152 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5153 const auto cs = d->effectiveAquaSizeConstrain(opt);
5154 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5155 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5156 if (!setupSlider(slider, sl))
5159 NSSliderCell *cell = slider.cell;
5160 if (sc == SC_SliderHandle) {
5161 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5162 }
else if (sc == SC_SliderGroove) {
5163 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5164 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5165 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5167 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5169 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5180 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5186 if (sc == SC_TitleBarLabel) {
5187 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5188 qreal labelHeight = titlebar->fontMetrics.height();
5190 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5191 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5192 if (!titlebar->icon.isNull()) {
5193 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5194 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5195 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5198 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5199 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5200 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5201 labelWidth, labelHeight);
5203 const auto currentButton = d->windowButtonCocoaControl(sc);
5204 if (currentButton == QMacStylePrivate::NoControl)
5207 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5209 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5210 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5211 QStyleHelper::SizeLarge);
5212 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5213 if (ct == currentButton)
5214 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5216 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5219 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5220 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5225 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5226 const auto ct = cocoaControlType(combo);
5227 const auto cs = d->effectiveAquaSizeConstrain(combo);
5228 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5236 case QStyleHelper::SizeLarge:
5237 editRect = combo->rect.adjusted(15, 7, -25, -9);
5239 case QStyleHelper::SizeSmall:
5240 if (combo->editable)
5241 editRect = combo->rect.adjusted(15, 6, -22, -9);
5243 editRect = combo->rect.adjusted(15, 8, -22, -6);
5246 if (combo->editable)
5247 editRect = combo->rect.adjusted(15, 6, -20, -7);
5249 editRect = combo->rect.adjusted(15, 5, -22, -6);
5254 case SC_ComboBoxEditField:{
5255 ret = editRect.toAlignedRect();
5257 case SC_ComboBoxArrow:{
5258 ret = editRect.toAlignedRect();
5259 ret.setX(ret.x() + ret.width());
5260 ret.setWidth(combo->rect.right() - ret.right());
5262 case SC_ComboBoxListBoxPopup:{
5263 if (combo->editable) {
5264 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5265 const int comboTop = combo->rect.top();
5266 ret = QRect(qRound(inner.origin.x),
5268 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5269 editRect.bottom() - comboTop + 2);
5271 ret = QRect(combo->rect.x() + 4 - 11,
5272 combo->rect.y() + 1,
5273 editRect.width() + 10 + 11,
5283 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5284 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5285 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5286 bool hasNoText = !checkable && groupBox->text.isEmpty();
5288 case SC_GroupBoxLabel:
5289 case SC_GroupBoxCheckBox: {
5291 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5292 const bool fontIsSet =
false;
5295 const int margin = flat || hasNoText ? 0 : 9;
5296 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5298 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5299 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5300 const int tw = qCeil(s.width());
5301 const int h = qCeil(fm.height());
5304 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5306 if (flat && checkable)
5307 labelRect.moveLeft(labelRect.left() + 4);
5308 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5309 bool rtl = groupBox->direction == Qt::RightToLeft;
5310 if (sc == SC_GroupBoxLabel) {
5312 int newSum = indicatorWidth + 1;
5313 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5314 labelRect.moveLeft(newLeft);
5316 labelRect.moveTop(labelRect.top() + 3);
5318 labelRect.moveTop(labelRect.top() + 4);
5320 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5321 labelRect.moveLeft(newLeft);
5322 labelRect.moveTop(labelRect.top() + 3);
5324 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5325 labelRect.moveLeft(newLeft);
5326 labelRect.moveTop(labelRect.top() + 4);
5331 if (sc == SC_GroupBoxCheckBox) {
5332 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5333 int top = flat ? ret.top() + 1 : ret.top() + 5;
5334 ret.setRect(left, top,
5335 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5339 case SC_GroupBoxContents:
5340 case SC_GroupBoxFrame: {
5341 QFontMetrics fm = groupBox->fontMetrics;
5347 yOffset = -qCeil(QFontMetricsF(fm).height());
5348 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5349 if (sc == SC_GroupBoxContents) {
5351 ret.adjust(3, -5, -3, -4);
5353 ret.adjust(3, 3, -3, -4);
5358 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5364 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5365 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5366 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5372 case QStyleHelper::SizeLarge:
5378 case QStyleHelper::SizeSmall:
5384 case QStyleHelper::SizeMini:
5396 case SC_SpinBoxDown: {
5397 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5401 const int x = spin->rect.width() - spinner_w;
5402 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5404 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5405 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5406 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5407 ret = QRectF::fromCGRect(outRect).toRect();
5411 ret.setHeight(ret.height() / 2);
5413 case SC_SpinBoxDown:
5414 ret.setY(ret.y() + ret.height() / 2);
5422 ret.translate(0, adjust_y);
5423 ret = visualRect(spin->direction, spin->rect, ret);
5426 case SC_SpinBoxEditField:
5427 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5428 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5429 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5430 ret = visualRect(spin->direction, spin->rect, ret);
5434 ret = QCommonStyle::subControlRect(cc, spin, sc);
5440 ret = QCommonStyle::subControlRect(cc, opt, sc);
5441 if (sc == SC_ToolButtonMenu) {
5442#ifndef QT_NO_ACCESSIBILITY
5443 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5444 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
5446 ret.adjust(-1, 0, 0, 0);
5449 case CC_SearchField:
5450 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5451 const auto cs = d->effectiveAquaSizeConstrain(sf);
5452 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5456 case QStyleHelper::SizeLarge:
5457 editRect = sf->rect.adjusted(16, 7, -22, -6);
5459 case QStyleHelper::SizeSmall:
5460 editRect = sf->rect.adjusted(16, 5, -22, -7);
5463 editRect = sf->rect.adjusted(16, 5, -18, -7);
5467 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5468 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5470 case SC_SearchFieldEditField:{
5471 ret = editRect.toAlignedRect();
5472 ret.setX(ret.x() + QMacStylePrivate::PushButtonContentPadding);
5475 case SC_SearchFieldClear: {
5476 ret = QRectF::fromCGRect([cell cancelButtonRectForBounds:searchField.bounds]).toAlignedRect();
5479 case SC_SearchFieldSearch: {
5480 ret = QRectF::fromCGRect([cell searchButtonRectForBounds:searchField.bounds]).toAlignedRect();
5483 case SC_SearchFieldPopup: {
5484 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5485 const int searchTop = sf->rect.top();
5486 ret = QRect(qRound(inner.origin.x),
5488 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5489 editRect.bottom() - searchTop + 2);
5498 ret = QCommonStyle::subControlRect(cc, opt, sc);
5504QSize QMacStyle::sizeFromContents(ContentsType ct,
const QStyleOption *opt,
const QSize &csz)
const
5506 Q_D(
const QMacStyle);
5509 bool useAquaGuideline =
true;
5513 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5514 if (vopt->subControls == SC_SpinBoxFrame) {
5515 const QSize minimumSize(20, 24);
5516 if (sz.width() < minimumSize.width())
5517 sz.setWidth(minimumSize.width());
5518 if (sz.height() < minimumSize.height())
5519 sz.setHeight(minimumSize.height());
5521 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5522 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5523 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5527 case QStyle::CT_TabWidget:
5530 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5562 if (
const QStyleOptionTabWidgetFrame *twf
5563 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5565 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5566 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5568 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5569 if (tabDirection == QMacStylePrivate::North
5570 || tabDirection == QMacStylePrivate::South) {
5571 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5573 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5578 case QStyle::CT_TabBarTab:
5579 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5582 const bool differentFont =
false;
5583 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5584 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5585 || tabDirection == QMacStylePrivate::West;
5587 sz = sz.transposed();
5589 int defaultTabHeight;
5590 const auto cs = d->effectiveAquaSizeConstrain(opt);
5592 case QStyleHelper::SizeLarge:
5593 if (tab->documentMode)
5594 defaultTabHeight = 24;
5596 defaultTabHeight = 21;
5598 case QStyleHelper::SizeSmall:
5599 defaultTabHeight = 18;
5601 case QStyleHelper::SizeMini:
5602 defaultTabHeight = 16;
5608 const bool widthSet = !differentFont && tab->icon.isNull();
5610 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5611 sz.rwidth() = textSize.width();
5612 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5614 sz.rheight() = qMax(defaultTabHeight, sz.height());
5616 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5619 sz = sz.transposed();
5621 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5622 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5624 int widgetWidth = 0;
5625 int widgetHeight = 0;
5627 if (tab->leftButtonSize.isValid()) {
5629 widgetWidth += tab->leftButtonSize.width();
5630 widgetHeight += tab->leftButtonSize.height();
5632 if (tab->rightButtonSize.isValid()) {
5634 widgetWidth += tab->rightButtonSize.width();
5635 widgetHeight += tab->rightButtonSize.height();
5639 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5640 sz.setHeight(sz.height() + widgetHeight + padding);
5643 sz.setWidth(sz.width() + widgetWidth + padding);
5644 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5649 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5651 if (sz.width() < 10)
5653 if (sz.height() < 20)
5657 int leftPadding = 4;
5658 int rightPadding = 4;
5660 int bottomPadding = 0;
5662 if (opt->state & QStyle::State_Small) {
5664 }
else if (opt->state & QStyle::State_Mini) {
5668 sz.rwidth() += leftPadding + rightPadding;
5669 sz.rheight() += topPadding + bottomPadding;
5672 case QStyle::CT_PushButton: {
5673 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5674 if (btn->features & QStyleOptionButton::CommandLinkButton)
5675 return QCommonStyle::sizeFromContents(ct, opt, sz);
5682 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5684 if (macsz.width() != -1)
5685 sz.setWidth(macsz.width());
5687 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
5689 if (controlSize != QStyleHelper::SizeMini)
5691 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5692 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5693 else if (controlSize == QStyleHelper::SizeMini)
5696 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5699 case QStyle::CT_MenuItem:
5700 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5701 int maxpmw = mi->maxIconWidth;
5703 int h = sz.height();
5709 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5711 h = qt_mac_aqua_get_metric(MenuSeparatorHeight);
5713 h = mi->fontMetrics.height() + 2;
5714 if (!mi->icon.isNull()) {
5723 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5724 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5728 if (mi->text.contains(QLatin1Char(
'\t')))
5730 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5749 case CT_MenuBarItem:
5756 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5757 if (tb->features & QStyleOptionToolButton::Menu)
5758 sz.rwidth() += toolButtonArrowMargin;
5761 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5762 const int controlSize = getControlSize(opt);
5765 if (sz.width() < 10)
5768 if (!cb->editable) {
5771 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset;
5773 if (controlSize == QStyleHelper::SizeLarge) {
5775 }
else if (controlSize == QStyleHelper::SizeSmall) {
5785 if (controlSize == QStyleHelper::SizeMini)
5788 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5793 case CT_SearchField:
5794 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5795 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5796 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5797 if (sf->subControls == SC_SearchFieldFrame) {
5798 const int controlSize = getControlSize(opt);
5802 if (controlSize == QStyleHelper::SizeLarge) {
5806 }
else if (controlSize == QStyleHelper::SizeSmall) {
5817 if (sz.width() < 60)
5820 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5821 sz.rwidth() += totalIconsSize;
5824 }
else if (sf->subControls == SC_SearchFieldClear) {
5826 }
else if (sf->subControls == SC_SearchFieldSearch) {
5827 return searchButton;
5832 if (proxy() ==
this) {
5835 QStyleHintReturnMask menuMask;
5836 QStyleOption myOption = *opt;
5837 myOption.rect.setSize(sz);
5838 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5839 sz = menuMask.region.boundingRect().size();
5842 case CT_HeaderSection:{
5843 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5844 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5845 if (header->text.contains(QLatin1Char(
'\n')))
5846 useAquaGuideline =
false;
5850 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5851 const int minimumWidth = 24;
5852 const int absoluteHeight = 14;
5853 if (slider->orientation == Qt::Horizontal) {
5854 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5855 sz.setHeight(absoluteHeight);
5857 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5858 sz.setWidth(absoluteHeight);
5862 case CT_ItemViewItem:
5863 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5864 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5865 sz.setHeight(sz.height() + 2);
5869 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5872 if (useAquaGuideline && ct != CT_PushButton) {
5875 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5876 if (macsz.width() != -1)
5877 sz.setWidth(macsz.width());
5878 if (macsz.height() != -1)
5879 sz.setHeight(macsz.height());
5885 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5886 if (combo->editable) {
5887 const auto widgetSize = d->aquaSizeConstrain(opt);
5888 QMacStylePrivate::CocoaControl cw;
5889 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
5890 cw.size = widgetSize;
5891 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5892 sz.rwidth() -= qRound(diffRect.size.width);
5893 sz.rheight() -= qRound(diffRect.size.height);
5899QFont QMacStyle::font(QStyle::ControlElement element,
const QStyle::State state)
const
5901 QFont font = QCommonStyle::font(element, state);
5903 if (state & QStyle::State_Small) {
5904 font.setPixelSize(11);
5905 }
else if (state & QStyle::State_Mini) {
5906 font.setPixelSize(9);
5912QMargins QMacStyle::ninePatchMargins(QStyle::ComplexControl cc,
const QStyleOptionComplex *opt,
const QSize &imageSize)
const
5918 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5919 margins = QMargins(10, 0, arrow.width() + 1, -1);
5922 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
5929void QMacStyle::drawItemText(QPainter *p,
const QRect &r,
int flags,
const QPalette &pal,
5930 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
5932 if(flags & Qt::TextShowMnemonic)
5933 flags |= Qt::TextHideMnemonic;
5934 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
5937QIcon QMacStyle::standardIcon(StandardPixmap standardIcon,
const QStyleOption *opt)
const
5939 switch (standardIcon) {
5941 return QCommonStyle::standardIcon(standardIcon, opt);
5942 case SP_ToolBarHorizontalExtensionButton:
5943 case SP_ToolBarVerticalExtensionButton: {
5944 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
5945 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
5946 QPixmap pix2(pixmap.height(), pixmap.width());
5947 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
5948 pix2.fill(Qt::transparent);
5950 p.translate(pix2.width(), 0);
5952 p.drawPixmap(0, 0, pixmap);