Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qmacstyle_mac.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4/*
5 Note: The qdoc comments for QMacStyle are contained in
6 .../doc/src/qstyles.qdoc.
7*/
8
9#include <AppKit/AppKit.h>
10
11#include "qmacstyle_mac_p.h"
12#include "qmacstyle_mac_p_p.h"
13
14#define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
15//#define DEBUG_SIZE_CONSTRAINT
16
17#include <QtCore/qoperatingsystemversion.h>
18#include <QtCore/qvariant.h>
19#include <QtCore/qvarlengtharray.h>
20
21#include <QtCore/private/qcore_mac_p.h>
22
23#include <QtGui/qpainterpath.h>
24#include <QtGui/private/qcoregraphics_p.h>
25#include <QtGui/qpa/qplatformfontdatabase.h>
26#include <QtGui/qpa/qplatformtheme.h>
27
28#include <QtWidgets/private/qstyleanimation_p.h>
29
30#if QT_CONFIG(mdiarea)
31#include <QtWidgets/qmdisubwindow.h>
32#endif
33#if QT_CONFIG(scrollbar)
34#include <QtWidgets/qscrollbar.h>
35#endif
36#if QT_CONFIG(tabbar)
37#include <QtWidgets/private/qtabbar_p.h>
38#endif
39#if QT_CONFIG(wizard)
40#include <QtWidgets/qwizard.h>
41#endif
42
43#include <cmath>
44
46
48
49@property (readonly, nonatomic) NSInteger animators;
50
51- (instancetype)init;
52
55
56- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view;
57
58@end
59
61
63
64- (instancetype)init
65{
66 if ((self = [super init])) {
67 _animators = 0;
68 self.indeterminate = YES;
69 self.usesThreadedAnimation = NO;
70 self.alphaValue = 0.0;
71 }
72
73 return self;
74}
75
77{
78 if (_animators == 0) {
79 self.hidden = NO;
80 [super startAnimation:self];
81 }
82 ++_animators;
83}
84
86{
87 --_animators;
88 if (_animators == 0) {
89 [super stopAnimation:self];
90 self.hidden = YES;
91 [self removeFromSuperviewWithoutNeedingDisplay];
92 }
93}
94
95- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view
96{
97 // The alphaValue change is not strictly necessary, but feels safer.
98 self.alphaValue = 1.0;
99 if (self.superview != view)
100 [view addSubview:self];
101 if (!CGRectEqualToRect(self.frame, rect))
102 self.frame = rect;
103 [self drawRect:rect];
104 self.alphaValue = 0.0;
105}
106
107@end
108
110- (BOOL)isVertical;
111@end
112
114
115@implementation QVerticalSplitView
116- (BOOL)isVertical
117{
118 return YES;
119}
120@end
121
122// See render code in drawPrimitive(PE_FrameTabWidget)
124@end
125
127
128@implementation QDarkNSBox
129- (instancetype)init
130{
131 if ((self = [super init])) {
132 self.title = @"";
133 self.titlePosition = NSNoTitle;
134 self.boxType = NSBoxCustom;
135 self.cornerRadius = 3;
136 self.borderColor = [NSColor.controlColor colorWithAlphaComponent:0.1];
137 self.fillColor = [NSColor.darkGrayColor colorWithAlphaComponent:0.2];
138 }
139
140 return self;
141}
142
143- (void)drawRect:(NSRect)rect
144{
145 [super drawRect:rect];
146}
147@end
148
150
151// The following constants are used for adjusting the size
152// of push buttons so that they are drawn inside their bounds.
156
160
161QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
162
164
165#if QT_CONFIG(tabwidget)
166/*
167 Since macOS 10.14 AppKit is using transparency more extensively, especially for the
168 dark theme. Inactive buttons, for example, are semi-transparent. And we use them to
169 draw tab widget's tab bar. The combination of NSBox (also a part of tab widget)
170 and these transparent buttons gives us an undesired side-effect: an outline of
171 NSBox is visible through transparent buttons. To avoid this, we have this hack below:
172 we clip the area where the line would be visible through the buttons. The area we
173 want to clip away can be described as an intersection of the option's rect and
174 the tab widget's tab bar rect. But some adjustments are required, since those rects
175 are anyway adjusted during the rendering and they are not exactly what you'll see on
176 the screen. Thus this switch-statement inside.
177*/
178static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style, CGContextRef ctx)
179{
181 Q_ASSERT(style);
182 Q_ASSERT(ctx);
183
184 if (isDarkMode()) {
185 QTabWidget *tabWidget = qobject_cast<QTabWidget *>(option->styleObject);
186 Q_ASSERT(tabWidget);
187
188 QRect tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, option, tabWidget).adjusted(2, 0, -3, 0);
189 switch (tabWidget->tabPosition()) {
191 tabBarRect.setY(tabBarRect.y() + tabBarRect.height() / 2);
192 break;
194 case QTabWidget::West:
195 tabBarRect = tabBarRect.adjusted(0, 2, 0, -2);
196 break;
197 case QTabWidget::East:
198 tabBarRect = tabBarRect.adjusted(tabBarRect.width() / 2, 2, tabBarRect.width() / 2, -2);
199 }
200
201 const QRegion clipPath = QRegion(option->rect) - tabBarRect;
202 QVarLengthArray<CGRect, 3> cgRects;
203 for (const QRect &qtRect : clipPath)
204 cgRects.push_back(qtRect.toCGRect());
205 if (cgRects.size())
206 CGContextClipToRects(ctx, &cgRects[0], size_t(cgRects.size()));
207 }
208}
209#endif
210
211static const QColor titlebarSeparatorLineActive(111, 111, 111);
212static const QColor titlebarSeparatorLineInactive(131, 131, 131);
213static const QColor darkModeSeparatorLine(88, 88, 88);
214
215// Gradient colors used for the dock widget title bar and
216// non-unifed tool bar background.
217static const QColor lightMainWindowGradientBegin(240, 240, 240);
218static const QColor lightMainWindowGradientEnd(200, 200, 200);
219static const QColor darkMainWindowGradientBegin(47, 47, 47);
220static const QColor darkMainWindowGradientEnd(47, 47, 47);
221
222static const int DisclosureOffset = 4;
223
227
228// Tab bar colors
229// active: window is active
230// selected: tab is selected
231// hovered: tab is hovered
232
233#if QT_CONFIG(tabbar)
234static const QColor lightTabBarTabBackgroundActive(190, 190, 190);
235static const QColor darkTabBarTabBackgroundActive(38, 38, 38);
236static const QColor tabBarTabBackgroundActive() { return isDarkMode() ? darkTabBarTabBackgroundActive : lightTabBarTabBackgroundActive; }
237
238static const QColor lightTabBarTabBackgroundActiveHovered(178, 178, 178);
239static const QColor darkTabBarTabBackgroundActiveHovered(32, 32, 32);
240static const QColor tabBarTabBackgroundActiveHovered() { return isDarkMode() ? darkTabBarTabBackgroundActiveHovered : lightTabBarTabBackgroundActiveHovered; }
241
242static const QColor lightTabBarTabBackgroundActiveSelected(211, 211, 211);
243static const QColor darkTabBarTabBackgroundActiveSelected(52, 52, 52);
244static const QColor tabBarTabBackgroundActiveSelected() { return isDarkMode() ? darkTabBarTabBackgroundActiveSelected : lightTabBarTabBackgroundActiveSelected; }
245
246static const QColor lightTabBarTabBackground(227, 227, 227);
247static const QColor darkTabBarTabBackground(38, 38, 38);
248static const QColor tabBarTabBackground() { return isDarkMode() ? darkTabBarTabBackground : lightTabBarTabBackground; }
249
250static const QColor lightTabBarTabBackgroundSelected(246, 246, 246);
251static const QColor darkTabBarTabBackgroundSelected(52, 52, 52);
252static const QColor tabBarTabBackgroundSelected() { return isDarkMode() ? darkTabBarTabBackgroundSelected : lightTabBarTabBackgroundSelected; }
253
254static const QColor lightTabBarTabLineActive(160, 160, 160);
255static const QColor darkTabBarTabLineActive(90, 90, 90);
256static const QColor tabBarTabLineActive() { return isDarkMode() ? darkTabBarTabLineActive : lightTabBarTabLineActive; }
257
258static const QColor lightTabBarTabLineActiveHovered(150, 150, 150);
259static const QColor darkTabBarTabLineActiveHovered(90, 90, 90);
260static const QColor tabBarTabLineActiveHovered() { return isDarkMode() ? darkTabBarTabLineActiveHovered : lightTabBarTabLineActiveHovered; }
261
262static const QColor lightTabBarTabLine(210, 210, 210);
263static const QColor darkTabBarTabLine(90, 90, 90);
264static const QColor tabBarTabLine() { return isDarkMode() ? darkTabBarTabLine : lightTabBarTabLine; }
265
266static const QColor lightTabBarTabLineSelected(189, 189, 189);
267static const QColor darkTabBarTabLineSelected(90, 90, 90);
268static const QColor tabBarTabLineSelected() { return isDarkMode() ? darkTabBarTabLineSelected : lightTabBarTabLineSelected; }
269
270static const QColor tabBarCloseButtonBackgroundHovered(162, 162, 162);
271static const QColor tabBarCloseButtonBackgroundPressed(153, 153, 153);
272static const QColor tabBarCloseButtonBackgroundSelectedHovered(192, 192, 192);
273static const QColor tabBarCloseButtonBackgroundSelectedPressed(181, 181, 181);
274static const QColor tabBarCloseButtonCross(100, 100, 100);
275static const QColor tabBarCloseButtonCrossSelected(115, 115, 115);
276
277static const int closeButtonSize = 14;
278static const qreal closeButtonCornerRadius = 2.0;
279#endif // QT_CONFIG(tabbar)
280
281#if QT_CONFIG(accessibility) // This ifdef to avoid "unused function" warning.
282QBrush brushForToolButton(bool isOnKeyWindow)
283{
284 // When a toolbutton in a toolbar is in the 'ON' state, we draw a
285 // partially transparent background. The colors must be different
286 // for 'Aqua' and 'DarkAqua' appearances though.
287 if (isDarkMode())
288 return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
289
290 return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
291}
292#endif // QT_CONFIG(accessibility)
293
294
295static const int headerSectionArrowHeight = 6;
296static const int headerSectionSeparatorInset = 2;
297
298// One for each of QStyleHelper::WidgetSizePolicy
300 { 0.5, 2, 3.5, 4 },
301 { 0.5, 1, 2.5, 4 },
302 { 0.5, 1.5, 2.5, 3.5 }
303};
304
306 { 0.5, -1, 0.5, 2 },
307 { 0.5, -1.5, 0.5, 2.5 },
308 { 0.5, 0, 0.5, 1 }
309};
310
312 { 1.5, -1.5, 1.5, 4.5 },
313 { 1.5, -1, 1.5, 4 },
314 { 1.5, 0.5, 1.5, 2.5 }
315};
316
317// These are frame heights as reported by Xcode 9's Interface Builder
318// and determined experimentally.
319
320static const qreal comboBoxDefaultHeight[3] = {
321 26, 22, 19
322};
323
325 32, 28, 24
326};
327
329 26, 22, 15
330};
331
332static const int toolButtonArrowSize = 7;
333static const int toolButtonArrowMargin = 2;
334
335static const qreal focusRingWidth = 3.5;
336
337// An application can force 'Aqua' theme while the system theme is one of
338// the 'Dark' variants. Since in Qt we sometimes use NSControls and even
339// NSCells directly without attaching them to any view hierarchy, we have
340// to set NSAppearance.currentAppearance to 'Aqua' manually, to make sure
341// the correct rendering path is triggered. Apple recommends us to un-set
342// the current appearance back after we finished with drawing. This is what
343// AppearanceSync is for.
344
346public:
348 {
350 && !isDarkMode()) {
351 auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
352 if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
353 previous = NSAppearance.currentAppearance;
354 NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
355 }
356 }
357 }
358
360 {
361 if (previous)
362 NSAppearance.currentAppearance = previous;
363 }
364
365private:
366 NSAppearance *previous = nil;
367
368 Q_DISABLE_COPY(AppearanceSync)
369};
370
371static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
372{
373 const qreal length = sb->maximum - sb->minimum + sb->pageStep;
374 if (qFuzzyIsNull(length))
375 return false;
376 const qreal proportion = sb->pageStep / length;
377 const qreal range = qreal(sb->maximum - sb->minimum);
378 qreal value = range ? qreal(sb->sliderValue - sb->minimum) / range : 0;
379 if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
380 value = 1.0 - value;
381
382 scroller.frame = sb->rect.toCGRect();
383 scroller.floatValue = value;
384 scroller.knobProportion = proportion;
385 return true;
386}
387
388static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
389{
390 if (sl->minimum >= sl->maximum)
391 return false;
392
393 slider.frame = sl->rect.toCGRect();
394
395 slider.minValue = sl->minimum;
396 slider.maxValue = sl->maximum;
397 slider.intValue = sl->sliderPosition;
398 slider.enabled = sl->state & QStyle::State_Enabled;
399 if (sl->tickPosition != QSlider::NoTicks) {
400 // Set numberOfTickMarks, but TicksBothSides will be treated differently
401 int interval = sl->tickInterval;
402 if (interval == 0) {
403 interval = sl->pageStep;
404 if (interval == 0)
405 interval = sl->singleStep;
406 if (interval == 0)
407 interval = 1; // return false?
408 }
409 slider.numberOfTickMarks = 1 + ((sl->maximum - sl->minimum) / interval);
410
411 const bool ticksAbove = sl->tickPosition == QSlider::TicksAbove;
412 if (sl->orientation == Qt::Horizontal)
413 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
414 else
415 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
416 } else {
417 slider.numberOfTickMarks = 0;
418 }
419
420 // Ensure the values set above are reflected when asking
421 // the cell for its metrics and to draw itself.
422 [slider layoutSubtreeIfNeeded];
423
424 return true;
425}
426
427static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
428{
431 nativeInterface->nativeResourceFunctionForIntegration("testContentBorderPosition");
432 if (!function)
433 return false; // Not Cocoa platform plugin.
434
435 typedef bool (*TestContentBorderPositionFunction)(QWindow *, int);
436 return (reinterpret_cast<TestContentBorderPositionFunction>(function))(window, windowY);
437}
438
439
440#if QT_CONFIG(tabbar)
441static void drawTabCloseButton(QPainter *p, bool hover, bool selected, bool pressed, bool documentMode)
442{
443 p->setRenderHints(QPainter::Antialiasing);
444 QRect rect(0, 0, closeButtonSize, closeButtonSize);
445 const int width = rect.width();
446 const int height = rect.height();
447
448 if (hover) {
449 // draw background circle
450 QColor background;
451 if (selected) {
452 if (documentMode)
453 background = pressed ? tabBarCloseButtonBackgroundSelectedPressed : tabBarCloseButtonBackgroundSelectedHovered;
454 else
455 background = QColor(255, 255, 255, pressed ? 150 : 100); // Translucent white
456 } else {
457 background = pressed ? tabBarCloseButtonBackgroundPressed : tabBarCloseButtonBackgroundHovered;
458 if (!documentMode)
459 background = background.lighter(pressed ? 135 : 140); // Lighter tab background, lighter color
460 }
461
462 p->setPen(Qt::transparent);
463 p->setBrush(background);
464 p->drawRoundedRect(rect, closeButtonCornerRadius, closeButtonCornerRadius);
465 }
466
467 // draw cross
468 const int margin = 3;
469 QPen crossPen;
470 crossPen.setColor(selected ? (documentMode ? tabBarCloseButtonCrossSelected : Qt::white) : tabBarCloseButtonCross);
471 crossPen.setWidthF(1.1);
472 crossPen.setCapStyle(Qt::FlatCap);
473 p->setPen(crossPen);
474 p->drawLine(margin, margin, width - margin, height - margin);
475 p->drawLine(margin, height - margin, width - margin, margin);
476}
477
479{
480 const auto tabDirection = QMacStylePrivate::tabDirection(shape);
481 if (QMacStylePrivate::verticalTabs(tabDirection)) {
482 int newX, newY, newRot;
483 if (tabDirection == QMacStylePrivate::East) {
484 newX = tabRect.width();
485 newY = tabRect.y();
486 newRot = 90;
487 } else {
488 newX = 0;
489 newY = tabRect.y() + tabRect.height();
490 newRot = -90;
491 }
492 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
494 transform.translate(newX, newY);
495 transform.rotate(newRot);
496 p->setTransform(transform, true);
497 }
498 return tabRect;
499}
500
501void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
502{
503 QRect rect = tabOpt->rect;
504 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
505 rect = rect.adjusted(-tabOverlap, 0, 0, 0);
506 else
507 rect = rect.adjusted(0, -tabOverlap, 0, 0);
508
509 p->translate(rect.x(), rect.y());
510 rect.moveLeft(0);
511 rect.moveTop(0);
512 const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
513
514 const int width = tabRect.width();
515 const int height = tabRect.height();
516 const bool active = (tabOpt->state & QStyle::State_Active);
517 const bool selected = (tabOpt->state & QStyle::State_Selected);
518
519 const QRect bodyRect(1, 2, width - 2, height - 3);
520 const QRect topLineRect(1, 0, width - 2, 1);
521 const QRect bottomLineRect(1, height - 1, width - 2, 1);
522 if (selected) {
523 // fill body
524 if (tabOpt->documentMode && isUnified) {
525 p->save();
526 p->setCompositionMode(QPainter::CompositionMode_Source);
527 p->fillRect(tabRect, QColor(Qt::transparent));
528 p->restore();
529 } else if (active) {
530 p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
531 // top line
532 p->fillRect(topLineRect, tabBarTabLineSelected());
533 } else {
534 p->fillRect(bodyRect, tabBarTabBackgroundSelected());
535 }
536 } else {
537 // when the mouse is over non selected tabs they get a new color
538 const bool hover = (tabOpt->state & QStyle::State_MouseOver);
539 if (hover) {
540 // fill body
541 p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
542 // bottom line
543 p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
544 }
545 }
546
547 // separator lines between tabs
548 const QRect leftLineRect(0, 1, 1, height - 2);
549 const QRect rightLineRect(width - 1, 1, 1, height - 2);
550 const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
551 p->fillRect(leftLineRect, separatorLineColor);
552 p->fillRect(rightLineRect, separatorLineColor);
553}
554
555void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb, const QWidget *w)
556{
557 QRect r = tbb->rect;
558 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tbb->shape)))
559 r.setWidth(w->width());
560 else
561 r.setHeight(w->height());
562
563 const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
564 const int width = tabRect.width();
565 const int height = tabRect.height();
566 const bool active = (tbb->state & QStyle::State_Active);
567
568 // fill body
569 const QRect bodyRect(0, 1, width, height - 1);
570 const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
571 p->fillRect(bodyRect, bodyColor);
572
573 // top line
574 const QRect topLineRect(0, 0, width, 1);
575 const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
576 p->fillRect(topLineRect, topLineColor);
577
578 // bottom line
579 const QRect bottomLineRect(0, height - 1, width, 1);
580 bool isDocument = false;
581 if (const QTabBar *tabBar = qobject_cast<const QTabBar*>(w))
582 isDocument = tabBar->documentMode();
583 const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
584 p->fillRect(bottomLineRect, bottomLineColor);
585}
586#endif
587
589{
591 if (wsp == QStyleHelper::SizeDefault)
593
594 return wsp;
595}
596
597#if QT_CONFIG(treeview)
598static inline bool isTreeView(const QWidget *widget)
599{
600 return (widget && widget->parentWidget() &&
601 qobject_cast<const QTreeView *>(widget->parentWidget()));
602}
603#endif
604
606{
607 QString returnText(original.size(), QChar(0));
608 int finalDest = 0;
609 int currPos = 0;
610 int l = original.length();
611 while (l) {
612 if (original.at(currPos) == QLatin1Char('&')) {
613 ++currPos;
614 --l;
615 if (l == 0)
616 break;
617 } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 &&
618 original.at(currPos + 1) == QLatin1Char('&') &&
619 original.at(currPos + 2) != QLatin1Char('&') &&
620 original.at(currPos + 3) == QLatin1Char(')')) {
621 /* remove mnemonics its format is "\s*(&X)" */
622 int n = 0;
623 while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
624 ++n;
625 finalDest -= n;
626 currPos += 4;
627 l -= 4;
628 continue;
629 }
630 returnText[finalDest] = original.at(currPos);
631 ++currPos;
632 ++finalDest;
633 --l;
634 }
635 returnText.truncate(finalDest);
636 return returnText;
637}
638
640{
641 if (QWindow *w = window->windowHandle()) {
642 if (w->handle()) {
643 if (NSWindow *nswindow = static_cast<NSWindow*>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("nswindow"), w))) {
644 return [nswindow isMainWindow];
645 }
646 }
647 }
648 return false;
649}
650
651/*****************************************************************************
652 QMacCGStyle globals
653 *****************************************************************************/
654const int macItemFrame = 2; // menu item frame width
655const int macItemHMargin = 3; // menu item hor text margin
656const int macRightBorder = 12; // right border on mac
657
658/*****************************************************************************
659 QMacCGStyle utility functions
660 *****************************************************************************/
661
705
706static const int qt_mac_aqua_metrics[] = {
707 // Values as of macOS 10.12.4 and Xcode 8.3.1
708 18 /* CheckBoxHeight */,
709 18 /* CheckBoxWidth */,
710 1 /* EditTextFrameOutset */,
711 4 /* FocusRectOutset */,
712 22 /* HSliderHeight */,
713 5 /* HSliderTickHeight */,
714 16 /* LargeProgressBarThickness */,
715 17 /* ListHeaderHeight */,
716 12 /* MenuSeparatorHeight, aka GetThemeMenuSeparatorHeight */,
717 11 /* MiniCheckBoxHeight */,
718 10 /* MiniCheckBoxWidth */,
719 12 /* MiniHSliderHeight */,
720 4 /* MiniHSliderTickHeight */,
721 15 /* MiniPopupButtonHeight */,
722 16 /* MiniPushButtonHeight */,
723 11 /* MiniRadioButtonHeight */,
724 10 /* MiniRadioButtonWidth */,
725 4 /* MiniVSliderTickWidth */,
726 12 /* MiniVSliderWidth */,
727 12 /* NormalProgressBarThickness */,
728 20 /* PopupButtonHeight */,
729 4 /* ProgressBarShadowOutset */,
730 20 /* PushButtonHeight */,
731 18 /* RadioButtonHeight */,
732 18 /* RadioButtonWidth */,
733 1 /* SeparatorSize */,
734 16 /* SmallCheckBoxHeight */,
735 14 /* SmallCheckBoxWidth */,
736 15 /* SmallHSliderHeight */,
737 4 /* SmallHSliderTickHeight */,
738 17 /* SmallPopupButtonHeight */,
739 2 /* SmallProgressBarShadowOutset */,
740 17 /* SmallPushButtonHeight */,
741 15 /* SmallRadioButtonHeight */,
742 14 /* SmallRadioButtonWidth */,
743 4 /* SmallVSliderTickWidth */,
744 15 /* SmallVSliderWidth */,
745 5 /* VSliderTickWidth */,
746 22 /* VSliderWidth */
747};
748
750{
751 return qt_mac_aqua_metrics[m];
752}
753
755 const QWidget *widg, QSize szHint,
757{
758 QSize ret(-1, -1);
760 qDebug("Not sure how to return this...");
761 return ret;
762 }
763 if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
764 // If you're using a custom font and it's bigger than the default font,
765 // then no constraints for you. If you are smaller, we can try to help you out
766 QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
767 if (widg->font().pointSize() > font.pointSize())
768 return ret;
769 }
770
772
773 if (ct == QStyle::CT_CustomBase && widg) {
774#if QT_CONFIG(pushbutton)
775 if (qobject_cast<const QPushButton *>(widg))
777#endif
778 else if (qobject_cast<const QRadioButton *>(widg))
780#if QT_CONFIG(checkbox)
781 else if (qobject_cast<const QCheckBox *>(widg))
783#endif
784#if QT_CONFIG(combobox)
785 else if (qobject_cast<const QComboBox *>(widg))
787#endif
788#if QT_CONFIG(toolbutton)
789 else if (qobject_cast<const QToolButton *>(widg))
791#endif
792 else if (qobject_cast<const QSlider *>(widg))
794#if QT_CONFIG(progressbar)
795 else if (qobject_cast<const QProgressBar *>(widg))
797#endif
798#if QT_CONFIG(lineedit)
799 else if (qobject_cast<const QLineEdit *>(widg))
801#endif
802#if QT_CONFIG(itemviews)
803 else if (qobject_cast<const QHeaderView *>(widg))
805#endif
806#if QT_CONFIG(menubar)
807 else if (qobject_cast<const QMenuBar *>(widg))
809#endif
810#if QT_CONFIG(sizegrip)
811 else if (qobject_cast<const QSizeGrip *>(widg))
813#endif
814 else
815 return ret;
816 }
817
818 switch (ct) {
819#if QT_CONFIG(pushbutton)
821 const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt);
822 if (btn) {
823 QString buttonText = qt_mac_removeMnemonics(btn->text);
824 if (buttonText.contains(QLatin1Char('\n')))
825 ret = QSize(-1, -1);
826 else if (sz == QStyleHelper::SizeLarge)
828 else if (sz == QStyleHelper::SizeSmall)
830 else if (sz == QStyleHelper::SizeMini)
832
833 if (!btn->icon.isNull()){
834 // If the button got an icon, and the icon is larger than the
835 // button, we can't decide on a default size
836 ret.setWidth(-1);
837 if (ret.height() < btn->iconSize.height())
838 ret.setHeight(-1);
839 }
840 else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
841 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
842 // However, this doesn't work for German, therefore only do it for English,
843 // I suppose it would be better to do some sort of lookups for languages
844 // that like to have really long words.
845 // FIXME This is not exactly true. Out of context, OK buttons have their
846 // implicit size calculated the same way as any other button. Inside a
847 // QDialogButtonBox, their size should be calculated such that the action
848 // or accept button (i.e., rightmost) and cancel button have the same width.
849 ret.setWidth(69);
850 }
851 }
852#endif
853#if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
854 } else if (ct == QStyle::CT_RadioButton) {
855 QRadioButton *rdo = static_cast<QRadioButton *>(widg);
856 // Exception for case where multiline radio button text requires no size constrainment
857 if (rdo->text().find('\n') != -1)
858 return ret;
859 if (sz == QStyleHelper::SizeLarge)
861 else if (sz == QStyleHelper::SizeSmall)
863 else if (sz == QStyleHelper::SizeMini)
865 } else if (ct == QStyle::CT_CheckBox) {
866 if (sz == QStyleHelper::SizeLarge)
868 else if (sz == QStyleHelper::SizeSmall)
870 else if (sz == QStyleHelper::SizeMini)
872#endif
873 break;
874 }
876 // Not HIG kosher: mimic what we were doing earlier until we support 4-edge resizing in MDI subwindows
878 int s = sz == QStyleHelper::SizeSmall ? 16 : 22; // large: pixel measured from HITheme, small: from my hat
879 int width = 0;
880#if QT_CONFIG(mdiarea)
881 if (widg && qobject_cast<QMdiSubWindow *>(widg->parentWidget()))
882 width = s;
883#endif
884 ret = QSize(width, s);
885 }
886 break;
888 switch (sz) {
891 break;
894 break;
897 break;
898 default:
899 break;
900 }
901 break;
903 if (sz == QStyleHelper::SizeSmall) {
904 int width = 0, height = 0;
905 if (szHint == QSize(-1, -1)) { //just 'guess'..
906#if QT_CONFIG(toolbutton)
907 const QStyleOptionToolButton *bt = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
908 // If this conversion fails then the widget was not what it claimed to be.
909 if (bt) {
910 if (!bt->icon.isNull()) {
911 QSize iconSize = bt->iconSize;
912 QSize pmSize = bt->icon.actualSize(QSize(32, 32), QIcon::Normal);
913 width = qMax(width, qMax(iconSize.width(), pmSize.width()));
914 height = qMax(height, qMax(iconSize.height(), pmSize.height()));
915 }
916 if (!bt->text.isNull() && bt->toolButtonStyle != Qt::ToolButtonIconOnly) {
917 int text_width = bt->fontMetrics.horizontalAdvance(bt->text),
918 text_height = bt->fontMetrics.height();
919 if (bt->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
920 width = qMax(width, text_width);
921 height += text_height;
922 } else {
923 width += text_width;
924 width = qMax(height, text_height);
925 }
926 }
927 } else
928#endif
929 {
930 // Let's return the size hint...
931 width = szHint.width();
932 height = szHint.height();
933 }
934 } else {
935 width = szHint.width();
936 height = szHint.height();
937 }
938 width = qMax(20, width + 5); //border
939 height = qMax(20, height + 5); //border
940 ret = QSize(width, height);
941 }
942 break;
943 case QStyle::CT_Slider: {
944 int w = -1;
945 const QStyleOptionSlider *sld = qstyleoption_cast<const QStyleOptionSlider *>(opt);
946 // If this conversion fails then the widget was not what it claimed to be.
947 if (sld) {
948 if (sz == QStyleHelper::SizeLarge) {
949 if (sld->orientation == Qt::Horizontal) {
951 if (sld->tickPosition != QSlider::NoTicks)
953 else if (isBigSurOrAbove)
954 w += 3;
955 } else {
957 if (sld->tickPosition != QSlider::NoTicks)
959 }
960 } else if (sz == QStyleHelper::SizeSmall) {
961 if (sld->orientation == Qt::Horizontal) {
963 if (sld->tickPosition != QSlider::NoTicks)
965 } else {
967 if (sld->tickPosition != QSlider::NoTicks)
969 }
970 } else if (sz == QStyleHelper::SizeMini) {
971 if (sld->orientation == Qt::Horizontal) {
973 if (sld->tickPosition != QSlider::NoTicks)
975 } else {
977 if (sld->tickPosition != QSlider::NoTicks)
979 }
980 }
981 } else {
982 // This is tricky, we were requested to find a size for a slider which is not
983 // a slider. We don't know if this is vertical or horizontal or if we need to
984 // have tick marks or not.
985 // For this case we will return an horizontal slider without tick marks.
988 }
989 if (sld->orientation == Qt::Horizontal)
990 ret.setHeight(w);
991 else
992 ret.setWidth(w);
993 break;
994 }
995#if QT_CONFIG(progressbar)
997 int finalValue = -1;
999 if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
1000 orient = pb->orientation();
1001
1002 if (sz == QStyleHelper::SizeLarge)
1005 else
1008 if (orient == Qt::Horizontal)
1009 ret.setHeight(finalValue);
1010 else
1011 ret.setWidth(finalValue);
1012 break;
1013 }
1014#endif
1015#if QT_CONFIG(combobox)
1017 if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
1018 //should I take into account the font dimensions of the lineedit? -Sam
1019 if (sz == QStyleHelper::SizeLarge)
1020 ret = QSize(-1, 21);
1021 else
1022 ret = QSize(-1, 19);
1023 }
1024 break;
1025#endif
1027#if QT_CONFIG(treeview)
1028 if (isTreeView(widg))
1030#endif
1031 break;
1032 case QStyle::CT_MenuBar:
1033 if (sz == QStyleHelper::SizeLarge) {
1034 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
1035 // In the qt_mac_set_native_menubar(false) case,
1036 // we come it here with a zero-height main menu,
1037 // preventing the in-window menu from displaying.
1038 // Use 22 pixels for the height, by observation.
1039 if (ret.height() <= 0)
1040 ret.setHeight(22);
1041 }
1042 break;
1043 default:
1044 break;
1045 }
1046 return ret;
1047}
1048
1049
1050#if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1052{
1053 Q_UNUSED(widg);
1054
1055 if (large == QSize(-1, -1)) {
1056 if (small != QSize(-1, -1))
1058 if (mini != QSize(-1, -1))
1061 } else if (small == QSize(-1, -1)) {
1062 if (mini != QSize(-1, -1))
1065 } else if (mini == QSize(-1, -1)) {
1067 }
1068
1069 if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL"))
1071 else if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI"))
1073
1075}
1076#endif
1077
1078void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
1079{
1081
1082 QPainterPath focusRingPath;
1083 focusRingPath.setFillRule(Qt::OddEvenFill);
1084
1085 qreal hOffset = 0.0;
1086 qreal vOffset = 0.0;
1087 switch (cw.type) {
1088 case Box:
1089 case Button_SquareButton:
1090 case SegmentedControl_Middle:
1091 case TextField: {
1092 auto innerRect = targetRect;
1093 if (cw.type == Button_SquareButton)
1094 innerRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
1095 if (cw.type == TextField)
1096 innerRect = innerRect.adjusted(hMargin, vMargin, -hMargin, -vMargin).adjusted(0.5, 0.5, -0.5, -0.5);
1097 const auto outerRect = innerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1098 const auto outerRadius = focusRingWidth;
1099 focusRingPath.addRect(innerRect);
1100 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1101 break;
1102 }
1103 case Button_CheckBox: {
1104 const auto cbInnerRadius = (cw.size == QStyleHelper::SizeMini ? 2.0 : 3.0);
1105 const auto cbSize = cw.size == QStyleHelper::SizeLarge ? 13 :
1106 cw.size == QStyleHelper::SizeSmall ? 11 : 9; // As measured
1107 hOffset = hMargin + (cw.size == QStyleHelper::SizeLarge ? 2.5 :
1108 cw.size == QStyleHelper::SizeSmall ? 2.0 : 1.0); // As measured
1109 vOffset = 0.5 * qreal(targetRect.height() - cbSize);
1110 const auto cbInnerRect = QRectF(0, 0, cbSize, cbSize);
1111 const auto cbOuterRadius = cbInnerRadius + focusRingWidth;
1112 const auto cbOuterRect = cbInnerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1113 focusRingPath.addRoundedRect(cbOuterRect, cbOuterRadius, cbOuterRadius);
1114 focusRingPath.addRoundedRect(cbInnerRect, cbInnerRadius, cbInnerRadius);
1115 break;
1116 }
1117 case Button_RadioButton: {
1118 const auto rbSize = cw.size == QStyleHelper::SizeLarge ? 15 :
1119 cw.size == QStyleHelper::SizeSmall ? 13 : 9; // As measured
1120 hOffset = hMargin + (cw.size == QStyleHelper::SizeLarge ? 1.5 :
1121 cw.size == QStyleHelper::SizeSmall ? 1.0 : 1.0); // As measured
1122 vOffset = 0.5 * qreal(targetRect.height() - rbSize);
1123 const auto rbInnerRect = QRectF(0, 0, rbSize, rbSize);
1124 const auto rbOuterRect = rbInnerRect.adjusted(-focusRingWidth, -focusRingWidth, focusRingWidth, focusRingWidth);
1125 focusRingPath.addEllipse(rbInnerRect);
1126 focusRingPath.addEllipse(rbOuterRect);
1127 break;
1128 }
1129 case Button_PullDown:
1130 case Button_PushButton: {
1131 QRectF focusRect;
1132 auto *pb = static_cast<NSButton *>(cocoaControl(cw));
1133 const QRectF frameRect = cw.adjustedControlFrame(targetRect.adjusted(hMargin, vMargin, -hMargin, -vMargin));
1134 pb.frame = frameRect.toCGRect();
1135 focusRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]);
1137 focusRect -= pushButtonShadowMargins[cw.size];
1138 if (cw.size == QStyleHelper::SizeMini)
1139 focusRect.adjust(0, 3, 0, -3);
1140 } else if (cw.type == QMacStylePrivate::Button_PullDown) {
1141 focusRect -= pullDownButtonShadowMargins[cw.size];
1142 //fix focus ring drawn slightly off for pull downs
1143 if (cw.size == QStyleHelper::SizeLarge)
1144 focusRect = focusRect.adjusted(0, 0, 0, -1);
1145 else if (cw.size == QStyleHelper::SizeMini)
1146 focusRect = focusRect.adjusted(0, -1, 0, 0);
1147 }
1148 if (isBigSurOrAbove)
1149 focusRect = focusRect.translated(0, 1);
1150 const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
1151 const qreal outerRadius = innerRadius + focusRingWidth;
1152 hOffset = focusRect.left();
1153 vOffset = focusRect.top();
1154 const auto innerRect = focusRect.translated(-focusRect.topLeft());
1155 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1156 focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
1157 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1158 break;
1159 }
1160 case Button_PopupButton:
1161 case SegmentedControl_Single: {
1162 QRectF focusRect = targetRect;
1163 if (isBigSurOrAbove)
1164 focusRect.translate(0, -1.5);
1166 focusRect.adjust(0, 0, 0, -1);
1167 const qreal innerRadius = cw.type == Button_PushButton ? 3 : 4;
1168 const qreal outerRadius = innerRadius + focusRingWidth;
1169 hOffset = focusRect.left();
1170 vOffset = focusRect.top();
1171 const auto innerRect = focusRect.translated(-focusRect.topLeft());
1172 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1173 focusRingPath.addRoundedRect(innerRect, innerRadius, innerRadius);
1174 focusRingPath.addRoundedRect(outerRect, outerRadius, outerRadius);
1175 break;
1176 }
1177 case ComboBox:
1178 case SegmentedControl_First:
1179 case SegmentedControl_Last: {
1180 hOffset = targetRect.left();
1181 vOffset = targetRect.top();
1182 const qreal innerRadius = 8;
1183 const qreal outerRadius = innerRadius + focusRingWidth;
1184 const auto innerRect = targetRect.translated(-targetRect.topLeft());
1185 const auto outerRect = innerRect.adjusted(-hMargin, -vMargin, hMargin, vMargin);
1186
1187 const auto cbFocusFramePath = [](const QRectF &rect, qreal tRadius, qreal bRadius) {
1189
1190 if (tRadius > 0) {
1191 const auto topLeftCorner = QRectF(rect.topLeft(), QSizeF(tRadius, tRadius));
1192 path.arcMoveTo(topLeftCorner, 180);
1193 path.arcTo(topLeftCorner, 180, -90);
1194 } else {
1195 path.moveTo(rect.topLeft());
1196 }
1197 const auto rightEdge = rect.right() - bRadius;
1198 path.arcTo(rightEdge, rect.top(), bRadius, bRadius, 90, -90);
1199 path.arcTo(rightEdge, rect.bottom() - bRadius, bRadius, bRadius, 0, -90);
1200 if (tRadius > 0)
1201 path.arcTo(rect.left(), rect.bottom() - tRadius, tRadius, tRadius, 270, -90);
1202 else
1203 path.lineTo(rect.bottomLeft());
1204 path.closeSubpath();
1205
1206 return path;
1207 };
1208
1209 const auto innerPath = cbFocusFramePath(innerRect, 0, innerRadius);
1210 focusRingPath.addPath(innerPath);
1211 const auto outerPath = cbFocusFramePath(outerRect, 2 * focusRingWidth, outerRadius);
1212 focusRingPath.addPath(outerPath);
1213 break;
1214 }
1215 default:
1216 Q_UNREACHABLE();
1217 }
1218
1219 auto focusRingColor = qt_mac_toQColor(NSColor.keyboardFocusIndicatorColor.CGColor);
1220 if (!isDarkMode()) {
1221 // This color already has alpha ~ 0.25, this value is too small - the ring is
1222 // very pale and nothing like the native one. 0.39 makes it better (not ideal
1223 // anyway). The color seems to be correct in dark more without any modification.
1224 focusRingColor.setAlphaF(0.39);
1225 }
1226
1227 p->save();
1228 p->setRenderHint(QPainter::Antialiasing);
1229
1230 if (cw.type == SegmentedControl_First) {
1231 // TODO Flip left-right
1232 }
1233 p->translate(hOffset, vOffset);
1234 p->fillPath(focusRingPath, focusRingColor);
1235 p->restore();
1236}
1237
1239{
1240 static const qreal CornerPointOffset = 5.5;
1241 static const qreal CornerControlOffset = 2.1;
1242
1244 // Top-left corner
1245 path.moveTo(r.left(), r.top() + CornerPointOffset);
1246 path.cubicTo(r.left(), r.top() + CornerControlOffset,
1247 r.left() + CornerControlOffset, r.top(),
1248 r.left() + CornerPointOffset, r.top());
1249 // Top-right corner
1250 path.lineTo(r.right() - CornerPointOffset, r.top());
1251 path.cubicTo(r.right() - CornerControlOffset, r.top(),
1252 r.right(), r.top() + CornerControlOffset,
1253 r.right(), r.top() + CornerPointOffset);
1254 // Bottom-right corner
1255 path.lineTo(r.right(), r.bottom() - CornerPointOffset);
1256 path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
1257 r.right() - CornerControlOffset, r.bottom(),
1258 r.right() - CornerPointOffset, r.bottom());
1259 // Bottom-right corner
1260 path.lineTo(r.left() + CornerPointOffset, r.bottom());
1261 path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
1262 r.left(), r.bottom() - CornerControlOffset,
1263 r.left(), r.bottom() - CornerPointOffset);
1264 path.lineTo(r.left(), r.top() + CornerPointOffset);
1265
1266 return path;
1267}
1268
1270{
1271 struct WindowButtons {
1274 };
1275
1276 static const WindowButtons buttons[] = {
1280 };
1281
1282 for (const auto &wb : buttons)
1283 if (wb.sc == sc)
1284 return wb.ct;
1285
1286 return NoControl;
1287}
1288
1289
1290#if QT_CONFIG(tabbar)
1291void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const
1292{
1294 Q_ASSERT(iconRect);
1295 QRect tr = opt->rect;
1296 const bool verticalTabs = opt->shape == QTabBar::RoundedEast
1297 || opt->shape == QTabBar::RoundedWest
1298 || opt->shape == QTabBar::TriangularEast
1299 || opt->shape == QTabBar::TriangularWest;
1300 if (verticalTabs)
1301 tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
1302
1303 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget);
1304 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget);
1305 const int hpadding = 4;
1306 const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2;
1307 if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth)
1308 verticalShift = -verticalShift;
1309 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
1310
1311 // left widget
1312 if (!opt->leftButtonSize.isEmpty()) {
1313 const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
1314 tr.setLeft(tr.left() + 4 + buttonSize);
1315 // make text aligned to center
1316 if (opt->rightButtonSize.isEmpty())
1317 tr.setRight(tr.right() - 4 - buttonSize);
1318 }
1319 // right widget
1320 if (!opt->rightButtonSize.isEmpty()) {
1321 const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
1322 tr.setRight(tr.right() - 4 - buttonSize);
1323 // make text aligned to center
1324 if (opt->leftButtonSize.isEmpty())
1325 tr.setLeft(tr.left() + 4 + buttonSize);
1326 }
1327
1328 // icon
1329 if (!opt->icon.isNull()) {
1331 if (!iconSize.isValid()) {
1332 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
1333 iconSize = QSize(iconExtent, iconExtent);
1334 }
1335 QSize tabIconSize = opt->icon.actualSize(iconSize,
1337 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
1338 // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
1339 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
1340
1341 const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2 - hpadding;
1342
1343 if (opt->documentMode) {
1344 // documents show the icon as part of the the text
1345 const int textWidth =
1347 *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
1348 tr.center().y() - tabIconSize.height() / 2,
1349 tabIconSize.width(), tabIconSize.height());
1350 } else {
1351 *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
1352 tabIconSize.width(), tabIconSize.height());
1353 }
1354 if (!verticalTabs)
1355 *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
1356
1357 tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
1358 tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
1359 }
1360
1361 if (!verticalTabs)
1362 tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
1363
1364 *textRect = tr;
1365}
1366
1367QMacStylePrivate::Direction QMacStylePrivate::tabDirection(QTabBar::Shape shape)
1368{
1369 switch (shape) {
1372 return South;
1375 return North;
1378 return West;
1381 return East;
1382 }
1383}
1384
1385bool QMacStylePrivate::verticalTabs(QMacStylePrivate::Direction direction)
1386{
1389}
1390
1391#endif // QT_CONFIG(tabbar)
1392
1394 const QWidget *widg,
1396 QSize szHint, QSize *insz) const
1397{
1398 QStyleHelper::WidgetSizePolicy sz = aquaSizeConstrain(option, widg, ct, szHint, insz);
1399 if (sz == QStyleHelper::SizeDefault)
1401 return sz;
1402}
1403
1405 QStyle::ContentsType ct, QSize szHint, QSize *insz) const
1406{
1407#if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1408 if (option) {
1409 if (option->state & QStyle::State_Small)
1411 if (option->state & QStyle::State_Mini)
1413 }
1414
1415 if (!widg) {
1416 if (insz)
1417 *insz = QSize();
1418 if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL"))
1420 if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI"))
1423 }
1424
1425 QSize large = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeLarge),
1426 small = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeSmall),
1427 mini = qt_aqua_get_known_size(ct, option, widg, szHint, QStyleHelper::SizeMini);
1428 bool guess_size = false;
1431 if (wsp == QStyleHelper::SizeDefault)
1432 guess_size = true;
1433 else if (wsp == QStyleHelper::SizeMini)
1435 else if (wsp == QStyleHelper::SizeSmall)
1437 else if (wsp == QStyleHelper::SizeLarge)
1439 if (guess_size)
1440 ret = qt_aqua_guess_size(widg, large, small, mini);
1441
1442 QSize *sz = nullptr;
1444 sz = &small;
1445 else if (ret == QStyleHelper::SizeLarge)
1446 sz = &large;
1447 else if (ret == QStyleHelper::SizeMini)
1448 sz = &mini;
1449 if (insz)
1450 *insz = sz ? *sz : QSize(-1, -1);
1451#ifdef DEBUG_SIZE_CONSTRAINT
1452 if (sz) {
1453 const char *size_desc = "Unknown";
1454 if (sz == &small)
1455 size_desc = "Small";
1456 else if (sz == &large)
1457 size_desc = "Large";
1458 else if (sz == &mini)
1459 size_desc = "Mini";
1460 qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
1461 widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
1462 widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
1463 sz->width(), sz->height());
1464 }
1465#endif
1466 return ret;
1467#else
1468 if (insz)
1469 *insz = QSize();
1470 Q_UNUSED(widg);
1471 Q_UNUSED(ct);
1472 Q_UNUSED(szHint);
1474#endif
1475}
1476
1478{
1479 return ((cw.type << 2) | cw.size) ^ seed;
1480}
1481
1483 : type(NoControl), size(QStyleHelper::SizeDefault)
1484{
1485}
1486
1491
1493{
1494 return other.type == type && other.size == size;
1495}
1496
1498{
1499 // We need this because things like NSView.alignmentRectInsets
1500 // or -[NSCell titleRectForBounds:] won't work unless the control
1501 // has a reasonable frame set. IOW, it's a chicken and egg problem.
1502 // These values are as observed in Xcode 9's Interface Builder.
1503
1504 if (type == Button_PushButton)
1505 return QSizeF(-1, pushButtonDefaultHeight[size]);
1506
1508 || type == Button_PullDown)
1510
1511 if (type == ComboBox)
1512 return QSizeF(-1, comboBoxDefaultHeight[size]);
1513
1514 return QSizeF();
1515}
1516
1518{
1519 QRectF frameRect;
1520 const auto frameSize = defaultFrameSize();
1522 frameRect = rect.adjusted(3, 1, -3, -1)
1524 .adjusted(-6.5, 0, 6.5, 0);
1526 // Start from the style option's top-left corner.
1527 frameRect = QRectF(rect.topLeft(),
1528 QSizeF(rect.width(), frameSize.height()));
1530 frameRect.translate(0, 0.5);
1531 else if (size == QStyleHelper::SizeMini)
1532 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, -0.5);
1533 frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0,
1535 } else {
1536 // Center in the style option's rect.
1537 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1538 QSizeF(rect.width(), frameSize.height()));
1539 frameRect = frameRect.translated(rect.topLeft());
1542 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1543 else if (size == QStyleHelper::SizeSmall)
1544 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1545 else if (size == QStyleHelper::SizeMini)
1546 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1548 frameRect = frameRect.adjusted(-pushButtonBevelRectOffsets[size], 0,
1550 } else if (type == QMacStylePrivate::ComboBox) {
1551 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1552 }
1553 }
1554
1555 return frameRect;
1556}
1557
1559{
1562 return QMarginsF(12, 5, 12, 9);
1564 return QMarginsF(12, 4, 12, 9);
1566 return QMarginsF(10, 1, 10, 2);
1567 }
1568
1571 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1573 return QMarginsF(7.5, 2, 20.5, 4);
1575 return QMarginsF(4.5, 0, 16.5, 2);
1576 }
1577
1579 return QMarginsF(6, 1, 6, 2);
1580
1581 return QMarginsF();
1582}
1583
1584bool QMacStylePrivate::CocoaControl::getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const
1585{
1586 switch (type) {
1587 case Button_CheckBox:
1588 *buttonType = NSButtonTypeSwitch;
1589 *bezelStyle = NSBezelStyleRegularSquare;
1590 break;
1591 case Button_Disclosure:
1592 *buttonType = NSButtonTypeOnOff;
1593 *bezelStyle = NSBezelStyleDisclosure;
1594 break;
1595 case Button_RadioButton:
1596 *buttonType = NSButtonTypeRadio;
1597 *bezelStyle = NSBezelStyleRegularSquare;
1598 break;
1600 *buttonType = NSButtonTypePushOnPushOff;
1601 *bezelStyle = NSBezelStyleShadowlessSquare;
1602 break;
1603 case Button_PushButton:
1604 *buttonType = NSButtonTypeMomentaryPushIn;
1605 *bezelStyle = NSBezelStyleRounded;
1606 break;
1607 default:
1608 return false;
1609 }
1610
1611 return true;
1612}
1613
1615{
1616 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1617 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
1618 // Buttons that don't fit (or don't get filled by) the default bevel
1619 // will be made of square type, unless WA_MacNormalSize is not set.
1620 // Threshold used to be at 34, not 32.
1621 // Needs to be in sync with similar logic in CE_FocusFrame handling
1623 if (sizePolicy == QStyleHelper::SizeDefault)
1624 sizePolicy = QStyleHelper::SizeLarge;
1625 const bool isSquare = (btn->features & QStyleOptionButton::Flat)
1626 || (btn->rect.height() != pushButtonDefaultHeight[sizePolicy]);
1627 return (isSquare? QMacStylePrivate::Button_SquareButton :
1630 }
1631
1632 if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1633 if (combo->editable)
1635 // TODO Me may support square, non-editable combo boxes, but not more than that
1637 }
1638
1640}
1641
1646CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget)
1647{
1648 CGRect innerBounds = outerBounds;
1649 // Carbon draw parts of the view outside the rect.
1650 // So make the rect a bit smaller to compensate
1651 // (I wish HIThemeGetButtonBackgroundBounds worked)
1652 if (cocoaWidget.type == Button_PopupButton) {
1653 switch (cocoaWidget.size) {
1655 innerBounds.origin.x += 3;
1656 innerBounds.origin.y += 3;
1657 innerBounds.size.width -= 6;
1658 innerBounds.size.height -= 7;
1659 break;
1661 innerBounds.origin.x += 2;
1662 innerBounds.origin.y += 2;
1663 innerBounds.size.width -= 5;
1664 innerBounds.size.height -= 6;
1665 break;
1668 innerBounds.origin.x += 2;
1669 innerBounds.origin.y += 2;
1670 innerBounds.size.width -= 5;
1671 innerBounds.size.height -= 6;
1672 }
1673 } else if (cocoaWidget.type == ComboBox) {
1674 switch (cocoaWidget.size) {
1676 innerBounds.origin.x += 3;
1677 innerBounds.origin.y += 3;
1678 innerBounds.size.width -= 7;
1679 innerBounds.size.height -= 8;
1680 break;
1682 innerBounds.origin.x += 3;
1683 innerBounds.origin.y += 3;
1684 innerBounds.size.width -= 4;
1685 innerBounds.size.height -= 8;
1686 break;
1689 innerBounds.origin.x += 3;
1690 innerBounds.origin.y += 2;
1691 innerBounds.size.width -= 6;
1692 innerBounds.size.height -= 8;
1693 }
1694 }
1695
1696 return innerBounds;
1697}
1698
1704{
1705 QRectF ret = outerBounds;
1706 if (cw.type == ComboBox) {
1707 switch (cw.size) {
1709 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1710 ret.setHeight(16);
1711 break;
1713 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1714 ret.setHeight(14);
1715 break;
1717 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1718 ret.setHeight(10.5);
1719 break;
1720 default:
1721 break;
1722 }
1723 } else if (cw.type == Button_PopupButton) {
1724 switch (cw.size) {
1726 ret.adjust(10, 1, -23, -4);
1727 break;
1729 ret.adjust(10, 4, -20, -3);
1730 break;
1732 ret.adjust(9, 0, -19, 0);
1733 ret.setHeight(13);
1734 break;
1735 default:
1736 break;
1737 }
1738 }
1739 return ret;
1740}
1741
1746
1748{
1750 for (NSView *b : cocoaControls)
1751 [b release];
1752 for (NSCell *cell : cocoaCells)
1753 [cell release];
1754}
1755
1757{
1760 return nil;
1761
1762 if (widget.type == Box && isDarkMode()) {
1763 // See render code in drawPrimitive(PE_FrameTabWidget)
1764 widget.type = Box_Dark;
1765 }
1766
1767 NSView *bv = cocoaControls.value(widget, nil);
1768 if (!bv) {
1769 switch (widget.type) {
1770 case Box: {
1771 NSBox *box = [[NSBox alloc] init];
1772 bv = box;
1773 box.title = @"";
1774 box.titlePosition = NSNoTitle;
1775 break;
1776 }
1777 case Box_Dark:
1778 bv = [[QDarkNSBox alloc] init];
1779 break;
1780 case Button_CheckBox:
1781 case Button_Disclosure:
1782 case Button_PushButton:
1783 case Button_RadioButton:
1784 case Button_SquareButton: {
1785 NSButton *bc = [[NSButton alloc] init];
1786 bc.title = @"";
1787 // See below for style and bezel setting.
1788 bv = bc;
1789 break;
1790 }
1791 case Button_PopupButton:
1792 case Button_PullDown: {
1793 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1794 bc.title = @"";
1795 if (widget.type == Button_PullDown)
1796 bc.pullsDown = YES;
1797 bv = bc;
1798 break;
1799 }
1800 case Button_WindowClose:
1802 case Button_WindowZoom: {
1803 const NSWindowButton button = [=] {
1804 switch (widget.type) {
1805 case Button_WindowClose:
1806 return NSWindowCloseButton;
1808 return NSWindowMiniaturizeButton;
1809 case Button_WindowZoom:
1810 return NSWindowZoomButton;
1811 default:
1812 break;
1813 }
1814 Q_UNREACHABLE();
1815 } ();
1816 const auto styleMask = NSWindowStyleMaskTitled
1817 | NSWindowStyleMaskClosable
1818 | NSWindowStyleMaskMiniaturizable
1819 | NSWindowStyleMaskResizable;
1820 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1821 [bv retain];
1822 break;
1823 }
1824 case ComboBox:
1825 bv = [[NSComboBox alloc] init];
1826 break;
1828 bv = [[NSProgressIndicator alloc] init];
1829 break;
1831 bv = [[QIndeterminateProgressIndicator alloc] init];
1832 break;
1834 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1835 break;
1836 case Scroller_Vertical:
1837 // Cocoa sets the orientation from the view's frame
1838 // at construction time, and it cannot be changed later.
1839 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1840 break;
1841 case Slider_Horizontal:
1842 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1843 break;
1844 case Slider_Vertical:
1845 // Cocoa sets the orientation from the view's frame
1846 // at construction time, and it cannot be changed later.
1847 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1848 break;
1850 bv = [[NSSplitView alloc] init];
1851 break;
1852 case SplitView_Vertical:
1853 bv = [[QVerticalSplitView alloc] init];
1854 break;
1855 case TextField:
1856 bv = [[NSTextField alloc] init];
1857 break;
1858 default:
1859 break;
1860 }
1861
1862 if ([bv isKindOfClass:[NSControl class]]) {
1863 auto *ctrl = static_cast<NSControl *>(bv);
1864 switch (widget.size) {
1866 ctrl.controlSize = NSControlSizeSmall;
1867 break;
1869 ctrl.controlSize = NSControlSizeMini;
1870 break;
1871 default:
1872 break;
1873 }
1874 } else if (widget.type == ProgressIndicator_Determinate ||
1876 auto *pi = static_cast<NSProgressIndicator *>(bv);
1877 pi.indeterminate = (widget.type == ProgressIndicator_Indeterminate);
1878 switch (widget.size) {
1880 pi.controlSize = NSControlSizeSmall;
1881 break;
1883 pi.controlSize = NSControlSizeMini;
1884 break;
1885 default:
1886 break;
1887 }
1888 }
1889
1890 cocoaControls.insert(widget, bv);
1891 }
1892
1893 NSButtonType buttonType;
1894 NSBezelStyle bezelStyle;
1895 if (widget.getCocoaButtonTypeAndBezelStyle(&buttonType, &bezelStyle)) {
1896 // FIXME We need to reset the button's type and
1897 // bezel style properties, even when cached.
1898 auto *button = static_cast<NSButton *>(bv);
1899 button.buttonType = buttonType;
1900 button.bezelStyle = bezelStyle;
1901 if (widget.type == Button_CheckBox)
1902 button.allowsMixedState = YES;
1903 }
1904
1905 return bv;
1906}
1907
1909{
1910 NSCell *cell = cocoaCells[widget];
1911 if (!cell) {
1912 switch (widget.type) {
1913 case Stepper:
1914 cell = [[NSStepperCell alloc] init];
1915 break;
1916 case Button_Disclosure: {
1917 NSButtonCell *bc = [[NSButtonCell alloc] init];
1918 bc.buttonType = NSButtonTypeOnOff;
1919 bc.bezelStyle = NSBezelStyleDisclosure;
1920 cell = bc;
1921 break;
1922 }
1923 default:
1924 break;
1925 }
1926
1927 switch (widget.size) {
1929 cell.controlSize = NSControlSizeSmall;
1930 break;
1932 cell.controlSize = NSControlSizeMini;
1933 break;
1934 default:
1935 break;
1936 }
1937
1938 cocoaCells.insert(widget, cell);
1939 }
1940
1941 return cell;
1942}
1943
1945 __attribute__((noescape)) DrawRectBlock drawRectBlock) const
1946{
1949
1950 // FIXME: The rect that we get in is relative to the widget that we're drawing
1951 // style on behalf of, and doesn't take into account the offset of that widget
1952 // to the widget that owns the backingstore, which we are placing the native
1953 // view into below. This means most of the views are placed in the upper left
1954 // corner of backingStoreNSView, which does not map to where the actual widget
1955 // is, and which may cause problems such as triggering a setNeedsDisplay of the
1956 // backingStoreNSView for the wrong rect. We work around this by making the view
1957 // layer-backed, which prevents triggering display of the backingStoreNSView, but
1958 // but there may be other issues lurking here due to the wrong position. QTBUG-68023
1959 view.wantsLayer = YES;
1960
1961 // FIXME: We are also setting the frame of the incoming view a lot at the call
1962 // sites of this function, making it unclear who's actually responsible for
1963 // maintaining the size and position of the view. In theory the call sites
1964 // should ensure the _size_ of the view is correct, and then let this code
1965 // take care of _positioning_ the view at the right place inside backingStoreNSView.
1966 // For now we pass on the rect as is, to prevent any regressions until this
1967 // can be investigated properly.
1968 view.frame = rect.toCGRect();
1969
1970 [backingStoreNSView addSubview:view];
1971
1972 // FIXME: Based on the code below, this method isn't drawing an NSView into
1973 // a rect, it's drawing _part of the NSView_, defined by the incoming clip
1974 // or dirty rect, into the current graphics context. We're doing some manual
1975 // translations at the call sites that would indicate that this relationship
1976 // is a bit fuzzy.
1977 const CGRect dirtyRect = rect.toCGRect();
1978
1979 if (drawRectBlock)
1980 drawRectBlock(ctx, dirtyRect);
1981 else
1982 [view drawRect:dirtyRect];
1983
1984 [view removeFromSuperviewWithoutNeedingDisplay];
1985
1987}
1988
1990{
1991 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1992}
1993
1996{
1998
1999 static QMacNotificationObserver scrollbarStyleObserver(nil,
2000 NSPreferredScrollerStyleDidChangeNotification, []() {
2001 // Purge destroyed scroll bars
2002 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
2003
2005 for (const auto &o : QMacStylePrivate::scrollBars)
2007 });
2008
2009 Q_D(QMacStyle);
2010 // FIXME: Tie this logic into theme change, or even polish/unpolish
2012 d->appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
2013 Q_D(QMacStyle);
2014 for (NSView *b : d->cocoaControls)
2015 [b release];
2016 d->cocoaControls.clear();
2017 });
2018 }
2019}
2020
2024
2026{
2027}
2028
2032
2036
2038{
2039 Q_D(QMacStyle);
2040 if (!d->smallSystemFont && QGuiApplicationPrivate::platformTheme()) {
2042 d->smallSystemFont = *ssf;
2043 else
2044 d->smallSystemFont = QFont();
2045 }
2046
2047 if (false
2048#if QT_CONFIG(menu)
2049 || qobject_cast<QMenu*>(w)
2050# if QT_CONFIG(combobox)
2051 || qobject_cast<QComboBoxPrivateContainer *>(w)
2052# endif
2053#endif
2054#if QT_CONFIG(mdiarea)
2055 || qobject_cast<QMdiSubWindow *>(w)
2056#endif
2057 ) {
2058 w->setAttribute(Qt::WA_TranslucentBackground, true);
2059 w->setAutoFillBackground(false);
2060 }
2061
2062#if QT_CONFIG(tabbar)
2063 if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
2064 if (tb->documentMode()) {
2065 w->setAttribute(Qt::WA_Hover);
2066 w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2067 QPalette p = w->palette();
2068 p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2069 w->setPalette(p);
2070 w->setAttribute(Qt::WA_SetPalette, false);
2071 w->setAttribute(Qt::WA_SetFont, false);
2072 }
2073 }
2074#endif
2075
2077
2078 if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2079 rubber->setWindowOpacity(0.25);
2080 rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2081 rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2082 }
2083
2084 if (qobject_cast<QScrollBar*>(w)) {
2085 w->setAttribute(Qt::WA_OpaquePaintEvent, false);
2086 w->setAttribute(Qt::WA_Hover, true);
2087 w->setMouseTracking(true);
2088 }
2089}
2090
2092{
2093 if (
2094#if QT_CONFIG(menu)
2095 qobject_cast<QMenu*>(w) &&
2096#endif
2097 !w->testAttribute(Qt::WA_SetPalette))
2098 {
2099 w->setPalette(QPalette());
2100 w->setWindowOpacity(1.0);
2101 }
2102
2103#if QT_CONFIG(combobox)
2104 if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2105 if (!combo->isEditable()) {
2108 }
2109 }
2110#endif
2111
2112#if QT_CONFIG(tabbar)
2113 if (qobject_cast<QTabBar*>(w)) {
2114 if (!w->testAttribute(Qt::WA_SetFont))
2115 w->setFont(QFont());
2116 if (!w->testAttribute(Qt::WA_SetPalette))
2117 w->setPalette(QPalette());
2118 }
2119#endif
2120
2121 if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2122 rubber->setWindowOpacity(1.0);
2123 rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2124 rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2125 }
2126
2127 if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
2129
2131
2132 if (qobject_cast<QScrollBar*>(w)) {
2133 w->setAttribute(Qt::WA_OpaquePaintEvent, true);
2134 w->setAttribute(Qt::WA_Hover, false);
2135 w->setMouseTracking(false);
2136 }
2137}
2138
2140{
2141 Q_D(const QMacStyle);
2142 const int controlSize = getControlSize(opt, widget);
2143 int ret = 0;
2144
2145 switch (metric) {
2146#if QT_CONFIG(tabbar)
2149 ret = closeButtonSize;
2150 break;
2151#endif
2152 case PM_ToolBarIconSize:
2154 break;
2158 break;
2159
2160 case PM_MenuBarHMargin:
2161 ret = 8;
2162 break;
2163
2164 case PM_MenuBarVMargin:
2165 ret = 0;
2166 break;
2167
2169 ret = 0;
2170 break;
2171
2174 break;
2175
2177 ret = 5;
2178 break;
2179
2182 ret = [=] {
2183 if (opt) {
2184 if (opt->state & State_Mini)
2185 return 4;
2186 if (opt->state & State_Small)
2187 return 3;
2188 }
2189 return 2;
2190 } ();
2191 break;
2193 ret = 15; // I hate having magic numbers in here...
2194 break;
2196#if QT_CONFIG(mainwindow)
2197 if (widget && (widget->isWindow() || !widget->parentWidget()
2198 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2199 && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2200 && qobject_cast<const QAbstractScrollArea *>(widget))
2201 ret = 0;
2202 else
2203#endif
2204 // The combo box popup has no frame.
2205 if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2206 ret = 0;
2207 else
2208 ret = 1;
2209 break;
2211 ret = -1;
2212 break;
2214 ret = 24;
2215 break;
2218 break;
2221 ret = 0;
2222 break;
2223 case PM_SliderLength:
2224 ret = 17;
2225 break;
2226 // Returns the number of pixels to use for the business part of the
2227 // slider (i.e., the non-tickmark portion). The remaining space is shared
2228 // equally between the tickmark regions.
2230 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
2231 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
2232 int ticks = sl->tickPosition;
2233 int n = 0;
2234 if (ticks & QSlider::TicksAbove)
2235 ++n;
2236 if (ticks & QSlider::TicksBelow)
2237 ++n;
2238 if (!n) {
2239 ret = space;
2240 break;
2241 }
2242
2243 int thick = 6; // Magic constant to get 5 + 16 + 5
2244 if (ticks != QSlider::TicksBothSides && ticks != QSlider::NoTicks)
2245 thick += proxy()->pixelMetric(PM_SliderLength, sl, widget) / 4;
2246
2247 space -= thick;
2248 if (space > 0)
2249 thick += (space * 2) / (n + 2);
2250 ret = thick;
2251 } else {
2252 ret = 0;
2253 }
2254 break;
2255 case PM_SmallIconSize:
2256 ret = int(QStyleHelper::dpiScaled(16., opt));
2257 break;
2258
2259 case PM_LargeIconSize:
2260 ret = int(QStyleHelper::dpiScaled(32., opt));
2261 break;
2262
2265 break;
2266
2268 ret = 0;
2269 break;
2270 case PM_TitleBarHeight: {
2271 NSUInteger style = NSWindowStyleMaskTitled;
2272 if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool))
2273 style |= NSWindowStyleMaskUtilityWindow;
2274 ret = int([NSWindow frameRectForContentRect:NSZeroRect
2275 styleMask:style].size.height);
2276 break; }
2278 switch (d->aquaSizeConstrain(opt, widget)) {
2281 break;
2283 ret = 20;
2284 break;
2286 ret = 16;
2287 break;
2289#if QT_CONFIG(tabbar)
2290 const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
2291 if (tb && tb->documentMode)
2292 ret = 30;
2293 else
2294#endif
2296 break;
2297 }
2298 break;
2299 case PM_TabBarTabVSpace:
2300 ret = 4;
2301 break;
2304 ret = 0;
2305 break;
2307 ret = 0;
2308 break;
2310 ret = 1;
2311 break;
2313 switch (d->aquaSizeConstrain(opt, widget)) {
2316 ret = 11;
2317 break;
2319 ret = 8;
2320 break;
2322 ret = 7;
2323 break;
2324 }
2325 break;
2326 case PM_ScrollBarExtent: {
2327 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt, widget);
2328 ret = static_cast<int>([NSScroller
2329 scrollerWidthForControlSize:static_cast<NSControlSize>(size)
2330 scrollerStyle:[NSScroller preferredScrollerStyle]]);
2331 break; }
2332 case PM_IndicatorHeight: {
2333 switch (d->aquaSizeConstrain(opt, widget)) {
2337 break;
2340 break;
2343 break;
2344 }
2345 break; }
2346 case PM_IndicatorWidth: {
2347 switch (d->aquaSizeConstrain(opt, widget)) {
2351 break;
2354 break;
2357 break;
2358 }
2359 ++ret;
2360 break; }
2362 switch (d->aquaSizeConstrain(opt, widget)) {
2366 break;
2369 break;
2372 break;
2373 }
2374 break; }
2376 switch (d->aquaSizeConstrain(opt, widget)) {
2380 break;
2383 break;
2386 break;
2387 }
2388 ++ret;
2389 break; }
2390 case PM_MenuVMargin:
2391 ret = 4;
2392 break;
2393 case PM_MenuPanelWidth:
2394 ret = 0;
2395 break;
2397 ret = 0;
2398 break;
2399 case PM_SizeGripSize: {
2401 if (widget && widget->window()->windowType() == Qt::Tool)
2403 else
2406 ret = size.width();
2407 break; }
2409 ret = 1;
2410 break;
2412 ret = 0;
2413 break;
2415 ret = 0;
2416 break;
2418 ret = 1;
2419 break;
2421 ret = 11;
2422 break;
2424 ret = 0;
2425 break;
2427 ret = 4;
2428 break;
2429 case PM_SplitterWidth:
2430 ret = 7;
2431 break;
2433 case PM_LayoutTopMargin:
2436 {
2437 bool isWindow = false;
2438 if (opt) {
2440 } else if (widget) {
2442 }
2443
2444 if (isWindow) {
2445 /*
2446 AHIG would have (20, 8, 10) here but that makes
2447 no sense. It would also have 14 for the top margin
2448 but this contradicts both Builder and most
2449 applications.
2450 */
2451 return_SIZE(20, 10, 10); // AHIG
2452 } else {
2453 // hack to detect QTabWidget
2454 if (widget && widget->parentWidget()
2456 if (metric == PM_LayoutTopMargin) {
2457 /*
2458 Builder would have 14 (= 20 - 6) instead of 12,
2459 but that makes the tab look disproportionate.
2460 */
2461 return_SIZE(12, 6, 6); // guess
2462 } else {
2463 return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2464 }
2465 } else {
2466 /*
2467 Child margins are highly inconsistent in AHIG and Builder.
2468 */
2469 return_SIZE(12, 8, 6); // guess
2470 }
2471 }
2472 }
2475 return -1;
2476 case PM_MenuHMargin:
2477 ret = 0;
2478 break;
2480 ret = 21;
2481 break;
2483 ret = 1;
2484 break;
2486 const QStyle *realStyle = widget ? widget->style() : proxy();
2487 ret = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget)
2488 ? realStyle->pixelMetric(PM_ScrollBarExtent, opt, widget)
2489 : 0;
2490 break;
2491 }
2492 default:
2494 break;
2495 }
2496 return ret;
2497}
2498
2500{
2501 auto platformTheme = QGuiApplicationPrivate::platformTheme();
2502 auto styleNames = platformTheme->themeHint(QPlatformTheme::StyleNames);
2503 if (styleNames.toStringList().contains("macOS"))
2504 return QPalette(); // Inherit everything from theme
2505 else
2506 return QStyle::standardPalette();
2507}
2508
2510 QStyleHintReturn *hret) const
2511{
2513
2514 int ret = 0;
2515 switch (sh) {
2524 ret = 1;
2525 break;
2527 ret = 0;
2528 break;
2530 ret = 0;
2531 break;
2533 ret = false;
2534 break;
2536 ret = true;
2537 break;
2539 ret = true;
2540 break;
2543 break;
2545 ret = 0;
2546 break;
2548 ret = false;
2549 break;
2551 ret = true;
2552 break;
2554 ret = false;
2555 break;
2557 ret = 100;
2558 break;
2560 ret = true;
2561 break;
2563 ret = false;
2564 break;
2566 ret = true;
2567 break;
2569 ret = true;
2570 break;
2571
2573 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2574 bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
2575 const QStyleOptionSlider *sliderOpt = qstyleoption_cast<const QStyleOptionSlider*>(opt);
2576 if (sliderOpt && sliderOpt->keyboardModifiers & Qt::AltModifier)
2577 ret = !result;
2578 else
2579 ret = result;
2580 break; }
2582 ret = true;
2583 break;
2584 /*
2585 case SH_DialogButtons_DefaultButton:
2586 ret = QDialogButtons::Reject;
2587 break;
2588 */
2590 ret = Qt::AlignTop;
2591 break;
2593 ret = QCommonStyle::styleHint(sh, opt, w, hret);
2594 break;
2596 ret = false;
2597 break;
2598 case SH_Menu_Scrollable:
2599 ret = true;
2600 break;
2602 ret = true;
2603 break;
2605 ret = false;
2606 break;
2608 ret = true;
2609 break;
2612 break;
2614#if QT_CONFIG(tabbar)
2615 if (const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
2617 } else
2618#endif
2619 {
2621 }
2622 break;
2623 case SH_ComboBox_Popup:
2624 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2625 ret = !cmb->editable;
2626 else
2627 ret = 0;
2628 break;
2630 ret = true;
2631 break;
2633 ret = true;
2634 break;
2637 break;
2638 case SH_TabBar_Alignment: {
2639#if QT_CONFIG(tabwidget)
2640 if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2641 if (tab->documentMode()) {
2643 break;
2644 }
2645 }
2646#endif
2647#if QT_CONFIG(tabbar)
2648 if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2649 if (tab->documentMode()) {
2651 break;
2652 }
2653 }
2654#endif
2656 } break;
2658 ret = false;
2659 break;
2661 ret = 242; // About 95%
2662 break;
2664 ret = Qt::TabFocus;
2665 break;
2667 ret = false;
2668 break;
2669 case SH_FocusFrame_Mask: {
2670 ret = true;
2671 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2672 const uchar fillR = 192, fillG = 191, fillB = 190;
2673 QImage img;
2674
2675 QSize pixmapSize = opt->rect.size();
2676 if (!pixmapSize.isEmpty()) {
2677 QPixmap pix(pixmapSize);
2678 pix.fill(QColor(fillR, fillG, fillB));
2679 QPainter pix_paint(&pix);
2680 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w);
2681 pix_paint.end();
2682 img = pix.toImage();
2683 }
2684
2685 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2686 const qsizetype sbpl = img.bytesPerLine();
2687 const int w = sbpl/4, h = img.height();
2688
2689 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2690 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2691 const qsizetype dbpl = img_mask.bytesPerLine();
2692
2693 for (int y = 0; y < h; ++y) {
2694 srow = sptr+((y*sbpl)/4);
2695 drow = dptr+((y*dbpl)/4);
2696 for (int x = 0; x < w; ++x) {
2697 const int redDiff = qRed(*srow) - fillR;
2698 const int greenDiff = qGreen(*srow) - fillG;
2699 const int blueDiff = qBlue(*srow) - fillB;
2700 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2701 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2702 ++srow;
2703 }
2704 }
2705 QBitmap qmask = QBitmap::fromImage(img_mask);
2706 mask->region = QRegion(qmask);
2707 }
2708 break; }
2710 ret = 1;
2711 break;
2712 case SH_RubberBand_Mask:
2713 ret = 0;
2714 break;
2717 break;
2720 break;
2722 ret = true;
2723 break;
2725 ret = false;
2726 break;
2728 ret = true;
2729 break;
2731 ret = false;
2732 break;
2735 break;
2736#if QT_CONFIG(dialogbuttonbox)
2739 break;
2740#endif
2743 break;
2746 break;
2749 break;
2752 break;
2755 break;
2758 break;
2760 ret = false;
2761 break;
2763 ret = false;
2764 break;
2766 ret = false;
2767 break;
2769 ret = true;
2770 break;
2771#if QT_CONFIG(wizard)
2772 case SH_WizardStyle:
2774 break;
2775#endif
2777 ret = false;
2778 break;
2780 ret = true;
2781 break;
2783 ret = true;
2784 break;
2786 ret = true;
2787 break;
2788#if QT_CONFIG(tabbar)
2791 break;
2792#endif
2794 ret = false;
2795 break;
2797 if ((qobject_cast<const QScrollBar *>(w) && w->parent() &&
2798 qobject_cast<QAbstractScrollArea*>(w->parent()->parent()))
2799#if QT_CONFIG(accessibility)
2800 || (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))
2801#endif
2802 ) {
2803 ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
2804 }
2805 break;
2806#if QT_CONFIG(itemviews)
2809 break;
2810#endif
2812 // min/max/close buttons on windows don't show tool tips
2813 ret = false;
2814 break;
2816 ret = false;
2817 break;
2819 ret = false;
2820 break;
2822 ret = int(qt_mac_toQColor(NSColor.gridColor).rgba());
2823 break;
2825 ret = false;
2826 break;
2827 default:
2828 ret = QCommonStyle::styleHint(sh, opt, w, hret);
2829 break;
2830 }
2831 return ret;
2832}
2833
2835 const QStyleOption *opt) const
2836{
2837 switch (iconMode) {
2838 case QIcon::Disabled: {
2840 int imgh = img.height();
2841 int imgw = img.width();
2842 QRgb pixel;
2843 for (int y = 0; y < imgh; ++y) {
2844 for (int x = 0; x < imgw; ++x) {
2845 pixel = img.pixel(x, y);
2846 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2847 qAlpha(pixel) / 2));
2848 }
2849 }
2850 return QPixmap::fromImage(img);
2851 }
2852 default:
2853 ;
2854 }
2855 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2856}
2857
2858
2860 const QWidget *widget) const
2861{
2862 // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2863 // I don't want infinite recursion so if we do get in that situation, just return the Window's
2864 // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2865 // someone changes how Windows standard
2866 // pixmap works.
2867 static bool recursionGuard = false;
2868
2869 if (recursionGuard)
2871
2872 recursionGuard = true;
2874 recursionGuard = false;
2875 int size;
2876 switch (standardPixmap) {
2877 default:
2878 size = 32;
2879 break;
2884 size = 64;
2885 break;
2886 }
2887 qreal dpr = widget ? widget->devicePixelRatio() : qApp->devicePixelRatio();
2888 return icon.pixmap(QSize(size, size), dpr);
2889}
2890
2892 const QWidget *w) const
2893{
2894 Q_D(const QMacStyle);
2895 const AppearanceSync appSync;
2896 QMacCGContext cg(p);
2897 QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
2898 d->resolveCurrentNSView(window);
2899 switch (pe) {
2903 case PE_IndicatorArrowLeft: {
2904 p->save();
2905 p->setRenderHint(QPainter::Antialiasing);
2906 const int xOffset = 1; // FIXME: opt->direction == Qt::LeftToRight ? 2 : -1;
2907 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2908 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2909#if QT_CONFIG(toolbutton)
2910 if (const QToolButton *tb = qobject_cast<const QToolButton *>(w)) {
2911 // When stroking the arrow, make sure it fits in the tool button
2912 if (tb->arrowType() != Qt::NoArrow
2913 || tb->popupMode() == QToolButton::MenuButtonPopup)
2914 halfSize -= penWidth;
2915 }
2916#endif
2917
2919 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2921 switch(pe) {
2922 default:
2924 break;
2926 transform.rotate(180);
2927 break;
2929 transform.rotate(90);
2930 break;
2932 transform.rotate(-90);
2933 break;
2934 }
2935 p->setTransform(transform);
2936
2937 path.moveTo(-halfSize, -halfSize * 0.5);
2938 path.lineTo(0.0, halfSize * 0.5);
2939 path.lineTo(halfSize, -halfSize * 0.5);
2940
2941 const QPen arrowPen(opt->palette.text(), penWidth,
2943 p->strokePath(path, arrowPen);
2944 p->restore();
2945 break; }
2946#if QT_CONFIG(tabbar)
2947 case PE_FrameTabBarBase:
2948 if (const QStyleOptionTabBarBase *tbb
2949 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
2950 if (tbb->documentMode) {
2951 p->save();
2952 drawTabBase(p, tbb, w);
2953 p->restore();
2954 return;
2955 }
2956#if QT_CONFIG(tabwidget)
2957 QRegion region(tbb->rect);
2958 region -= tbb->tabBarRect.adjusted(3, 0, -3, 0);
2959 p->save();
2960 p->setClipRegion(region);
2961 QStyleOptionTabWidgetFrame twf;
2962 twf.QStyleOption::operator=(*tbb);
2963 twf.shape = tbb->shape;
2964 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2966 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2967 break;
2969 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2970 break;
2972 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2973 break;
2975 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2976 break;
2977 }
2979 p->restore();
2980#endif
2981 }
2982 break;
2983#endif
2984 case PE_PanelTipLabel:
2986 break;
2987 case PE_FrameGroupBox:
2988 if (const auto *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt))
2989 if (groupBox->features & QStyleOptionFrame::Flat) {
2991 break;
2992 }
2993#if QT_CONFIG(tabwidget)
2994 Q_FALLTHROUGH();
2995 case PE_FrameTabWidget:
2996#endif
2997 {
2999 auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
3000 // FIXME Since macOS 10.14, simply calling drawRect: won't display anything anymore.
3001 // The AppKit team is aware of this and has proposed a couple of solutions.
3002 // The first solution was to call displayRectIgnoringOpacity:inContext: instead.
3003 // However, it doesn't seem to work on 10.13. More importantly, dark mode on 10.14
3004 // is extremely slow. Light mode works fine.
3005 // The second solution is to subclass NSBox and reimplement a trivial drawRect: which
3006 // would only call super. This works without any issue on 10.13, but a double border
3007 // shows on 10.14 in both light and dark modes.
3008 // The code below picks what works on each version and mode. On 10.13 and earlier, we
3009 // simply call drawRect: on a regular NSBox. On 10.14, we call displayRectIgnoringOpacity:
3010 // inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass,
3011 // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so
3012 // we can use this for now.
3013 auto adjustedRect = opt->rect;
3014 bool needTranslation = false;
3016 && !isDarkMode()) {
3017 // In Aqua theme we have to use the 'default' NSBox (as opposite
3018 // to the 'custom' QDarkNSBox we use in dark theme). Since -drawRect:
3019 // does nothing in default NSBox, we call -displayRectIgnoringOpaticty:.
3020 // Unfortunately, the resulting box is smaller then the actual rect we
3021 // wanted. This can be seen, e.g. because tabs (buttons) are misaligned
3022 // vertically and even worse, if QTabWidget has autoFillBackground
3023 // set, this background overpaints NSBox making it to disappear.
3024 // We trick our NSBox to render in a larger rectangle, so that
3025 // the actual result (which is again smaller than requested),
3026 // more or less is what we really want. We'll have to adjust CTM
3027 // and translate accordingly.
3028 adjustedRect.adjust(0, 0, 6, 6);
3029 needTranslation = true;
3030 }
3031 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx, const CGRect &rect) {
3032#if QT_CONFIG(tabwidget)
3033 if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(opt->styleObject))
3034 clipTabBarFrame(opt, this, ctx);
3035#endif
3036 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
3037 CGContextScaleCTM(ctx, 1, -1);
3039 || [box isMemberOfClass:QDarkNSBox.class]) {
3040 [box drawRect:rect];
3041 } else {
3042 if (needTranslation)
3043 CGContextTranslateCTM(ctx, -3.0, 5.0);
3044 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
3045 }
3046 });
3047 break;
3048 }
3051 if (opt->state & State_Horizontal) {
3052 int xpoint = opt->rect.center().x();
3053 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3054 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3055 } else {
3056 int ypoint = opt->rect.center().y();
3057 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3058 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3059 }
3060 QPainterPathStroker theStroker;
3061 theStroker.setCapStyle(Qt::FlatCap);
3062 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3063 path = theStroker.createStroke(path);
3064 const auto dark = isDarkMode() ? opt->palette.dark().color().darker()
3065 : QColor(0, 0, 0, 119);
3066 p->fillPath(path, dark);
3067 }
3068 break;
3069 case PE_FrameWindow:
3070 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3071 if (qobject_cast<const QMdiSubWindow*>(w)) {
3072 p->save();
3073 p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
3074 p->setBrush(frame->palette.window());
3075 p->drawRect(frame->rect);
3076 p->restore();
3077 }
3078 }
3079 break;
3081 // The docwidget resize handle is drawn as a one-pixel wide line.
3082 p->save();
3083 if (opt->state & State_Horizontal) {
3084 p->setPen(QColor(160, 160, 160));
3085 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3086 } else {
3087 p->setPen(QColor(145, 145, 145));
3088 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3089 }
3090 p->restore();
3091 } break;
3093 p->save();
3095 int x = opt->rect.x() + 6;
3096 int y = opt->rect.y() + 7;
3097 static const int RectHeight = 2;
3098 if (opt->state & State_Horizontal) {
3099 while (y < opt->rect.height() - RectHeight - 5) {
3100 path.moveTo(x, y);
3101 path.addEllipse(x, y, RectHeight, RectHeight);
3102 y += 6;
3103 }
3104 } else {
3105 while (x < opt->rect.width() - RectHeight - 5) {
3106 path.moveTo(x, y);
3107 path.addEllipse(x, y, RectHeight, RectHeight);
3108 x += 6;
3109 }
3110 }
3111 p->setPen(Qt::NoPen);
3112 QColor dark = opt->palette.dark().color().darker();
3113 dark.setAlphaF(0.50);
3114 p->fillPath(path, dark);
3115 p->restore();
3116
3117 break;
3118 }
3120 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3121 // In HITheme, up is down, down is up and hamburgers eat people.
3122 if (header->sortIndicator != QStyleOptionHeader::None)
3124 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3126 }
3127 break;
3129 QColor pc;
3130 if (opt->state & State_On)
3131 pc = opt->palette.highlightedText().color();
3132 else
3133 pc = opt->palette.text().color();
3134
3135 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()),
3136 static_cast<CGFloat>(pc.greenF()),
3137 static_cast<CGFloat>(pc.blueF()),
3138 static_cast<CGFloat>(pc.alphaF()));
3139 // kCTFontUIFontSystem and others give the same result
3140 // as kCTFontUIFontMenuItemMark. However, the latter is
3141 // more reminiscent to HITheme's kThemeMenuItemMarkFont.
3142 // See also the font for small- and mini-sized widgets,
3143 // where we end up using the generic system font type.
3144 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
3145 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
3146 kCTFontUIFontMenuItemMark;
3147 // Similarly for the font size, where there is a small difference
3148 // between regular combobox and item view items, and and menu items.
3149 // However, we ignore any difference for small- and mini-sized widgets.
3150 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
3151 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
3152
3153 CGContextSaveGState(cg);
3154 CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks
3155
3156 // Baseline alignment tweaks for QComboBox and QMenu
3157 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
3158 (opt->state & State_Small) ? 1.0 :
3159 0.75;
3160
3161 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
3162 CGContextScaleCTM(cg, 1, -1);
3163 // Translate back to the original position and add rect origin and offset
3164 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
3165
3166 // CTFont has severe difficulties finding the checkmark character among its
3167 // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth.
3168 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
3169 static const int numValues = sizeof(keys) / sizeof(keys[0]);
3170 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
3171 static_assert((sizeof(values) / sizeof(values[0])) == numValues);
3172 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
3173 numValues, NULL, NULL);
3174 // U+2713: CHECK MARK
3175 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes);
3176 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
3177
3178 CTLineDraw((CTLineRef)line, cg);
3179 CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush
3180
3181 CGContextRestoreGState(cg);
3182 break; }
3185 case PE_IndicatorCheckBox: {
3186 const bool isEnabled = opt->state & State_Enabled;
3187 const bool isPressed = opt->state & State_Sunken;
3188 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
3190 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3191 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3192 auto *tb = static_cast<NSButton *>(d->cocoaControl(cw));
3193 tb.enabled = isEnabled;
3194 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
3195 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
3196 [tb highlight:isPressed];
3197 const auto vOffset = [=] {
3198 // As measured
3199 if (cs == QStyleHelper::SizeMini)
3200 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
3201
3202 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
3203 } ();
3204 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
3205 CGContextTranslateCTM(ctx, 0, vOffset);
3206 [tb.cell drawInteriorWithFrame:rect inView:tb];
3207 });
3208 break; }
3209 case PE_FrameFocusRect:
3210 // Use the our own focus widget stuff.
3211 break;
3212 case PE_IndicatorBranch: {
3213 if (!(opt->state & State_Children))
3214 break;
3216 NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
3217 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
3218 bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
3219 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
3220
3221 d->setupNSGraphicsContext(cg, NO);
3222
3224 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
3225 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
3226 CGContextScaleCTM(cg, 1, -1);
3227 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
3228
3229 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
3230
3231 d->restoreNSGraphicsContext(cg);
3232 break; }
3233
3234 case PE_Frame: {
3235 QPen oldPen = p->pen();
3236 p->setPen(opt->palette.base().color().darker(140));
3237 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3238 p->setPen(opt->palette.base().color().darker(180));
3239 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3240 p->setPen(oldPen);
3241 break; }
3242
3243 case PE_FrameLineEdit:
3244 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3245 if (frame->state & State_Sunken) {
3246 const bool isEnabled = opt->state & State_Enabled;
3247 const bool isReadOnly = opt->state & State_ReadOnly;
3248 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
3249 const auto cs = d->effectiveAquaSizeConstrain(opt, w, CT_LineEdit);
3251 auto *tf = static_cast<NSTextField *>(d->cocoaControl(cw));
3252 tf.enabled = isEnabled;
3253 tf.editable = !isReadOnly;
3254 tf.bezeled = YES;
3255 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
3256 tf.frame = opt->rect.toCGRect();
3257 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
3258 if (!isDarkMode()) {
3259 // In 'Dark' mode controls are transparent, so we do not
3260 // over-paint the (potentially custom) color in the background.
3261 // In 'Light' mode we have to care about the correct
3262 // background color. See the comments below for PE_PanelLineEdit.
3263 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
3264 // See QMacCGContext, here we expect bitmap context created with
3265 // color space 'kCGColorSpaceSRGB', if it's something else - we
3266 // give up.
3267 if (cgContext ? bool(CGBitmapContextGetColorSpace(cgContext)) : false) {
3268 tf.drawsBackground = YES;
3269 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
3270 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
3271 green:bgColor.greenF()
3272 blue:bgColor.blueF()
3273 alpha:bgColor.alphaF()];
3274 if (bgColor.alpha() != 255) {
3275 // No way we can have it bezeled and transparent ...
3276 tf.bordered = YES;
3277 }
3278 }
3279 }
3280
3281 [tf.cell drawWithFrame:rect inView:tf];
3282 });
3283 } else {
3285 }
3286 }
3287 break;
3288 case PE_PanelLineEdit:
3289 {
3290 const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt);
3291 if (isDarkMode() || (panel && panel->lineWidth <= 0)) {
3292 // QCommonStyle::drawPrimitive(PE_PanelLineEdit) fill the background with
3293 // a proper color, defined in opt->palette and then, if lineWidth > 0, it
3294 // calls QMacStyle::drawPrimitive(PE_FrameLineEdit). We use NSTextFieldCell
3295 // to handle PE_FrameLineEdit, which will use system-default background.
3296 // In 'Dark' mode it's transparent and thus it's not over-painted.
3298 } else {
3299 // In 'Light' mode, if panel->lineWidth > 0, we have to use the correct
3300 // background color when drawing PE_FrameLineEdit, so let's call it
3301 // directly and set the proper color there.
3303 }
3304
3305 // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit).
3306 // Focus frame is drawn outside the rectangle passed in the option-rect.
3307 if (panel) {
3308#if QT_CONFIG(lineedit)
3309 if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(w)) {
3312 QStyleOptionFrame focusFrame = *panel;
3313 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3314 drawControl(CE_FocusFrame, &focusFrame, p, w);
3315 }
3316#endif
3317 }
3318 }
3319 break;
3322 p->fillRect(opt->rect, brush);
3323 p->setPen(QPen(QColor(217, 217, 217)));
3324 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3325 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3326 } break;
3328 break;
3329#if QT_CONFIG(tabbar)
3330 case PE_IndicatorTabClose: {
3331 // Make close button visible only on the hovered tab.
3332 QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
3333 const QWidget *closeBtn = w;
3334 if (!tabBar) {
3335 // QStyleSheetStyle instead of CloseButton (which has
3336 // a QTabBar as a parent widget) uses the QTabBar itself:
3337 tabBar = qobject_cast<QTabBar *>(const_cast<QWidget*>(w));
3338 closeBtn = decltype(closeBtn)(property("_q_styleSheetRealCloseButton").value<void *>());
3339 }
3340 if (tabBar) {
3341 const bool documentMode = tabBar->documentMode();
3342 const QTabBarPrivate *tabBarPrivate = static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
3343 const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
3344 if (!documentMode ||
3345 (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
3346 (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
3347 const bool hover = (opt->state & State_MouseOver);
3348 const bool selected = (opt->state & State_Selected);
3349 const bool pressed = (opt->state & State_Sunken);
3350 drawTabCloseButton(p, hover, selected, pressed, documentMode);
3351 }
3352 }
3353 } break;
3354#endif // QT_CONFIG(tabbar)
3355 case PE_PanelStatusBar: {
3356 p->fillRect(opt->rect, opt->palette.window());
3357
3358 // Draw the black separator line at the top of the status bar.
3359 if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
3361 else
3363 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3364
3365 break;
3366 }
3367 case PE_PanelMenu: {
3368 p->save();
3369 p->fillRect(opt->rect, Qt::transparent);
3370 p->setPen(Qt::transparent);
3371 p->setBrush(opt->palette.window());
3372 p->setRenderHint(QPainter::Antialiasing, true);
3373 const QPainterPath path = d->windowPanelPath(opt->rect);
3374 p->drawPath(path);
3375 p->restore();
3376 } break;
3377
3378 default:
3380 break;
3381 }
3382}
3383
3385{
3387 int imgh = img.height();
3388 int imgw = img.width();
3389 int h, s, v, a;
3390 QRgb pixel;
3391 for (int y = 0; y < imgh; ++y) {
3392 for (int x = 0; x < imgw; ++x) {
3393 pixel = img.pixel(x, y);
3394 a = qAlpha(pixel);
3395 QColor hsvColor(pixel);
3396 hsvColor.getHsv(&h, &s, &v);
3397 s = qMin(100, s * 2);
3398 v = v / 2;
3399 hsvColor.setHsv(h, s, v);
3400 pixel = hsvColor.rgb();
3401 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3402 }
3403 }
3404 return QPixmap::fromImage(img);
3405}
3406
3407void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const
3408{
3409 if (vertical) {
3410 CGContextTranslateCTM(cg, rect.size.height, 0);
3411 CGContextRotateCTM(cg, M_PI_2);
3412 }
3413 if (vertical != reverse) {
3414 CGContextTranslateCTM(cg, rect.size.width, 0);
3415 CGContextScaleCTM(cg, -1, 1);
3416 }
3417}
3418
3420 const QWidget *w) const
3421{
3422 Q_D(const QMacStyle);
3423 const AppearanceSync sync;
3425 QMacCGContext cg(p);
3426 QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
3427 d->resolveCurrentNSView(window);
3428 switch (ce) {
3429 case CE_HeaderSection:
3430 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3431 State flags = header->state;
3432 QRect ir = header->rect;
3433
3434
3435#if 0 // FIXME: What's this solving exactly?
3436 bool noVerticalHeader = true;
3437#if QT_CONFIG(tableview)
3438 if (w)
3439 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3440 noVerticalHeader = !table->verticalHeader()->isVisible();
3441#endif
3442
3443 const bool drawLeftBorder = header->orientation == Qt::Vertical
3445 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3446#endif
3447
3448 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
3449 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
3450 p->setPen(QPen(header->palette.dark(), 1.0));
3451 if (header->orientation == Qt::Horizontal)
3452 p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
3453 ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
3454 else
3455 p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
3456 ir.right() - headerSectionSeparatorInset, ir.bottom()));
3457 }
3458
3459 break;
3460 case CE_ToolButtonLabel:
3461 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3462 QStyleOptionToolButton myTb = *tb;
3463 myTb.state &= ~State_AutoRaise;
3464#if QT_CONFIG(accessibility)
3465 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
3466 QRect cr = tb->rect;
3467 int shiftX = 0;
3468 int shiftY = 0;
3469 bool needText = false;
3470 int alignment = 0;
3471 bool down = tb->state & (State_Sunken | State_On);
3472 if (down) {
3473 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3474 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3475 }
3476 // The down state is special for QToolButtons in a toolbar on the Mac
3477 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3478 // This doesn't really fit into any particular case in QIcon, so we
3479 // do the majority of the work ourselves.
3480 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3481 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3482 if (tb->icon.isNull() && !tb->text.isEmpty())
3483 tbstyle = Qt::ToolButtonTextOnly;
3484
3485 switch (tbstyle) {
3487 needText = true;
3489 break; }
3493 QRect pr = cr;
3494 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3496 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3497 : QIcon::Off;
3498 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), p->device()->devicePixelRatio(),
3499 iconMode, iconState);
3500
3501 // Draw the text if it's needed.
3502 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3503 needText = true;
3504 QSizeF size = pixmap.deviceIndependentSize();
3505 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3506 pr.setHeight(size.height() + 6);
3507 cr.adjust(0, pr.bottom(), 0, -3);
3509 } else {
3510 pr.setWidth(size.width() + 8);
3511 cr.adjust(pr.right(), 0, 0, 0);
3513 }
3514 }
3515 if (opt->state & State_Sunken) {
3516 pr.translate(shiftX, shiftY);
3518 }
3520 break; }
3521 default:
3522 Q_ASSERT(false);
3523 break;
3524 }
3525
3526 if (needText) {
3527 QPalette pal = tb->palette;
3529 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3531 if (down)
3532 cr.translate(shiftX, shiftY);
3533 if (tbstyle == Qt::ToolButtonTextOnly
3534 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3535 QPen pen = p->pen();
3536 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3537 light.setAlphaF(0.375f);
3538 p->setPen(light);
3539 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3540 p->setPen(pen);
3541 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3542 pal = QApplication::palette("QMenu");
3543 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3545 }
3546 }
3547 proxy()->drawItemText(p, cr, alignment, pal,
3548 tb->state & State_Enabled, tb->text, role);
3549 }
3550 } else {
3551 QCommonStyle::drawControl(ce, &myTb, p, w);
3552 }
3553 } else
3554#endif // QT_CONFIG(accessibility)
3555 {
3556 QCommonStyle::drawControl(ce, &myTb, p, w);
3557 }
3558 }
3559 break;
3560 case CE_ToolBoxTabShape:
3562 break;
3563 case CE_PushButtonBevel:
3564 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3565 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3566 break;
3567
3570 break;
3571 }
3572
3573 const bool hasFocus = btn->state & State_HasFocus;
3574 const bool isActive = btn->state & State_Active;
3575
3576 // a focused auto-default button within an active window
3577 // takes precedence over a normal default button
3579 && isActive && hasFocus)
3580 d->autoDefaultButton = btn->styleObject;
3581 else if (d->autoDefaultButton == btn->styleObject)
3582 d->autoDefaultButton = nullptr;
3583
3584 const bool isEnabled = btn->state & State_Enabled;
3585 const bool isPressed = btn->state & State_Sunken;
3586 const bool isHighlighted = isActive &&
3587 ((btn->state & State_On)
3590 && d->autoDefaultButton == btn->styleObject));
3591 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3592 const auto ct = cocoaControlType(btn, w);
3593 const auto cs = d->effectiveAquaSizeConstrain(btn, w);
3594 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3595 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
3596 // Ensure same size and location as we used to have with HITheme.
3597 // This is more convoluted than we initially thought. See for example
3598 // differences between plain and menu button frames.
3599 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3600 pb.frame = frameRect.toCGRect();
3601
3602 pb.enabled = isEnabled;
3603
3604 // With the 'momentary push in' type this gives an impression of a
3605 // button in a 'pressed' state (the 'momentary push in' does
3606 // not show its state otherwise):
3607 [pb highlight:isPressed];
3608
3609
3611 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3612 } else {
3613 // For default/checked button this will give the required
3614 // button accent color:
3615 pb.keyEquivalent = isHighlighted ? @"\r" : @"";
3616 }
3617
3618 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
3619 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3620 });
3621 [pb highlight:NO];
3622
3623 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3624 // Using -[NSPopuButtonCell drawWithFrame:inView:] above won't do
3625 // it right because we don't set the text in the native button.
3627 const auto ir = frameRect.toRect();
3628 int arrowYOffset = 0;
3629#if 0
3630 // FIXME What's this for again?
3631 if (!w) {
3632 // adjustment for Qt Quick Controls
3633 arrowYOffset -= ir.top();
3634 if (cw.second == QStyleHelper::SizeSmall)
3635 arrowYOffset += 1;
3636 }
3637#endif
3638 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3639
3640 QStyleOption arrowOpt = *opt;
3641 arrowOpt.rect = ar;
3642 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, w);
3643 }
3644 }
3645 break;
3646 case CE_PushButtonLabel:
3647 if (const QStyleOptionButton *b = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3649 // We really don't want the label to be drawn the same as on
3650 // windows style if it has an icon and text, then it should be more like a
3651 // tab. So, cheat a little here. However, if it *is* only an icon
3652 // the windows style works great, so just use that implementation.
3653 const bool isEnabled = btn.state & State_Enabled;
3654 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3655 const bool hasIcon = !btn.icon.isNull();
3656 const bool hasText = !btn.text.isEmpty();
3657 const bool isActive = btn.state & State_Active;
3658 const bool isPressed = btn.state & State_Sunken;
3659 const bool isDefault = (btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
3660 || d->autoDefaultButton == btn.styleObject;
3661
3662 // cocoaControlType evaluates the type based on the control's geometry, not on the
3663 // label's geometry
3664 const QRect oldRect = btn.rect;
3665 if (w)
3666 btn.rect = w->rect();
3667 const auto ct = cocoaControlType(&btn, w);
3668 btn.rect = oldRect;
3669
3670 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
3671 if (isPressed || (isActive && isEnabled && ((btn.state & State_On) || isDefault)))
3673 }
3674
3676 if (!isDefault && !(btn.state & State_On)) {
3677 // On macOS 12 it's a gray button, white text color (if set in the
3678 // previous statement) would be almost invisible.
3680 }
3681 }
3682
3683 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3685 } else {
3686 QRect freeContentRect = btn.rect;
3688 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3689 if (hasMenu) {
3691 textRect.moveTo(w ? 8 : 11, textRect.top());
3692 else
3693 textRect.moveTo(w ? (15 - pushButtonBevelRectOffsets[d->effectiveAquaSizeConstrain(b, w)])
3694 : 11, textRect.top()); // Supports Qt Quick Controls
3695 }
3696 // Draw the icon:
3697 if (hasIcon) {
3698 int contentW = textRect.width();
3699 if (hasMenu)
3700 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3704 // Decide if the icon is should be on or off:
3706 if (btn.state & State_On)
3707 state = QIcon::On;
3708 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, p->device()->devicePixelRatio(), mode, state);
3709 QSizeF pixmapSize = pixmap.deviceIndependentSize();
3710 contentW += pixmapSize.width() + QMacStylePrivate::PushButtonContentPadding;
3711 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3712 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapSize.height()) / 2;
3713 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapSize.width(), pixmapSize.height());
3714 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3715 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3716 int newOffset = iconDestRect.x() + iconDestRect.width()
3718 textRect.adjust(newOffset, 0, newOffset, 0);
3719 }
3720 // Draw the text:
3721 if (hasText) {
3722 textRect = visualRect(btn.direction, freeContentRect, textRect);
3724 isEnabled, btn.text, QPalette::ButtonText);
3725 }
3726 }
3727 }
3728 break;
3729#if QT_CONFIG(combobox)
3730 case CE_ComboBoxLabel:
3731 if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3732 auto comboCopy = *cb;
3733 comboCopy.direction = Qt::LeftToRight;
3734 // The rectangle will be adjusted to SC_ComboBoxEditField with comboboxEditBounds()
3736 }
3737 break;
3738#endif // #if QT_CONFIG(combobox)
3739#if QT_CONFIG(tabbar)
3740 case CE_TabBarTabShape:
3741 if (const auto *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3742 if (tabOpt->documentMode) {
3743 p->save();
3744 bool isUnified = false;
3745 if (w) {
3746 QRect tabRect = tabOpt->rect;
3747 QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
3748 isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y());
3749 }
3750
3751 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w);
3752 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3753
3754 p->restore();
3755 return;
3756 }
3757
3758 const bool isActive = tabOpt->state & State_Active;
3759 const bool isEnabled = tabOpt->state & State_Enabled;
3760 const bool isPressed = tabOpt->state & State_Sunken;
3761 const bool isSelected = tabOpt->state & State_Selected;
3762 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3763 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3764 || tabDirection == QMacStylePrivate::West;
3765
3766 QStyleOptionTab::TabPosition tp = tabOpt->position;
3767 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3768 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3769 if (tp == QStyleOptionTab::Beginning)
3770 tp = QStyleOptionTab::End;
3771 else if (tp == QStyleOptionTab::End)
3772 tp = QStyleOptionTab::Beginning;
3773
3774 if (sp == QStyleOptionTab::NextIsSelected)
3775 sp = QStyleOptionTab::PreviousIsSelected;
3776 else if (sp == QStyleOptionTab::PreviousIsSelected)
3777 sp = QStyleOptionTab::NextIsSelected;
3778 }
3779
3780 // Alas, NSSegmentedControl and NSSegmentedCell are letting us down.
3781 // We're not able to draw it at will, either calling -[drawSegment:
3782 // inFrame:withView:], -[drawRect:] or anything in between. Besides,
3783 // there's no public API do draw the pressed state, AFAICS. We'll use
3784 // a push NSButton instead and clip the CGContext.
3785
3786 const auto cs = d->effectiveAquaSizeConstrain(opt, w);
3787 // Extra hacks to get the proper pressed appreance when not selected or selected and inactive
3788 const bool needsInactiveHack = (!isActive && isSelected);
3790 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3793 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
3794 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3795 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
3796
3797 auto vOffset = isPopupButton ? 1 : 2;
3798 if (isBigSurOrAbove) {
3799 // Make it 1, otherwise, offset is very visible compared
3800 // to selected tab (which is not a popup button).
3801 vOffset = 1;
3802 }
3803
3804 if (tabDirection == QMacStylePrivate::East)
3805 vOffset -= 1;
3806 const auto outerAdjust = isPopupButton ? 1 : 4;
3807 const auto innerAdjust = isPopupButton ? 20 : 10;
3808 QRectF frameRect = tabOpt->rect;
3809 if (verticalTabs)
3810 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3811 // Adjust before clipping
3812 frameRect = frameRect.translated(0, vOffset);
3813 switch (tp) {
3814 case QStyleOptionTab::Beginning:
3815 // Pressed state hack: tweak adjustments in preparation for flip below
3816 if (!isSelected && tabDirection == QMacStylePrivate::West)
3817 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3818 else
3819 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3820
3821 if (isSelected && isBigSurOrAbove) {
3822 // 1 pixed of 'roundness' is still visible on the right
3823 // (the left is OK, it's rounded).
3824 frameRect = frameRect.adjusted(0, 0, 1, 0);
3825 }
3826
3827 break;
3828 case QStyleOptionTab::Middle:
3829 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3830
3831 if (isSelected && isBigSurOrAbove) {
3832 // 1 pixel of 'roundness' is still visible on both
3833 // sides - left and right.
3834 frameRect = frameRect.adjusted(-1, 0, 1, 0);
3835 }
3836 break;
3837 case QStyleOptionTab::Moving: // Moving tab treated like End
3838 case QStyleOptionTab::End:
3839 // Pressed state hack: tweak adjustments in preparation for flip below
3840 if (isSelected || tabDirection == QMacStylePrivate::West)
3841 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3842 else
3843 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3844
3845 if (isSelected && isBigSurOrAbove) {
3846 // 1 pixel of 'roundness' is still visible on the left.
3847 frameRect = frameRect.adjusted(-1, 0, 0, 0);
3848 }
3849 break;
3850 case QStyleOptionTab::OnlyOneTab:
3851 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3852 break;
3853 }
3854 pb.frame = frameRect.toCGRect();
3855
3856 if (!isPopupButton) {
3857 // Note: these days we use 'momentary push in' for Button_PushButton,
3858 // but tabs are also rendered using NSButton/ButtonPushButton, and
3859 // here we need 'push on/off' to make it work (tab highlight colors).
3860 pb.buttonType = NSButtonTypePushOnPushOff;
3861 }
3862
3863 pb.enabled = isEnabled;
3864 [pb highlight:isPressed];
3865
3866 // Set off state when inactive. See needsInactiveHack for when it's selected
3867 // On macOS 12, don't set the Off state for selected tabs as it draws a gray backgorund even when highlighted
3869 pb.state = (isActive && isSelected) ? NSControlStateValueOn : NSControlStateValueOff;
3870 else
3871 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3872
3873 const auto drawBezelBlock = ^(CGContextRef ctx, const CGRect &r) {
3874 CGContextClipToRect(ctx, opt->rect.toCGRect());
3875 if (!isSelected || needsInactiveHack) {
3876 // Final stage of the pressed state hack: flip NSPopupButton rendering
3877 if (!verticalTabs && tp == QStyleOptionTab::End) {
3878 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3879 CGContextScaleCTM(ctx, -1, 1);
3880 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3881 } else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3882 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3883 CGContextScaleCTM(ctx, 1, -1);
3884 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3885 } else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3886 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3887 CGContextScaleCTM(ctx, 1, -1);
3888 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3889 }
3890 }
3891
3892 // Rotate and translate CTM when vertical
3893 // On macOS: positive angle is CW, negative is CCW
3894 if (tabDirection == QMacStylePrivate::West) {
3895 CGContextTranslateCTM(ctx, 0, frameRect.right());
3896 CGContextRotateCTM(ctx, -M_PI_2);
3897 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3898 } else if (tabDirection == QMacStylePrivate::East) {
3899 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3900 CGContextRotateCTM(ctx, M_PI_2);
3901 }
3902
3903 // Now, if it's a trick with a popup button, it has an arrow
3904 // which makes no sense on tabs.
3905 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3906 NSPopUpButtonCell *pbCell = nil;
3907 auto rAdjusted = r;
3908 if (isPopupButton && (tp == QStyleOptionTab::OnlyOneTab || isBigSurOrAbove)) {
3909 // Note: starting from macOS BigSur NSPopupButton has this
3910 // arrow 'button' in a different place and it became
3911 // quite visible 'in between' inactive tabs.
3912 pbCell = static_cast<NSPopUpButtonCell *>(pb.cell);
3913 oldPosition = pbCell.arrowPosition;
3914 pbCell.arrowPosition = NSPopUpNoArrow;
3915 if (pb.state == NSControlStateValueOff) {
3916 // NSPopUpButton in this state is smaller.
3917 rAdjusted.origin.x -= 3;
3918 rAdjusted.size.width += 6;
3919 if (isBigSurOrAbove) {
3920 if (tp == QStyleOptionTab::End)
3921 rAdjusted.origin.x -= 2;
3922 }
3923 }
3924 }
3925
3926 [pb.cell drawBezelWithFrame:rAdjusted inView:pb.superview];
3927
3928 if (pbCell) // Restore, we may reuse it for a ComboBox.
3929 pbCell.arrowPosition = oldPosition;
3930 };
3931
3932 if (needsInactiveHack) {
3933 // First, render tab as non-selected tab on a pixamp
3934 const qreal pixelRatio = p->device()->devicePixelRatio();
3935 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3936 tabPixmap.setDevicePixelRatio(pixelRatio);
3937 tabPixmap.fill(Qt::transparent);
3938 QPainter tabPainter(&tabPixmap);
3939 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx, const CGRect &r) {
3940 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3941 drawBezelBlock(ctx, r);
3942 });
3943 tabPainter.end();
3944
3945 // Then, darken it with the proper shade of gray
3946 const qreal inactiveGray = 0.898; // As measured
3947 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3948 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3949 for (int l = 0; l < tabPixmap.height(); ++l) {
3950 auto *line = reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3951 for (int i = 0; i < tabPixmap.width(); ++i) {
3952 if (qAlpha(line[i]) == 255) {
3953 line[i] = inactiveGrayRGB;
3954 } else if (qAlpha(line[i]) > 128) {
3955 const int g = qRound(inactiveGray * qRed(line[i]));
3956 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3957 }
3958 }
3959 }
3960
3961 // Finally, draw the tab pixmap on the current painter
3962 p->drawImage(opt->rect, tabPixmap);
3963 } else {
3964 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3965 }
3966
3967 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3968 && tp != QStyleOptionTab::End
3969 && tp != QStyleOptionTab::OnlyOneTab) {
3970 static const QPen separatorPen(Qt::black, 1.0);
3971 p->save();
3972 p->setOpacity(isEnabled ? 0.105 : 0.06); // As measured
3973 p->setPen(separatorPen);
3974 if (tabDirection == QMacStylePrivate::West) {
3975 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3976 opt->rect.right() - 0.5, opt->rect.bottom()));
3977 } else if (tabDirection == QMacStylePrivate::East) {
3978 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3979 opt->rect.right() - 0.5, opt->rect.bottom()));
3980 } else {
3981 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3982 opt->rect.right(), opt->rect.bottom() - 0.5));
3983 }
3984 p->restore();
3985 }
3986 }
3987 break;
3988 case CE_TabBarTabLabel:
3989 if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3990 QStyleOptionTab myTab = *tab;
3991 const auto foregroundRole = w ? w->foregroundRole() : QPalette::WindowText;
3992 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3993 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3994 || tabDirection == QMacStylePrivate::West;
3995
3996 // Check to see if we use have the same as the system font
3997 // (QComboMenuItem is internal and should never be seen by the
3998 // outside world, unless they read the source, in which case, it's
3999 // their own fault).
4000 const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
4001
4002 if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
4003 if (const auto *tabBar = qobject_cast<const QTabBar *>(w))
4004 if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
4005 myTab.palette.setColor(foregroundRole, Qt::white);
4006
4007 if (myTab.documentMode && isDarkMode()) {
4008 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
4009 myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray);
4010 }
4011
4012 int heightOffset = 0;
4013 if (verticalTabs) {
4014 heightOffset = -1;
4015 } else if (nonDefaultFont) {
4016 if (p->fontMetrics().height() == myTab.rect.height())
4017 heightOffset = 2;
4018 }
4019 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4020
4021 QCommonStyle::drawControl(ce, &myTab, p, w);
4022 }
4023 break;
4024#endif
4025#if QT_CONFIG(dockwidget)
4026 case CE_DockWidgetTitle:
4027 if (const auto *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4028 const bool isVertical = dwOpt->verticalTitleBar;
4029 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
4030 p->save();
4031 if (isVertical) {
4032 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
4033 p->rotate(-90);
4034 p->translate(-effectiveRect.left(), -effectiveRect.top());
4035 }
4036
4037 // fill title bar background
4038 p->fillRect(effectiveRect, opt->palette.window());
4039
4040 // draw horizontal line at bottom
4041 p->setPen(opt->palette.dark().color());
4042 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
4043
4044 if (!dwOpt->title.isEmpty()) {
4045 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt, w);
4046 if (isVertical)
4047 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
4048 effectiveRect.top() + titleRect.left() - opt->rect.left(),
4049 titleRect.height(),
4050 titleRect.width());
4051
4052 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
4053 proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
4054 dwOpt->state & State_Enabled, text, QPalette::WindowText);
4055 }
4056 p->restore();
4057 }
4058 break;
4059#endif
4060 case CE_FocusFrame: {
4061 const auto *ff = qobject_cast<const QFocusFrame *>(w);
4062 const auto *ffw = ff ? ff->widget() : nullptr;
4063 const auto ct = [=] {
4064 if (ffw) {
4065 if (qobject_cast<const QCheckBox*>(ffw))
4067 if (qobject_cast<const QRadioButton*>(ffw))
4069 if (qobject_cast<const QLineEdit*>(ffw) || qobject_cast<const QTextEdit*>(ffw))
4071 if (const auto *pb = qobject_cast<const QPushButton *>(ffw)) {
4072 // keep in sync with cocoaControlType
4073 auto sizePolicy = QStyleHelper::widgetSizePolicy(ffw, opt);
4074 if (sizePolicy == QStyleHelper::SizeDefault)
4075 sizePolicy = QStyleHelper::SizeLarge;
4076 if (pb->isFlat()
4077 || (pb->rect().height() != pushButtonDefaultHeight[sizePolicy])) {
4079 }
4080 if (pb->menu() != nullptr)
4083 }
4084 }
4085
4086 return QMacStylePrivate::Box; // Not really, just make it the default
4087 } ();
4088 auto cs = QStyleHelper::widgetSizePolicy(ffw, opt);
4089 if (cs == QStyleHelper::SizeDefault)
4093 d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
4094 break; }
4095 case CE_MenuEmptyArea:
4096 // Skip: PE_PanelMenu fills in everything
4097 break;
4098 case CE_MenuItem:
4099 case CE_MenuHMargin:
4100 case CE_MenuVMargin:
4101 case CE_MenuTearoff:
4102 case CE_MenuScroller:
4103 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4104 const bool active = mi->state & State_Selected;
4105 if (active)
4106 p->fillRect(mi->rect, mi->palette.highlight());
4107
4108 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt, w);
4109
4110 if (ce == CE_MenuTearoff) {
4111 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4112 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4113 mi->rect.x() + mi->rect.width() - 4,
4114 mi->rect.y() + mi->rect.height() / 2 - 1);
4115 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4116 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4117 mi->rect.x() + mi->rect.width() - 4,
4118 mi->rect.y() + mi->rect.height() / 2);
4119 } else if (ce == CE_MenuScroller) {
4120 const QSize scrollerSize = QSize(10, 8);
4121 const int scrollerVOffset = 5;
4122 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
4123 const int right = left + scrollerSize.width();
4124 int top;
4125 int bottom;
4126 if (opt->state & State_DownArrow) {
4127 bottom = mi->rect.y() + scrollerVOffset;
4128 top = bottom + scrollerSize.height();
4129 } else {
4130 bottom = mi->rect.bottom() - scrollerVOffset;
4131 top = bottom - scrollerSize.height();
4132 }
4133 p->save();
4134 p->setRenderHint(QPainter::Antialiasing);
4136 path.moveTo(left, bottom);
4137 path.lineTo(right, bottom);
4138 path.lineTo((left + right) / 2, top);
4139 p->fillPath(path, opt->palette.buttonText());
4140 p->restore();
4141 } else if (ce != CE_MenuItem) {
4142 break;
4143 }
4144
4145 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4146 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
4147 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
4148 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
4149 break;
4150 }
4151
4152 const int maxpmw = mi->maxIconWidth;
4153 const bool enabled = mi->state & State_Enabled;
4154
4155 int xpos = mi->rect.x() + 18;
4156 int checkcol = maxpmw;
4157 if (!enabled)
4158 p->setPen(mi->palette.text().color());
4159 else if (active)
4160 p->setPen(mi->palette.highlightedText().color());
4161 else
4162 p->setPen(mi->palette.buttonText().color());
4163
4164 if (mi->checked) {
4165 QStyleOption checkmarkOpt;
4166 checkmarkOpt.initFrom(w);
4167
4168 const int mw = checkcol + macItemFrame;
4169 const int mh = mi->rect.height() + macItemFrame;
4170 const int xp = mi->rect.x() + macItemFrame;
4171 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
4172
4173 checkmarkOpt.state.setFlag(State_On, active);
4174 checkmarkOpt.state.setFlag(State_Enabled, enabled);
4175 if (widgetSize == QStyleHelper::SizeMini)
4176 checkmarkOpt.state |= State_Mini;
4177 else if (widgetSize == QStyleHelper::SizeSmall)
4178 checkmarkOpt.state |= State_Small;
4179
4180 // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color
4181 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
4182 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
4183
4184 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w);
4185 }
4186 if (!mi->icon.isNull()) {
4189 // Always be normal or disabled to follow the Mac style.
4190 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4191 QSize iconSize(smallIconSize, smallIconSize);
4192#if QT_CONFIG(combobox)
4193 if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
4194 iconSize = comboBox->iconSize();
4195 }
4196#endif
4197 QPixmap pixmap = mi->icon.pixmap(iconSize, p->device()->devicePixelRatio(), mode);
4198 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
4199 QSize size = pixmap.deviceIndependentSize().toSize();
4200 QRect pmr(QPoint(0, 0), size);
4201 pmr.moveCenter(cr.center());
4202 p->drawPixmap(pmr.topLeft(), pixmap);
4203 xpos += size.width() + 6;
4204 }
4205
4206 QString s = mi->text;
4207 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
4209 int yPos = mi->rect.y();
4210 if (widgetSize == QStyleHelper::SizeMini)
4211 yPos += 1;
4212
4213 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
4214 const int tabwidth = isSubMenu ? 9 : mi->reservedShortcutWidth;
4215
4216 QString rightMarginText;
4217 if (isSubMenu)
4218 rightMarginText = QStringLiteral("\u25b6\ufe0e"); // U+25B6 U+FE0E: BLACK RIGHT-POINTING TRIANGLE
4219
4220 // If present, save and remove embedded shorcut from text
4221 const int tabIndex = s.indexOf(QLatin1Char('\t'));
4222 if (tabIndex >= 0) {
4223 if (!isSubMenu) // ... but ignore it if it's a submenu.
4224 rightMarginText = s.mid(tabIndex + 1);
4225 s = s.left(tabIndex);
4226 }
4227
4228 p->save();
4229 if (!rightMarginText.isEmpty()) {
4230 p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
4231 int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
4232 if (isSubMenu) {
4233 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
4234 } else {
4235 xp -= macItemHMargin + macItemFrame + 3; // Adjust for shortcut
4236 // try to render modifier part of shortcut string right aligned, key part left aligned
4238 if (seq.count() == 1) { // one-combo sequence, the right most character is the key
4239 // we don't know which key of all menu items is the widest, so use the widest possible
4240 const int maxKeyWidth = p->fontMetrics().maxWidth();
4241 const QChar key = rightMarginText.at(rightMarginText.length() - 1);
4242 const QString modifiers = rightMarginText.left(rightMarginText.size() - 1);
4243 p->drawText(xp + tabwidth - maxKeyWidth, yPos, maxKeyWidth, mi->rect.height(), text_flags, key);
4244 // don't clip the shortcuts; maxKeyWidth might be more than what we have been allotted by the menu
4245 p->drawText(xp, yPos, tabwidth - maxKeyWidth, mi->rect.height(),
4246 text_flags | Qt::AlignRight | Qt::TextDontClip, modifiers);
4247 } else { // draw the whole thing left-aligned for complex or unparsable cases
4248 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags, rightMarginText);
4249 }
4250 }
4251 }
4252
4253 if (!s.isEmpty()) {
4254 const int xm = macItemFrame + maxpmw + macItemHMargin;
4255 QFont myFont = mi->font;
4256 // myFont may not have any "hard" flags set. We override
4257 // the point size so that when it is resolved against the device, this font will win.
4258 // This is mainly to handle cases where someone sets the font on the window
4259 // and then the combo inherits it and passes it onward. At that point the resolve mask
4260 // is very, very weak. This makes it stonger.
4261 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4262
4263 // QTBUG-65653: Our own text rendering doesn't look good enough, especially on non-retina
4264 // displays. Worked around here while waiting for a proper fix in QCoreTextFontEngine.
4265 // Only if we're not using QCoreTextFontEngine we do fallback to our own text rendering.
4266 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
4267 Q_ASSERT(fontEngine);
4268 if (fontEngine->type() == QFontEngine::Multi) {
4269 fontEngine = static_cast<const QFontEngineMulti *>(fontEngine)->engine(0);
4270 Q_ASSERT(fontEngine);
4271 }
4272 if (fontEngine->type() == QFontEngine::Mac) {
4273 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
4274
4275 // Respect the menu item palette as set in the style option.
4276 const auto pc = p->pen().color();
4277 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
4278 green:pc.greenF()
4279 blue:pc.blueF()
4280 alpha:pc.alphaF()];
4281
4283
4284 QMacCGContext cgCtx(p);
4285 d->setupNSGraphicsContext(cgCtx, YES);
4286
4287 // Draw at point instead of in rect, as the rect we've computed for the menu item
4288 // is based on the font metrics we got from HarfBuzz, so we may risk having CoreText
4289 // line-break the string if it doesn't fit the given rect. It's better to draw outside
4290 // the rect and possibly overlap something than to have part of the text disappear.
4291 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
4292 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
4293 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0],
4294 NSUnderlineStyleAttributeName: [NSNumber numberWithInt: myFont.underline() ? NSUnderlineStyleSingle
4295 : NSUnderlineStyleNone]}];
4296
4297 d->restoreNSGraphicsContext(cgCtx);
4298 } else {
4299 p->setFont(myFont);
4300 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
4301 mi->rect.height(), text_flags, s);
4302 }
4303 }
4304 p->restore();
4305 }
4306 break;
4307 case CE_MenuBarItem:
4309 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4310 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
4311 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
4312 p->fillRect(mi->rect, bg);
4313
4314 if (ce != CE_MenuBarItem)
4315 break;
4316
4317 if (!mi->icon.isNull()) {
4318 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4319 drawItemPixmap(p, mi->rect,
4322 mi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(),
4323 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4324 } else {
4325 drawItemText(p, mi->rect,
4328 mi->palette, mi->state & State_Enabled,
4329 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
4330 }
4331 }
4332 break;
4335 // Do nothing. All done in CE_ProgressBarContents. Only keep these for proxy style overrides.
4336 break;
4338 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4339 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4340 const bool vertical = !(pb->state & QStyle::State_Horizontal);
4341 const bool inverted = pb->invertedAppearance;
4342 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4343 if (inverted)
4344 reverse = !reverse;
4345
4346 QRect rect = pb->rect;
4347 if (vertical)
4348 rect = rect.transposed();
4349 const CGRect cgRect = rect.toCGRect();
4350
4351 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, w);
4352 const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
4354 if (isIndeterminate || animation)
4355 ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
4356 if (isIndeterminate) {
4357 // QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
4358 // instance that we start animating as soon as one of the progress bars is indeterminate.
4359 // Since they will be in sync (as it's the case in Cocoa), we just need to draw it with
4360 // the right geometry when the animation triggers an update. However, we can't hide it
4361 // entirely between frames since that would stop the animation, so we just set its alpha
4362 // value to 0. Same if we remove it from its superview. See QIndeterminateProgressIndicator
4363 // implementation for details.
4364 if (!animation && opt->styleObject) {
4366 // NSProgressIndicator is heavier to draw than the HITheme API, so we reduce the frame rate a couple notches.
4368 d->startAnimation(animation);
4369 [ipi startAnimation];
4370 }
4371
4372 d->setupNSGraphicsContext(cg, NO);
4373 d->setupVerticalInvertedXform(cg, reverse, vertical, cgRect);
4374 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
4375 d->restoreNSGraphicsContext(cg);
4376 } else {
4377 if (animation) {
4378 d->stopAnimation(opt->styleObject);
4379 [ipi stopAnimation];
4380 }
4381
4383 auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
4384 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx, const CGRect &rect) {
4385 d->setupVerticalInvertedXform(ctx, reverse, vertical, rect);
4386 pi.minValue = pb->minimum;
4387 pi.maxValue = pb->maximum;
4388 pi.doubleValue = pb->progress;
4389 [pi drawRect:rect];
4390 });
4391 }
4392 }
4393 break;
4394 case CE_SizeGrip: {
4395 // This is not HIG kosher: Fall back to the old stuff until we decide what to do.
4396#ifndef QT_NO_MDIAREA
4397 if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
4398#endif
4399 break;
4400
4401 if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
4402 p->fillRect(opt->rect, opt->palette.window());
4403
4404 QPen lineColor = QColor(82, 82, 82, 192);
4405 lineColor.setWidth(1);
4406 p->save();
4407 p->setRenderHint(QPainter::Antialiasing);
4408 p->setPen(lineColor);
4409 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4410 const int NumLines = 3;
4411 for (int l = 0; l < NumLines; ++l) {
4412 const int offset = (l * 4 + 3);
4413 QPoint start, end;
4414 if (layoutDirection == Qt::LeftToRight) {
4415 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4416 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4417 } else {
4418 start = QPoint(offset, opt->rect.height() - 1);
4419 end = QPoint(1, opt->rect.height() - offset);
4420 }
4421 p->drawLine(start, end);
4422 }
4423 p->restore();
4424 break;
4425 }
4426 case CE_Splitter:
4427 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
4428 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
4429 // Qt refers to the layout orientation, while Cocoa refers to the divider's.
4432 auto *sv = static_cast<NSSplitView *>(d->cocoaControl(cw));
4433 sv.frame = opt->rect.toCGRect();
4434 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
4435 [sv drawDividerInRect:rect];
4436 });
4437 } else {
4438 QPen oldPen = p->pen();
4439 p->setPen(opt->palette.dark().color());
4441 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4442 else
4443 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4444 p->setPen(oldPen);
4445 }
4446 break;
4447 case CE_RubberBand:
4448 if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
4450 if (!rubber->opaque) {
4451 QColor strokeColor;
4452 // I retrieved these colors from the Carbon-Dev mailing list
4453 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4454 fillColor.setHsvF(0, 0, 0.53, 0.25);
4455 if (opt->rect.width() * opt->rect.height() <= 3) {
4456 p->fillRect(opt->rect, strokeColor);
4457 } else {
4458 QPen oldPen = p->pen();
4459 QBrush oldBrush = p->brush();
4460 QPen pen(strokeColor);
4461 p->setPen(pen);
4462 p->setBrush(fillColor);
4463 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
4464 if (adjusted.isValid())
4465 p->drawRect(adjusted);
4466 p->setPen(oldPen);
4467 p->setBrush(oldBrush);
4468 }
4469 } else {
4470 p->fillRect(opt->rect, fillColor);
4471 }
4472 }
4473 break;
4474#ifndef QT_NO_TOOLBAR
4475 case CE_ToolBar: {
4476 const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt);
4477 const bool darkMode = isDarkMode();
4478
4479 // Unified title and toolbar drawing. In this mode the cocoa platform plugin will
4480 // fill the top toolbar area part with a background gradient that "unifies" with
4481 // the title bar. The following code fills the toolBar area with transparent pixels
4482 // to make that gradient visible.
4483 if (w) {
4484#if QT_CONFIG(mainwindow)
4485 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4486 if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
4487 // fill with transparent pixels.
4488 p->save();
4489 p->setCompositionMode(QPainter::CompositionMode_Source);
4490 p->fillRect(opt->rect, Qt::transparent);
4491 p->restore();
4492
4493 // Draw a horizontal separator line at the toolBar bottom if the "unified" area ends here.
4494 // There might be additional toolbars or other widgets such as tab bars in document
4495 // mode below. Determine this by making a unified toolbar area test for the row below
4496 // this toolbar.
4497 const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
4498 const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowToolbarEnd.y() + 1);
4499 if (isEndOfUnifiedArea) {
4500 const int margin = qt_mac_aqua_get_metric(SeparatorSize);
4501 const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
4502 p->fillRect(separatorRect, darkMode ? darkModeSeparatorLine : opt->palette.dark().color());
4503 }
4504 break;
4505 }
4506 }
4507#endif
4508 }
4509
4510 // draw background gradient
4511 QLinearGradient linearGrad;
4512 if (opt->state & State_Horizontal)
4513 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4514 else
4515 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
4516
4517 QColor mainWindowGradientBegin = darkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
4518 QColor mainWindowGradientEnd = darkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
4519
4520 linearGrad.setColorAt(0, mainWindowGradientBegin);
4521 linearGrad.setColorAt(1, mainWindowGradientEnd);
4522 p->fillRect(opt->rect, linearGrad);
4523
4524 p->save();
4525 QRect toolbarRect = darkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
4526 if (opt->state & State_Horizontal) {
4527 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
4528 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
4529 p->setPen(darkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
4530 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
4531 } else {
4532 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
4533 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
4534 p->setPen(darkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
4535 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
4536 }
4537 p->restore();
4538
4539
4540 } break;
4541#endif
4542 default:
4544 break;
4545 }
4546}
4547
4549{
4550 if (dir == Qt::RightToLeft) {
4551 rect->adjust(-right, top, -left, bottom);
4552 } else {
4553 rect->adjust(left, top, right, bottom);
4554 }
4555}
4556
4558 const QWidget *widget) const
4559{
4560 Q_D(const QMacStyle);
4561 QRect rect;
4562 const int controlSize = getControlSize(opt, widget);
4563
4564 switch (sr) {
4565#if QT_CONFIG(itemviews)
4567 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
4569 // We add the focusframeargin between icon and text in commonstyle
4571 if (vopt->features & QStyleOptionViewItem::HasDecoration)
4572 rect.adjust(-fw, 0, 0, 0);
4573 }
4574 break;
4575#endif
4578 break;
4579 case SE_PushButtonBevel:
4581 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4582 // Comment from the old HITheme days:
4583 // "Unlike Carbon, we want the button to always be drawn inside its bounds.
4584 // Therefore, the button is a bit smaller, so that even if it got focus,
4585 // the focus 'shadow' will be inside. Adjust the content rect likewise."
4586 // In the future, we should consider using -[NSCell titleRectForBounds:].
4587 // Since it requires configuring the NSButton fully, i.e. frame, image,
4588 // title and font, we keep things more manual until we are more familiar
4589 // with side effects when changing NSButton state.
4590 const auto ct = cocoaControlType(btn, widget);
4591 const auto cs = d->effectiveAquaSizeConstrain(btn, widget);
4592 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4593 auto frameRect = cw.adjustedControlFrame(btn->rect);
4594 if (sr == SE_PushButtonContents) {
4595 frameRect -= cw.titleMargins();
4596 } else if (cw.type != QMacStylePrivate::Button_SquareButton) {
4597 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
4598 frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:frameRect.toCGRect()]);
4600 frameRect -= pushButtonShadowMargins[cw.size];
4601 else if (cw.type == QMacStylePrivate::Button_PullDown)
4602 frameRect -= pullDownButtonShadowMargins[cw.size];
4603 }
4604 rect = frameRect.toRect();
4605 }
4606 break;
4607 case SE_HeaderLabel: {
4609 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
4610 opt->rect.width() - margin * 2, opt->rect.height() - 2);
4611 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4612 // Subtract width needed for arrow, if there is one
4613 if (header->sortIndicator != QStyleOptionHeader::None) {
4614 if (opt->state & State_Horizontal)
4615 rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
4616 else
4617 rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
4618 }
4619 }
4621 break;
4622 }
4623 case SE_HeaderArrow: {
4624 int h = opt->rect.height();
4625 int w = opt->rect.width();
4626 int x = opt->rect.x();
4627 int y = opt->rect.y();
4629
4630 if (opt->state & State_Horizontal) {
4631 rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
4632 headerSectionArrowHeight, h - margin * 2 - 5);
4633 } else {
4634 rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
4635 w - margin * 2 - 5, headerSectionArrowHeight);
4636 }
4638 break;
4639 }
4641 // Wrong in the secondary dimension, but accurate enough in the main dimension.
4642 rect = opt->rect;
4643 break;
4645 break;
4647 rect = opt->rect;
4648 break;
4650 rect = opt->rect;
4651 // As previously returned by HIThemeGetButtonContentBounds
4652 rect.setLeft(rect.left() + 2 + DisclosureOffset);
4653 break;
4654 }
4655#if QT_CONFIG(tabwidget)
4657 if (const QStyleOptionTabWidgetFrame *twf
4658 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4659 switch (twf->shape) {
4662 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4663 break;
4666 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4667 twf->leftCornerWidgetSize);
4668 break;
4669 default:
4670 break;
4671 }
4672 rect = visualRect(twf->direction, twf->rect, rect);
4673 }
4674 break;
4676 if (const QStyleOptionTabWidgetFrame *twf
4677 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4678 switch (twf->shape) {
4681 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4682 twf->rightCornerWidgetSize);
4683 break;
4686 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4687 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4688 twf->rightCornerWidgetSize);
4689 break;
4690 default:
4691 break;
4692 }
4693 rect = visualRect(twf->direction, twf->rect, rect);
4694 }
4695 break;
4698 if (const auto *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4699 if (twf->lineWidth != 0) {
4700 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4702 rect.adjust(+1, +14, -1, -1);
4703 break;
4705 rect.adjust(+1, +1, -1, -14);
4706 break;
4708 rect.adjust(+14, +1, -1, -1);
4709 break;
4711 rect.adjust(+1, +1, -14, -1);
4712 }
4713 }
4714 }
4715 break;
4716 case SE_TabBarTabText:
4717 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4718 QRect dummyIconRect;
4719 d->tabLayout(tab, widget, &rect, &dummyIconRect);
4720 }
4721 break;
4724 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4725 bool selected = tab->state & State_Selected;
4726 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget);
4727 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget);
4728 int hpadding = 5;
4729
4730 bool verticalTabs = tab->shape == QTabBar::RoundedEast
4731 || tab->shape == QTabBar::RoundedWest
4732 || tab->shape == QTabBar::TriangularEast
4733 || tab->shape == QTabBar::TriangularWest;
4734
4735 QRect tr = tab->rect;
4736 if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
4737 verticalShift = -verticalShift;
4738 if (verticalTabs) {
4739 qSwap(horizontalShift, verticalShift);
4740 horizontalShift *= -1;
4741 verticalShift *= -1;
4742 }
4743 if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
4744 horizontalShift = -horizontalShift;
4745
4746 tr.adjust(0, 0, horizontalShift, verticalShift);
4747 if (selected)
4748 {
4749 tr.setBottom(tr.bottom() - verticalShift);
4750 tr.setRight(tr.right() - horizontalShift);
4751 }
4752
4753 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4754 int w = size.width();
4755 int h = size.height();
4756 int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2));
4757 int midWidth = ((tr.width() - w) / 2);
4758
4759 bool atTheTop = true;
4760 switch (tab->shape) {
4763 atTheTop = (sr == SE_TabBarTabLeftButton);
4764 break;
4767 atTheTop = (sr == SE_TabBarTabRightButton);
4768 break;
4769 default:
4770 if (sr == SE_TabBarTabLeftButton)
4771 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4772 else
4773 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4774 rect = visualRect(tab->direction, tab->rect, rect);
4775 }
4776 if (verticalTabs) {
4777 if (atTheTop)
4778 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4779 else
4780 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4781 }
4782 }
4783 break;
4784#endif
4787#if QT_CONFIG(combobox)
4788 if (widget && qobject_cast<const QComboBox*>(widget->parentWidget()))
4789 rect.adjust(-1, -2, 0, 0);
4790 else
4791#endif
4792 rect.adjust(-1, -1, 0, +1);
4793 break;
4795 rect = opt->rect;
4796 if (controlSize == QStyleHelper::SizeLarge) {
4797 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4798 } else if (controlSize == QStyleHelper::SizeSmall) {
4799 setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction);
4800 } else {
4801 setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction);
4802 }
4803 break;
4805#ifndef QT_NO_TOOLBAR
4806 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4807 // Do nothing, because QToolbar needs the entire widget rect.
4808 // Otherwise it will be clipped. Equivalent to
4809 // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4810 // all the hassle.
4811 } else
4812#endif
4813 {
4814 rect = opt->rect;
4815 if (controlSize == QStyleHelper::SizeLarge) {
4816 rect.adjust(+3, +2, -3, -4);
4817 } else if (controlSize == QStyleHelper::SizeSmall) {
4818 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4819 } else {
4820 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4821 }
4822 }
4823 break;
4824 case SE_LabelLayoutItem:
4825 rect = opt->rect;
4826 setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4827 break;
4829 rect = opt->rect;
4830 int bottom = SIZE(3, 8, 8);
4831 if (opt->state & State_Horizontal) {
4832 rect.adjust(0, +1, 0, -bottom);
4833 } else {
4835 }
4836 break;
4837 }
4839 if (const QStyleOptionButton *buttonOpt
4840 = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4841 if ((buttonOpt->features & QStyleOptionButton::Flat))
4842 break; // leave rect alone
4843 if ((buttonOpt->features & QStyleOptionButton::CommandLinkButton)) {
4844 rect = opt->rect;
4845 if (controlSize == QStyleHelper::SizeLarge)
4846 rect.adjust(+6, +4, -6, -8);
4847 else if (controlSize == QStyleHelper::SizeSmall)
4848 rect.adjust(+5, +4, -5, -6);
4849 else
4850 rect.adjust(+1, 0, -1, -2);
4851 break;
4852 }
4853 }
4854 rect = opt->rect;
4855 if (controlSize == QStyleHelper::SizeLarge) {
4856 rect.adjust(0, +4, 0, -8);
4857 } else if (controlSize == QStyleHelper::SizeSmall) {
4858 rect.adjust(0, +4, 0, -6);
4859 } else {
4860 rect.adjust(0, 0, 0, -2);
4861 }
4862 break;
4864 rect = opt->rect;
4865 if (controlSize == QStyleHelper::SizeLarge) {
4866 setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */,
4867 0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction);
4868 } else if (controlSize == QStyleHelper::SizeSmall) {
4869 rect.adjust(0, +6, 0 /* fix */, -5);
4870 } else {
4871 rect.adjust(0, +6, 0 /* fix */, -7);
4872 }
4873 break;
4875 if (const QStyleOptionSlider *sliderOpt
4876 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4877 rect = opt->rect;
4878 if (sliderOpt->tickPosition == QSlider::NoTicks) {
4879 int above = SIZE(3, 0, 2);
4880 int below = SIZE(4, 3, 0);
4881 if (sliderOpt->orientation == Qt::Horizontal) {
4882 rect.adjust(0, +above, 0, -below);
4883 } else {
4884 rect.adjust(+above, 0, -below, 0); //### Seems that QSlider flip the position of the ticks in reverse mode.
4885 }
4886 } else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4887 int below = SIZE(3, 2, 0);
4888 if (sliderOpt->orientation == Qt::Horizontal) {
4889 rect.setHeight(rect.height() - below);
4890 } else {
4891 rect.setWidth(rect.width() - below);
4892 }
4893 } else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4894 int above = SIZE(3, 2, 0);
4895 if (sliderOpt->orientation == Qt::Horizontal) {
4896 rect.setTop(rect.top() + above);
4897 } else {
4898 rect.setLeft(rect.left() + above);
4899 }
4900 }
4901 }
4902 break;
4903 case SE_FrameLayoutItem:
4904 // hack because QStyleOptionFrame doesn't have a frameStyle member
4905 if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4906 rect = opt->rect;
4907 switch (frame->frameStyle() & QFrame::Shape_Mask) {
4908 case QFrame::HLine:
4909 rect.adjust(0, +1, 0, -1);
4910 break;
4911 case QFrame::VLine:
4912 rect.adjust(+1, 0, -1, 0);
4913 break;
4914 default:
4915 ;
4916 }
4917 }
4918 break;
4920 rect = opt->rect;
4921 if (const QStyleOptionGroupBox *groupBoxOpt =
4922 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4923 /*
4924 AHIG is very inconsistent when it comes to group boxes.
4925 Basically, we make sure that (non-checkable) group boxes
4926 and tab widgets look good when laid out side by side.
4927 */
4928 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4930 int delta;
4931 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4932 delta = SIZE(8, 4, 4); // guess
4933 } else {
4934 delta = SIZE(15, 12, 12); // guess
4935 }
4936 rect.setTop(rect.top() + delta);
4937 }
4938 }
4939 rect.setBottom(rect.bottom() - 1);
4940 break;
4941#if QT_CONFIG(tabwidget)
4943 if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4944 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4945 /*
4946 AHIG specifies "12 or 14" as the distance from the window
4947 edge. We choose 14 and since the default top margin is 20,
4948 the overlap is 6.
4949 */
4950 rect = tabWidgetOpt->rect;
4951 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4952 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4953 }
4954 break;
4955#endif
4956#if QT_CONFIG(dockwidget)
4960 case SE_DockWidgetIcon: {
4963 QRect srect = opt->rect;
4964
4965 const QStyleOptionDockWidget *dwOpt
4966 = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
4967 bool canClose = dwOpt == 0 ? true : dwOpt->closable;
4968 bool canFloat = dwOpt == 0 ? false : dwOpt->floatable;
4969
4970 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4971
4972 // If this is a vertical titlebar, we transpose and work as if it was
4973 // horizontal, then transpose again.
4974 if (verticalTitleBar)
4975 srect = srect.transposed();
4976
4977 do {
4978 int right = srect.right();
4979 int left = srect.left();
4980
4981 QRect closeRect;
4982 if (canClose) {
4984 opt, widget).actualSize(QSize(iconSize, iconSize));
4985 sz += QSize(buttonMargin, buttonMargin);
4986 if (verticalTitleBar)
4987 sz = sz.transposed();
4988 closeRect = QRect(left,
4989 srect.center().y() - sz.height()/2,
4990 sz.width(), sz.height());
4991 left = closeRect.right() + 1;
4992 }
4993 if (sr == SE_DockWidgetCloseButton) {
4994 rect = closeRect;
4995 break;
4996 }
4997
4998 QRect floatRect;
4999 if (canFloat) {
5001 opt, widget).actualSize(QSize(iconSize, iconSize));
5002 sz += QSize(buttonMargin, buttonMargin);
5003 if (verticalTitleBar)
5004 sz = sz.transposed();
5005 floatRect = QRect(left,
5006 srect.center().y() - sz.height()/2,
5007 sz.width(), sz.height());
5008 left = floatRect.right() + 1;
5009 }
5010 if (sr == SE_DockWidgetFloatButton) {
5011 rect = floatRect;
5012 break;
5013 }
5014
5015 QRect iconRect;
5016 if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(widget)) {
5017 QIcon icon;
5018 if (dw->isFloating())
5019 icon = dw->windowIcon();
5020 if (!icon.isNull()
5022 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
5023 if (verticalTitleBar)
5024 sz = sz.transposed();
5025 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
5026 sz.width(), sz.height());
5027 right = iconRect.left() - 1;
5028 }
5029 }
5030 if (sr == SE_DockWidgetIcon) {
5031 rect = iconRect;
5032 break;
5033 }
5034
5035 QRect textRect = QRect(left, srect.top(),
5036 right - left, srect.height());
5037 if (sr == SE_DockWidgetTitleBarText) {
5038 rect = textRect;
5039 break;
5040 }
5041 } while (false);
5042
5043 if (verticalTitleBar) {
5044 rect = QRect(srect.left() + rect.top() - srect.top(),
5045 srect.top() + srect.right() - rect.right(),
5046 rect.height(), rect.width());
5047 } else {
5048 rect = visualRect(opt->direction, srect, rect);
5049 }
5050 break;
5051 }
5052#endif
5053 default:
5055 break;
5056 }
5057 return rect;
5058}
5059
5061{
5062 Q_Q(const QMacStyle);
5063 QStyleOption arrowOpt = *opt;
5068 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
5069}
5070
5072{
5073 CGContextSaveGState(cg);
5074 [NSGraphicsContext saveGraphicsState];
5075
5076 [NSGraphicsContext setCurrentContext:
5077 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
5078}
5079
5081{
5082 [NSGraphicsContext restoreGraphicsState];
5083 CGContextRestoreGState(cg);
5084}
5085
5087 const QWidget *widget) const
5088{
5089 Q_D(const QMacStyle);
5090 const AppearanceSync sync;
5091 QMacCGContext cg(p);
5092 QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : nullptr;
5093 d->resolveCurrentNSView(window);
5094 switch (cc) {
5095 case CC_ScrollBar:
5096 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5097
5098 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
5099 const bool drawKnob = sb->subControls & SC_ScrollBarSlider && sb->minimum != sb->maximum;
5100 if (!drawTrack && !drawKnob)
5101 break;
5102
5103 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5104
5106 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
5107
5108 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
5109 static const CGFloat expandedKnobWidths[] = { 11.0, 9.0, 9.0 };
5110 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt, widget);
5111 const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
5112
5113 const QStyle *realStyle = widget ? widget->style() : proxy();
5114 const bool isTransient = realStyle->styleHint(SH_ScrollBar_Transient, opt, widget);
5115 if (!isTransient)
5116 d->stopAnimation(opt->styleObject);
5117 bool wasActive = false;
5118 CGFloat opacity = 0.0;
5119 CGFloat expandScale = 1.0;
5120 CGFloat expandOffset = 0.0;
5121 bool shouldExpand = false;
5122
5124 const int oldPos = styleObject->property("_q_stylepos").toInt();
5125 const int oldMin = styleObject->property("_q_stylemin").toInt();
5126 const int oldMax = styleObject->property("_q_stylemax").toInt();
5127 const QRect oldRect = styleObject->property("_q_stylerect").toRect();
5128 const QStyle::State oldState = static_cast<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
5129 const uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
5130
5131 // a scrollbar is transient when the scrollbar itself and
5132 // its sibling are both inactive (ie. not pressed/hovered/moved)
5133 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
5134
5135 if (!transient ||
5136 oldPos != sb->sliderPosition ||
5137 oldMin != sb->minimum ||
5138 oldMax != sb->maximum ||
5139 oldRect != sb->rect ||
5140 oldState != sb->state ||
5141 oldActiveControls != sb->activeSubControls) {
5142
5143 // if the scrollbar is transient or its attributes, geometry or
5144 // state has changed, the opacity is reset back to 100% opaque
5145 opacity = 1.0;
5146
5147 styleObject->setProperty("_q_stylepos", sb->sliderPosition);
5148 styleObject->setProperty("_q_stylemin", sb->minimum);
5149 styleObject->setProperty("_q_stylemax", sb->maximum);
5150 styleObject->setProperty("_q_stylerect", sb->rect);
5151 styleObject->setProperty("_q_stylestate", static_cast<QStyle::State::Int>(sb->state));
5152 styleObject->setProperty("_q_stylecontrols", static_cast<uint>(sb->activeSubControls));
5153
5154 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5155 if (transient) {
5156 if (!anim) {
5158 d->startAnimation(anim);
5159 } else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5160 // the scrollbar was already fading out while the
5161 // state changed -> restart the fade out animation
5162 anim->setCurrentTime(0);
5163 }
5164 } else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5165 d->stopAnimation(styleObject);
5166 }
5167 }
5168
5169 QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
5170 if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
5171 // once a scrollbar was active (hovered/pressed), it retains
5172 // the active look even if it's no longer active while fading out
5173 if (oldActiveControls)
5174 anim->setActive(true);
5175
5176 wasActive = anim->wasActive();
5177 opacity = anim->currentValue();
5178 }
5179
5180 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
5181 if (shouldExpand) {
5182 if (!anim && !oldActiveControls) {
5183 // Start expand animation only once and when entering
5185 d->startAnimation(anim);
5186 }
5187 if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
5188 expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
5189 expandOffset = 5.5 * (1.0 - anim->currentValue());
5190 } else {
5191 // Keep expanded state after the animation ends, and when fading out
5192 expandScale = maxExpandScale;
5193 expandOffset = 0.0;
5194 }
5195 }
5196 }
5197
5198 d->setupNSGraphicsContext(cg, NO /* flipped */);
5199
5200 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
5201 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
5202 NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
5203
5205 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
5206 if (isTransient) {
5207 // macOS behavior: as soon as one color channel is >= 128,
5208 // the background is considered bright, scroller is dark.
5209 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
5210 } else {
5211 scroller.knobStyle = NSScrollerKnobStyleDefault;
5212 }
5213
5214 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
5215
5216 if (!setupScroller(scroller, sb))
5217 break;
5218
5219 if (isTransient) {
5220 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame, nullptr);
5221 CGContextSetAlpha(cg, opacity);
5222 }
5223
5224 if (drawTrack) {
5225 // Draw the track when hovering. Expand by shifting the track rect.
5226 if (!isTransient || opt->activeSubControls || wasActive) {
5227 CGRect trackRect = scroller.bounds;
5228 if (isHorizontal)
5229 trackRect.origin.y += expandOffset;
5230 else
5231 trackRect.origin.x += expandOffset;
5232 [scroller drawKnobSlotInRect:trackRect highlight:NO];
5233 }
5234 }
5235
5236 if (drawKnob) {
5237 if (shouldExpand) {
5238 // -[NSScroller drawKnob] is not useful here because any scaling applied
5239 // will only be used to draw the hi-DPI artwork. And even if did scale,
5240 // the stretched knob would look wrong, actually. So we need to draw the
5241 // scroller manually when it's being hovered.
5242 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
5243 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
5244 // Cocoa can help get the exact knob length in the current orientation
5245 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
5246 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
5247 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
5248 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
5249 const CGFloat knobRadius = knobWidth / 2.0;
5250 CGRect knobRect;
5251 if (isHorizontal)
5252 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
5253 else
5254 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
5255 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius, nullptr);
5256 CGContextAddPath(cg, knobPath);
5257 CGContextSetAlpha(cg, 0.5);
5258 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
5259 CGContextSetFillColorWithColor(cg, knobColor);
5260 CGContextFillPath(cg);
5261 } else {
5262 [scroller drawKnob];
5263
5264 if (!isTransient && opt->activeSubControls) {
5265 // The knob should appear darker (going from 0.76 down to 0.49).
5266 // But no blending mode can help darken enough in a single pass,
5267 // so we resort to drawing the knob twice with a small help from
5268 // blending. This brings the gray level to a close enough 0.53.
5269 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
5270 [scroller drawKnob];
5271 }
5272 }
5273 }
5274
5275 if (isTransient)
5276 CGContextEndTransparencyLayer(cg);
5277
5278 d->restoreNSGraphicsContext(cg);
5279 }
5280 break;
5281 case CC_Slider:
5282 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5283 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5285 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5286 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5287 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
5288 if (!setupSlider(slider, sl))
5289 break;
5290
5291 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5292 const bool hasDoubleTicks = sl->tickPosition == QSlider::TicksBothSides;
5293 const bool drawKnob = sl->subControls & SC_SliderHandle;
5294 const bool drawBar = sl->subControls & SC_SliderGroove;
5295 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
5296 const bool isPressed = sl->state & State_Sunken;
5297
5298 CGPoint pressPoint;
5299 if (isPressed) {
5300 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
5301 pressPoint.x = CGRectGetMidX(knobRect);
5302 pressPoint.y = CGRectGetMidY(knobRect);
5303
5304 // The only way to tell a NSSlider/NSSliderCell to render as pressed
5305 // is to start tracking. But this API has some weird behaviors that
5306 // we have to account for. First of all, the pressed state will not
5307 // be visually reflected unless we start tracking twice. And secondly
5308 // if we don't track twice, the state of one render-pass will affect
5309 // the render pass of other sliders, even if we set up the shared
5310 // NSSlider with a new slider value.
5311 [slider.cell startTrackingAt:pressPoint inView:slider];
5312 [slider.cell startTrackingAt:pressPoint inView:slider];
5313 }
5314
5315 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
5316
5317 // Since the GC is flipped, upsideDown means *not* inverted when vertical.
5318 const bool verticalFlip = !isHorizontal && !sl->upsideDown; // FIXME: && !isSierraOrLater
5319
5320 if (isHorizontal) {
5321 if (sl->upsideDown) {
5322 CGContextTranslateCTM(ctx, rect.size.width, rect.origin.y);
5323 CGContextScaleCTM(ctx, -1, 1);
5324 } else {
5325 CGContextTranslateCTM(ctx, 0, rect.origin.y);
5326 }
5327 } else if (verticalFlip) {
5328 CGContextTranslateCTM(ctx, rect.origin.x, rect.size.height);
5329 CGContextScaleCTM(ctx, 1, -1);
5330 }
5331
5332 if (hasDoubleTicks) {
5333 // This ain't HIG kosher: eye-proved constants
5334 if (isHorizontal)
5335 CGContextTranslateCTM(ctx, 0, 4);
5336 else
5337 CGContextTranslateCTM(ctx, 1, 0);
5338 }
5339
5340#if 0
5341 // FIXME: Sadly, this part doesn't work. It seems to somehow pollute the
5342 // NSSlider's internal state and, when we need to use the "else" part,
5343 // the slider's frame is not in sync with its cell dimensions.
5344 const bool drawAllParts = drawKnob && drawBar && (!hasTicks || drawTicks);
5345 if (drawAllParts && !hasDoubleTicks && (!verticalFlip || drawTicks)) {
5346 // Draw eveything at once if we're going to, except for inverted vertical
5347 // sliders which need to be drawn part by part because of the shadow below
5348 // the knob. Same for two-sided tickmarks.
5349 if (verticalFlip && drawTicks) {
5350 // Since tickmarks are always rendered symmetrically, a vertically
5351 // flipped slider with tickmarks only needs to get its value flipped.
5352 slider.intValue = slider.maxValue - slider.intValue + slider.minValue;
5353 }
5354 [slider drawRect:CGRectZero];
5355 } else
5356#endif
5357 {
5358 NSSliderCell *cell = slider.cell;
5359
5360 const int numberOfTickMarks = slider.numberOfTickMarks;
5361 // This ain't HIG kosher: force tick-less bar position.
5362 if (hasDoubleTicks)
5363 slider.numberOfTickMarks = 0;
5364
5365 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
5366 if (drawBar) {
5367 if (!isHorizontal && !sl->upsideDown && (hasDoubleTicks || !hasTicks)) {
5368 // The logic behind verticalFlip and upsideDown is the twisted one.
5369 // Bar is the only part of the cell affected by this 'flipped'
5370 // parameter in the call below, all other parts (knob, etc.) 'fixed'
5371 // by scaling/translating. With ticks on one side it's not a problem
5372 // at all - the bar is gray anyway. Without ticks or with ticks on
5373 // the both sides, for inverted appearance and vertical orientation -
5374 // we must flip so that knob and blue filling work in accordance.
5375 [cell drawBarInside:barRect flipped:true];
5376 } else {
5377 [cell drawBarInside:barRect flipped:!verticalFlip];
5378 }
5379 // This ain't HIG kosher: force unfilled bar look.
5380 if (hasDoubleTicks)
5381 slider.numberOfTickMarks = numberOfTickMarks;
5382 }
5383
5384 if (hasTicks && drawTicks) {
5385 if (!drawBar && hasDoubleTicks)
5386 slider.numberOfTickMarks = numberOfTickMarks;
5387
5388 [cell drawTickMarks];
5389
5390 if (hasDoubleTicks) {
5391 // This ain't HIG kosher: just slap a set of tickmarks on each side, like we used to.
5392 CGAffineTransform tickMarksFlip;
5393 const CGRect tickMarkRect = [cell rectOfTickMarkAtIndex:0];
5394 if (isHorizontal) {
5395 tickMarksFlip = CGAffineTransformMakeTranslation(0, rect.size.height - tickMarkRect.size.height - 3);
5396 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, 1, -1);
5397 } else {
5398 tickMarksFlip = CGAffineTransformMakeTranslation(rect.size.width - tickMarkRect.size.width / 2, 0);
5399 tickMarksFlip = CGAffineTransformScale(tickMarksFlip, -1, 1);
5400 }
5401 CGContextConcatCTM(ctx, tickMarksFlip);
5402 [cell drawTickMarks];
5403 CGContextConcatCTM(ctx, CGAffineTransformInvert(tickMarksFlip));
5404 }
5405 }
5406
5407 if (drawKnob) {
5408 // This ain't HIG kosher: force round knob look.
5409 if (hasDoubleTicks)
5410 slider.numberOfTickMarks = 0;
5411 [cell drawKnob];
5412 }
5413 }
5414 });
5415
5416 if (isPressed) {
5417 // We stop twice to be on the safe side, even if one seems to be enough.
5418 // See startTracking above for why we do this.
5419 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5420 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
5421 }
5422 }
5423 break;
5424#if QT_CONFIG(spinbox)
5425 case CC_SpinBox:
5426 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5427 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5428 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5430 static_cast<QStyleOption &>(frame) = *opt;
5431 frame.rect = lineEditRect;
5432 frame.state |= State_Sunken;
5433 frame.lineWidth = 1;
5434 frame.midLineWidth = 0;
5435 frame.features = QStyleOptionFrame::None;
5438 }
5439 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5440 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget)
5442
5443 d->setupNSGraphicsContext(cg, NO);
5444
5445 const auto aquaSize = d->effectiveAquaSizeConstrain(opt, widget);
5447 NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
5448 cell.enabled = (sb->state & State_Enabled);
5449
5450 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
5451
5452 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
5453 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
5454 const CGFloat x = CGRectGetMidX(newRect);
5455 const CGFloat y = upPressed ? -3 : 3; // Weird coordinate shift going on. Verified with Hopper
5456 const CGPoint pressPoint = CGPointMake(x, y);
5457 // Pretend we're pressing the mouse on the right button. Unfortunately, NSStepperCell has no
5458 // API to highlight a specific button. The highlighted property works only on the down button.
5459 if (upPressed || downPressed)
5460 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
5461
5462 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
5463
5464 if (upPressed || downPressed)
5465 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
5466
5467 d->restoreNSGraphicsContext(cg);
5468 }
5469 }
5470 break;
5471#endif
5472#if QT_CONFIG(combobox)
5473 case CC_ComboBox:
5474 if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5475 const bool isEnabled = combo->state & State_Enabled;
5476 const bool isPressed = combo->state & State_Sunken;
5477
5478 const auto ct = cocoaControlType(combo, widget);
5479 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5480 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5481 auto *cc = static_cast<NSControl *>(d->cocoaControl(cw));
5482 cc.enabled = isEnabled;
5483 QRectF frameRect = cw.adjustedControlFrame(combo->rect);
5485 // Non-editable QComboBox
5486 auto *pb = static_cast<NSPopUpButton *>(cc);
5487 // FIXME Old offsets. Try to move to adjustedControlFrame()
5488 if (cw.size == QStyleHelper::SizeSmall) {
5489 frameRect = frameRect.translated(0, 1);
5490 } else if (cw.size == QStyleHelper::SizeMini) {
5491 // Same 0.5 pt misalignment as AppKit and fit the focus ring
5492 frameRect = frameRect.translated(2, -0.5);
5493 }
5494 pb.frame = frameRect.toCGRect();
5495 [pb highlight:isPressed];
5496 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
5497 [pb.cell drawBezelWithFrame:r inView:pb.superview];
5498 });
5499 } else if (cw.type == QMacStylePrivate::ComboBox) {
5500 // Editable QComboBox
5501 auto *cb = static_cast<NSComboBox *>(cc);
5502 const auto frameRect = cw.adjustedControlFrame(combo->rect);
5503 cb.frame = frameRect.toCGRect();
5504
5505 // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3
5506 if (NSButtonCell *cell = static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) {
5507 cell.highlighted = isPressed;
5508 } else {
5509 // TODO Render to pixmap and darken the button manually
5510 }
5511
5512 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef, const CGRect &r) {
5513 // FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case
5514 [cb.cell drawWithFrame:r inView:cb];
5515 });
5516 }
5517
5518 if (combo->state & State_HasFocus) {
5519 // TODO Remove and use QFocusFrame instead.
5522 QRectF focusRect;
5524 focusRect = QRectF::fromCGRect([cc alignmentRectForFrame:cc.frame]);
5525 focusRect -= pullDownButtonShadowMargins[cw.size];
5526 if (cw.size == QStyleHelper::SizeSmall)
5527 focusRect = focusRect.translated(0, 1);
5528 else if (cw.size == QStyleHelper::SizeMini)
5529 focusRect = focusRect.translated(2, -1);
5530 } else if (cw.type == QMacStylePrivate::ComboBox) {
5531 focusRect = frameRect - comboBoxFocusRingMargins[cw.size];
5532 }
5533 d->drawFocusRing(p, focusRect, hMargin, vMargin, cw);
5534 }
5535 }
5536 break;
5537#endif // QT_CONFIG(combobox)
5538 case CC_TitleBar:
5539 if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5540 const bool isActive = (titlebar->state & State_Active)
5541 && (titlebar->titleBarState & State_Active);
5542
5543 p->fillRect(opt->rect, Qt::transparent);
5544 p->setRenderHint(QPainter::Antialiasing);
5545 p->setClipRect(opt->rect, Qt::IntersectClip);
5546
5547 // FIXME A single drawPath() with 0-sized pen
5548 // doesn't look as good as this double fillPath().
5549 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
5550 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
5551 p->fillPath(outerFramePath, opt->palette.dark());
5552
5553 const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
5554 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
5555 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
5556 p->fillPath(innerFramePath, opt->palette.button());
5557
5558 if (titlebar->subControls & (SC_TitleBarCloseButton
5562 const bool isHovered = (titlebar->state & State_MouseOver);
5563 static const SubControl buttons[] = {
5565 };
5566 for (const auto sc : buttons) {
5567 const auto ct = d->windowButtonCocoaControl(sc);
5569 auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
5570 wb.enabled = (sc & titlebar->subControls) && isActive;
5571 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
5572 Q_UNUSED(isHovered); // FIXME No public API for this
5573
5574 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc, widget);
5575 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
5576 auto *wbCell = static_cast<NSButtonCell *>(wb.cell);
5577 [wbCell drawWithFrame:rect inView:wb];
5578 });
5579 }
5580 }
5581
5582 if (titlebar->subControls & SC_TitleBarLabel) {
5583 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
5584 if (!titlebar->icon.isNull()) {
5585 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5586 const auto iconSize = QSize(iconExtent, iconExtent);
5587 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
5588 // Only render the icon if it'll be fully visible
5589 if (iconPos < tr.right() - titleBarIconTitleSpacing)
5590 p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(iconSize, QIcon::Normal));
5591 }
5592
5593 if (!titlebar->text.isEmpty())
5595 }
5596 }
5597 break;
5598 case CC_GroupBox:
5599 if (const QStyleOptionGroupBox *gb
5600 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5601
5603 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
5604 if (!flat)
5605 groupBox.state |= QStyle::State_Mini; // Force mini-sized checkbox to go with small-sized label
5606 else
5607 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame; // We don't like frames and ugly lines
5608
5609 const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
5610 const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
5611 if (didModifySubControls)
5612 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
5614 if (didModifySubControls) {
5616 const bool rtl = groupBox.direction == Qt::RightToLeft;
5618 const QFont savedFont = p->font();
5619 if (!flat && d->smallSystemFont)
5620 p->setFont(*d->smallSystemFont);
5622 if (!flat)
5623 p->setFont(savedFont);
5624 }
5625 }
5626 break;
5627 case CC_ToolButton:
5628 if (const QStyleOptionToolButton *tb
5629 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5630#if QT_CONFIG(accessibility)
5631 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
5632 if (tb->subControls & SC_ToolButtonMenu) {
5633 QStyleOption arrowOpt = *tb;
5634 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5635 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5636 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5638 } else if ((tb->features & QStyleOptionToolButton::HasMenu)
5639 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
5640 d->drawToolbarButtonArrow(tb, p);
5641 }
5642 if (tb->state & State_On) {
5643 NSView *view = window ? (NSView *)window->winId() : nil;
5644 bool isKey = false;
5645 if (view)
5646 isKey = [view.window isKeyWindow];
5647
5648 QBrush brush(brushForToolButton(isKey));
5650 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
5651 p->setRenderHint(QPainter::Antialiasing);
5652 p->fillPath(path, brush);
5653 }
5655 } else
5656#endif // QT_CONFIG(accessibility)
5657 {
5658 auto bflags = tb->state;
5659 if (tb->subControls & SC_ToolButton)
5660 bflags |= State_Sunken;
5661 auto mflags = tb->state;
5662 if (tb->subControls & SC_ToolButtonMenu)
5663 mflags |= State_Sunken;
5664
5665 if (tb->subControls & SC_ToolButton) {
5666 if (bflags & (State_Sunken | State_On | State_Raised)) {
5667 const bool isEnabled = tb->state & State_Enabled;
5668 const bool isPressed = tb->state & State_Sunken;
5669 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
5671 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5672 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5673 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
5674 pb.bezelStyle = NSBezelStyleShadowlessSquare; // TODO Use NSTexturedRoundedBezelStyle in the future.
5675 pb.frame = opt->rect.toCGRect();
5676 pb.buttonType = NSButtonTypePushOnPushOff;
5677 pb.enabled = isEnabled;
5678 [pb highlight:isPressed];
5679 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
5680 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
5681 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
5682 [pb.cell drawBezelWithFrame:rect inView:pb];
5683 });
5684 }
5685 }
5686
5687 if (tb->subControls & SC_ToolButtonMenu) {
5688 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5689 QStyleOption arrowOpt = *tb;
5690 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
5691 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
5695 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5696 d->drawToolbarButtonArrow(tb, p);
5697 }
5701 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5703 }
5704 }
5705 break;
5706#if QT_CONFIG(dial)
5707 case CC_Dial:
5708 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5709 QStyleHelper::drawDial(dial, p);
5710 break;
5711#endif
5712 default:
5714 break;
5715 }
5716}
5717
5719 const QStyleOptionComplex *opt,
5720 const QPoint &pt, const QWidget *widget) const
5721{
5722 Q_D(const QMacStyle);
5724 switch (cc) {
5725 case CC_ComboBox:
5726 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5728 if (!cmb->editable && sc != QStyle::SC_None)
5729 sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
5730 }
5731 break;
5732 case CC_Slider:
5733 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5734 if (!sl->rect.contains(pt))
5735 break;
5736
5737 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5738 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5740 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5741 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5742 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
5743 if (!setupSlider(slider, sl))
5744 break;
5745
5746 NSSliderCell *cell = slider.cell;
5747 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5748 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5749 if (knobRect.contains(pt)) {
5750 sc = SC_SliderHandle;
5751 } else if (barRect.contains(pt)) {
5752 sc = SC_SliderGroove;
5753 } else if (hasTicks) {
5754 sc = SC_SliderTickmarks;
5755 }
5756 }
5757 break;
5758 case CC_ScrollBar:
5759 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5760 if (!sb->rect.contains(pt)) {
5761 sc = SC_None;
5762 break;
5763 }
5764
5765 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5767 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5768 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5769 auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
5770 if (!setupScroller(scroller, sb)) {
5771 sc = SC_None;
5772 break;
5773 }
5774
5775 // Since -[NSScroller testPart:] doesn't want to cooperate, we do it the
5776 // straightforward way. In any case, macOS doesn't return line-sized changes
5777 // with NSScroller since 10.7, according to the aforementioned method's doc.
5778 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5779 if (isHorizontal) {
5780 const bool isReverse = sb->direction == Qt::RightToLeft;
5781 if (pt.x() < knobRect.left())
5782 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5783 else if (pt.x() > knobRect.right())
5784 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5785 else
5786 sc = SC_ScrollBarSlider;
5787 } else {
5788 if (pt.y() < knobRect.top())
5790 else if (pt.y() > knobRect.bottom())
5792 else
5793 sc = SC_ScrollBarSlider;
5794 }
5795 }
5796 break;
5797 default:
5799 break;
5800 }
5801 return sc;
5802}
5803
5805 const QWidget *widget) const
5806{
5807 Q_D(const QMacStyle);
5808 QRect ret;
5809 switch (cc) {
5810 case CC_ScrollBar:
5811 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5812 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5813 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5814
5815 NSScrollerPart part = NSScrollerNoPart;
5816 if (sc == SC_ScrollBarSlider) {
5817 part = NSScrollerKnob;
5818 } else if (sc == SC_ScrollBarGroove) {
5819 part = NSScrollerKnobSlot;
5820 } else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5821 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5822 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5823 part = NSScrollerDecrementPage;
5824 else
5825 part = NSScrollerIncrementPage;
5826 }
5827 // And nothing else since 10.7
5828
5829 if (part != NSScrollerNoPart) {
5831 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5832 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5833 auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
5834 if (setupScroller(scroller, sb))
5835 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5836 }
5837 }
5838 break;
5839 case CC_Slider:
5840 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5841 const bool hasTicks = sl->tickPosition != QSlider::NoTicks;
5842 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5844 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
5845 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5846 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
5847 if (!setupSlider(slider, sl))
5848 break;
5849
5850 NSSliderCell *cell = slider.cell;
5851 if (sc == SC_SliderHandle) {
5852 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5853 if (isHorizontal) {
5854 ret.setTop(sl->rect.top());
5855 ret.setBottom(sl->rect.bottom());
5856 } else {
5857 ret.setLeft(sl->rect.left());
5858 ret.setRight(sl->rect.right());
5859 }
5860 } else if (sc == SC_SliderGroove) {
5861 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5862 } else if (hasTicks && sc == SC_SliderTickmarks) {
5863 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5864 if (isHorizontal)
5865 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5866 else
5867 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5868 }
5869
5870 // Invert if needed and extend to the actual bounds of the slider
5871 if (isHorizontal) {
5872 if (sl->upsideDown) {
5873 ret = QRect(sl->rect.right() - ret.right(), sl->rect.top(), ret.width(), sl->rect.height());
5874 } else {
5875 ret.setTop(sl->rect.top());
5876 ret.setBottom(sl->rect.bottom());
5877 }
5878 } else {
5879 if (!sl->upsideDown) {
5880 ret = QRect(sl->rect.left(), sl->rect.bottom() - ret.bottom(), sl->rect.width(), ret.height());
5881 } else {
5882 ret.setLeft(sl->rect.left());
5883 ret.setRight(sl->rect.right());
5884 }
5885 }
5886 }
5887 break;
5888 case CC_TitleBar:
5889 if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5890 // The title bar layout is as follows: close, min, zoom, icon, title
5891 // [ x _ + @ Window Title ]
5892 // Center the icon and title until it starts to overlap with the buttons.
5893 // The icon doesn't count towards SC_TitleBarLabel, but it's still rendered
5894 // next to the title text. See drawComplexControl().
5895 if (sc == SC_TitleBarLabel) {
5896 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1; // FIXME Rounding error?
5897 qreal labelHeight = titlebar->fontMetrics.height();
5898
5899 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
5900 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5901 if (!titlebar->icon.isNull()) {
5902 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5903 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
5904 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5905 }
5906
5907 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5908 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5909 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5910 labelWidth, labelHeight);
5911 } else {
5912 const auto currentButton = d->windowButtonCocoaControl(sc);
5913 if (currentButton == QMacStylePrivate::NoControl)
5914 break;
5915
5916 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5917 QSizeF buttonSize;
5918 for (int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5921 auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
5922 if (ct == currentButton)
5923 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5924 else
5925 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5926 }
5927
5928 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5929 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5930 }
5931 }
5932 break;
5933 case CC_ComboBox:
5934 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5935 const auto ct = cocoaControlType(combo, widget);
5936 const auto cs = d->effectiveAquaSizeConstrain(combo, widget);
5937 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5938 const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
5939
5940 switch (sc) {
5942 ret = editRect.toAlignedRect();
5943 break; }
5944 case SC_ComboBoxArrow:{
5945 ret = editRect.toAlignedRect();
5946 ret.setX(ret.x() + ret.width());
5947 ret.setWidth(combo->rect.right() - ret.right());
5948 break; }
5950 if (combo->editable) {
5951 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5952 const int comboTop = combo->rect.top();
5953 ret = QRect(qRound(inner.origin.x),
5954 comboTop,
5955 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5956 editRect.bottom() - comboTop + 2);
5957 } else {
5958 ret = QRect(combo->rect.x() + 4 - 11,
5959 combo->rect.y() + 1,
5960 editRect.width() + 10 + 11,
5961 1);
5962 }
5963 break; }
5964 default:
5965 break;
5966 }
5967 }
5968 break;
5969 case CC_GroupBox:
5970 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5971 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5972 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5973 bool hasNoText = !checkable && groupBox->text.isEmpty();
5974 switch (sc) {
5975 case SC_GroupBoxLabel:
5976 case SC_GroupBoxCheckBox: {
5977 // Cheat and use the smaller font if we need to
5978 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5979 const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
5981 const int margin = flat || hasNoText ? 0 : 9;
5982 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5983
5984 const QFontMetricsF fm = flat || fontIsSet || !d->smallSystemFont
5986 : QFontMetricsF(*d->smallSystemFont);
5987 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0, nullptr);
5988 const int tw = qCeil(s.width());
5989 const int h = qCeil(fm.height());
5990 ret.setHeight(h);
5991
5992 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5993 QSize(tw, h), ret);
5994 if (flat && checkable)
5995 labelRect.moveLeft(labelRect.left() + 4);
5996 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
5997 bool rtl = groupBox->direction == Qt::RightToLeft;
5998 if (sc == SC_GroupBoxLabel) {
5999 if (checkable) {
6000 int newSum = indicatorWidth + 1;
6001 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
6002 labelRect.moveLeft(newLeft);
6003 if (flat)
6004 labelRect.moveTop(labelRect.top() + 3);
6005 else
6006 labelRect.moveTop(labelRect.top() + 4);
6007 } else if (flat) {
6008 int newLeft = labelRect.left() - (rtl ? 3 : -3);
6009 labelRect.moveLeft(newLeft);
6010 labelRect.moveTop(labelRect.top() + 3);
6011 } else {
6012 int newLeft = labelRect.left() - (rtl ? 3 : 2);
6013 labelRect.moveLeft(newLeft);
6014 labelRect.moveTop(labelRect.top() + 4);
6015 }
6016 ret = labelRect;
6017 }
6018
6019 if (sc == SC_GroupBoxCheckBox) {
6020 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
6021 int top = flat ? ret.top() + 1 : ret.top() + 5;
6022 ret.setRect(left, top,
6023 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
6024 }
6025 break;
6026 }
6028 case SC_GroupBoxFrame: {
6030 int yOffset = 3;
6031 if (!flat) {
6034 fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
6035 yOffset = 5;
6036 }
6037
6038 if (hasNoText)
6039 yOffset = -qCeil(QFontMetricsF(fm).height());
6040 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
6041 if (sc == SC_GroupBoxContents) {
6042 if (flat)
6043 ret.adjust(3, -5, -3, -4); // guess too
6044 else
6045 ret.adjust(3, 3, -3, -4); // guess
6046 }
6047 }
6048 break;
6049 default:
6051 break;
6052 }
6053 }
6054 break;
6055#if QT_CONFIG(spinbox)
6056 case CC_SpinBox:
6057 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
6058 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin, widget);
6059 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
6060 int spinner_w;
6061 int spinBoxSep;
6062 switch (aquaSize) {
6064 spinner_w = 14;
6065 spinBoxSep = 2;
6066 break;
6068 spinner_w = 12;
6069 spinBoxSep = 2;
6070 break;
6072 spinner_w = 10;
6073 spinBoxSep = 1;
6074 break;
6075 default:
6076 Q_UNREACHABLE();
6077 }
6078
6079 switch (sc) {
6080 case SC_SpinBoxUp:
6081 case SC_SpinBoxDown: {
6082 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
6083 break;
6084
6085 const int y = fw;
6086 const int x = spin->rect.width() - spinner_w;
6087 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
6088 int hackTranslateX;
6089 switch (aquaSize) {
6091 hackTranslateX = 0;
6092 break;
6094 hackTranslateX = -2;
6095 break;
6097 hackTranslateX = -1;
6098 break;
6099 default:
6100 Q_UNREACHABLE();
6101 }
6102
6104 NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
6105 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
6106 ret = QRectF::fromCGRect(outRect).toRect();
6107
6108 switch (sc) {
6109 case SC_SpinBoxUp:
6110 ret.setHeight(ret.height() / 2);
6111 break;
6112 case SC_SpinBoxDown:
6113 ret.setY(ret.y() + ret.height() / 2);
6114 break;
6115 default:
6116 Q_ASSERT(0);
6117 break;
6118 }
6119 ret.translate(hackTranslateX, 0); // hack: position the buttons correctly (weird that we need this)
6120 ret = visualRect(spin->direction, spin->rect, ret);
6121 break;
6122 }
6124 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
6125 if (spin->buttonSymbols != QAbstractSpinBox::NoButtons) {
6126 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
6127 ret = visualRect(spin->direction, spin->rect, ret);
6128 }
6129 break;
6130 default:
6131 ret = QCommonStyle::subControlRect(cc, spin, sc, widget);
6132 break;
6133 }
6134 }
6135 break;
6136#endif
6137 case CC_ToolButton:
6139 if (sc == SC_ToolButtonMenu) {
6140#if QT_CONFIG(accessibility)
6141 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
6142 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
6143#endif
6144 ret.adjust(-1, 0, 0, 0);
6145 }
6146 break;
6147 default:
6149 break;
6150 }
6151 return ret;
6152}
6153
6155 const QSize &csz, const QWidget *widget) const
6156{
6157 Q_D(const QMacStyle);
6158 QSize sz(csz);
6159 bool useAquaGuideline = true;
6160
6161 switch (ct) {
6162#if QT_CONFIG(spinbox)
6163 case CT_SpinBox:
6164 if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
6165 const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons);
6166 const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0;
6167 sz += QSize(buttonWidth, 0);
6168 }
6169 break;
6170#endif
6172 // the size between the pane and the "contentsRect" (+4,+4)
6173 // (the "contentsRect" is on the inside of the pane)
6205 // then add the size between the stackwidget and the "contentsRect"
6206#if QT_CONFIG(tabwidget)
6207 if (const QStyleOptionTabWidgetFrame *twf
6208 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
6209 QSize extra(0,0);
6210 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
6211 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
6212
6213 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
6214 if (tabDirection == QMacStylePrivate::North
6215 || tabDirection == QMacStylePrivate::South) {
6216 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
6217 } else {
6218 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
6219 }
6220 sz+= extra;
6221 }
6222#endif
6223 break;
6224#if QT_CONFIG(tabbar)
6226 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
6227 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
6229 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
6230 const bool verticalTabs = tabDirection == QMacStylePrivate::East
6231 || tabDirection == QMacStylePrivate::West;
6232 if (verticalTabs)
6233 sz = sz.transposed();
6234
6235 int defaultTabHeight;
6236 const auto cs = d->effectiveAquaSizeConstrain(opt, widget);
6237 switch (cs) {
6239 if (tab->documentMode)
6240 defaultTabHeight = 24;
6241 else
6242 defaultTabHeight = 21;
6243 break;
6245 defaultTabHeight = 18;
6246 break;
6248 defaultTabHeight = 16;
6249 break;
6250 default:
6251 break;
6252 }
6253
6254 const bool widthSet = !differentFont && tab->icon.isNull();
6255 if (widthSet) {
6256 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
6257 sz.rwidth() = textSize.width();
6258 sz.rheight() = qMax(defaultTabHeight, textSize.height());
6259 } else {
6260 sz.rheight() = qMax(defaultTabHeight, sz.height());
6261 }
6263
6264 if (verticalTabs)
6265 sz = sz.transposed();
6266
6267 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
6268 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
6269
6270 int widgetWidth = 0;
6271 int widgetHeight = 0;
6272 int padding = 0;
6273 if (tab->leftButtonSize.isValid()) {
6274 padding += 8;
6275 widgetWidth += tab->leftButtonSize.width();
6276 widgetHeight += tab->leftButtonSize.height();
6277 }
6278 if (tab->rightButtonSize.isValid()) {
6279 padding += 8;
6280 widgetWidth += tab->rightButtonSize.width();
6281 widgetHeight += tab->rightButtonSize.height();
6282 }
6283
6284 if (verticalTabs) {
6285 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
6286 sz.setHeight(sz.height() + widgetHeight + padding);
6287 } else {
6288 if (widthSet)
6289 sz.setWidth(sz.width() + widgetWidth + padding);
6290 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
6291 }
6292 }
6293 break;
6294#endif
6295 case QStyle::CT_PushButton: {
6296 bool isFlat = false;
6297 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6299 return QCommonStyle::sizeFromContents(ct, opt, sz, widget);
6301 }
6302
6303 // By default, we fit the contents inside a normal rounded push button.
6304 // Do this by add enough space around the contents so that rounded
6305 // borders (including highlighting when active) will show.
6306 QSize macsz;
6307 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget, CT_PushButton, sz, &macsz);
6308 // FIXME See comment in CT_PushButton case in qt_aqua_get_known_size().
6309 if (macsz.width() != -1)
6310 sz.setWidth(macsz.width());
6311 else
6313 // All values as measured from HIThemeGetButtonBackgroundBounds()
6314 if (controlSize != QStyleHelper::SizeMini)
6315 sz.rwidth() += 12; // We like 12 over here.
6316
6317 if (controlSize == QStyleHelper::SizeLarge) {
6318 if (!isFlat)
6319 sz.rwidth() -= 12;
6320 if (sz.height() > 16)
6321 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6322 else
6324 } else {
6325 if (!isFlat)
6326 sz.rwidth() -= 10;
6327 if (controlSize == QStyleHelper::SizeMini)
6328 sz.setHeight(24);
6329 else
6331 }
6332 if (isFlat)
6333 sz.rwidth() -= 13;
6334 break;
6335 }
6337 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
6338 int maxpmw = mi->maxIconWidth;
6339#if QT_CONFIG(combobox)
6340 const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
6341#endif
6342 int w = sz.width(),
6343 h = sz.height();
6344 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
6345 w = 10;
6347 } else {
6348 h = mi->fontMetrics.height() + 2;
6349 if (!mi->icon.isNull()) {
6350#if QT_CONFIG(combobox)
6351 if (comboBox) {
6352 const QSize &iconSize = comboBox->iconSize();
6353 h = qMax(h, iconSize.height() + 4);
6354 maxpmw = qMax(maxpmw, iconSize.width());
6355 } else
6356#endif
6357 {
6358 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
6359 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
6360 }
6361 }
6362 }
6363 if (mi->text.contains(QLatin1Char('\t')))
6364 w += 12;
6365 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
6366 w += 35; // Not quite exactly as it seems to depend on other factors
6367 if (maxpmw)
6368 w += maxpmw + 6;
6369 // add space for a check. All items have place for a check too.
6370 w += 20;
6371#if QT_CONFIG(combobox)
6372 if (comboBox && comboBox->isVisible()) {
6374 cmb.initFrom(comboBox);
6375 cmb.editable = false;
6376 cmb.subControls = QStyle::SC_ComboBoxEditField;
6377 cmb.activeSubControls = QStyle::SC_None;
6380 comboBox).width());
6381 } else
6382#endif
6383 {
6384 w += 12;
6385 }
6386 sz = QSize(w, h);
6387 }
6388 break;
6389 case CT_MenuBarItem:
6390 if (!sz.isEmpty())
6391 sz += QSize(12, 4); // Constants from QWindowsStyle
6392 break;
6393 case CT_ToolButton:
6394 sz.rwidth() += 10;
6395 sz.rheight() += 10;
6396 if (const auto *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt))
6397 if (tb->features & QStyleOptionToolButton::Menu)
6399 return sz;
6400 case CT_ComboBox:
6401 if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
6402 const auto controlSize = d->effectiveAquaSizeConstrain(opt, widget);
6403 if (!cb->editable) {
6404 // See CT_PushButton; we have to fit the focus
6405 // ring and a non-editable combo box is a NSPopUpButton.
6407 // All values as measured from HIThemeGetButtonBackgroundBounds()
6408 if (controlSize != QStyleHelper::SizeMini)
6409 sz.rwidth() += 12; // We like 12 over here.
6410#if 0
6411 // TODO Maybe support square combo boxes
6412 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
6413 sz.rheight() += popupButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
6414 else
6415#endif
6416 } else {
6417 sz.rwidth() += 50; // FIXME Double check this
6418 }
6419
6420 // This should be enough to fit the focus ring
6421 if (controlSize == QStyleHelper::SizeMini)
6422 sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this for CT_PushButton.
6423 else
6424 sz.setHeight(pushButtonDefaultHeight[controlSize]);
6425
6426 return sz;
6427 }
6428 break;
6429 case CT_Menu: {
6430 if (proxy() == this) {
6431 sz = csz;
6432 } else {
6433 QStyleHintReturnMask menuMask;
6434 QStyleOption myOption = *opt;
6435 myOption.rect.setSize(sz);
6436 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask))
6437 sz = menuMask.region.boundingRect().size();
6438 }
6439 break; }
6440 case CT_HeaderSection:{
6441 const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
6443 if (header->text.contains(QLatin1Char('\n')))
6444 useAquaGuideline = false;
6445 break; }
6446 case CT_ScrollBar :
6447 // Make sure that the scroll bar is large enough to display the thumb indicator.
6448 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6449 const int minimumSize = 24; // Smallest knob size, but Cocoa doesn't seem to care
6450 if (slider->orientation == Qt::Horizontal)
6451 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6452 else
6453 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6454 }
6455 break;
6456#if QT_CONFIG(itemviews)
6457 case CT_ItemViewItem:
6458 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
6459 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6460 sz.setHeight(sz.height() + 2);
6461 }
6462 break;
6463#endif
6464
6465 default:
6467 }
6468
6469 if (useAquaGuideline && ct != CT_PushButton) {
6470 // TODO Probably going away at some point
6471 QSize macsz;
6472 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
6473 if (macsz.width() != -1)
6474 sz.setWidth(macsz.width());
6475 if (macsz.height() != -1)
6476 sz.setHeight(macsz.height());
6477 }
6478 }
6479
6480 // The sizes that Carbon and the guidelines gives us excludes the focus frame.
6481 // We compensate for this by adding some extra space here to make room for the frame when drawing:
6482 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
6483 if (combo->editable) {
6484 const auto widgetSize = d->aquaSizeConstrain(opt, widget);
6487 cw.size = widgetSize;
6488 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
6489 sz.rwidth() -= qRound(diffRect.size.width);
6490 sz.rheight() -= qRound(diffRect.size.height);
6491 }
6492 }
6493 return sz;
6494}
6495
6496void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
6497 bool enabled, const QString &text, QPalette::ColorRole textRole) const
6498{
6501 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6502}
6503
6505{
6506 Q_D(QMacStyle);
6507 if (e->type() == QEvent::FocusIn) {
6508 QWidget *f = nullptr;
6509 QWidget *focusWidget = QApplication::focusWidget();
6510#if QT_CONFIG(graphicsview)
6511 if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
6512 QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
6513 if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
6514 QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(focusItem);
6515 if (proxy->widget())
6516 focusWidget = proxy->widget()->focusWidget();
6517 }
6518 }
6519#endif
6520
6521 if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) {
6522#if QT_CONFIG(spinbox)
6523 if (const auto sb = qobject_cast<QAbstractSpinBox *>(focusWidget))
6524 f = sb->property("_q_spinbox_lineedit").value<QWidget *>();
6525 else
6526#endif
6527 f = focusWidget;
6528 }
6529 if (f) {
6530 if (!d->focusWidget)
6531 d->focusWidget = new QFocusFrame(f);
6532 d->focusWidget->setWidget(f);
6533 } else if (d->focusWidget) {
6534 d->focusWidget->setWidget(0);
6535 }
6536 } else if (e->type() == QEvent::FocusOut) {
6537 if (d->focusWidget)
6538 d->focusWidget->setWidget(0);
6539 }
6540 return false;
6541}
6542
6544 const QWidget *widget) const
6545{
6546 switch (standardIcon) {
6547 default:
6551 QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext-macstyle.png"));
6553 QPixmap pix2(pixmap.height(), pixmap.width());
6554 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
6555 pix2.fill(Qt::transparent);
6556 QPainter p(&pix2);
6557 p.translate(pix2.width(), 0);
6558 p.rotate(90);
6559 p.drawPixmap(0, 0, pixmap);
6560 return pix2;
6561 }
6562 return pixmap;
6563 }
6564 }
6565}
6566
6568 QSizePolicy::ControlType control2,
6569 Qt::Orientation orientation,
6570 const QStyleOption *option,
6571 const QWidget *widget) const
6572{
6574 const int controlSize = getControlSize(option, widget);
6575
6576 if (control2 == QSizePolicy::ButtonBox) {
6577 /*
6578 AHIG seems to prefer a 12-pixel margin between group
6579 boxes and the row of buttons. The 20 pixel comes from
6580 Builder.
6581 */
6582 if (control1 & (QSizePolicy::Frame // guess
6583 | QSizePolicy::GroupBox // (AHIG, guess, guess)
6584 | QSizePolicy::TabWidget // guess
6585 | ButtonMask)) { // AHIG
6586 return_SIZE(14, 8, 8);
6587 } else if (control1 == QSizePolicy::LineEdit) {
6588 return_SIZE(8, 8, 8); // Interface Builder
6589 } else {
6590 return_SIZE(20, 7, 7); // Interface Builder
6591 }
6592 }
6593
6594 if ((control1 | control2) & ButtonMask) {
6595 if (control1 == QSizePolicy::LineEdit)
6596 return_SIZE(8, 8, 8); // Interface Builder
6597 else if (control2 == QSizePolicy::LineEdit) {
6598 if (orientation == Qt::Vertical)
6599 return_SIZE(20, 7, 7); // Interface Builder
6600 else
6601 return_SIZE(20, 8, 8);
6602 }
6603 return_SIZE(14, 8, 8); // Interface Builder
6604 }
6605
6606 switch (CT2(control1, control2)) {
6607 case CT1(QSizePolicy::Label): // guess
6616 return_SIZE(8, 6, 5);
6618 return 8; // AHIG
6622 if (orientation == Qt::Vertical)
6623 return_SIZE(8, 8, 7); // AHIG and Builder
6624 break;
6626 if (orientation == Qt::Vertical)
6627 return 5; // (Builder, guess, AHIG)
6628 }
6629
6630 if (orientation == Qt::Horizontal
6632 return_SIZE(12, 10, 8); // guess
6633
6634 if ((control1 | control2) & (QSizePolicy::Frame
6637 /*
6638 These values were chosen so that nested container widgets
6639 look good side by side. Builder uses 8, which looks way
6640 too small, and AHIG doesn't say anything.
6641 */
6642 return_SIZE(16, 10, 10); // guess
6643 }
6644
6645 if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider))
6646 return_SIZE(12, 10, 8); // AHIG
6647
6648 if ((control1 | control2) & QSizePolicy::LineEdit)
6649 return_SIZE(10, 8, 8); // AHIG
6650
6651 /*
6652 AHIG and Builder differ by up to 4 pixels for stacked editable
6653 comboboxes. We use some values that work fairly well in all
6654 cases.
6655 */
6656 if ((control1 | control2) & QSizePolicy::ComboBox)
6657 return_SIZE(10, 8, 7); // guess
6658
6659 /*
6660 Builder defaults to 8, 6, 5 in lots of cases, but most of the time the
6661 result looks too cramped.
6662 */
6663 return_SIZE(10, 8, 6); // guess
6664}
6665
struct capHdr __attribute__
bool isActive
void setCurrentTime(int msecs)
The QApplication class manages the GUI application's control flow and main settings.
static QPalette palette()
Returns the current application palette.
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or \nullptr if no widget in this ap...
\inmodule QtGui
Definition qbitmap.h:16
static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Returns a copy of the given image converted to a bitmap using the specified image conversion flags.
Definition qbitmap.cpp:170
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
void setAlphaF(float alpha)
Sets the alpha of this color to alpha.
Definition qcolor.cpp:1511
QColor darker(int f=200) const noexcept
Definition qcolor.cpp:2857
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
QRgb rgba() const noexcept
Returns the RGB value of the color, including its alpha.
Definition qcolor.cpp:1376
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
QColor lighter(int f=150) const noexcept
Definition qcolor.cpp:2812
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
void setHsvF(float h, float s, float v, float a=1.0)
Sets a HSV color value; h is the hue, s is the saturation, v is the value and a is the alpha componen...
Definition qcolor.cpp:1071
The QComboBox widget combines a button with a dropdown list.
Definition qcombobox.h:24
QSize iconSize
the size of the icons shown in the combobox.
Definition qcombobox.h:38
The QCommonStyle class encapsulates the common Look and Feel of a GUI.
int pixelMetric(PixelMetric m, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const override
\reimp
QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *widget=nullptr) const override
\reimp
QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget=nullptr) const override
\reimp
void unpolish(QWidget *widget) override
\reimp
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const override
QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const override
\reimp
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
\reimp
SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w=nullptr) const override
\reimp
int styleHint(StyleHint sh, const QStyleOption *opt=nullptr, const QWidget *w=nullptr, QStyleHintReturn *shret=nullptr) const override
\reimp
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const override
\reimp
void polish(QPalette &) override
\reimp
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *w=nullptr) const override
\reimp
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *w=nullptr) const override
\reimp
void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const override
\reimp
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition qdockwidget.h:20
\inmodule QtCore
Definition qcoreevent.h:45
@ FocusOut
Definition qcoreevent.h:67
@ StyleChange
Definition qcoreevent.h:136
@ FocusIn
Definition qcoreevent.h:66
@ MouseButtonPress
Definition qcoreevent.h:60
@ MouseButtonRelease
Definition qcoreevent.h:61
Type type() const
Returns the event type.
Definition qcoreevent.h:304
The QFocusFrame widget provides a focus frame which can be outside of a widget's normal paintable are...
Definition qfocusframe.h:17
\reentrant
Definition qfontinfo.h:16
qreal pointSizeF() const
Returns the point size of the matched window system font.
Definition qfont.cpp:3131
\reentrant \inmodule QtGui
\reentrant \inmodule QtGui
int height() const
Returns the height of the font.
QRect boundingRect(QChar) const
Returns the rectangle that is covered by ink if character ch were to be drawn at the origin of the co...
QSize size(int flags, const QString &str, int tabstops=0, int *tabarray=nullptr) const
Returns the size in pixels of text.
static QFontPrivate * get(const QFont &font)
Definition qfont_p.h:193
\reentrant
Definition qfont.h:22
int pointSize() const
Returns the point size of the font.
Definition qfont.cpp:884
void setPointSizeF(qreal)
Sets the point size to pointSize.
Definition qfont.cpp:1010
@ FieldsStayAtSizeHint
Definition qformlayout.h:34
The QFrame class is the base class of widgets that can have a frame.
Definition qframe.h:17
int midLineWidth
the width of the mid-line
Definition qframe.h:23
@ Shape_Mask
Definition qframe.h:57
int frameStyle() const
Returns the frame style.
Definition qframe.cpp:238
@ HLine
Definition qframe.h:43
@ NoFrame
Definition qframe.h:39
@ Box
Definition qframe.h:40
@ VLine
Definition qframe.h:44
int lineWidth
the line width
Definition qframe.h:22
Shape frameShape
the frame shape value from the frame style
Definition qframe.h:20
The QGraphicsItem class is the base class for all graphical items in a QGraphicsScene.
QGraphicsScene * scene() const
Returns the current scene for the item, or \nullptr if the item is not stored in a scene.
virtual int type() const
Returns the type of an item as an int.
The QGraphicsProxyWidget class provides a proxy layer for embedding a QWidget in a QGraphicsScene.
QGraphicsItem * focusItem() const
When the scene is active, this functions returns the scene's current focus item, or \nullptr if no it...
The QGraphicsView class provides a widget for displaying the contents of a QGraphicsScene.
static QPlatformTheme * platformTheme()
static QPlatformNativeInterface * platformNativeInterface()
static bool desktopSettingsAware()
Returns true if Qt is set to use the system's standard colors, fonts, etc.; otherwise returns false.
QIcon windowIcon
the default window icon
T value(const Key &key) const noexcept
Definition qhash.h:1054
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:1019
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
qint64 cacheKey() const
Returns a number that identifies the contents of this QIcon object.
Definition qicon.cpp:819
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
@ Off
Definition qicon.h:23
@ On
Definition qicon.h:23
QSize actualSize(const QSize &size, Mode mode=Normal, State state=Off) const
Returns the actual size of the icon for the requested size, mode, and state.
Definition qicon.cpp:926
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition qicon.cpp:834
\inmodule QtGui
Definition qimage.h:37
int height() const
Returns the height of the image.
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:125
The QKeySequence class encapsulates a key sequence as used by shortcuts.
static QKeySequence fromString(const QString &str, SequenceFormat format=PortableText)
int count() const
Returns the number of keys in the key sequence.
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
\inmodule QtGui
Definition qbrush.h:394
void drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, __attribute__((noescape)) DrawRectBlock drawRectBlock=nil) const
static const int PushButtonRightOffset
QHash< CocoaControl, NSCell * > cocoaCells
void drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
CocoaControlType windowButtonCocoaControl(QStyle::SubControl sc) const
void resolveCurrentNSView(QWindow *window) const
NSView * cocoaControl(CocoaControl widget) const
QHash< CocoaControl, NSView * > cocoaControls
void drawToolbarButtonArrow(const QStyleOption *opt, QPainter *p) const
NSCell * cocoaCell(CocoaControl widget) const
static CGRect comboboxInnerBounds(const CGRect &outterBounds, const CocoaControl &cocoaWidget)
static QList< QPointer< QObject > > scrollBars
void setupNSGraphicsContext(CGContextRef cg, bool flipped) const
QPainterPath windowPanelPath(const QRectF &r) const
static const int PushButtonLeftOffset
static const int PushButtonContentPadding
static QRectF comboboxEditBounds(const QRectF &outterBounds, const CocoaControl &cw)
QStyleHelper::WidgetSizePolicy effectiveAquaSizeConstrain(const QStyleOption *option, const QWidget *widg, QStyle::ContentsType ct=QStyle::CT_CustomBase, QSize szHint=QSize(-1, -1), QSize *insz=0) const
void restoreNSGraphicsContext(CGContextRef cg) const
QStyleHelper::WidgetSizePolicy aquaSizeConstrain(const QStyleOption *option, const QWidget *widg, QStyle::ContentsType ct=QStyle::CT_CustomBase, QSize szHint=QSize(-1, -1), QSize *insz=0) const
void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const
virtual void drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole=QPalette::NoRole) const
Draws the given text in the specified rectangle using the provided painter and palette.
int pixelMetric(PixelMetric pm, const QStyleOption *opt=0, const QWidget *widget=nullptr) const
\reimp
QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *w=nullptr) const
\reimp
void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const
\reimp
virtual int styleHint(StyleHint sh, const QStyleOption *opt=0, const QWidget *w=nullptr, QStyleHintReturn *shret=nullptr) const
\reimp
QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget=nullptr) const
\reimp
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *w=nullptr) const
\reimp
SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w=nullptr) const
\reimp
void polish(QWidget *w)
\reimp
int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const
\reimp
void unpolish(QWidget *w)
\reimp
QPalette standardPalette() const
Returns the style's standard palette.
bool event(QEvent *e)
This virtual function receives events to an object and should return true if the event e was recogniz...
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
\reimp
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt=nullptr, const QWidget *widget=nullptr) const
virtual ~QMacStyle()
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const
\reimp
QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt, const QWidget *widget=nullptr) const
\reimp
void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *w=nullptr) const
\reimp
The QMainWindow class provides a main application window.
Definition qmainwindow.h:25
QWidget * centralWidget() const
Returns the central widget for the main window.
\inmodule QtCore
Definition qmargins.h:270
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
T findChild(QAnyStringView aName, Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns the child of this object that can be cast into type T and that is called name,...
Definition qobject.h:155
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
static constexpr QOperatingSystemVersionBase MacOSCatalina
\variable QOperatingSystemVersion::MacOSCatalina
static constexpr QOperatingSystemVersionBase MacOSMojave
\variable QOperatingSystemVersion::MacOSMojave
static constexpr QOperatingSystemVersionBase MacOSBigSur
\variable QOperatingSystemVersion::MacOSBigSur
qreal devicePixelRatio() const
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
\inmodule QtGui
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ Antialiasing
Definition qpainter.h:52
@ CompositionMode_Source
Definition qpainter.h:101
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
const QBrush & button() const
Returns the button brush of the current color group.
Definition qpalette.h:84
const QBrush & text() const
Returns the text foreground brush of the current color group.
Definition qpalette.h:88
const QBrush & dark() const
Returns the dark brush of the current color group.
Definition qpalette.h:86
const QBrush & brush(ColorGroup cg, ColorRole cr) const
Returns the brush in the specified color group, used for the given color role.
Definition qpalette.cpp:748
void setCurrentColorGroup(ColorGroup cg)
Set the palette's current color group to cg.
Definition qpalette.h:65
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition qpalette.h:67
@ Disabled
Definition qpalette.h:49
void setColor(ColorGroup cg, ColorRole cr, const QColor &color)
Sets the color in the specified color group, used for the given color role, to the specified solid co...
Definition qpalette.h:146
const QBrush & window() const
Returns the window (general background) brush of the current color group.
Definition qpalette.h:93
const QBrush & base() const
Returns the base brush of the current color group.
Definition qpalette.h:89
@ HighlightedText
Definition qpalette.h:53
@ ToolTipBase
Definition qpalette.h:57
@ ButtonText
Definition qpalette.h:52
@ WindowText
Definition qpalette.h:51
@ Highlight
Definition qpalette.h:53
const QBrush & buttonText() const
Returns the button text foreground brush of the current color group.
Definition qpalette.h:96
const QBrush & highlightedText() const
Returns the highlighted text brush of the current color group.
Definition qpalette.h:99
\inmodule QtGui
Definition qpen.h:28
void setColor(const QColor &color)
Sets the color of this pen's brush to the given color.
Definition qpen.cpp:705
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QImage toImage() const
Converts the pixmap to a QImage.
Definition qpixmap.cpp:408
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:468
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
Definition qpixmap.cpp:604
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:850
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
Definition qpixmap.cpp:1437
The QPlatformNativeInterface class provides an abstraction for retrieving native resource handles.
virtual NativeResourceForIntegrationFunction nativeResourceFunctionForIntegration(const QByteArray &resource)
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
The QProgressBar widget provides a horizontal or vertical progress bar.
The QRadioButton widget provides a radio button with a text label.
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr QRectF translated(qreal dx, qreal dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:762
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:859
constexpr void translate(qreal dx, qreal dy) noexcept
Moves the rectangle dx along the x-axis and dy along the y-axis, relative to the current position.
Definition qrect.h:738
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:499
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QPoint bottomLeft() const noexcept
Returns the position of the rectangle's bottom-left corner.
Definition qrect.h:230
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr void setSize(const QSize &s) noexcept
Sets the size of the rectangle to the given size.
Definition qrect.h:387
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr QPoint topRight() const noexcept
Returns the position of the rectangle's top-right corner.
Definition qrect.h:227
constexpr void setLeft(int pos) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:191
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr void setRect(int x, int y, int w, int h) noexcept
Sets the coordinates of the rectangle's top-left corner to ({x}, {y}), and its size to the given widt...
Definition qrect.h:346
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr void setWidth(int w) noexcept
Sets the width of the rectangle to the given width.
Definition qrect.h:381
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr QRect transposed() const noexcept
Definition qrect.h:267
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
Definition qrect.h:245
constexpr QPoint bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
Definition qrect.h:224
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
constexpr void moveTo(int x, int t) noexcept
Moves the rectangle, leaving the top-left corner at the given position (x, y).
Definition qrect.h:270
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:233
constexpr void setY(int y) noexcept
Sets the top edge of the rectangle to the given y coordinate.
Definition qrect.h:218
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
The QRubberBand class provides a rectangle or line that can indicate a selection or a boundary.
Definition qrubberband.h:18
\inmodule QtCore
Definition qsize.h:208
constexpr void setHeight(qreal h) noexcept
Sets the height to the given finite height.
Definition qsize.h:341
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
ControlType controlType() const noexcept
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr QSize expandedTo(const QSize &) const noexcept
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition qsize.h:192
constexpr void setWidth(int w) noexcept
Sets the width to the given width.
Definition qsize.h:136
constexpr QSize transposed() const noexcept
Definition qsize.h:142
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:139
@ TicksAbove
Definition qslider.h:27
@ TicksBelow
Definition qslider.h:29
@ TicksBothSides
Definition qslider.h:31
@ NoTicks
Definition qslider.h:26
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString left(qsizetype n) const &
Definition qstring.h:363
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
The QStyleHintReturnMask class provides style hints that return a QRegion.
\variable QStyleOptionGraphicsItem::exposedRect
\variable QStyleOptionHeaderV2::textElideMode
ButtonFeatures features
\variable QStyleOptionToolButton::features
\variable QStyleOptionMenuItem::menuItemType
\variable QStyleOptionComplex::subControls
\variable QStyleOptionFocusRect::backgroundColor
\variable QStyleOptionFrame::features
The QStyleOptionHeader class is used to describe the parameters for drawing a header.
\variable QStyleOptionProgressBar::minimum
\variable QStyleOptionButton::features
\variable QStyleOptionDockWidget::title
The QStyleOption class stores the parameters used by QStyle functions.
QFontMetrics fontMetrics
QStyle::State state
QPalette palette
void initFrom(const QWidget *w)
QObject * styleObject
Qt::LayoutDirection direction
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
@ State_Window
Definition qstyle.h:84
@ State_MouseOver
Definition qstyle.h:80
@ State_Sunken
Definition qstyle.h:69
@ State_HasFocus
Definition qstyle.h:75
@ State_Active
Definition qstyle.h:83
@ State_Children
Definition qstyle.h:86
@ State_Mini
Definition qstyle.h:96
@ State_Small
Definition qstyle.h:95
@ State_NoChange
Definition qstyle.h:71
@ State_Enabled
Definition qstyle.h:67
@ State_DownArrow
Definition qstyle.h:73
@ State_ReadOnly
Definition qstyle.h:94
@ State_Horizontal
Definition qstyle.h:74
@ State_On
Definition qstyle.h:72
@ State_Raised
Definition qstyle.h:68
@ State_Selected
Definition qstyle.h:82
ContentsType
This enum describes the available contents types.
Definition qstyle.h:546
@ CT_Menu
Definition qstyle.h:557
@ CT_ProgressBar
Definition qstyle.h:553
@ CT_CheckBox
Definition qstyle.h:548
@ CT_ItemViewItem
Definition qstyle.h:569
@ CT_SpinBox
Definition qstyle.h:562
@ CT_ToolButton
Definition qstyle.h:550
@ CT_MenuBar
Definition qstyle.h:556
@ CT_PushButton
Definition qstyle.h:547
@ CT_MenuItem
Definition qstyle.h:554
@ CT_CustomBase
Definition qstyle.h:571
@ CT_RadioButton
Definition qstyle.h:549
@ CT_MenuBarItem
Definition qstyle.h:555
@ CT_SizeGrip
Definition qstyle.h:563
@ CT_TabBarTab
Definition qstyle.h:558
@ CT_LineEdit
Definition qstyle.h:561
@ CT_ScrollBar
Definition qstyle.h:560
@ CT_HeaderSection
Definition qstyle.h:566
@ CT_TabWidget
Definition qstyle.h:564
@ CT_Slider
Definition qstyle.h:559
@ CT_ComboBox
Definition qstyle.h:551
virtual QPalette standardPalette() const
Returns the style's standard palette.
Definition qstyle.cpp:2301
virtual QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget=nullptr) const =0
Returns the rectangle containing the specified subControl of the given complex control (with the styl...
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
StyleHint
This enum describes the available style hints.
Definition qstyle.h:584
@ SH_TitleBar_ShowToolTipsOnButtons
Definition qstyle.h:699
@ SH_TabBar_ElideMode
Definition qstyle.h:652
@ SH_ComboBox_ListMouseTracking
Definition qstyle.h:604
@ SH_TabBar_CloseButtonPosition
Definition qstyle.h:677
@ SH_Slider_PageSetButtons
Definition qstyle.h:650
@ SH_TitleBar_NoBorder
Definition qstyle.h:611
@ SH_Menu_Scrollable
Definition qstyle.h:615
@ SH_ScrollView_FrameOnlyAroundContents
Definition qstyle.h:602
@ SH_MainWindow_SpaceBelowMenuBar
Definition qstyle.h:597
@ SH_Menu_Mask
Definition qstyle.h:665
@ SH_ComboBox_Popup
Definition qstyle.h:610
@ SH_EtchDisabledText
Definition qstyle.h:585
@ SH_TabBar_Alignment
Definition qstyle.h:590
@ SH_ItemView_PaintAlternatingRowColorsForEmptyArea
Definition qstyle.h:669
@ SH_ItemView_ChangeHighlightOnFocus
Definition qstyle.h:607
@ SH_ItemView_MovementWithoutUpdatingSelection
Definition qstyle.h:659
@ SH_MenuBar_AltKeyNavigation
Definition qstyle.h:603
@ SH_Menu_SubMenuUniDirection
Definition qstyle.h:692
@ SH_ScrollBar_RollBetweenButtons
Definition qstyle.h:648
@ SH_Menu_MouseTracking
Definition qstyle.h:605
@ SH_ScrollBar_Transient
Definition qstyle.h:681
@ SH_Table_GridLineColor
Definition qstyle.h:619
@ SH_TabBar_AllowWheelScrolling
Definition qstyle.h:704
@ SH_Menu_FlashTriggeredItem
Definition qstyle.h:666
@ SH_Menu_SubMenuPopupDelay
Definition qstyle.h:601
@ SH_ItemView_ArrowKeysNavigateIntoChildren
Definition qstyle.h:664
@ SH_Slider_AbsoluteSetButtons
Definition qstyle.h:649
@ SH_Menu_SubMenuResetWhenReenteringParent
Definition qstyle.h:696
@ SH_ComboBox_PopupFrameStyle
Definition qstyle.h:654
@ SH_Header_ArrowAlignment
Definition qstyle.h:591
@ SH_ToolBox_SelectedPageTitleBold
Definition qstyle.h:622
@ SH_TabBar_PreferNoArrows
Definition qstyle.h:623
@ SH_Menu_KeyboardSearch
Definition qstyle.h:651
@ SH_Button_FocusPolicy
Definition qstyle.h:634
@ SH_Menu_SubMenuSloppySelectOtherActions
Definition qstyle.h:694
@ SH_Menu_SelectionWrap
Definition qstyle.h:658
@ SH_FormLayoutWrapPolicy
Definition qstyle.h:670
@ SH_Widget_ShareActivation
Definition qstyle.h:608
@ SH_ComboBox_LayoutDirection
Definition qstyle.h:643
@ SH_ComboBox_AllowWheelScrolling
Definition qstyle.h:701
@ SH_Menu_AllowActiveAndDisabled
Definition qstyle.h:599
@ SH_TabBar_SelectMouseType
Definition qstyle.h:589
@ SH_Menu_FillScreenWithScroll
Definition qstyle.h:630
@ SH_FontDialog_SelectAssociatedText
Definition qstyle.h:598
@ SH_ToolTipLabel_Opacity
Definition qstyle.h:631
@ SH_ScrollBar_LeftClickAbsolutePosition
Definition qstyle.h:624
@ SH_DialogButtonBox_ButtonsHaveIcons
Definition qstyle.h:656
@ SH_MenuBar_MouseTracking
Definition qstyle.h:606
@ SH_FormLayoutFieldGrowthPolicy
Definition qstyle.h:673
@ SH_UnderlineShortcut
Definition qstyle.h:626
@ SH_ScrollBar_ContextMenu
Definition qstyle.h:647
@ SH_FormLayoutFormAlignment
Definition qstyle.h:674
@ SH_Menu_SubMenuDontStartSloppyOnLeave
Definition qstyle.h:697
@ SH_MessageBox_CenterButtons
Definition qstyle.h:657
@ SH_TitleBar_ModifyNotification
Definition qstyle.h:633
@ SH_Slider_StopMouseOverSlider
Definition qstyle.h:612
@ SH_Slider_SnapToValue
Definition qstyle.h:592
@ SH_SpinBox_ButtonsInsideFrame
Definition qstyle.h:702
@ SH_Menu_FadeOutOnHide
Definition qstyle.h:667
@ SH_GroupBox_TextLabelVerticalAlignment
Definition qstyle.h:616
@ SH_ItemView_ScrollMode
Definition qstyle.h:698
@ SH_PrintDialog_RightAlignButtons
Definition qstyle.h:596
@ SH_BlinkCursorWhenTextSelected
Definition qstyle.h:613
@ SH_DialogButtonLayout
Definition qstyle.h:653
@ SH_TitleBar_AutoRaise
Definition qstyle.h:636
@ SH_ListViewExpand_SelectMouseType
Definition qstyle.h:625
@ SH_ItemView_EllipsisLocation
Definition qstyle.h:644
@ SH_MessageBox_TextInteractionFlags
Definition qstyle.h:655
@ SH_WindowFrame_Mask
Definition qstyle.h:640
@ SH_RichText_FullWidthSelection
Definition qstyle.h:614
@ SH_RubberBand_Mask
Definition qstyle.h:639
@ SH_FormLayoutLabelAlignment
Definition qstyle.h:675
@ SH_ItemView_ShowDecorationSelected
Definition qstyle.h:645
@ SH_DockWidget_ButtonsHaveFrame
Definition qstyle.h:678
@ SH_WizardStyle
Definition qstyle.h:663
@ SH_Menu_SpaceActivatesItem
Definition qstyle.h:600
@ SH_FocusFrame_AboveWidget
Definition qstyle.h:661
@ SH_FocusFrame_Mask
Definition qstyle.h:638
@ SH_Workspace_FillSpaceOnMaximize
Definition qstyle.h:609
virtual void drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const
Draws the given pixmap in the specified rectangle, according to the specified alignment,...
Definition qstyle.cpp:612
virtual QRect itemTextRect(const QFontMetrics &fm, const QRect &r, int flags, bool enabled, const QString &text) const
Returns the area within the given rectangle in which to draw the provided text according to the speci...
Definition qstyle.cpp:510
StandardPixmap
This enum describes the available standard pixmaps.
Definition qstyle.h:716
@ SP_TitleBarCloseButton
Definition qstyle.h:720
@ SP_TitleBarNormalButton
Definition qstyle.h:721
@ SP_MessageBoxQuestion
Definition qstyle.h:729
@ SP_MessageBoxCritical
Definition qstyle.h:728
@ SP_MessageBoxInformation
Definition qstyle.h:726
@ SP_ToolBarVerticalExtensionButton
Definition qstyle.h:745
@ SP_ToolBarHorizontalExtensionButton
Definition qstyle.h:744
@ SP_MessageBoxWarning
Definition qstyle.h:727
ControlElement
This enum represents a control element.
Definition qstyle.h:170
@ CE_ProgressBarLabel
Definition qstyle.h:188
@ CE_MenuItem
Definition qstyle.h:190
@ CE_MenuEmptyArea
Definition qstyle.h:195
@ CE_DockWidgetTitle
Definition qstyle.h:210
@ CE_MenuVMargin
Definition qstyle.h:192
@ CE_TabBarTabLabel
Definition qstyle.h:183
@ CE_Splitter
Definition qstyle.h:208
@ CE_ToolButtonLabel
Definition qstyle.h:200
@ CE_RubberBand
Definition qstyle.h:209
@ CE_HeaderSection
Definition qstyle.h:203
@ CE_TabBarTabShape
Definition qstyle.h:182
@ CE_ProgressBarContents
Definition qstyle.h:187
@ CE_ToolBar
Definition qstyle.h:223
@ CE_MenuBarItem
Definition qstyle.h:197
@ CE_FocusFrame
Definition qstyle.h:220
@ CE_MenuHMargin
Definition qstyle.h:193
@ CE_ToolBoxTabShape
Definition qstyle.h:224
@ CE_MenuTearoff
Definition qstyle.h:194
@ CE_PushButtonBevel
Definition qstyle.h:172
@ CE_ComboBoxLabel
Definition qstyle.h:221
@ CE_MenuBarEmptyArea
Definition qstyle.h:198
@ CE_SizeGrip
Definition qstyle.h:207
@ CE_ProgressBarGroove
Definition qstyle.h:186
@ CE_MenuScroller
Definition qstyle.h:191
@ CE_PushButtonLabel
Definition qstyle.h:173
static QRect alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
Returns a new rectangle of the specified size that is aligned to the given rectangle according to the...
Definition qstyle.cpp:2173
virtual QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget=nullptr) const =0
Returns the sub-area for the given element as described in the provided style option.
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2143
PixelMetric
This enum describes the various available pixel metrics.
Definition qstyle.h:413
@ PM_MenuVMargin
Definition qstyle.h:452
@ PM_LayoutBottomMargin
Definition qstyle.h:515
@ PM_MenuBarHMargin
Definition qstyle.h:460
@ PM_FocusFrameVMargin
Definition qstyle.h:498
@ PM_MenuPanelWidth
Definition qstyle.h:453
@ PM_ScrollBarExtent
Definition qstyle.h:426
@ PM_DockWidgetFrameWidth
Definition qstyle.h:437
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_SizeGripSize
Definition qstyle.h:504
@ PM_DockWidgetTitleMargin
Definition qstyle.h:505
@ PM_ExclusiveIndicatorHeight
Definition qstyle.h:465
@ PM_TabBarTabHSpace
Definition qstyle.h:440
@ PM_LayoutLeftMargin
Definition qstyle.h:512
@ PM_DefaultFrameWidth
Definition qstyle.h:420
@ PM_MaximumDragDistance
Definition qstyle.h:424
@ PM_ToolBarHandleExtent
Definition qstyle.h:484
@ PM_ButtonShiftHorizontal
Definition qstyle.h:417
@ PM_MdiSubWindowFrameWidth
Definition qstyle.h:473
@ PM_ToolBarItemSpacing
Definition qstyle.h:485
@ PM_DockWidgetTitleBarButtonMargin
Definition qstyle.h:509
@ PM_IndicatorWidth
Definition qstyle.h:462
@ PM_TabBarBaseOverlap
Definition qstyle.h:443
@ PM_ScrollView_ScrollBarOverlap
Definition qstyle.h:526
@ PM_DockWidgetSeparatorExtent
Definition qstyle.h:435
@ PM_TabCloseIndicatorWidth
Definition qstyle.h:522
@ PM_CheckBoxLabelSpacing
Definition qstyle.h:502
@ PM_LayoutVerticalSpacing
Definition qstyle.h:517
@ PM_TabBarTabShiftVertical
Definition qstyle.h:480
@ PM_LayoutHorizontalSpacing
Definition qstyle.h:516
@ PM_TabBarBaseHeight
Definition qstyle.h:442
@ PM_ButtonShiftVertical
Definition qstyle.h:418
@ PM_IndicatorHeight
Definition qstyle.h:463
@ PM_ButtonDefaultIndicator
Definition qstyle.h:415
@ PM_LayoutTopMargin
Definition qstyle.h:513
@ PM_SliderControlThickness
Definition qstyle.h:430
@ PM_MenuBarPanelWidth
Definition qstyle.h:457
@ PM_ToolBarItemMargin
Definition qstyle.h:486
@ PM_ToolBarIconSize
Definition qstyle.h:492
@ PM_MenuButtonIndicator
Definition qstyle.h:416
@ PM_MenuDesktopFrameWidth
Definition qstyle.h:455
@ PM_HeaderMargin
Definition qstyle.h:476
@ PM_TabBarTabVSpace
Definition qstyle.h:441
@ PM_MenuHMargin
Definition qstyle.h:451
@ PM_SmallIconSize
Definition qstyle.h:495
@ PM_LargeIconSize
Definition qstyle.h:496
@ PM_IconViewIconSize
Definition qstyle.h:494
@ PM_ToolBarExtensionExtent
Definition qstyle.h:488
@ PM_TabCloseIndicatorHeight
Definition qstyle.h:523
@ PM_SliderLength
Definition qstyle.h:431
@ PM_SplitterWidth
Definition qstyle.h:447
@ PM_RadioButtonLabelSpacing
Definition qstyle.h:511
@ PM_TabBarTabShiftHorizontal
Definition qstyle.h:479
@ PM_SpinBoxFrameWidth
Definition qstyle.h:421
@ PM_LayoutRightMargin
Definition qstyle.h:514
@ PM_FocusFrameHMargin
Definition qstyle.h:499
@ PM_ExclusiveIndicatorWidth
Definition qstyle.h:464
@ PM_ToolTipLabelFrameWidth
Definition qstyle.h:501
@ PM_MenuScrollerHeight
Definition qstyle.h:450
@ PM_TabBarTabOverlap
Definition qstyle.h:439
@ PM_ScrollBarSliderMin
Definition qstyle.h:427
@ PM_MenuBarVMargin
Definition qstyle.h:459
@ PM_ToolBarFrameWidth
Definition qstyle.h:483
ComplexControl
This enum describes the available complex controls.
Definition qstyle.h:331
@ CC_ComboBox
Definition qstyle.h:333
@ CC_GroupBox
Definition qstyle.h:339
@ CC_Slider
Definition qstyle.h:335
@ CC_Dial
Definition qstyle.h:338
@ CC_ToolButton
Definition qstyle.h:336
@ CC_TitleBar
Definition qstyle.h:337
@ CC_SpinBox
Definition qstyle.h:332
@ CC_ScrollBar
Definition qstyle.h:334
PrimitiveElement
This enum describes the various primitive elements.
Definition qstyle.h:102
@ PE_IndicatorToolBarHandle
Definition qstyle.h:141
@ PE_PanelMenu
Definition qstyle.h:159
@ PE_IndicatorArrowLeft
Definition qstyle.h:125
@ PE_IndicatorArrowRight
Definition qstyle.h:126
@ PE_FrameLineEdit
Definition qstyle.h:108
@ PE_PanelLineEdit
Definition qstyle.h:122
@ PE_IndicatorHeaderArrow
Definition qstyle.h:133
@ PE_PanelStatusBar
Definition qstyle.h:156
@ PE_PanelScrollAreaCorner
Definition qstyle.h:146
@ PE_FrameTabWidget
Definition qstyle.h:111
@ PE_FrameGroupBox
Definition qstyle.h:107
@ PE_IndicatorDockWidgetResizeHandle
Definition qstyle.h:132
@ PE_IndicatorArrowDown
Definition qstyle.h:124
@ PE_FrameWindow
Definition qstyle.h:112
@ PE_IndicatorCheckBox
Definition qstyle.h:131
@ PE_PanelTipLabel
Definition qstyle.h:143
@ PE_Frame
Definition qstyle.h:103
@ PE_IndicatorRadioButton
Definition qstyle.h:136
@ PE_IndicatorToolBarSeparator
Definition qstyle.h:142
@ PE_FrameTabBarBase
Definition qstyle.h:115
@ PE_IndicatorArrowUp
Definition qstyle.h:127
@ PE_IndicatorMenuCheckMark
Definition qstyle.h:134
@ PE_IndicatorBranch
Definition qstyle.h:128
@ PE_FrameFocusRect
Definition qstyle.h:106
@ PE_FrameStatusBarItem
Definition qstyle.h:110
@ PE_IndicatorItemViewItemCheck
Definition qstyle.h:130
@ PE_IndicatorTabClose
Definition qstyle.h:158
virtual void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given element with the provided painter with the style options specified by option.
virtual int pixelMetric(PixelMetric metric, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
Returns the value of the given pixel metric.
virtual void drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled, const QString &text, QPalette::ColorRole textRole=QPalette::NoRole) const
Draws the given text in the specified rectangle using the provided painter and palette.
Definition qstyle.cpp:574
SubElement
This enum represents a sub-area of a widget.
Definition qstyle.h:242
@ SE_GroupBoxLayoutItem
Definition qstyle.h:301
@ SE_HeaderLabel
Definition qstyle.h:266
@ SE_ProgressBarGroove
Definition qstyle.h:260
@ SE_RadioButtonLayoutItem
Definition qstyle.h:295
@ SE_ProgressBarLabel
Definition qstyle.h:262
@ SE_TreeViewDisclosureItem
Definition qstyle.h:279
@ SE_TabBarTabRightButton
Definition qstyle.h:309
@ SE_LabelLayoutItem
Definition qstyle.h:292
@ SE_TabWidgetRightCorner
Definition qstyle.h:273
@ SE_TabBarTabText
Definition qstyle.h:310
@ SE_CheckBoxLayoutItem
Definition qstyle.h:289
@ SE_DockWidgetIcon
Definition qstyle.h:287
@ SE_FrameLayoutItem
Definition qstyle.h:300
@ SE_LineEditContents
Definition qstyle.h:281
@ SE_HeaderArrow
Definition qstyle.h:267
@ SE_ProgressBarLayoutItem
Definition qstyle.h:293
@ SE_PushButtonContents
Definition qstyle.h:243
@ SE_TabWidgetLayoutItem
Definition qstyle.h:302
@ SE_DockWidgetTitleBarText
Definition qstyle.h:286
@ SE_ProgressBarContents
Definition qstyle.h:261
@ SE_TabWidgetTabBar
Definition qstyle.h:269
@ SE_TabBarTabLeftButton
Definition qstyle.h:308
@ SE_ComboBoxLayoutItem
Definition qstyle.h:290
@ SE_DockWidgetFloatButton
Definition qstyle.h:285
@ SE_SliderLayoutItem
Definition qstyle.h:296
@ SE_ItemViewItemText
Definition qstyle.h:305
@ SE_PushButtonLayoutItem
Definition qstyle.h:294
@ SE_PushButtonBevel
Definition qstyle.h:320
@ SE_DockWidgetCloseButton
Definition qstyle.h:284
@ SE_TabWidgetLeftCorner
Definition qstyle.h:272
@ SE_ToolBoxTabContents
Definition qstyle.h:264
@ SE_TabWidgetTabContents
Definition qstyle.h:271
virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given primitive element with the provided painter using the style options specified by opti...
const QStyle * proxy() const
Definition qstyle.cpp:2400
SubControl
This enum describes the available sub controls.
Definition qstyle.h:347
@ SC_SliderGroove
Definition qstyle.h:369
@ SC_TitleBarMinButton
Definition qstyle.h:377
@ SC_ScrollBarAddPage
Definition qstyle.h:352
@ SC_TitleBarLabel
Definition qstyle.h:384
@ SC_TitleBarNormalButton
Definition qstyle.h:380
@ SC_ToolButton
Definition qstyle.h:373
@ SC_ScrollBarGroove
Definition qstyle.h:357
@ SC_ScrollBarSlider
Definition qstyle.h:356
@ SC_GroupBoxContents
Definition qstyle.h:392
@ SC_ScrollBarSubPage
Definition qstyle.h:353
@ SC_SpinBoxDown
Definition qstyle.h:360
@ SC_ComboBoxListBoxPopup
Definition qstyle.h:367
@ SC_SpinBoxUp
Definition qstyle.h:359
@ SC_GroupBoxCheckBox
Definition qstyle.h:390
@ SC_GroupBoxLabel
Definition qstyle.h:391
@ SC_None
Definition qstyle.h:348
@ SC_ComboBoxEditField
Definition qstyle.h:365
@ SC_SliderTickmarks
Definition qstyle.h:371
@ SC_TitleBarMaxButton
Definition qstyle.h:378
@ SC_TitleBarCloseButton
Definition qstyle.h:379
@ SC_SpinBoxFrame
Definition qstyle.h:361
@ SC_ComboBoxArrow
Definition qstyle.h:366
@ SC_GroupBoxFrame
Definition qstyle.h:393
@ SC_SpinBoxEditField
Definition qstyle.h:362
@ SC_SliderHandle
Definition qstyle.h:370
@ SC_ToolButtonMenu
Definition qstyle.h:374
int hoveredTabIndex() const
Definition qtabbar.cpp:658
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
@ LeftSide
Definition qtabbar.h:48
@ RightSide
Definition qtabbar.h:49
QWidget * tabButton(int index, ButtonPosition position) const
Returns the widget set a tab index and position or \nullptr if one is not set.
Definition qtabbar.cpp:2821
bool documentMode
Whether or not the tab bar is rendered in a mode suitable for the main window.
Definition qtabbar.h:34
Shape
This enum type lists the built-in shapes supported by QTabBar.
Definition qtabbar.h:42
@ RoundedSouth
Definition qtabbar.h:42
@ RoundedNorth
Definition qtabbar.h:42
@ TriangularEast
Definition qtabbar.h:43
@ RoundedWest
Definition qtabbar.h:42
@ TriangularSouth
Definition qtabbar.h:43
@ RoundedEast
Definition qtabbar.h:42
@ TriangularWest
Definition qtabbar.h:43
@ TriangularNorth
Definition qtabbar.h:43
The QTabWidget class provides a stack of tabbed widgets.
Definition qtabwidget.h:20
The QTableView class provides a default model/view implementation of a table view.
Definition qtableview.h:18
The QToolButton class provides a quick-access button to commands or options, usually used inside a QT...
Definition qtoolbutton.h:20
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
T value() const &
Definition qvariant.h:516
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
uint toUInt(bool *ok=nullptr) const
Returns the variant as an unsigned int if the variant has userType() \l QMetaType::UInt,...
QRect toRect() const
Returns the variant as a QRect if the variant has userType() \l QMetaType::QRect; otherwise returns a...
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4313
Qt::WindowFlags windowFlags() const
Window flags are a combination of a type (e.g.
Definition qwidget.h:803
QSize size
the size of the widget excluding any window frame
Definition qwidget.h:113
void setWindowOpacity(qreal level)
QPalette palette
the widget's palette
Definition qwidget.h:132
QFontMetrics fontMetrics() const
Returns the font metrics for the widget's current font.
Definition qwidget.h:847
QWidget * focusWidget() const
Returns the last child of this widget that setFocus had been called on.
Definition qwidget.cpp:6828
QSizePolicy sizePolicy
the default layout behavior of the widget
Definition qwidget.h:119
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
QWindow * windowHandle() const
If this is a native widget, return the associated QWindow.
Definition qwidget.cpp:2483
QStyle * style() const
Definition qwidget.cpp:2600
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
bool isVisible() const
Definition qwidget.h:874
Qt::WindowType windowType() const
Returns the window type of this widget.
Definition qwidget.h:801
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition qwidget.h:910
\inmodule QtGui
Definition qwindow.h:63
@ MacStyle
Definition qwizard.h:57
EGLContext ctx
EGLImageKHR int int EGLuint64KHR * modifiers
QOpenGLWidget * widget
[1]
QString text
QPushButton * button
[2]
opt iconSize
rect
[4]
QPixmap pix
uint alignment
direction
QStyleOptionButton opt
else opt state
[0]
QRect textRect
const QStyleOptionButton * btn
[3]
QBrush brushForToolButton(bool isOnKeyWindow)
QRect rotateTabPainter(QPainter *p, QStyleOptionTab::Shape shape, QRect tabRect)
void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb)
Q_WIDGETS_EXPORT qreal dpiScaled(qreal value, qreal dpi)
WidgetSizePolicy widgetSizePolicy(const QWidget *widget, const QStyleOption *opt)
QColor backgroundColor(const QPalette &pal, const QWidget *widget)
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ AlignRight
Definition qnamespace.h:146
@ AlignVCenter
Definition qnamespace.h:155
@ AlignTop
Definition qnamespace.h:153
@ AlignHCenter
Definition qnamespace.h:148
@ AlignCenter
Definition qnamespace.h:163
@ AlignAbsolute
Definition qnamespace.h:150
@ AlignLeft
Definition qnamespace.h:144
@ LeftButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:60
@ TextSelectableByMouse
@ LinksAccessibleByMouse
@ TextSelectableByKeyboard
@ WA_SetPalette
Definition qnamespace.h:303
@ WA_MacOpaqueSizeGrip
Definition qnamespace.h:355
@ WA_Hover
Definition qnamespace.h:340
@ WA_TranslucentBackground
Definition qnamespace.h:402
@ WA_PaintOnScreen
Definition qnamespace.h:290
@ WA_MacShowFocusRect
Definition qnamespace.h:359
@ WA_NoSystemBackground
Definition qnamespace.h:291
@ WA_SetFont
Definition qnamespace.h:304
@ WA_OpaquePaintEvent
Definition qnamespace.h:287
@ IntersectClip
@ TopToolBarArea
LayoutDirection
@ LeftToRight
@ RightToLeft
@ TabFocus
Definition qnamespace.h:108
Orientation
Definition qnamespace.h:98
@ Horizontal
Definition qnamespace.h:99
@ Vertical
Definition qnamespace.h:100
@ NoArrow
@ TextSingleLine
Definition qnamespace.h:170
@ TextDontClip
Definition qnamespace.h:171
@ TextHideMnemonic
Definition qnamespace.h:178
@ TextShowMnemonic
Definition qnamespace.h:173
@ gray
Definition qnamespace.h:33
@ white
Definition qnamespace.h:31
@ transparent
Definition qnamespace.h:47
@ black
Definition qnamespace.h:30
@ SolidLine
@ DashLine
@ NoPen
@ AltModifier
@ RoundJoin
@ OddEvenFill
@ Tool
Definition qnamespace.h:212
@ ElideRight
Definition qnamespace.h:190
ToolButtonStyle
@ ToolButtonTextOnly
@ ToolButtonTextUnderIcon
@ ToolButtonTextBesideIcon
@ ToolButtonIconOnly
@ RoundCap
@ FlatCap
Definition brush.cpp:5
QString self
Definition language.cpp:58
@ ButtonMask
static int fontType(const QString &androidControl)
FontHash * qt_app_fonts_hash()
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
float CGFloat
long NSInteger
unsigned long NSUInteger
#define Q_FALLTHROUGH()
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
Definition qcore_mac_p.h:58
#define qApp
QColor qt_mac_toQColor(CGColorRef color)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qDebug
[1]
Definition qlogging.h:164
const int macRightBorder
static const QColor darkModeSeparatorLine(88, 88, 88)
static QStyleHelper::WidgetSizePolicy getControlSize(const QStyleOption *option, const QWidget *widget)
const int macItemFrame
static const qreal focusRingWidth
static const int toolButtonArrowSize
static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
static const QColor darkMainWindowGradientBegin(47, 47, 47)
static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QStyleOption *opt, const QWidget *widg, QSize szHint, QStyleHelper::WidgetSizePolicy sz)
static const QColor lightMainWindowGradientEnd(200, 200, 200)
static const QColor lightMainWindowGradientBegin(240, 240, 240)
bool isDarkMode()
static const QColor titlebarSeparatorLineInactive(131, 131, 131)
static const int headerSectionArrowHeight
static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
static const qreal titleBarIconTitleSpacing
return ret
static QPixmap darkenPixmap(const QPixmap &pixmap)
static const int qt_mac_aqua_metrics[]
static const QColor titlebarSeparatorLineActive(111, 111, 111)
static const qreal titleBarButtonSpacing
static const int toolButtonArrowMargin
QAquaMetric
@ CheckBoxHeight
@ MiniPushButtonHeight
@ HSliderHeight
@ RadioButtonWidth
@ VSliderWidth
@ SmallPopupButtonHeight
@ SmallCheckBoxHeight
@ EditTextFrameOutset
@ MenuSeparatorHeight
@ ProgressBarShadowOutset
@ MiniVSliderWidth
@ ListHeaderHeight
@ MiniVSliderTickWidth
@ SmallProgressBarShadowOutset
@ MiniCheckBoxHeight
@ MiniRadioButtonHeight
@ SmallHSliderHeight
@ SmallRadioButtonHeight
@ SmallVSliderWidth
@ MiniRadioButtonWidth
@ FocusRectOutset
@ HSliderTickHeight
@ SmallCheckBoxWidth
@ SmallHSliderTickHeight
@ SeparatorSize
@ MiniHSliderHeight
@ PushButtonHeight
@ MiniPopupButtonHeight
@ LargeProgressBarThickness
@ RadioButtonHeight
@ SmallVSliderTickWidth
@ SmallRadioButtonWidth
@ MiniHSliderTickHeight
@ SmallPushButtonHeight
@ VSliderTickWidth
@ CheckBoxWidth
@ MiniCheckBoxWidth
@ PopupButtonHeight
@ NormalProgressBarThickness
QMacStylePrivate::CocoaControlType cocoaControlType(const QStyleOption *opt, const QWidget *w)
const int macItemHMargin
static const QMarginsF pullDownButtonShadowMargins[3]
static const qreal popupButtonDefaultHeight[3]
static const QColor darkMainWindowGradientEnd(47, 47, 47)
static QString qt_mac_removeMnemonics(const QString &original)
static const qreal pushButtonDefaultHeight[3]
static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
static const qreal comboBoxDefaultHeight[3]
static const QMarginsF pushButtonShadowMargins[3]
const int pushButtonBevelRectOffsets[3]
static const QMarginsF comboBoxFocusRingMargins[3]
static const int headerSectionSeparatorInset
static int qt_mac_aqua_get_metric(QAquaMetric m)
static const int DisclosureOffset
static const qreal titleBarTitleRightMargin
static bool qt_macWindowMainWindow(const QWidget *window)
#define CT1(c)
#define return_SIZE(large, small, mini)
#define CT2(c1, c2)
#define SIZE(large, small, mini)
#define M_PI_2
Definition qmath.h:213
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLfloat GLfloat f
GLsizei range
GLint GLsizei width
GLint left
GLenum type
GLuint GLsizei const GLchar * label
[43]
GLint GLint bottom
GLenum GLsizeiptr fontSize
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLsizei const GLint * box
GLint y
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLuint GLenum GLenum transform
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLenum GLsizei void * table
struct CGContext * CGContextRef
static constexpr QSize frameSize(const T &frame)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
static bool isWindow(QObject *object)
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(name)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr QRgb qRgba(int r, int g, int b, int a)
Definition qrgb.h:33
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
static const struct TessellationWindingOrderTab cw[]
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define sp
constexpr bool verticalTabs(QTabBar::Shape shape) noexcept
Definition qtabbar_p.h:248
#define QT_CONFIG(feature)
#define tr(X)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
static const int hMargin
static const int vMargin
static QStringList styleNames()
QObject * styleObject(const QStyleOption *option)
const char property[13]
Definition qwizard.cpp:101
static bool isTransient(const QWindow *w)
QWidget * panel
Definition settings.cpp:7
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFile defaults(defaultsPath)
QStringList keys
sem release()
QPropertyAnimation animation
[0]
QPoint oldPosition
[6]
QSharedPointer< T > other(t)
[5]
QString dir
[11]
widget render & pixmap
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
QMenu menu
[5]
QQuickView * view
[0]
QJSEngine engine
[0]
QScroller * scroller
\inmodule QtCore \reentrant
Definition qchar.h:18
QRectF adjustedControlFrame(const QRectF &rect) const
bool operator==(const CocoaControl &other) const
bool getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const
QStyleHelper::WidgetSizePolicy size