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);
4708 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4710 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4711 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4712 const CGFloat x = CGRectGetMidX(newRect);
4713 const CGFloat y = upPressed ? -3 : 3;
4714 const CGPoint pressPoint = CGPointMake(x, y);
4717 if (upPressed || downPressed)
4718 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4720 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4722 if (upPressed || downPressed)
4723 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4725 d->restoreNSGraphicsContext(cg);
4730 if (
const auto *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4731 const bool isEnabled = combo->state & State_Enabled;
4732 const bool isPressed = combo->state & State_Sunken;
4734 const auto ct = cocoaControlType(combo);
4735 const auto cs = d->effectiveAquaSizeConstrain(combo);
4736 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4737 auto *cc =
static_cast<NSControl *>(d->cocoaControl(cw));
4738 cc.enabled = isEnabled;
4739 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4740 if (cw.type == QMacStylePrivate::Button_PopupButton) {
4742 auto *pb =
static_cast<NSPopUpButton *>(cc);
4744 if (cw.size == QStyleHelper::SizeSmall) {
4745 frameRect = frameRect.translated(0, 1);
4746 }
else if (cw.size == QStyleHelper::SizeMini) {
4748 frameRect = frameRect.translated(2, -0.5);
4750 pb.frame = frameRect.toCGRect();
4751 [pb highlight:isPressed];
4752 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4753 QMacAutoReleasePool pool;
4754 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4756 }
else if (cw.type == QMacStylePrivate::ComboBox) {
4758 auto *cb =
static_cast<NSComboBox *>(cc);
4759 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4760 cb.frame = frameRect.toCGRect();
4763 if (NSButtonCell *cell =
static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@
"_buttonCell"])) {
4764 cell.highlighted = isPressed;
4769 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4771 QMacAutoReleasePool pool;
4772 [cb.cell drawWithFrame:r inView:cb];
4777 case CC_SearchField:
4778 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
4779 const bool isEnabled = sf->state & State_Enabled;
4781 const auto cs = d->effectiveAquaSizeConstrain(sf);
4782 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
4783 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
4784 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
4786 searchField.enabled = isEnabled;
4788 if (sf->subControls == QStyle::SC_SearchFieldSearch) {
4790 CGRect rect = [cell searchButtonRectForBounds:searchField.bounds];
4791 [cell drawWithFrame:rect inView:searchField];
4792 }
else if (sf->subControls == QStyle::SC_SearchFieldClear) {
4794 CGRect rect = [cell cancelButtonRectForBounds:searchField.bounds];
4795 [cell drawWithFrame:rect inView:searchField];
4798 QRectF frameRect = cw.adjustedControlFrame(sf->rect);
4799 searchField.frame = frameRect.toCGRect();
4800 [cell setStringValue:sf->text.toNSString()];
4801 d->drawNSViewInRect(searchField, frameRect, p, ^(CGContextRef,
const CGRect &r) {
4802 [cell drawWithFrame:r inView:searchField];
4808 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
4809 const bool isActive = (titlebar->state & State_Active)
4810 && (titlebar->titleBarState & State_Active);
4812 p->fillRect(opt->rect, Qt::transparent);
4813 p->setRenderHint(QPainter::Antialiasing);
4814 p->setClipRect(opt->rect, Qt::IntersectClip);
4818 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4819 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4820 p->fillPath(outerFramePath, opt->palette.dark());
4822 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4823 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4824 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4825 p->fillPath(innerFramePath, opt->palette.button());
4827 if (titlebar->subControls & (SC_TitleBarCloseButton
4828 | SC_TitleBarMaxButton
4829 | SC_TitleBarMinButton
4830 | SC_TitleBarNormalButton)) {
4831 const bool isHovered = (titlebar->state & State_MouseOver);
4832 static const SubControl buttons[] = {
4833 SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
4835 for (
const auto sc : buttons) {
4836 const auto ct = d->windowButtonCocoaControl(sc);
4837 const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
4838 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
4839 wb.enabled = (sc & titlebar->subControls) && isActive;
4840 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4841 Q_UNUSED(isHovered);
4843 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4844 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4845 QMacAutoReleasePool pool;
4846 auto *wbCell =
static_cast<NSButtonCell *>(wb.cell);
4847 [wbCell drawWithFrame:rect inView:wb];
4852 if (titlebar->subControls & SC_TitleBarLabel) {
4853 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4854 if (!titlebar->icon.isNull()) {
4855 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4856 const auto iconSize = QSize(iconExtent, iconExtent);
4857 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4859 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4860 p->drawPixmap(iconPos, tr.y(),
4861 titlebar->icon.pixmap(iconSize,
4862 opt->window->devicePixelRatio(),
4866 if (!titlebar->text.isEmpty())
4867 drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
4872 if (
const QStyleOptionGroupBox *gb
4873 = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
4875 QStyleOptionGroupBox groupBox(*gb);
4876 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4878 groupBox.state |= QStyle::State_Mini;
4880 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame;
4886 QCommonStyle::drawComplexControl(cc, &groupBox, p);
4901 if (
const QStyleOptionToolButton *tb
4902 = qstyleoption_cast<
const QStyleOptionToolButton *>(opt)) {
4903#ifndef QT_NO_ACCESSIBILITY
4904 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4905 if (tb->subControls & SC_ToolButtonMenu) {
4906 QStyleOption arrowOpt = *tb;
4907 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4908 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4909 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4910 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4911 }
else if ((tb->features & QStyleOptionToolButton::HasMenu)
4912 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4913 d->drawToolbarButtonArrow(tb, p);
4915 if (tb->state & State_On) {
4916 NSView *view =
reinterpret_cast<NSView *>(opt->window->winId());
4919 isKey = [view.window isKeyWindow];
4921 QBrush brush(brushForToolButton(isKey));
4923 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4924 p->setRenderHint(QPainter::Antialiasing);
4925 p->fillPath(path, brush);
4927 proxy()->drawControl(CE_ToolButtonLabel, opt, p);
4931 auto bflags = tb->state;
4932 if (tb->subControls & SC_ToolButton)
4933 bflags |= State_Sunken;
4934 auto mflags = tb->state;
4935 if (tb->subControls & SC_ToolButtonMenu)
4936 mflags |= State_Sunken;
4938 if (tb->subControls & SC_ToolButton) {
4939 if (bflags & (State_Sunken | State_On | State_Raised)) {
4940 const bool isEnabled = tb->state & State_Enabled;
4941 const bool isPressed = tb->state & State_Sunken;
4942 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
4943 const auto ct = QMacStylePrivate::Button_PushButton;
4944 const auto cs = d->effectiveAquaSizeConstrain(opt);
4945 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4946 auto *pb =
static_cast<NSButton *>(d->cocoaControl(cw));
4947 pb.bezelStyle = NSBezelStyleShadowlessSquare;
4948 pb.frame = opt->rect.toCGRect();
4949 pb.buttonType = NSButtonTypePushOnPushOff;
4950 pb.enabled = isEnabled;
4951 [pb highlight:isPressed];
4952 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
4953 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
4954 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef,
const CGRect &rect) {
4955 QMacAutoReleasePool pool;
4956 [pb.cell drawBezelWithFrame:rect inView:pb];
4961 if (tb->subControls & SC_ToolButtonMenu) {
4962 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4963 QStyleOption arrowOpt = *tb;
4964 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
4965 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
4966 toolButtonArrowSize,
4967 toolButtonArrowSize);
4968 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
4969 }
else if (tb->features & QStyleOptionToolButton::HasMenu) {
4970 d->drawToolbarButtonArrow(tb, p);
4972 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
4973 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
4974 QStyleOptionToolButton label = *tb;
4975 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
4976 proxy()->drawControl(CE_ToolButtonLabel, &label, p);
4981 if (
const QStyleOptionSlider *dial = qstyleoption_cast<
const QStyleOptionSlider *>(opt))
4982 QStyleHelper::drawDial(dial, p);
4985 QCommonStyle::drawComplexControl(cc, opt, p);
4990QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
const QStyleOptionComplex *opt,
const QPoint &pt)
const
4992 Q_D(
const QMacStyle);
4994 SubControl sc = QStyle::SC_None;
4998 if (
const QStyleOptionComboBox *cmb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
4999 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
5000 if (!cmb->editable && sc != QStyle::SC_None)
5001 sc = SC_ComboBoxArrow;
5005 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5006 if (!sl->rect.contains(pt))
5009 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5010 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5011 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5012 const auto cs = d->effectiveAquaSizeConstrain(opt);
5013 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5014 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5015 if (!setupSlider(slider, sl))
5018 NSSliderCell *cell = slider.cell;
5019 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5020 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5021 if (knobRect.contains(pt)) {
5022 sc = SC_SliderHandle;
5023 }
else if (barRect.contains(pt)) {
5024 sc = SC_SliderGroove;
5025 }
else if (hasTicks) {
5026 sc = SC_SliderTickmarks;
5031 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5032 if (!sb->rect.contains(pt)) {
5037 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5038 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5039 const auto cs = d->effectiveAquaSizeConstrain(opt);
5040 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5041 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5042 if (!setupScroller(scroller, sb)) {
5050 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5052 const bool isReverse = sb->direction == Qt::RightToLeft;
5053 if (pt.x() < knobRect.left())
5054 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5055 else if (pt.x() > knobRect.right())
5056 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5058 sc = SC_ScrollBarSlider;
5060 if (pt.y() < knobRect.top())
5061 sc = SC_ScrollBarSubPage;
5062 else if (pt.y() > knobRect.bottom())
5063 sc = SC_ScrollBarAddPage;
5065 sc = SC_ScrollBarSlider;
5069 case CC_SearchField:
5070 if (
const auto *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5071 if (!sf->rect.contains(pt))
5074 const auto cs = d->effectiveAquaSizeConstrain(sf);
5075 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5076 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5077 searchField.frame = cw.adjustedControlFrame(sf->rect).toCGRect();
5079 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5080 const CGRect bounds = searchField.bounds;
5082 const QRectF cancelRect = QRectF::fromCGRect([cell cancelButtonRectForBounds:bounds]);
5083 const QRectF searchIconRect = QRectF::fromCGRect([cell searchButtonRectForBounds:bounds]);
5084 const QRectF textFieldRect = QRectF::fromCGRect([cell searchTextRectForBounds:bounds]);
5086 const QPointF localPt = pt - sf->rect.topLeft();
5088 if (cancelRect.contains(localPt))
5089 sc = SC_SearchFieldClear;
5090 else if (searchIconRect.contains(localPt))
5091 sc = SC_SearchFieldSearch;
5092 else if (textFieldRect.contains(localPt))
5093 sc = SC_SearchFieldEditField;
5095 sc = SC_SearchFieldPopup;
5101 sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
5107QRect QMacStyle::subControlRect(ComplexControl cc,
const QStyleOptionComplex *opt, SubControl sc)
const
5109 Q_D(
const QMacStyle);
5115 if (
const QStyleOptionSlider *sb = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5116 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5117 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5119 NSScrollerPart part = NSScrollerNoPart;
5120 if (sc == SC_ScrollBarSlider) {
5121 part = NSScrollerKnob;
5122 }
else if (sc == SC_ScrollBarGroove) {
5123 part = NSScrollerKnobSlot;
5124 }
else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5125 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5126 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5127 part = NSScrollerDecrementPage;
5129 part = NSScrollerIncrementPage;
5133 if (part != NSScrollerNoPart) {
5134 const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5135 const auto cs = d->effectiveAquaSizeConstrain(opt);
5136 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5137 auto *scroller =
static_cast<NSScroller *>(d->cocoaControl(cw));
5138 if (setupScroller(scroller, sb))
5139 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5144 if (
const QStyleOptionSlider *sl = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5145 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5146 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5147 const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
5148 const auto cs = d->effectiveAquaSizeConstrain(opt);
5149 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5150 auto *slider =
static_cast<NSSlider *>(d->cocoaControl(cw));
5151 if (!setupSlider(slider, sl))
5154 NSSliderCell *cell = slider.cell;
5155 if (sc == SC_SliderHandle) {
5156 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5157 }
else if (sc == SC_SliderGroove) {
5158 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5159 }
else if (hasTicks && sc == SC_SliderTickmarks) {
5160 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5162 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5164 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5175 if (
const auto *titlebar = qstyleoption_cast<
const QStyleOptionTitleBar *>(opt)) {
5181 if (sc == SC_TitleBarLabel) {
5182 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1;
5183 qreal labelHeight = titlebar->fontMetrics.height();
5185 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5186 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5187 if (!titlebar->icon.isNull()) {
5188 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5189 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5190 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5193 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5194 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5195 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5196 labelWidth, labelHeight);
5198 const auto currentButton = d->windowButtonCocoaControl(sc);
5199 if (currentButton == QMacStylePrivate::NoControl)
5202 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5204 for (
int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5205 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
5206 QStyleHelper::SizeLarge);
5207 auto *wb =
static_cast<NSButton *>(d->cocoaControl(cw));
5208 if (ct == currentButton)
5209 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5211 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5214 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5215 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5220 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5221 const auto ct = cocoaControlType(combo);
5222 const auto cs = d->effectiveAquaSizeConstrain(combo);
5223 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5231 case QStyleHelper::SizeLarge:
5232 editRect = combo->rect.adjusted(15, 7, -25, -9);
5234 case QStyleHelper::SizeSmall:
5235 if (combo->editable)
5236 editRect = combo->rect.adjusted(15, 6, -22, -9);
5238 editRect = combo->rect.adjusted(15, 8, -22, -6);
5241 if (combo->editable)
5242 editRect = combo->rect.adjusted(15, 6, -20, -7);
5244 editRect = combo->rect.adjusted(15, 5, -22, -6);
5249 case SC_ComboBoxEditField:{
5250 ret = editRect.toAlignedRect();
5252 case SC_ComboBoxArrow:{
5253 ret = editRect.toAlignedRect();
5254 ret.setX(ret.x() + ret.width());
5255 ret.setWidth(combo->rect.right() - ret.right());
5257 case SC_ComboBoxListBoxPopup:{
5258 if (combo->editable) {
5259 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5260 const int comboTop = combo->rect.top();
5261 ret = QRect(qRound(inner.origin.x),
5263 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5264 editRect.bottom() - comboTop + 2);
5266 ret = QRect(combo->rect.x() + 4 - 11,
5267 combo->rect.y() + 1,
5268 editRect.width() + 10 + 11,
5278 if (
const QStyleOptionGroupBox *groupBox = qstyleoption_cast<
const QStyleOptionGroupBox *>(opt)) {
5279 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5280 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5281 bool hasNoText = !checkable && groupBox->text.isEmpty();
5283 case SC_GroupBoxLabel:
5284 case SC_GroupBoxCheckBox: {
5286 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5287 const bool fontIsSet =
false;
5290 const int margin = flat || hasNoText ? 0 : 9;
5291 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5293 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5294 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0,
nullptr);
5295 const int tw = qCeil(s.width());
5296 const int h = qCeil(fm.height());
5299 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5301 if (flat && checkable)
5302 labelRect.moveLeft(labelRect.left() + 4);
5303 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5304 bool rtl = groupBox->direction == Qt::RightToLeft;
5305 if (sc == SC_GroupBoxLabel) {
5307 int newSum = indicatorWidth + 1;
5308 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5309 labelRect.moveLeft(newLeft);
5311 labelRect.moveTop(labelRect.top() + 3);
5313 labelRect.moveTop(labelRect.top() + 4);
5315 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5316 labelRect.moveLeft(newLeft);
5317 labelRect.moveTop(labelRect.top() + 3);
5319 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5320 labelRect.moveLeft(newLeft);
5321 labelRect.moveTop(labelRect.top() + 4);
5326 if (sc == SC_GroupBoxCheckBox) {
5327 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5328 int top = flat ? ret.top() + 1 : ret.top() + 5;
5329 ret.setRect(left, top,
5330 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5334 case SC_GroupBoxContents:
5335 case SC_GroupBoxFrame: {
5336 QFontMetrics fm = groupBox->fontMetrics;
5342 yOffset = -qCeil(QFontMetricsF(fm).height());
5343 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5344 if (sc == SC_GroupBoxContents) {
5346 ret.adjust(3, -5, -3, -4);
5348 ret.adjust(3, 3, -3, -4);
5353 ret = QCommonStyle::subControlRect(cc, groupBox, sc);
5359 if (
const QStyleOptionSpinBox *spin = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5360 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5361 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5367 case QStyleHelper::SizeLarge:
5373 case QStyleHelper::SizeSmall:
5379 case QStyleHelper::SizeMini:
5391 case SC_SpinBoxDown: {
5392 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5396 const int x = spin->rect.width() - spinner_w;
5397 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5399 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
5400 NSStepperCell *cell =
static_cast<NSStepperCell *>(d->cocoaCell(cw));
5401 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5402 ret = QRectF::fromCGRect(outRect).toRect();
5406 ret.setHeight(ret.height() / 2);
5408 case SC_SpinBoxDown:
5409 ret.setY(ret.y() + ret.height() / 2);
5417 ret.translate(0, adjust_y);
5418 ret = visualRect(spin->direction, spin->rect, ret);
5421 case SC_SpinBoxEditField:
5422 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5423 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5424 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5425 ret = visualRect(spin->direction, spin->rect, ret);
5429 ret = QCommonStyle::subControlRect(cc, spin, sc);
5435 ret = QCommonStyle::subControlRect(cc, opt, sc);
5436 if (sc == SC_ToolButtonMenu) {
5437#ifndef QT_NO_ACCESSIBILITY
5438 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5439 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
5441 ret.adjust(-1, 0, 0, 0);
5444 case CC_SearchField:
5445 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5446 const auto cs = d->effectiveAquaSizeConstrain(sf);
5447 const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::SearchField, cs);
5451 case QStyleHelper::SizeLarge:
5452 editRect = sf->rect.adjusted(16, 7, -22, -6);
5454 case QStyleHelper::SizeSmall:
5455 editRect = sf->rect.adjusted(16, 5, -22, -7);
5458 editRect = sf->rect.adjusted(16, 5, -18, -7);
5462 auto *searchField =
static_cast<NSSearchField *>(d->cocoaControl(cw));
5463 auto *cell =
static_cast<NSSearchFieldCell *>(searchField.cell);
5465 case SC_SearchFieldEditField:{
5466 ret = editRect.toAlignedRect();
5467 ret.setX(ret.x() + QMacStylePrivate::PushButtonContentPadding);
5470 case SC_SearchFieldClear: {
5471 ret = QRectF::fromCGRect([cell cancelButtonRectForBounds:searchField.bounds]).toAlignedRect();
5474 case SC_SearchFieldSearch: {
5475 ret = QRectF::fromCGRect([cell searchButtonRectForBounds:searchField.bounds]).toAlignedRect();
5478 case SC_SearchFieldPopup: {
5479 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(sf->rect.toCGRect(), cw);
5480 const int searchTop = sf->rect.top();
5481 ret = QRect(qRound(inner.origin.x),
5483 qRound(inner.origin.x - sf->rect.left() + inner.size.width),
5484 editRect.bottom() - searchTop + 2);
5493 ret = QCommonStyle::subControlRect(cc, opt, sc);
5499QSize QMacStyle::sizeFromContents(ContentsType ct,
const QStyleOption *opt,
const QSize &csz)
const
5501 Q_D(
const QMacStyle);
5504 bool useAquaGuideline =
true;
5508 if (
const QStyleOptionSpinBox *vopt = qstyleoption_cast<
const QStyleOptionSpinBox *>(opt)) {
5509 if (vopt->subControls == SC_SpinBoxFrame) {
5510 const QSize minimumSize(20, 24);
5511 if (sz.width() < minimumSize.width())
5512 sz.setWidth(minimumSize.width());
5513 if (sz.height() < minimumSize.height())
5514 sz.setHeight(minimumSize.height());
5516 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5517 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5518 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5522 case QStyle::CT_TabWidget:
5525 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5557 if (
const QStyleOptionTabWidgetFrame *twf
5558 = qstyleoption_cast<
const QStyleOptionTabWidgetFrame *>(opt)) {
5560 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5561 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5563 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5564 if (tabDirection == QMacStylePrivate::North
5565 || tabDirection == QMacStylePrivate::South) {
5566 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5568 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5573 case QStyle::CT_TabBarTab:
5574 if (
const QStyleOptionTab *tab = qstyleoption_cast<
const QStyleOptionTab *>(opt)) {
5577 const bool differentFont =
false;
5578 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5579 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5580 || tabDirection == QMacStylePrivate::West;
5582 sz = sz.transposed();
5584 int defaultTabHeight;
5585 const auto cs = d->effectiveAquaSizeConstrain(opt);
5587 case QStyleHelper::SizeLarge:
5588 if (tab->documentMode)
5589 defaultTabHeight = 24;
5591 defaultTabHeight = 21;
5593 case QStyleHelper::SizeSmall:
5594 defaultTabHeight = 18;
5596 case QStyleHelper::SizeMini:
5597 defaultTabHeight = 16;
5603 const bool widthSet = !differentFont && tab->icon.isNull();
5605 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5606 sz.rwidth() = textSize.width();
5607 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5609 sz.rheight() = qMax(defaultTabHeight, sz.height());
5611 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5614 sz = sz.transposed();
5616 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5617 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5619 int widgetWidth = 0;
5620 int widgetHeight = 0;
5622 if (tab->leftButtonSize.isValid()) {
5624 widgetWidth += tab->leftButtonSize.width();
5625 widgetHeight += tab->leftButtonSize.height();
5627 if (tab->rightButtonSize.isValid()) {
5629 widgetWidth += tab->rightButtonSize.width();
5630 widgetHeight += tab->rightButtonSize.height();
5634 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5635 sz.setHeight(sz.height() + widgetHeight + padding);
5638 sz.setWidth(sz.width() + widgetWidth + padding);
5639 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5644 if (qstyleoption_cast<
const QStyleOptionFrame *>(opt)) {
5646 if (sz.width() < 10)
5648 if (sz.height() < 20)
5652 int leftPadding = 4;
5653 int rightPadding = 4;
5655 int bottomPadding = 0;
5657 if (opt->state & QStyle::State_Small) {
5659 }
else if (opt->state & QStyle::State_Mini) {
5663 sz.rwidth() += leftPadding + rightPadding;
5664 sz.rheight() += topPadding + bottomPadding;
5667 case QStyle::CT_PushButton: {
5668 if (
const QStyleOptionButton *btn = qstyleoption_cast<
const QStyleOptionButton *>(opt))
5669 if (btn->features & QStyleOptionButton::CommandLinkButton)
5670 return QCommonStyle::sizeFromContents(ct, opt, sz);
5677 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5679 if (macsz.width() != -1)
5680 sz.setWidth(macsz.width());
5682 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
5684 if (controlSize != QStyleHelper::SizeMini)
5686 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5687 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5688 else if (controlSize == QStyleHelper::SizeMini)
5691 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5694 case QStyle::CT_MenuItem:
5695 if (
const QStyleOptionMenuItem *mi = qstyleoption_cast<
const QStyleOptionMenuItem *>(opt)) {
5696 int maxpmw = mi->maxIconWidth;
5698 int h = sz.height();
5704 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5706 h = qt_mac_aqua_get_metric(MenuSeparatorHeight);
5708 h = mi->fontMetrics.height() + 2;
5709 if (!mi->icon.isNull()) {
5718 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5719 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5723 if (mi->text.contains(QLatin1Char(
'\t')))
5725 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5744 case CT_MenuBarItem:
5751 if (
const auto *tb = qstyleoption_cast<
const QStyleOptionToolButton *>(opt))
5752 if (tb->features & QStyleOptionToolButton::Menu)
5753 sz.rwidth() += toolButtonArrowMargin;
5756 if (
const auto *cb = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)) {
5757 const int controlSize = getControlSize(opt);
5760 if (sz.width() < 10)
5763 if (!cb->editable) {
5766 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset;
5768 if (controlSize == QStyleHelper::SizeLarge) {
5770 }
else if (controlSize == QStyleHelper::SizeSmall) {
5780 if (controlSize == QStyleHelper::SizeMini)
5783 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5788 case CT_SearchField:
5789 if (
const QStyleOptionSearchField *sf = qstyleoption_cast<
const QStyleOptionSearchField *>(opt)) {
5790 const QSize clearButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldClear).size();
5791 const QSize searchButton = proxy()->subControlRect(CC_SearchField, sf, SC_SearchFieldSearch).size();
5792 if (sf->subControls == SC_SearchFieldFrame) {
5793 const int controlSize = getControlSize(opt);
5797 if (controlSize == QStyleHelper::SizeLarge) {
5801 }
else if (controlSize == QStyleHelper::SizeSmall) {
5812 if (sz.width() < 60)
5815 const int totalIconsSize = clearButton.width() + searchButton.width() + (padding + iconSpacing) * 2;
5816 sz.rwidth() += totalIconsSize;
5819 }
else if (sf->subControls == SC_SearchFieldClear) {
5821 }
else if (sf->subControls == SC_SearchFieldSearch) {
5822 return searchButton;
5827 if (proxy() ==
this) {
5830 QStyleHintReturnMask menuMask;
5831 QStyleOption myOption = *opt;
5832 myOption.rect.setSize(sz);
5833 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5834 sz = menuMask.region.boundingRect().size();
5837 case CT_HeaderSection:{
5838 const QStyleOptionHeader *header = qstyleoption_cast<
const QStyleOptionHeader *>(opt);
5839 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5840 if (header->text.contains(QLatin1Char(
'\n')))
5841 useAquaGuideline =
false;
5845 if (
const QStyleOptionSlider *slider = qstyleoption_cast<
const QStyleOptionSlider *>(opt)) {
5846 const int minimumWidth = 24;
5847 const int absoluteHeight = 14;
5848 if (slider->orientation == Qt::Horizontal) {
5849 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5850 sz.setHeight(absoluteHeight);
5852 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5853 sz.setWidth(absoluteHeight);
5857 case CT_ItemViewItem:
5858 if (
const QStyleOptionViewItem *vopt = qstyleoption_cast<
const QStyleOptionViewItem *>(opt)) {
5859 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5860 sz.setHeight(sz.height() + 2);
5864 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5867 if (useAquaGuideline && ct != CT_PushButton) {
5870 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5871 if (macsz.width() != -1)
5872 sz.setWidth(macsz.width());
5873 if (macsz.height() != -1)
5874 sz.setHeight(macsz.height());
5880 if (
const QStyleOptionComboBox *combo = qstyleoption_cast<
const QStyleOptionComboBox *>(opt)){
5881 if (combo->editable) {
5882 const auto widgetSize = d->aquaSizeConstrain(opt);
5883 QMacStylePrivate::CocoaControl cw;
5884 cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
5885 cw.size = widgetSize;
5886 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5887 sz.rwidth() -= qRound(diffRect.size.width);
5888 sz.rheight() -= qRound(diffRect.size.height);
5894QFont QMacStyle::font(QStyle::ControlElement element,
const QStyle::State state)
const
5896 QFont font = QCommonStyle::font(element, state);
5898 if (state & QStyle::State_Small) {
5899 font.setPixelSize(11);
5900 }
else if (state & QStyle::State_Mini) {
5901 font.setPixelSize(9);
5907QMargins QMacStyle::ninePatchMargins(QStyle::ComplexControl cc,
const QStyleOptionComplex *opt,
const QSize &imageSize)
const
5913 const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
5914 margins = QMargins(10, 0, arrow.width() + 1, -1);
5917 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
5924void QMacStyle::drawItemText(QPainter *p,
const QRect &r,
int flags,
const QPalette &pal,
5925 bool enabled,
const QString &text, QPalette::ColorRole textRole)
const
5927 if(flags & Qt::TextShowMnemonic)
5928 flags |= Qt::TextHideMnemonic;
5929 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
5932QIcon QMacStyle::standardIcon(StandardPixmap standardIcon,
const QStyleOption *opt)
const
5934 switch (standardIcon) {
5936 return QCommonStyle::standardIcon(standardIcon, opt);
5937 case SP_ToolBarHorizontalExtensionButton:
5938 case SP_ToolBarVerticalExtensionButton: {
5939 QPixmap pixmap(QLatin1String(
":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
5940 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
5941 QPixmap pix2(pixmap.height(), pixmap.width());
5942 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
5943 pix2.fill(Qt::transparent);
5945 p.translate(pix2.width(), 0);
5947 p.drawPixmap(0, 0, pixmap);