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