Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickmacstyle_mac.mm
Go to the documentation of this file.
1// Copyright (C) 2020 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
13#include "qquickstylehelper_p.h"
14
15#include <QtQuickTemplates2/private/qquickcontrol_p.h>
16
17#define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
18//#define DEBUG_SIZE_CONSTRAINT
19
20#include <QtCore/qoperatingsystemversion.h>
21#include <QtCore/qvariant.h>
22#include <QtCore/qvarlengtharray.h>
23
24#include <QtGui/qpainterpath.h>
25#include <QtGui/qpa/qplatformnativeinterface.h>
26#include <QtGui/qpa/qplatformfontdatabase.h>
27#include <QtGui/qpa/qplatformtheme.h>
28
29#include <QtCore/private/qcore_mac_p.h>
30#include <QtGui/private/qcoregraphics_p.h>
31#include <QtGui/private/qguiapplication_p.h>
32
33#include <cmath>
34
36
37// OBS! Changing QT_MANGLE_NAMESPACE and QT_NAMESPACE_ALIAS_OBJC_CLASS to take
38// both QT_NAMESPACE and QQC2_NAMESPACE into account (and not only QT_NAMESPACE, which
39// would otherwise be the case). This will make it possible to link in both widgets and
40// controls in the same application when building statically.
41#undef QT_MANGLE_NAMESPACE
42#undef QT_NAMESPACE_ALIAS_OBJC_CLASS
43
44#define QQC2_MANGLE1(a, b) a##_##b
45#define QQC2_MANGLE2(a, b) QQC2_MANGLE1(a, b)
46
47#if defined(QT_NAMESPACE)
48 #define QT_MANGLE_NAMESPACE(name) QQC2_MANGLE2(QQC2_MANGLE1(name, QQC2_NAMESPACE), QT_NAMESPACE)
49 #define QT_NAMESPACE_ALIAS_OBJC_CLASS(name) @compatibility_alias name QT_MANGLE_NAMESPACE(name)
50#else
51 #define QT_MANGLE_NAMESPACE(name) QQC2_MANGLE2(name, QQC2_NAMESPACE)
52 #define QT_NAMESPACE_ALIAS_OBJC_CLASS(name) @compatibility_alias name QT_MANGLE_NAMESPACE(name)
53#endif
54
55@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
56
57@property (readonly, nonatomic) NSInteger animators;
58
59- (instancetype)init;
60
63
64- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view;
65
66@end
67
69
71
72- (instancetype)init
73{
74 if ((self = [super init])) {
75 _animators = 0;
76 self.indeterminate = YES;
77 self.usesThreadedAnimation = NO;
78 self.alphaValue = 0.0;
79 }
80
81 return self;
82}
83
85{
86 if (_animators == 0) {
87 self.hidden = NO;
88 [super startAnimation:self];
89 }
90 ++_animators;
91}
92
94{
95 --_animators;
96 if (_animators == 0) {
97 [super stopAnimation:self];
98 self.hidden = YES;
99 [self removeFromSuperviewWithoutNeedingDisplay];
100 }
101}
102
103- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view
104{
105 // The alphaValue change is not strictly necessary, but feels safer.
106 self.alphaValue = 1.0;
107 if (self.superview != view)
108 [view addSubview:self];
109 if (!CGRectEqualToRect(self.frame, rect))
110 self.frame = rect;
111 [self drawRect:rect];
112 self.alphaValue = 0.0;
113}
114
115@end
116
117@interface QT_MANGLE_NAMESPACE(QVerticalSplitView) : NSSplitView
118- (BOOL)isVertical;
119@end
120
122
123@implementation QVerticalSplitView
124- (BOOL)isVertical
125{
126 return YES;
127}
128@end
129
130// See render code in drawPrimitive(PE_FrameTabWidget)
131@interface QT_MANGLE_NAMESPACE(QDarkNSBox) : NSBox
132@end
133
135
136@implementation QDarkNSBox
137- (instancetype)init
138{
139 if ((self = [super init])) {
140 self.title = @"";
141 self.titlePosition = NSNoTitle;
142 self.boxType = NSBoxCustom;
143 self.cornerRadius = 3;
144 self.borderColor = [NSColor.controlColor colorWithAlphaComponent:0.1];
145 self.fillColor = [NSColor.darkGrayColor colorWithAlphaComponent:0.2];
146 }
147
148 return self;
149}
150
151- (void)drawRect:(NSRect)rect
152{
153 [super drawRect:rect];
154}
155@end
156
158
159namespace QQC2_NAMESPACE {
160
161// The following constants are used for adjusting the size
162// of push buttons so that they are drawn inside their bounds.
166
167QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
168
169static const QColor titlebarSeparatorLineActive(111, 111, 111);
170static const QColor titlebarSeparatorLineInactive(131, 131, 131);
171static const QColor darkModeSeparatorLine(88, 88, 88);
172
173// Gradient colors used for the dock widget title bar and
174// non-unifed tool bar background.
175static const QColor lightMainWindowGradientBegin(240, 240, 240);
176static const QColor lightMainWindowGradientEnd(200, 200, 200);
177static const QColor darkMainWindowGradientBegin(47, 47, 47);
178static const QColor darkMainWindowGradientEnd(47, 47, 47);
179
180static const int DisclosureOffset = 4;
181
185
186// Tab bar colors
187// active: window is active
188// selected: tab is selected
189// hovered: tab is hovered
190bool isDarkMode() { return qt_mac_applicationIsInDarkMode(); }
191
192static const QColor lightTabBarTabBackgroundActive(190, 190, 190);
193static const QColor darkTabBarTabBackgroundActive(38, 38, 38);
195
199
203
204static const QColor lightTabBarTabBackground(227, 227, 227);
205static const QColor darkTabBarTabBackground(38, 38, 38);
207
208static const QColor lightTabBarTabBackgroundSelected(246, 246, 246);
211
212static const QColor lightTabBarTabLineActive(160, 160, 160);
213static const QColor darkTabBarTabLineActive(90, 90, 90);
215
216static const QColor lightTabBarTabLineActiveHovered(150, 150, 150);
217static const QColor darkTabBarTabLineActiveHovered(90, 90, 90);
219
220static const QColor lightTabBarTabLine(210, 210, 210);
221static const QColor darkTabBarTabLine(90, 90, 90);
223
224static const QColor lightTabBarTabLineSelected(189, 189, 189);
225static const QColor darkTabBarTabLineSelected(90, 90, 90);
227
228static const int closeButtonSize = 14;
229
230#ifndef QT_NO_ACCESSIBILITY // This ifdef to avoid "unused function" warning.
231QBrush brushForToolButton(bool isOnKeyWindow)
232{
233 // When a toolbutton in a toolbar is in the 'ON' state, we draw a
234 // partially transparent background. The colors must be different
235 // for 'Aqua' and 'DarkAqua' appearances though.
236 if (isDarkMode())
237 return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
238
239 return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
240}
241#endif // QT_NO_ACCESSIBILITY
242
243static const int headerSectionArrowHeight = 6;
244static const int headerSectionSeparatorInset = 2;
245
246// These are frame heights as reported by Xcode 9's Interface Builder.
247// Alignemnet rectangle's heights match for push and popup buttons
248// with respective values 21, 18 and 15.
249
250static const qreal comboBoxDefaultHeight[3] = {
251 26, 22, 19
252};
253
255 32, 28, 16
256};
257
259 26, 22, 15
260};
261
262static const int toolButtonArrowSize = 7;
263static const int toolButtonArrowMargin = 2;
264
265static const qreal focusRingWidth = 3.5;
266
267// An application can force 'Aqua' theme while the system theme is one of
268// the 'Dark' variants. Since in Qt we sometimes use NSControls and even
269// NSCells directly without attaching them to any view hierarchy, we have
270// to set NSAppearance.currentAppearance to 'Aqua' manually, to make sure
271// the correct rendering path is triggered. Apple recommends us to un-set
272// the current appearance back after we finished with drawing. This is what
273// AppearanceSync is for.
274
276public:
278 {
279#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
281 && !qt_mac_applicationIsInDarkMode()) {
282 auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
283 if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
284 previous = NSAppearance.currentAppearance;
285 NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
286 }
287 }
288#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
289 }
290
292 {
293 if (previous)
294 NSAppearance.currentAppearance = previous;
295 }
296
297private:
298 NSAppearance *previous = nil;
299
300 Q_DISABLE_COPY(AppearanceSync)
301};
302
303static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
304{
305 const qreal length = sb->maximum - sb->minimum + sb->pageStep;
306 if (qFuzzyIsNull(length))
307 return false;
308 const qreal proportion = sb->pageStep / length;
309 const qreal range = qreal(sb->maximum - sb->minimum);
310 qreal value = range ? qreal(sb->sliderValue - sb->minimum) / range : 0;
311 if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
312 value = 1.0 - value;
313
314 scroller.frame = sb->rect.toCGRect();
315 scroller.floatValue = value;
316 scroller.knobProportion = proportion;
317 return true;
318}
319
320static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
321{
322 if (sl->minimum >= sl->maximum)
323 return false;
324
325 // NSSlider seems to cache values based on tracking and the last layout of the
326 // NSView, resulting in incorrect knob rects that break the interaction with
327 // multiple sliders. So completely reinitialize the slider.
328 [slider initWithFrame:sl->rect.toCGRect()];
329
330 slider.minValue = sl->minimum;
331 slider.maxValue = sl->maximum;
332 slider.intValue = sl->sliderPosition;
333 slider.enabled = sl->state & QStyle::State_Enabled;
334 if (sl->tickPosition != QStyleOptionSlider::NoTicks) {
335 // Set numberOfTickMarks, but TicksBothSides will be treated differently
336 int interval = sl->tickInterval;
337 if (interval == 0) {
338 interval = sl->pageStep;
339 if (interval == 0)
340 interval = sl->singleStep;
341 if (interval == 0)
342 interval = 1; // return false?
343 }
344 slider.numberOfTickMarks = 1 + ((sl->maximum - sl->minimum) / interval);
345
346 const bool ticksAbove = sl->tickPosition == QStyleOptionSlider::TicksAbove;
347 if (sl->orientation == Qt::Horizontal)
348 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
349 else
350 slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
351 } else {
352 slider.numberOfTickMarks = 0;
353 }
354
355 // Ensure the values set above are reflected when asking
356 // the cell for its metrics and to draw itself.
357 [slider layoutSubtreeIfNeeded];
358
359 if (sl->state & QStyle::State_Sunken) {
360 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
361 CGPoint pressPoint;
362 pressPoint.x = CGRectGetMidX(knobRect);
363 pressPoint.y = CGRectGetMidY(knobRect);
364 [slider.cell startTrackingAt:pressPoint inView:slider];
365 }
366
367 return true;
368}
369
370QRect rotateTabPainter(QPainter *p, QStyleOptionTab::Shape shape, QRect tabRect)
371{
372 const auto tabDirection = QMacStylePrivate::tabDirection(shape);
373 if (QMacStylePrivate::verticalTabs(tabDirection)) {
374 int newX, newY, newRot;
375 if (tabDirection == QMacStylePrivate::East) {
376 newX = tabRect.width();
377 newY = tabRect.y();
378 newRot = 90;
379 } else {
380 newX = 0;
381 newY = tabRect.y() + tabRect.height();
382 newRot = -90;
383 }
384 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
386 transform.translate(newX, newY);
387 transform.rotate(newRot);
388 p->setTransform(transform, true);
389 }
390 return tabRect;
391}
392
393void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
394{
395 QRect rect = tabOpt->rect;
396 if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
397 rect = rect.adjusted(-tabOverlap, 0, 0, 0);
398 else
399 rect = rect.adjusted(0, -tabOverlap, 0, 0);
400
401 p->translate(rect.x(), rect.y());
402 rect.moveLeft(0);
403 rect.moveTop(0);
404 const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
405
406 const int width = tabRect.width();
407 const int height = tabRect.height();
408 const bool active = (tabOpt->state & QStyle::State_Active);
409 const bool selected = (tabOpt->state & QStyle::State_Selected);
410
411 const QRect bodyRect(1, 2, width - 2, height - 3);
412 const QRect topLineRect(1, 0, width - 2, 1);
413 const QRect bottomLineRect(1, height - 1, width - 2, 1);
414 if (selected) {
415 // fill body
416 if (tabOpt->documentMode && isUnified) {
417 p->save();
418 p->setCompositionMode(QPainter::CompositionMode_Source);
419 p->fillRect(tabRect, QColor(Qt::transparent));
420 p->restore();
421 } else if (active) {
422 p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
423 // top line
424 p->fillRect(topLineRect, tabBarTabLineSelected());
425 } else {
426 p->fillRect(bodyRect, tabBarTabBackgroundSelected());
427 }
428 } else {
429 // when the mouse is over non selected tabs they get a new color
430 const bool hover = (tabOpt->state & QStyle::State_MouseOver);
431 if (hover) {
432 // fill body
433 p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
434 // bottom line
435 p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
436 }
437 }
438
439 // separator lines between tabs
440 const QRect leftLineRect(0, 1, 1, height - 2);
441 const QRect rightLineRect(width - 1, 1, 1, height - 2);
442 const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
443 p->fillRect(leftLineRect, separatorLineColor);
444 p->fillRect(rightLineRect, separatorLineColor);
445}
446
447void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb)
448{
449 QRect r = tbb->rect;
450// if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tbb->shape)))
451// r.setWidth(w->width());
452// else
453// r.setHeight(w->height());
454
455 const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
456 const int width = tabRect.width();
457 const int height = tabRect.height();
458 const bool active = (tbb->state & QStyle::State_Active);
459
460 // fill body
461 const QRect bodyRect(0, 1, width, height - 1);
462 const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
463 p->fillRect(bodyRect, bodyColor);
464
465 // top line
466 const QRect topLineRect(0, 0, width, 1);
467 const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
468 p->fillRect(topLineRect, topLineColor);
469
470 // bottom line
471 const QRect bottomLineRect(0, height - 1, width, 1);
472 bool isDocument = false;
473// if (const QTabBar *tabBar = qobject_cast<const QTabBar*>(w))
474// isDocument = tabBar->documentMode();
475 const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
476 p->fillRect(bottomLineRect, bottomLineColor);
477}
478
480{
481 const auto wsp = QStyleHelper::widgetSizePolicy(option);
482 if (wsp == QStyleHelper::SizeDefault)
484
485 return wsp;
486}
487
489{
490 QString returnText(original.size(), QChar());
491 int finalDest = 0;
492 int currPos = 0;
493 int l = original.length();
494 while (l) {
495 if (original.at(currPos) == QLatin1Char('&')) {
496 ++currPos;
497 --l;
498 if (l == 0)
499 break;
500 } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 &&
501 original.at(currPos + 1) == QLatin1Char('&') &&
502 original.at(currPos + 2) != QLatin1Char('&') &&
503 original.at(currPos + 3) == QLatin1Char(')')) {
504 /* remove mnemonics its format is "\s*(&X)" */
505 int n = 0;
506 while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
507 ++n;
508 finalDest -= n;
509 currPos += 4;
510 l -= 4;
511 continue;
512 }
513 returnText[finalDest] = original.at(currPos);
514 ++currPos;
515 ++finalDest;
516 --l;
517 }
518 returnText.truncate(finalDest);
519 return returnText;
520}
521
523{
524 if (window->handle()) {
525 if (NSWindow *nswindow = static_cast<NSWindow*>(
527 nativeResourceForWindow(QByteArrayLiteral("nswindow"),
528 const_cast<QWindow *>(window)))) {
529 return [nswindow isMainWindow];
530 }
531 }
532 return false;
533}
534
535#define LargeSmallMini(option, large, small, mini) \
536 (option->state & QStyle::State_Small) ? small : ((option->state & QStyle::State_Mini) ? mini : large)
537
538/*****************************************************************************
539 QMacCGStyle globals
540 *****************************************************************************/
541const int macItemFrame = 2; // menu item frame width
542const int macItemHMargin = 3; // menu item hor text margin
543const int macRightBorder = 12; // right border on mac
544
545/*****************************************************************************
546 QMacCGStyle utility functions
547 *****************************************************************************/
548
592
593static const int qt_mac_aqua_metrics[] = {
594 // Values as of macOS 10.12.4 and Xcode 8.3.1
595 18 /* CheckBoxHeight */,
596 18 /* CheckBoxWidth */,
597 1 /* EditTextFrameOutset */,
598 4 /* FocusRectOutset */,
599 22 /* HSliderHeight */,
600 5 /* HSliderTickHeight */,
601 16 /* LargeProgressBarThickness */,
602 17 /* ListHeaderHeight */,
603 12 /* MenuSeparatorHeight, aka GetThemeMenuSeparatorHeight */,
604 11 /* MiniCheckBoxHeight */,
605 11 /* MiniCheckBoxWidth */,
606 12 /* MiniHSliderHeight */,
607 4 /* MiniHSliderTickHeight */,
608 15 /* MiniPopupButtonHeight */,
609 16 /* MiniPushButtonHeight */,
610 11 /* MiniRadioButtonHeight */,
611 11 /* MiniRadioButtonWidth */,
612 4 /* MiniVSliderTickWidth */,
613 12 /* MiniVSliderWidth */,
614 12 /* NormalProgressBarThickness */,
615 20 /* PopupButtonHeight */,
616 4 /* ProgressBarShadowOutset */,
617 20 /* PushButtonHeight */,
618 18 /* RadioButtonHeight */,
619 18 /* RadioButtonWidth */,
620 1 /* SeparatorSize */,
621 16 /* SmallCheckBoxHeight */,
622 14 /* SmallCheckBoxWidth */,
623 15 /* SmallHSliderHeight */,
624 4 /* SmallHSliderTickHeight */,
625 17 /* SmallPopupButtonHeight */,
626 2 /* SmallProgressBarShadowOutset */,
627 17 /* SmallPushButtonHeight */,
628 15 /* SmallRadioButtonHeight */,
629 15 /* SmallRadioButtonWidth */,
630 4 /* SmallVSliderTickWidth */,
631 15 /* SmallVSliderWidth */,
632 5 /* VSliderTickWidth */,
633 22 /* VSliderWidth */
634};
635
637{
638 return qt_mac_aqua_metrics[m];
639}
640
643{
644 QSize ret(-1, -1);
646 qDebug("Not sure how to return this...");
647 return ret;
648 }
649// if ((widget && widget->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
650// // If you're using a custom font and it's bigger than the default font,
651// // then no constraints for you. If you are smaller, we can try to help you out
652// QFont font = qt_app_fonts_hash()->value(widget->metaObject()->className(), QFont());
653// if (widget->font().pointSize() > font.pointSize())
654// return ret;
655// }
656
657 // TODO: investigate how this function is used. 'ct' can/should be
658 // filled out correctly in the styleoption already from the styleitem?
660// if (ct == QStyle::CT_CustomBase && widget) {
661//#if QT_CONFIG(pushbutton)
662// if (qobject_cast<const QPushButton *>(widg))
663// ct = QStyle::CT_PushButton;
664//#endif
665// else if (qobject_cast<const QRadioButton *>(widget))
666// ct = QStyle::CT_RadioButton;
667//#if QT_CONFIG(checkbox)
668// else if (qobject_cast<const QCheckBox *>(widg))
669// ct = QStyle::CT_CheckBox;
670//#endif
671//#if QT_CONFIG(combobox)
672// else if (qobject_cast<const QComboBox *>(widg))
673// ct = QStyle::CT_ComboBox;
674//#endif
675//#if QT_CONFIG(toolbutton)
676// else if (qobject_cast<const QToolButton *>(widg))
677// ct = QStyle::CT_ToolButton;
678//#endif
679// else if (qobject_cast<const QSlider *>(widget))
680// ct = QStyle::CT_Slider;
681//#if QT_CONFIG(progressbar)
682// else if (qobject_cast<const QProgressBar *>(widg))
683// ct = QStyle::CT_ProgressBar;
684//#endif
685//#if QT_CONFIG(lineedit)
686// else if (qobject_cast<const QLineEdit *>(widg))
687// ct = QStyle::CT_LineEdit;
688//#endif
689//#if QT_CONFIG(itemviews)
690// else if (qobject_cast<const QHeaderView *>(widg))
691// ct = QStyle::CT_HeaderSection;
692//#endif
693//#if QT_CONFIG(menubar)
694// else if (qobject_cast<const QMenuBar *>(widg))
695// ct = QStyle::CT_MenuBar;
696//#endif
697//#if QT_CONFIG(sizegrip)
698// else if (qobject_cast<const QSizeGrip *>(widg))
699// ct = QStyle::CT_SizeGrip;
700//#endif
701// else
702// return ret;
703// }
704
705 switch (ct) {
707 const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt);
708 if (btn) {
709 QString buttonText = qt_mac_removeMnemonics(btn->text);
710 if (buttonText.contains(QLatin1Char('\n')))
711 ret = QSize(-1, -1);
712 else if (sz == QStyleHelper::SizeLarge)
714 else if (sz == QStyleHelper::SizeSmall)
716 else if (sz == QStyleHelper::SizeMini)
718
719 if (!btn->icon.isNull()){
720 // If the button got an icon, and the icon is larger than the
721 // button, we can't decide on a default size
722 ret.setWidth(-1);
723 if (ret.height() < btn->iconSize.height())
724 ret.setHeight(-1);
725 }
726 else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
727 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
728 // However, this doesn't work for German, therefore only do it for English,
729 // I suppose it would be better to do some sort of lookups for languages
730 // that like to have really long words.
731 // FIXME This is not exactly true. Out of context, OK buttons have their
732 // implicit size calculated the same way as any other button. Inside a
733 // QDialogButtonBox, their size should be calculated such that the action
734 // or accept button (i.e., rightmost) and cancel button have the same width.
735 ret.setWidth(69);
736 }
737 } else {
738 // The only sensible thing to do is to return whatever the style suggests...
739 if (sz == QStyleHelper::SizeLarge)
741 else if (sz == QStyleHelper::SizeSmall)
743 else if (sz == QStyleHelper::SizeMini)
745 else
746 // Since there's no default size we return the large size...
748 }
749 break; }
751 // Not HIG kosher: mimic what we were doing earlier until we support 4-edge resizing in MDI subwindows
753 int s = sz == QStyleHelper::SizeSmall ? 16 : 22; // large: pixel measured from HITheme, small: from my hat
754 int width = 0;
755//#if QT_CONFIG(mdiarea)
756// if (widg && qobject_cast<QMdiSubWindow *>(widg->parentWidget()))
757// width = s;
758//#endif
759 ret = QSize(width, s);
760 }
761 break;
763 switch (sz) {
766 break;
769 break;
772 break;
773 default:
774 break;
775 }
776 break;
778 if (sz == QStyleHelper::SizeSmall) {
779 int width = 0, height = 0;
780 if (szHint == QSize(-1, -1)) { //just 'guess'..
781//#if QT_CONFIG(toolbutton)
782// const QStyleOptionToolButton *bt = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
783// // If this conversion fails then the widget was not what it claimed to be.
784// if(bt) {
785// if (!bt->icon.isNull()) {
786// QSize iconSize = bt->iconSize;
787// QSize pmSize = bt->icon.actualSize(QSize(32, 32), QIcon::Normal);
788// width = qMax(width, qMax(iconSize.width(), pmSize.width()));
789// height = qMax(height, qMax(iconSize.height(), pmSize.height()));
790// }
791// if (!bt->text.isNull() && bt->toolButtonStyle != Qt::ToolButtonIconOnly) {
792// int text_width = bt->fontMetrics.horizontalAdvance(bt->text),
793// text_height = bt->fontMetrics.height();
794// if (bt->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
795// width = qMax(width, text_width);
796// height += text_height;
797// } else {
798// width += text_width;
799// width = qMax(height, text_height);
800// }
801// }
802// } else
803//#endif
804 {
805 // Let's return the size hint...
806 width = szHint.width();
807 height = szHint.height();
808 }
809 } else {
810 width = szHint.width();
811 height = szHint.height();
812 }
813 width = qMax(20, width + 5); //border
814 height = qMax(20, height + 5); //border
815 ret = QSize(width, height);
816 }
817 break;
818 case QStyle::CT_Slider: {
819 int w = -1;
820 const QStyleOptionSlider *sld = qstyleoption_cast<const QStyleOptionSlider *>(opt);
821 // If this conversion fails then the widget was not what it claimed to be.
822 if(sld) {
823 if (sz == QStyleHelper::SizeLarge) {
824 if (sld->orientation == Qt::Horizontal) {
826 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
828 } else {
830 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
832 }
833 } else if (sz == QStyleHelper::SizeSmall) {
834 if (sld->orientation == Qt::Horizontal) {
836 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
838 } else {
840 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
842 }
843 } else if (sz == QStyleHelper::SizeMini) {
844 if (sld->orientation == Qt::Horizontal) {
846 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
848 } else {
850 if (sld->tickPosition != QStyleOptionSlider::NoTicks)
852 }
853 }
854 } else {
855 // This is tricky, we were requested to find a size for a slider which is not
856 // a slider. We don't know if this is vertical or horizontal or if we need to
857 // have tick marks or not.
858 // For this case we will return an horizontal slider without tick marks.
861 }
862 if (sld->orientation == Qt::Horizontal)
863 ret.setHeight(w);
864 else
865 ret.setWidth(w);
866 break;
867 }
868//#if QT_CONFIG(progressbar)
869// case QStyle::CT_ProgressBar: {
870// int finalValue = -1;
871// Qt::Orientation orient = Qt::Horizontal;
872// if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
873// orient = pb->orientation();
874
875// if (sz == QStyleHelper::SizeLarge)
876// finalValue = qt_mac_aqua_get_metric(LargeProgressBarThickness)
877// + qt_mac_aqua_get_metric(ProgressBarShadowOutset);
878// else
879// finalValue = qt_mac_aqua_get_metric(NormalProgressBarThickness)
880// + qt_mac_aqua_get_metric(SmallProgressBarShadowOutset);
881// if (orient == Qt::Horizontal)
882// ret.setHeight(finalValue);
883// else
884// ret.setWidth(finalValue);
885// break;
886// }
887//#endif
888//#if QT_CONFIG(combobox)
889// case QStyle::CT_LineEdit:
890// if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
891// //should I take into account the font dimentions of the lineedit? -Sam
892// if (sz == QStyleHelper::SizeLarge)
893// ret = QSize(-1, 21);
894// else
895// ret = QSize(-1, 19);
896// }
897// break;
898//#endif
900//#if QT_CONFIG(treeview)
901// if (isTreeView(widg))
902// ret = QSize(-1, qt_mac_aqua_get_metric(ListHeaderHeight));
903//#endif
904 break;
906 if (sz == QStyleHelper::SizeLarge) {
907 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
908 // In the qt_mac_set_native_menubar(false) case,
909 // we come it here with a zero-height main menu,
910 // preventing the in-window menu from displaying.
911 // Use 22 pixels for the height, by observation.
912 if (ret.height() <= 0)
913 ret.setHeight(22);
914 }
915 break;
916 default:
917 break;
918 }
919 return ret;
920}
921
922
924{
925 static const qreal CornerPointOffset = 5.5;
926 static const qreal CornerControlOffset = 2.1;
927
929 // Top-left corner
930 path.moveTo(r.left(), r.top() + CornerPointOffset);
931 path.cubicTo(r.left(), r.top() + CornerControlOffset,
932 r.left() + CornerControlOffset, r.top(),
933 r.left() + CornerPointOffset, r.top());
934 // Top-right corner
935 path.lineTo(r.right() - CornerPointOffset, r.top());
936 path.cubicTo(r.right() - CornerControlOffset, r.top(),
937 r.right(), r.top() + CornerControlOffset,
938 r.right(), r.top() + CornerPointOffset);
939 // Bottom-right corner
940 path.lineTo(r.right(), r.bottom() - CornerPointOffset);
941 path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
942 r.right() - CornerControlOffset, r.bottom(),
943 r.right() - CornerPointOffset, r.bottom());
944 // Bottom-right corner
945 path.lineTo(r.left() + CornerPointOffset, r.bottom());
946 path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
947 r.left(), r.bottom() - CornerControlOffset,
948 r.left(), r.bottom() - CornerPointOffset);
949 path.lineTo(r.left(), r.top() + CornerPointOffset);
950
951 return path;
952}
953
955{
956 struct WindowButtons {
959 };
960
961 static const WindowButtons buttons[] = {
965 };
966
967 for (const auto &wb : buttons)
968 if (wb.sc == sc)
969 return wb.ct;
970
971 return NoControl;
972}
973
974
975void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, QRect *textRect, QRect *iconRect) const
976{
978 Q_ASSERT(iconRect);
979 QRect tr = opt->rect;
980 const bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
981 || opt->shape == QStyleOptionTab::RoundedWest
982 || opt->shape == QStyleOptionTab::TriangularEast
983 || opt->shape == QStyleOptionTab::TriangularWest;
984 if (verticalTabs)
985 tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
986
987 int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
988 int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
989 const int hpadding = 4;
990 const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
991 if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
992 verticalShift = -verticalShift;
993 tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
994
995 // left widget
996 if (!opt->leftButtonSize.isEmpty()) {
997 const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
998 tr.setLeft(tr.left() + 4 + buttonSize);
999 // make text aligned to center
1000 if (opt->rightButtonSize.isEmpty())
1001 tr.setRight(tr.right() - 4 - buttonSize);
1002 }
1003 // right widget
1004 if (!opt->rightButtonSize.isEmpty()) {
1005 const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
1006 tr.setRight(tr.right() - 4 - buttonSize);
1007 // make text aligned to center
1008 if (opt->leftButtonSize.isEmpty())
1009 tr.setLeft(tr.left() + 4 + buttonSize);
1010 }
1011
1012 // icon
1013 if (!opt->icon.isNull()) {
1015 if (!iconSize.isValid()) {
1016 int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
1017 iconSize = QSize(iconExtent, iconExtent);
1018 }
1019 QSize tabIconSize = opt->icon.actualSize(iconSize,
1022 // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
1023 tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
1024
1025 const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2 - hpadding;
1026
1027 if (opt->documentMode) {
1028 // documents show the icon as part of the the text
1029 const int textWidth =
1031 *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
1032 tr.center().y() - tabIconSize.height() / 2,
1033 tabIconSize.width(), tabIconSize.height());
1034 } else {
1035 *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
1036 tabIconSize.width(), tabIconSize.height());
1037 }
1038 if (!verticalTabs)
1039 *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
1040
1041 tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
1042 tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
1043 }
1044
1045 if (!verticalTabs)
1046 tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
1047
1048 *textRect = tr;
1049}
1050
1051QMacStylePrivate::Direction QMacStylePrivate::tabDirection(QStyleOptionTab::Shape shape)
1052{
1053 switch (shape) {
1054 case QStyleOptionTab::RoundedSouth:
1055 case QStyleOptionTab::TriangularSouth:
1056 return South;
1057 case QStyleOptionTab::RoundedNorth:
1058 case QStyleOptionTab::TriangularNorth:
1059 return North;
1060 case QStyleOptionTab::RoundedWest:
1061 case QStyleOptionTab::TriangularWest:
1062 return West;
1063 case QStyleOptionTab::RoundedEast:
1064 case QStyleOptionTab::TriangularEast:
1065 return East;
1066 }
1067}
1068
1069bool QMacStylePrivate::verticalTabs(QMacStylePrivate::Direction direction)
1070{
1073}
1074
1077 QSize szHint, QSize *insz) const
1078{
1079 QStyleHelper::WidgetSizePolicy sz = aquaSizeConstrain(option, ct, szHint, insz);
1080 if (sz == QStyleHelper::SizeDefault)
1082 return sz;
1083}
1084
1086 QStyle::ContentsType /*ct*/, QSize /*szHint*/, QSize * /*insz*/) const
1087{
1088 if (!option)
1090
1091 if (option->state & QStyle::State_Small)
1093 if (option->state & QStyle::State_Mini)
1095
1097
1098}
1099
1101{
1102 return ((cw.type << 2) | cw.size) ^ seed;
1103}
1104
1106 : type(NoControl), size(QStyleHelper::SizeDefault)
1107{
1108}
1109
1111 : type(t), size(s)
1112{
1113}
1114
1115bool QMacStylePrivate::CocoaControl::operator==(const CocoaControl &other) const
1116{
1117 return other.type == type && other.size == size;
1118}
1119
1121{
1122 // We need this because things like NSView.alignmentRectInsets
1123 // or -[NSCell titleRectForBounds:] won't work unless the control
1124 // has a reasonable frame set. IOW, it's a chicken and egg problem.
1125 // These values are as observed in Xcode 9's Interface Builder.
1126
1127 if (type == Button_PushButton)
1128 return QSizeF(-1, pushButtonDefaultHeight[size]);
1129
1131 || type == Button_PullDown)
1133
1134 if (type == ComboBox)
1135 return QSizeF(-1, comboBoxDefaultHeight[size]);
1136
1137 return QSizeF();
1138}
1139
1141{
1142 QRectF frameRect;
1143 const auto frameSize = defaultFrameSize();
1145 frameRect = rect.adjusted(3, 1, -3, -1)
1148 // Start from the style option's top-left corner.
1149 frameRect = QRectF(rect.topLeft(),
1150 QSizeF(rect.width(), frameSize.height()));
1152 frameRect = frameRect.translated(0, 1.5);
1153 else if (size == QStyleHelper::SizeMini)
1154 frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
1155 } else {
1156 // Center in the style option's rect.
1157 frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
1158 QSizeF(rect.width(), frameSize.height()));
1159 frameRect = frameRect.translated(rect.topLeft());
1162 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
1163 else if (size == QStyleHelper::SizeSmall)
1164 frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
1165 else if (size == QStyleHelper::SizeMini)
1166 frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
1167 } else if (type == QMacStylePrivate::ComboBox) {
1168 frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
1169 }
1170 }
1171
1172 return frameRect;
1173}
1174
1176{
1179 return QMarginsF(12, 5, 12, 9);
1181 return QMarginsF(12, 4, 12, 9);
1183 return QMarginsF(10, 1, 10, 2);
1184 }
1185
1188 return QMarginsF(7.5, 2.5, 22.5, 5.5);
1190 return QMarginsF(7.5, 2, 20.5, 4);
1192 return QMarginsF(4.5, 0, 16.5, 2);
1193 }
1194
1196 return QMarginsF(6, 1, 6, 2);
1197
1198 return QMarginsF();
1199}
1200
1201bool QMacStylePrivate::CocoaControl::getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const
1202{
1203 switch (type) {
1204 case Button_CheckBox:
1205 *buttonType = NSButtonTypeSwitch;
1206 *bezelStyle = NSBezelStyleRegularSquare;
1207 break;
1208 case Button_Disclosure:
1209 *buttonType = NSButtonTypeOnOff;
1210 *bezelStyle = NSBezelStyleDisclosure;
1211 break;
1212 case Button_RadioButton:
1213 *buttonType = NSButtonTypeRadio;
1214 *bezelStyle = NSBezelStyleRegularSquare;
1215 break;
1217 *buttonType = NSButtonTypePushOnPushOff;
1218 *bezelStyle = NSBezelStyleShadowlessSquare;
1219 break;
1220 case Button_PushButton:
1221 *buttonType = NSButtonTypePushOnPushOff;
1222 *bezelStyle = NSBezelStyleRounded;
1223 break;
1224 default:
1225 return false;
1226 }
1227
1228 return true;
1229}
1230
1232{
1233 if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
1234 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
1235 // When the contents won't fit in a large sized button,
1236 // and WA_MacNormalSize is not set, make the button square.
1237 // Threshold used to be at 34, not 32.
1238 const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge];
1239 const bool isSquare = (btn->features & QStyleOptionButton::Flat)
1240 || (btn->rect.height() > maxNonSquareHeight);
1241// && !(w && w->testAttribute(Qt::WA_MacNormalSize)));
1242 return (isSquare? QMacStylePrivate::Button_SquareButton :
1245 }
1246
1247 if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
1248 if (combo->editable)
1250 // TODO Me may support square, non-editable combo boxes, but not more than that
1252 }
1253
1255}
1256
1261CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget)
1262{
1263 CGRect innerBounds = outerBounds;
1264 // Carbon draw parts of the view outside the rect.
1265 // So make the rect a bit smaller to compensate
1266 // (I wish HIThemeGetButtonBackgroundBounds worked)
1267 if (cocoaWidget.type == Button_PopupButton) {
1268 switch (cocoaWidget.size) {
1270 innerBounds.origin.x += 3;
1271 innerBounds.origin.y += 3;
1272 innerBounds.size.width -= 6;
1273 innerBounds.size.height -= 7;
1274 break;
1276 innerBounds.origin.x += 2;
1277 innerBounds.origin.y += 2;
1278 innerBounds.size.width -= 5;
1279 innerBounds.size.height -= 6;
1280 break;
1283 innerBounds.origin.x += 2;
1284 innerBounds.origin.y += 2;
1285 innerBounds.size.width -= 5;
1286 innerBounds.size.height -= 6;
1287 }
1288 } else if (cocoaWidget.type == ComboBox) {
1289 switch (cocoaWidget.size) {
1291 innerBounds.origin.x += 3;
1292 innerBounds.origin.y += 3;
1293 innerBounds.size.width -= 7;
1294 innerBounds.size.height -= 8;
1295 break;
1297 innerBounds.origin.x += 3;
1298 innerBounds.origin.y += 3;
1299 innerBounds.size.width -= 4;
1300 innerBounds.size.height -= 8;
1301 break;
1304 innerBounds.origin.x += 3;
1305 innerBounds.origin.y += 2;
1306 innerBounds.size.width -= 6;
1307 innerBounds.size.height -= 8;
1308 }
1309 }
1310
1311 return innerBounds;
1312}
1313
1318QRectF QMacStylePrivate::comboboxEditBounds(const QRectF &outerBounds, const CocoaControl &cw)
1319{
1320 QRectF ret = outerBounds;
1321 if (cw.type == ComboBox) {
1322 switch (cw.size) {
1324 ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
1325 ret.setHeight(16);
1326 break;
1328 ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
1329 ret.setHeight(14);
1330 break;
1332 ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
1333 ret.setHeight(10.5);
1334 break;
1335 default:
1336 break;
1337 }
1338 } else if (cw.type == Button_PopupButton) {
1339 switch (cw.size) {
1341 ret.adjust(10, 1, -23, -4);
1342 break;
1344 ret.adjust(10, 4, -20, -3);
1345 break;
1347 ret.adjust(9, 0, -19, 0);
1348 ret.setHeight(13);
1349 break;
1350 default:
1351 break;
1352 }
1353 }
1354 return ret;
1355}
1356
1358 : backingStoreNSView(nil)
1359{
1361 smallSystemFont = *ssf;
1363 miniSystemFont = *msf;
1364}
1365
1367{
1369 for (NSView *b : cocoaControls)
1370 [b release];
1371 for (NSCell *cell : cocoaCells)
1372 [cell release];
1373}
1374
1375NSView *QMacStylePrivate::cocoaControl(CocoaControl cocoaControl) const
1376{
1379 return nil;
1380
1381 if (cocoaControl.type == Box) {
1382 if (__builtin_available(macOS 10.14, *)) {
1383 if (qt_mac_applicationIsInDarkMode()) {
1384 // See render code in drawPrimitive(PE_FrameTabWidget)
1385 cocoaControl.type = Box_Dark;
1386 }
1387 }
1388 }
1389
1390 NSView *bv = cocoaControls.value(cocoaControl, nil);
1391 if (!bv) {
1392 switch (cocoaControl.type) {
1393 case Box: {
1394 NSBox *box = [[NSBox alloc] init];
1395 bv = box;
1396 box.title = @"";
1397 box.titlePosition = NSNoTitle;
1398 break;
1399 }
1400 case Box_Dark:
1401 bv = [[QDarkNSBox alloc] init];
1402 break;
1403 case Button_CheckBox:
1404 case Button_Disclosure:
1405 case Button_PushButton:
1406 case Button_RadioButton:
1407 case Button_SquareButton: {
1408 NSButton *bc = [[NSButton alloc] init];
1409 bc.title = @"";
1410 // See below for style and bezel setting.
1411 bv = bc;
1412 break;
1413 }
1414 case Button_PopupButton:
1415 case Button_PullDown: {
1416 NSPopUpButton *bc = [[NSPopUpButton alloc] init];
1417 bc.title = @"";
1418 if (cocoaControl.type == Button_PullDown)
1419 bc.pullsDown = YES;
1420 bv = bc;
1421 break;
1422 }
1423 case Button_WindowClose:
1425 case Button_WindowZoom: {
1426 const NSWindowButton button = [=] {
1427 switch (cocoaControl.type) {
1428 case Button_WindowClose:
1429 return NSWindowCloseButton;
1431 return NSWindowMiniaturizeButton;
1432 case Button_WindowZoom:
1433 return NSWindowZoomButton;
1434 default:
1435 break;
1436 }
1437 Q_UNREACHABLE();
1438 } ();
1439 const auto styleMask = NSWindowStyleMaskTitled
1440 | NSWindowStyleMaskClosable
1441 | NSWindowStyleMaskMiniaturizable
1442 | NSWindowStyleMaskResizable;
1443 bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
1444 [bv retain];
1445 break;
1446 }
1447 case ComboBox:
1448 bv = [[NSComboBox alloc] init];
1449 break;
1451 bv = [[NSProgressIndicator alloc] init];
1452 break;
1454 bv = [[QIndeterminateProgressIndicator alloc] init];
1455 break;
1457 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1458 break;
1459 case Scroller_Vertical:
1460 // Cocoa sets the orientation from the view's frame
1461 // at construction time, and it cannot be changed later.
1462 bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1463 break;
1464 case Slider_Horizontal:
1465 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
1466 break;
1467 case Slider_Vertical:
1468 // Cocoa sets the orientation from the view's frame
1469 // at construction time, and it cannot be changed later.
1470 bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
1471 break;
1473 bv = [[NSSplitView alloc] init];
1474 break;
1475 case SplitView_Vertical:
1476 bv = [[QVerticalSplitView alloc] init];
1477 break;
1478 case TextField:
1479 bv = [[NSTextField alloc] init];
1480 break;
1481 default:
1482 break;
1483 }
1484
1485 if ([bv isKindOfClass:[NSControl class]]) {
1486 auto *ctrl = static_cast<NSControl *>(bv);
1487 switch (cocoaControl.size) {
1489 ctrl.controlSize = NSControlSizeSmall;
1490 break;
1492 ctrl.controlSize = NSControlSizeMini;
1493 break;
1494 default:
1495 break;
1496 }
1497 } else if (cocoaControl.type == ProgressIndicator_Determinate ||
1499 auto *pi = static_cast<NSProgressIndicator *>(bv);
1500 pi.indeterminate = (cocoaControl.type == ProgressIndicator_Indeterminate);
1501 switch (cocoaControl.size) {
1503 pi.controlSize = NSControlSizeSmall;
1504 break;
1506 pi.controlSize = NSControlSizeMini;
1507 break;
1508 default:
1509 break;
1510 }
1511 }
1512
1513 cocoaControls.insert(cocoaControl, bv);
1514 }
1515
1516 NSButtonType buttonType;
1517 NSBezelStyle bezelStyle;
1518 if (cocoaControl.getCocoaButtonTypeAndBezelStyle(&buttonType, &bezelStyle)) {
1519 // FIXME We need to reset the button's type and
1520 // bezel style properties, even when cached.
1521 auto *button = static_cast<NSButton *>(bv);
1522 button.buttonType = buttonType;
1523 button.bezelStyle = bezelStyle;
1524 if (cocoaControl.type == Button_CheckBox)
1525 button.allowsMixedState = YES;
1526 }
1527
1528 return bv;
1529}
1530
1531NSCell *QMacStylePrivate::cocoaCell(CocoaControl cocoaControl) const
1532{
1533 NSCell *cell = cocoaCells[cocoaControl];
1534 if (!cell) {
1535 switch (cocoaControl.type) {
1536 case Stepper:
1537 cell = [[NSStepperCell alloc] init];
1538 break;
1539 case Button_Disclosure: {
1540 NSButtonCell *bc = [[NSButtonCell alloc] init];
1541 bc.buttonType = NSButtonTypeOnOff;
1542 bc.bezelStyle = NSBezelStyleDisclosure;
1543 cell = bc;
1544 break;
1545 }
1546 default:
1547 break;
1548 }
1549
1550 switch (cocoaControl.size) {
1552 cell.controlSize = NSControlSizeSmall;
1553 break;
1555 cell.controlSize = NSControlSizeMini;
1556 break;
1557 default:
1558 break;
1559 }
1560
1561 cocoaCells.insert(cocoaControl, cell);
1562 }
1563
1564 return cell;
1565}
1566
1567void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock) const
1568{
1572
1573 // FIXME: The rect that we get in is relative to the widget that we're drawing
1574 // style on behalf of, and doesn't take into account the offset of that widget
1575 // to the widget that owns the backingstore, which we are placing the native
1576 // view into below. This means most of the views are placed in the upper left
1577 // corner of backingStoreNSView, which does not map to where the actual widget
1578 // is, and which may cause problems such as triggering a setNeedsDisplay of the
1579 // backingStoreNSView for the wrong rect. We work around this by making the view
1580 // layer-backed, which prevents triggering display of the backingStoreNSView, but
1581 // but there may be other issues lurking here due to the wrong position. QTBUG-68023
1582 view.wantsLayer = YES;
1583
1584 // FIXME: We are also setting the frame of the incoming view a lot at the call
1585 // sites of this function, making it unclear who's actually responsible for
1586 // maintaining the size and position of the view. In theory the call sites
1587 // should ensure the _size_ of the view is correct, and then let this code
1588 // take care of _positioning_ the view at the right place inside backingStoreNSView.
1589 // For now we pass on the rect as is, to prevent any regressions until this
1590 // can be investigated properly.
1591 view.frame = rect.toCGRect();
1592
1593 [backingStoreNSView addSubview:view];
1594
1595 // FIXME: Based on the code below, this method isn't drawing an NSView into
1596 // a rect, it's drawing _part of the NSView_, defined by the incoming clip
1597 // or dirty rect, into the current graphics context. We're doing some manual
1598 // translations at the call sites that would indicate that this relationship
1599 // is a bit fuzzy.
1600 const CGRect dirtyRect = rect.toCGRect();
1601
1602 if (drawRectBlock)
1603 drawRectBlock(ctx, dirtyRect);
1604 else
1605 [view drawRect:dirtyRect];
1606
1607 [view removeFromSuperviewWithoutNeedingDisplay];
1608
1610}
1611
1613{
1614 backingStoreNSView = window ? (NSView *)window->winId() : nil;
1615}
1616
1619{
1621
1622 static QMacNotificationObserver scrollbarStyleObserver(nil,
1623 NSPreferredScrollerStyleDidChangeNotification, []() {
1624 // Purge destroyed scroll bars
1625 QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
1626
1628 for (const auto &o : QMacStylePrivate::scrollBars)
1630 });
1631
1632#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
1633 Q_D(QMacStyle);
1634 // FIXME: Tie this logic into theme change, or even polish/unpolish
1636 d->appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
1637 Q_D(QMacStyle);
1638 for (NSView *b : d->cocoaControls)
1639 [b release];
1640 d->cocoaControls.clear();
1641 });
1642 }
1643#endif
1644}
1645
1649
1651{
1652 Q_D(const QMacStyle);
1653 const int controlSize = getControlSize(opt);
1654 int ret = 0;
1655
1656 switch (metric) {
1660 break;
1661 case PM_ToolBarIconSize:
1662 ret = proxy()->pixelMetric(PM_LargeIconSize);
1663 break;
1667 break;
1668 case PM_DialogButtonsSeparator:
1669 ret = -5;
1670 break;
1671 case PM_DialogButtonsButtonHeight: {
1672 QSize sz;
1673 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1674 if (sz == QSize(-1, -1))
1675 ret = 32;
1676 else
1677 ret = sz.height();
1678 break; }
1679 case PM_DialogButtonsButtonWidth: {
1680 QSize sz;
1681 ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1682 if (sz == QSize(-1, -1))
1683 ret = 70;
1684 else
1685 ret = sz.width();
1686 break; }
1687
1688 case PM_MenuBarHMargin:
1689 ret = 8;
1690 break;
1691
1692 case PM_MenuBarVMargin:
1693 ret = 0;
1694 break;
1695
1697 ret = 0;
1698 break;
1699
1702 break;
1703
1705 ret = 5;
1706 break;
1707
1710 ret = [=] {
1711 if (opt) {
1712 if (opt->state & State_Mini)
1713 return 4;
1714 if (opt->state & State_Small)
1715 return 3;
1716 }
1717 return 2;
1718 } ();
1719 break;
1721 ret = 15; // I hate having magic numbers in here...
1722 break;
1724//#if QT_CONFIG(mainwindow)
1725// if (widget && (widget->isWindow() || !widget->parentWidget()
1726// || (qobject_cast<const QMainWindow*>(widget->parentWidget())
1727// && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
1728// && qobject_cast<const QAbstractScrollArea *>(widget))
1729// ret = 0;
1730// else
1731//#endif
1732 // The combo box popup has no frame.
1733 if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
1734 ret = 0;
1735 else
1736 ret = 1;
1737 break;
1739 ret = -1;
1740 break;
1742 ret = 24;
1743 break;
1746 break;
1749 ret = 0;
1750 break;
1751 case PM_SliderLength:
1752 ret = 17;
1753 break;
1754 // Returns the number of pixels to use for the business part of the
1755 // slider (i.e., the non-tickmark portion). The remaining space is shared
1756 // equally between the tickmark regions.
1758 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
1759 int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
1760 int ticks = sl->tickPosition;
1761 int n = 0;
1762 if (ticks & QStyleOptionSlider::TicksAbove)
1763 ++n;
1764 if (ticks & QStyleOptionSlider::TicksBelow)
1765 ++n;
1766 if (!n) {
1767 ret = space;
1768 break;
1769 }
1770
1771 int thick = 6; // Magic constant to get 5 + 16 + 5
1772 if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
1773 thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
1774
1775 space -= thick;
1776 if (space > 0)
1777 thick += (space * 2) / (n + 2);
1778 ret = thick;
1779 } else {
1780 ret = 0;
1781 }
1782 break;
1783 case PM_SmallIconSize:
1784 ret = int(QStyleHelper::dpiScaled(16., opt));
1785 break;
1786
1787 case PM_LargeIconSize:
1788 ret = int(QStyleHelper::dpiScaled(32., opt));
1789 break;
1790
1792 ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
1793 break;
1794
1796 ret = 0;
1797 break;
1798 case PM_TitleBarHeight: {
1799 NSUInteger style = NSWindowStyleMaskTitled;
1800// if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool))
1801// style |= NSWindowStyleMaskUtilityWindow;
1802 ret = int([NSWindow frameRectForContentRect:NSZeroRect
1803 styleMask:style].size.height);
1804 break; }
1806 switch (d->aquaSizeConstrain(opt)) {
1809 break;
1811 ret = 20;
1812 break;
1814 ret = 16;
1815 break;
1817 const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
1818 if (tb && tb->documentMode)
1819 ret = 30;
1820 else
1822 break;
1823 }
1824 break;
1825 case PM_TabBarTabVSpace:
1826 ret = 4;
1827 break;
1830 ret = 0;
1831 break;
1833 ret = 0;
1834 break;
1836 ret = 1;
1837 break;
1839 switch (d->aquaSizeConstrain(opt)) {
1842 ret = 11;
1843 break;
1845 ret = 8;
1846 break;
1848 ret = 7;
1849 break;
1850 }
1851 break;
1852 case PM_ScrollBarExtent: {
1853 const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
1854 ret = static_cast<int>([NSScroller
1855 scrollerWidthForControlSize:static_cast<NSControlSize>(size)
1856 scrollerStyle:[NSScroller preferredScrollerStyle]]);
1857 break; }
1858 case PM_IndicatorHeight: {
1859 switch (d->aquaSizeConstrain(opt)) {
1863 break;
1866 break;
1869 break;
1870 }
1871 break; }
1872 case PM_IndicatorWidth: {
1873 switch (d->aquaSizeConstrain(opt)) {
1877 break;
1880 break;
1883 break;
1884 }
1885 ++ret;
1886 break; }
1888 switch (d->aquaSizeConstrain(opt)) {
1892 break;
1895 break;
1898 break;
1899 }
1900 break; }
1902 switch (d->aquaSizeConstrain(opt)) {
1906 break;
1909 break;
1912 break;
1913 }
1914 ++ret;
1915 break; }
1916 case PM_MenuVMargin:
1917 ret = 4;
1918 break;
1919 case PM_MenuPanelWidth:
1920 ret = 0;
1921 break;
1923 ret = 0;
1924 break;
1925 case PM_SizeGripSize: {
1927// if (widget && widget->window()->windowType() == Qt::Tool)
1928// aSize = QStyleHelper::SizeSmall;
1929// else
1932 ret = size.width();
1933 break; }
1935 ret = 1;
1936 break;
1938 ret = 0;
1939 break;
1941 ret = 0;
1942 break;
1944 ret = 1;
1945 break;
1947 ret = 11;
1948 break;
1950 ret = 0;
1951 break;
1953 ret = 4;
1954 break;
1955 case PM_SplitterWidth:
1956 ret = 7;
1957 break;
1959 case PM_LayoutTopMargin:
1962 {
1963 if (opt->state & State_Window) {
1964 /*
1965 AHIG would have (20, 8, 10) here but that makes
1966 no sense. It would also have 14 for the top margin
1967 but this contradicts both Builder and most
1968 applications.
1969 */
1970 return_SIZE(20, 10, 10); // AHIG
1971 } else {
1972 // hack to detect QTabWidget
1973// if (widget && widget->parentWidget()
1974// && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
1975// if (metric == PM_LayoutTopMargin) {
1976// /*
1977// Builder would have 14 (= 20 - 6) instead of 12,
1978// but that makes the tab look disproportionate.
1979// */
1980// return_SIZE(12, 6, 6); // guess
1981// } else {
1982// return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
1983// }
1984// } else {
1985 /*
1986 Child margins are highly inconsistent in AHIG and Builder.
1987 */
1988 return_SIZE(12, 8, 6); // guess
1989// }
1990 }
1991 }
1994 return -1;
1995 case PM_MenuHMargin:
1996 ret = 0;
1997 break;
1999 ret = 21;
2000 break;
2002 ret = 1;
2003 break;
2007 : 0;
2008 break;
2009 case PM_PushButtonFocusFrameRadius:
2010 ret = LargeSmallMini(opt, 5, 4, 2);
2011 break;
2012 case PM_CheckBoxFocusFrameRadius:
2013 ret = LargeSmallMini(opt, 3, 2, 1);
2014 break;
2015 case PM_ComboBoxFocusFrameRadius:
2016 ret = LargeSmallMini(opt, 5, 4, 1);
2017 break;
2018 case PM_RadioButtonFocusFrameRadius:
2019 ret = 7;
2020 break;
2021 case PM_SliderFocusFrameRadius:
2022 // QTBUG-93423: We currently need to skip drawing a focus ring around the handle, since
2023 // the handle drawn by the UIKit is not centered inside the rect we get from calling
2024 // [cell knobRectFlipped:slider.isFlipped]. So we choose to draw the focus as
2025 // a rect instead until we have a better solution available.
2026 ret = 0;
2027 break;
2028 case PM_DialFocusFrameRadius:
2029 case PM_SpinBoxFocusFrameRadius:
2030 case PM_TextAreaFocusFrameRadius:
2031 case PM_TextFieldFocusFrameRadius:
2032 ret = 0;
2033 break;
2034 default:
2036 break;
2037 }
2038 return ret;
2039}
2040
2041//QPalette QMacStyle::standardPalette() const
2042//{
2043// auto platformTheme = QGuiApplicationPrivate::platformTheme();
2044// auto styleNames = platformTheme->themeHint(QPlatformTheme::StyleNames);
2045// if (styleNames.toStringList().contains("macintosh"))
2046// return QPalette(); // Inherit everything from theme
2047// else
2048// return QStyle::standardPalette();
2049//}
2050
2052{
2054
2055 int ret = 0;
2056 switch (sh) {
2065 ret = 1;
2066 break;
2068 ret = 0;
2069 break;
2071 ret = 0;
2072 break;
2074 ret = false;
2075 break;
2077 ret = true;
2078 break;
2080 ret = true;
2081 break;
2084 break;
2086 ret = 0;
2087 break;
2089 ret = false;
2090 break;
2092 ret = true;
2093 break;
2095 ret = false;
2096 break;
2098 ret = 100;
2099 break;
2101 ret = true;
2102 break;
2104 ret = false;
2105 break;
2107 ret = true;
2108 break;
2110 ret = true;
2111 break;
2112
2114 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2115 bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
2116// if(QApplication::keyboardModifiers() & Qt::AltModifier)
2117// ret = !result;
2118// else
2119 ret = result;
2120 break; }
2122 ret = true;
2123 break;
2124 /*
2125 case SH_DialogButtons_DefaultButton:
2126 ret = QDialogButtons::Reject;
2127 break;
2128 */
2130 ret = Qt::AlignTop;
2131 break;
2133 ret = QCommonStyle::styleHint(sh, opt, hret);
2134 break;
2136 ret = false;
2137 break;
2138 case SH_Menu_Scrollable:
2139 ret = true;
2140 break;
2142 ret = true;
2143 break;
2145 ret = false;
2146 break;
2148 ret = true;
2149 break;
2152 break;
2154 if (const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
2156 } else {
2158 }
2159 break;
2160 case SH_ComboBox_Popup:
2161 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2162 ret = !cmb->editable;
2163 else
2164 ret = 0;
2165 break;
2167 ret = true;
2168 break;
2170 ret = true;
2171 break;
2174 break;
2175 case SH_TabBar_Alignment: {
2176//#if QT_CONFIG(tabwidget)
2177// if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2178// if (tab->documentMode()) {
2179// ret = Qt::AlignLeft;
2180// break;
2181// }
2182// }
2183//#endif
2184//#if QT_CONFIG(tabbar)
2185// if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2186// if (tab->documentMode()) {
2187// ret = Qt::AlignLeft;
2188// break;
2189// }
2190// }
2191//#endif
2193 } break;
2195 ret = false;
2196 break;
2198 ret = 242; // About 95%
2199 break;
2201 ret = Qt::TabFocus;
2202 break;
2204 ret = false;
2205 break;
2206 case SH_FocusFrame_Mask: {
2207 ret = true;
2208 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2209 const uchar fillR = 192, fillG = 191, fillB = 190;
2210 QImage img;
2211
2212 QSize pixmapSize = opt->rect.size();
2213 if (!pixmapSize.isEmpty()) {
2214 QPixmap pix(pixmapSize);
2215 pix.fill(QColor(fillR, fillG, fillB));
2216 QPainter pix_paint(&pix);
2217 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
2218 pix_paint.end();
2219 img = pix.toImage();
2220 }
2221
2222 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2223 const qsizetype sbpl = img.bytesPerLine();
2224 const int w = sbpl/4, h = img.height();
2225
2226 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2227 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2228 const qsizetype dbpl = img_mask.bytesPerLine();
2229
2230 for (int y = 0; y < h; ++y) {
2231 srow = sptr+((y*sbpl)/4);
2232 drow = dptr+((y*dbpl)/4);
2233 for (int x = 0; x < w; ++x) {
2234 const int redDiff = qRed(*srow) - fillR;
2235 const int greenDiff = qGreen(*srow) - fillG;
2236 const int blueDiff = qBlue(*srow) - fillB;
2237 const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2238 (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2239 ++srow;
2240 }
2241 }
2242 QBitmap qmask = QBitmap::fromImage(std::move(img_mask));
2243 mask->region = QRegion(qmask);
2244 }
2245 break; }
2247 ret = 1;
2248 break;
2249 case SH_RubberBand_Mask:
2250 ret = 0;
2251 break;
2254 break;
2257 break;
2259 ret = true;
2260 break;
2262 ret = false;
2263 break;
2265 ret = true;
2266 break;
2268 ret = false;
2269 break;
2272 break;
2273// case SH_DialogButtonLayout:
2274// ret = QDialogButtonBox::MacLayout;
2275// break;
2276// case SH_FormLayoutWrapPolicy:
2277// ret = QFormLayout::DontWrapRows;
2278// break;
2279// case SH_FormLayoutFieldGrowthPolicy:
2280// ret = QFormLayout::FieldsStayAtSizeHint;
2281// break;
2284 break;
2287 break;
2288// case SH_ComboBox_PopupFrameStyle:
2289// ret = QFrame::NoFrame;
2290// break;
2293 break;
2294 case SH_SpellCheckUnderlineStyle:
2296 break;
2298 ret = false;
2299 break;
2301 ret = false;
2302 break;
2304 ret = false;
2305 break;
2307 ret = true;
2308 break;
2309// case SH_WizardStyle:
2310// ret = QWizard::MacStyle;
2311// break;
2313 ret = false;
2314 break;
2316 ret = true;
2317 break;
2319 ret = true;
2320 break;
2322 ret = true;
2323 break;
2325 ret = QStyleOptionTabBarBase::LeftSide;
2326 break;
2328 ret = false;
2329 break;
2331 // For the initial version in QQC2, we don't support transient scrollbars. When the
2332 // time comes, consider doing all such animations from QML.
2333 // ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
2334 ret = false;
2335 break;
2337 // min/max/close buttons on windows don't show tool tips
2338 ret = false;
2339 break;
2341 ret = false;
2342 break;
2344 ret = false;
2345 break;
2347 ret = int(qt_mac_toQColor(NSColor.gridColor).rgba());
2348 break;
2349 default:
2350 ret = QCommonStyle::styleHint(sh, opt, hret);
2351 break;
2352 }
2353 return ret;
2354}
2355
2357 const QStyleOption *opt) const
2358{
2359 switch (iconMode) {
2360 case QIcon::Disabled: {
2362 int imgh = img.height();
2363 int imgw = img.width();
2364 QRgb pixel;
2365 for (int y = 0; y < imgh; ++y) {
2366 for (int x = 0; x < imgw; ++x) {
2367 pixel = img.pixel(x, y);
2368 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2369 qAlpha(pixel) / 2));
2370 }
2371 }
2372 return QPixmap::fromImage(img);
2373 }
2374 default:
2375 ;
2376 }
2377 return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2378}
2379
2380
2382{
2383 // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2384 // I don't want infinite recursion so if we do get in that situation, just return the Window's
2385 // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2386 // someone changes how Windows standard
2387 // pixmap works.
2388 static bool recursionGuard = false;
2389
2390 if (recursionGuard)
2391 return QCommonStyle::standardPixmap(standardPixmap, opt);
2392
2393 recursionGuard = true;
2394 QIcon icon = proxy()->standardIcon(standardPixmap, opt);
2395 recursionGuard = false;
2396 int size;
2397 switch (standardPixmap) {
2398 default:
2399 size = 32;
2400 break;
2405 size = 64;
2406 break;
2407 }
2408 return icon.pixmap(QSize(size, size), opt->window->devicePixelRatio());
2409}
2410
2412{
2413 Q_D(const QMacStyle);
2414
2415 const AppearanceSync appSync;
2416 QMacCGContext cg(p);
2417 d->resolveCurrentNSView(opt->window);
2418
2419 switch (pe) {
2423 case PE_IndicatorArrowLeft: {
2424 p->save();
2425 p->setRenderHint(QPainter::Antialiasing);
2426 const int xOffset = 1; // FIXME: opt->direction == Qt::LeftToRight ? 2 : -1;
2427 qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
2428 const qreal penWidth = qMax(halfSize / 3.0, 1.25);
2429//#if QT_CONFIG(toolbutton)
2430// if (const QToolButton *tb = qobject_cast<const QToolButton *>(w)) {
2431// // When stroking the arrow, make sure it fits in the tool button
2432// if (tb->arrowType() != Qt::NoArrow
2433// || tb->popupMode() == QToolButton::MenuButtonPopup)
2434// halfSize -= penWidth;
2435// }
2436//#endif
2437
2439 transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2441 switch(pe) {
2442 default:
2444 break;
2446 transform.rotate(180);
2447 break;
2449 transform.rotate(90);
2450 break;
2452 transform.rotate(-90);
2453 break;
2454 }
2455 p->setTransform(transform);
2456
2457 path.moveTo(-halfSize, -halfSize * 0.5);
2458 path.lineTo(0.0, halfSize * 0.5);
2459 path.lineTo(halfSize, -halfSize * 0.5);
2460
2461 const QPen arrowPen(opt->palette.text(), penWidth,
2463 p->strokePath(path, arrowPen);
2464 p->restore();
2465 break; }
2466 case PE_FrameTabBarBase:
2467 if (const QStyleOptionTabBarBase *tbb
2468 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
2469 if (tbb->documentMode) {
2470 p->save();
2471 drawTabBase(p, tbb);
2472 p->restore();
2473 return;
2474 }
2475 QRegion region(tbb->rect);
2476 region -= tbb->tabBarRect;
2477 p->save();
2478 p->setClipRegion(region);
2479 QStyleOptionTabWidgetFrame twf;
2480 twf.QStyleOption::operator=(*tbb);
2481 twf.shape = tbb->shape;
2482 switch (QMacStylePrivate::tabDirection(twf.shape)) {
2484 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2485 break;
2487 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2488 break;
2490 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2491 break;
2493 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2494 break;
2495 }
2496 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
2497 p->restore();
2498 }
2499 break;
2500 case PE_PanelTipLabel:
2502 break;
2503 case PE_FrameGroupBox:
2504 if (const auto *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt))
2505 if (groupBox->features & QStyleOptionFrame::Flat) {
2507 break;
2508 }
2509 Q_FALLTHROUGH();
2510 case PE_FrameTabWidget:
2511 {
2513 auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
2514 // FIXME Since macOS 10.14, simply calling drawRect: won't display anything anymore.
2515 // The AppKit team is aware of this and has proposed a couple of solutions.
2516 // The first solution was to call displayRectIgnoringOpacity:inContext: instead.
2517 // However, it doesn't seem to work on 10.13. More importantly, dark mode on 10.14
2518 // is extremely slow. Light mode works fine.
2519 // The second solution is to subclass NSBox and reimplement a trivial drawRect: which
2520 // would only call super. This works without any issue on 10.13, but a double border
2521 // shows on 10.14 in both light and dark modes.
2522 // The code below picks what works on each version and mode. On 10.13 and earlier, we
2523 // simply call drawRect: on a regular NSBox. On 10.14, we call displayRectIgnoringOpacity:
2524 // inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass,
2525 // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so
2526 // we can use this for now.
2527 auto adjustedRect = opt->rect;
2528 bool needTranslation = false;
2530 && !qt_mac_applicationIsInDarkMode()) {
2531 // In Aqua theme we have to use the 'default' NSBox (as opposite
2532 // to the 'custom' QDarkNSBox we use in dark theme). Since -drawRect:
2533 // does nothing in default NSBox, we call -displayRectIgnoringOpaticty:.
2534 // Unfortunately, the resulting box is smaller then the actual rect we
2535 // wanted. This can be seen, e.g. because tabs (buttons) are misaligned
2536 // vertically and even worse, if QTabWidget has autoFillBackground
2537 // set, this background overpaints NSBox making it to disappear.
2538 // We trick our NSBox to render in a larger rectangle, so that
2539 // the actuall result (which is again smaller than requested),
2540 // more or less is what we really want. We'll have to adjust CTM
2541 // and translate accordingly.
2542 adjustedRect.adjust(0, 0, 6, 6);
2543 needTranslation = true;
2544 }
2545 d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx, const CGRect &rect) {
2546//#if QT_CONFIG(tabwidget)
2547// if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(opt->styleObject))
2548// clipTabBarFrame(opt, this, ctx);
2549//#endif
2551 CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
2552 CGContextScaleCTM(ctx, 1, -1);
2554 || [box isMemberOfClass:QDarkNSBox.class]) {
2555 [box drawRect:rect];
2556 } else {
2557 if (needTranslation)
2558 CGContextTranslateCTM(ctx, -3.0, 5.0);
2559 [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
2560 }
2561 });
2562 break;
2563 }
2566 if (opt->state & State_Horizontal) {
2567 int xpoint = opt->rect.center().x();
2568 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2569 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2570 } else {
2571 int ypoint = opt->rect.center().y();
2572 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2573 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2574 }
2575 QPainterPathStroker theStroker;
2576 theStroker.setCapStyle(Qt::FlatCap);
2577 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
2578 path = theStroker.createStroke(path);
2579 const auto dark = qt_mac_applicationIsInDarkMode() ? opt->palette.dark().color().darker()
2580 : QColor(0, 0, 0, 119);
2581 p->fillPath(path, dark);
2582 }
2583 break;
2584 case PE_FrameWindow:
2585 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2586// if (w && w->inherits("QMdiSubWindow")) {
2587// p->save();
2588// p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
2589// p->setBrush(frame->palette.window());
2590// p->drawRect(frame->rect);
2591// p->restore();
2592// }
2593 }
2594 break;
2596 // The docwidget resize handle is drawn as a one-pixel wide line.
2597 p->save();
2598 if (opt->state & State_Horizontal) {
2599 p->setPen(QColor(160, 160, 160));
2600 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2601 } else {
2602 p->setPen(QColor(145, 145, 145));
2603 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2604 }
2605 p->restore();
2606 } break;
2608 p->save();
2610 int x = opt->rect.x() + 6;
2611 int y = opt->rect.y() + 7;
2612 static const int RectHeight = 2;
2613 if (opt->state & State_Horizontal) {
2614 while (y < opt->rect.height() - RectHeight - 5) {
2615 path.moveTo(x, y);
2616 path.addEllipse(x, y, RectHeight, RectHeight);
2617 y += 6;
2618 }
2619 } else {
2620 while (x < opt->rect.width() - RectHeight - 5) {
2621 path.moveTo(x, y);
2622 path.addEllipse(x, y, RectHeight, RectHeight);
2623 x += 6;
2624 }
2625 }
2626 p->setPen(Qt::NoPen);
2627 QColor dark = opt->palette.dark().color().darker();
2628 dark.setAlphaF(0.50);
2629 p->fillPath(path, dark);
2630 p->restore();
2631
2632 break;
2633 }
2635 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2636 // In HITheme, up is down, down is up and hamburgers eat people.
2637 if (header->sortIndicator != QStyleOptionHeader::None)
2638 proxy()->drawPrimitive(
2639 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2641 }
2642 break;
2644 QColor pc;
2645 if (opt->state & State_On)
2646 pc = opt->palette.highlightedText().color();
2647 else
2648 pc = opt->palette.text().color();
2649
2650 QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()),
2651 static_cast<CGFloat>(pc.greenF()),
2652 static_cast<CGFloat>(pc.blueF()),
2653 static_cast<CGFloat>(pc.alphaF()));
2654 // kCTFontUIFontSystem and others give the same result
2655 // as kCTFontUIFontMenuItemMark. However, the latter is
2656 // more reminiscent to HITheme's kThemeMenuItemMarkFont.
2657 // See also the font for small- and mini-sized widgets,
2658 // where we end up using the generic system font type.
2659 const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
2660 (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
2661 kCTFontUIFontMenuItemMark;
2662 // Similarly for the font size, where there is a small difference
2663 // between regular combobox and item view items, and and menu items.
2664 // However, we ignore any difference for small- and mini-sized widgets.
2665 const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
2666 QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
2667
2668 CGContextSaveGState(cg);
2669 CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks
2670
2671 // Baseline alignment tweaks for QComboBox and QMenu
2672 const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
2673 (opt->state & State_Small) ? 1.0 :
2674 0.75;
2675
2676 CGContextTranslateCTM(cg, 0, opt->rect.bottom());
2677 CGContextScaleCTM(cg, 1, -1);
2678 // Translate back to the original position and add rect origin and offset
2679 CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
2680
2681 // CTFont has severe difficulties finding the checkmark character among its
2682 // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth.
2683 static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
2684 static const int numValues = sizeof(keys) / sizeof(keys[0]);
2685 const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
2686 Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues);
2687 QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
2688 numValues, NULL, NULL);
2689 // U+2713: CHECK MARK
2690 QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes);
2691 QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
2692
2693 CTLineDraw((CTLineRef)line, cg);
2694 CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush
2695
2696 CGContextRestoreGState(cg);
2697 break; }
2700 case PE_IndicatorCheckBox: {
2701 const bool isEnabled = opt->state & State_Enabled;
2702 const bool isPressed = opt->state & State_Sunken;
2703 const bool isRadioButton = (pe == PE_IndicatorRadioButton);
2705 const auto cs = d->effectiveAquaSizeConstrain(opt);
2706 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
2707 auto *tb = static_cast<NSButton *>(d->cocoaControl(cw));
2708 tb.enabled = isEnabled;
2709 tb.state = (opt->state & State_NoChange) ? NSControlStateValueMixed :
2710 (opt->state & State_On) ? NSControlStateValueOn : NSControlStateValueOff;
2711 [tb highlight:isPressed];
2712 const auto vOffset = [=] {
2713 // As measured
2714 if (cs == QStyleHelper::SizeMini)
2715 return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
2716
2717 return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
2718 } ();
2719 d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
2721 CGContextTranslateCTM(ctx, 0, vOffset);
2722 [tb.cell drawInteriorWithFrame:rect inView:tb];
2723 });
2724 break; }
2725 case PE_FrameFocusRect:
2726 // Use the our own focus widget stuff.
2727 break;
2728 case PE_IndicatorBranch: {
2729 if (!(opt->state & State_Children))
2730 break;
2732 NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
2733 [triangleCell setState:(opt->state & State_Open) ? NSControlStateValueOn : NSControlStateValueOff];
2734// bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
2735 bool viewHasFocus = false;
2736 [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
2737
2738 d->setupNSGraphicsContext(cg, NO);
2739
2741 CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
2742 CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
2743 CGContextScaleCTM(cg, 1, -1);
2744 CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
2745
2746 [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
2747
2748 d->restoreNSGraphicsContext(cg);
2749 break; }
2750
2751 case PE_Frame: {
2752 const QPen oldPen = p->pen();
2753 QPen penCpy = p->pen();
2754 penCpy.setWidth(2);
2755 penCpy.setColor(opt->palette.dark().color());
2756 p->setPen(penCpy);
2757 p->drawRect(opt->rect);
2758 p->setPen(oldPen);
2759 break; }
2760 case PE_PanelLineEdit:
2761 case PE_FrameLineEdit:
2762 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2763 if (frame->state & State_Sunken) {
2764 const bool isEnabled = opt->state & State_Enabled;
2765 const bool isReadOnly = opt->state & State_ReadOnly;
2766 const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
2767 const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
2769 auto *tf = static_cast<NSTextField *>(d->cocoaControl(cw));
2770 tf.enabled = isEnabled;
2771 tf.editable = !isReadOnly;
2772 tf.bezeled = YES;
2773 static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
2774 tf.frame = opt->rect.toCGRect();
2775 d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
2776 QMacAutoReleasePool pool;
2777 if (!qt_mac_applicationIsInDarkMode()) {
2778 // In 'Dark' mode controls are transparent, so we do not
2779 // over-paint the (potentially custom) color in the background.
2780 // In 'Light' mode we have to care about the correct
2781 // background color. See the comments below for PE_PanelLineEdit.
2782 CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
2783 // See QMacCGContext, here we expect bitmap context created with
2784 // color space 'kCGColorSpaceSRGB', if it's something else - we
2785 // give up.
2786 if (cgContext ? bool(CGBitmapContextGetColorSpace(cgContext)) : false) {
2787 tf.drawsBackground = YES;
2788 const QColor bgColor = frame->palette.brush(QPalette::Base).color();
2789 tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
2790 green:bgColor.greenF()
2791 blue:bgColor.blueF()
2792 alpha:bgColor.alphaF()];
2793 if (bgColor.alpha() != 255) {
2794 // No way we can have it bezeled and transparent ...
2795 tf.bordered = YES;
2796 }
2797 }
2798 }
2799
2800 [tf.cell drawWithFrame:rect inView:tf];
2801 });
2802 } else {
2804 }
2805 }
2806 break;
2809 p->fillRect(opt->rect, brush);
2810 p->setPen(QPen(QColor(217, 217, 217)));
2811 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2812 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
2813 } break;
2815 break;
2816//#if QT_CONFIG(tabbar)
2817// case PE_IndicatorTabClose: {
2818// // Make close button visible only on the hovered tab.
2819// QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
2820// const QWidget *closeBtn = w;
2821// if (!tabBar) {
2822// // QStyleSheetStyle instead of CloseButton (which has
2823// // a QTabBar as a parent widget) uses the QTabBar itself:
2824// tabBar = qobject_cast<QTabBar *>(const_cast<QWidget*>(w));
2825// closeBtn = decltype(closeBtn)(property("_q_styleSheetRealCloseButton").value<void *>());
2826// }
2827// if (tabBar) {
2828// const bool documentMode = tabBar->documentMode();
2829// const QTabBarPrivate *tabBarPrivate = static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
2830// const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
2831// if (!documentMode ||
2832// (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
2833// (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
2834// const bool hover = (opt->state & State_MouseOver);
2835// const bool selected = (opt->state & State_Selected);
2836// const bool pressed = (opt->state & State_Sunken);
2837// drawTabCloseButton(p, hover, selected, pressed, documentMode);
2838// }
2839// }
2840// } break;
2841//#endif // QT_CONFIG(tabbar)
2842 case PE_PanelStatusBar: {
2843 p->fillRect(opt->rect, opt->palette.window());
2844
2845 // Draw the black separator line at the top of the status bar.
2846 if (qt_macWindowMainWindow(opt->window))
2848 else
2850 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
2851
2852 break;
2853 }
2854 case PE_PanelMenu: {
2855 p->save();
2856 p->fillRect(opt->rect, Qt::transparent);
2857 p->setPen(Qt::transparent);
2858 p->setBrush(opt->palette.window());
2859 p->setRenderHint(QPainter::Antialiasing, true);
2860 const QPainterPath path = d->windowPanelPath(opt->rect);
2861 p->drawPath(path);
2862 p->restore();
2863 } break;
2864
2865 default:
2867 break;
2868 }
2869}
2870
2872{
2874 int imgh = img.height();
2875 int imgw = img.width();
2876 int h, s, v, a;
2877 QRgb pixel;
2878 for (int y = 0; y < imgh; ++y) {
2879 for (int x = 0; x < imgw; ++x) {
2880 pixel = img.pixel(x, y);
2881 a = qAlpha(pixel);
2882 QColor hsvColor(pixel);
2883 hsvColor.getHsv(&h, &s, &v);
2884 s = qMin(100, s * 2);
2885 v = v / 2;
2886 hsvColor.setHsv(h, s, v);
2887 pixel = hsvColor.rgb();
2888 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
2889 }
2890 }
2891 return QPixmap::fromImage(img);
2892}
2893
2894void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const
2895{
2896 if (vertical) {
2897 CGContextTranslateCTM(cg, rect.size.height, 0);
2898 CGContextRotateCTM(cg, M_PI_2);
2899 }
2900 if (vertical != reverse) {
2901 CGContextTranslateCTM(cg, rect.size.width, 0);
2902 CGContextScaleCTM(cg, -1, 1);
2903 }
2904}
2905
2907{
2908 Q_D(const QMacStyle);
2909
2910 const AppearanceSync sync;
2912
2913 QMacCGContext cg(p);
2914 d->resolveCurrentNSView(opt->window);
2915
2916 switch (ce) {
2917 case CE_HeaderSection:
2918 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2919 State flags = header->state;
2920 QRect ir = header->rect;
2921 const bool pressed = (flags & State_Sunken) && !(flags & State_On);
2922 p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
2923 p->setPen(QPen(header->palette.dark(), 1.0));
2924 if (header->orientation == Qt::Horizontal)
2925 p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
2926 ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
2927 else
2928 p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
2929 ir.right() - headerSectionSeparatorInset, ir.bottom()));
2930 }
2931
2932 break;
2933 case CE_HeaderLabel:
2934 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2935 p->save();
2936 QRect textr = header->rect;
2937 if (!header->icon.isNull()) {
2939 if (opt->state & State_Enabled)
2941 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
2942 QPixmap pixmap = header->icon.pixmap(QSize(iconExtent, iconExtent),
2943 opt->window->devicePixelRatio(), mode);
2944
2945 QRect pixr = header->rect;
2946 pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
2948 textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
2949 }
2950
2951 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
2953 p->restore();
2954 }
2955 break;
2956 case CE_ToolButtonLabel:
2957 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
2958 QStyleOptionToolButton myTb = *tb;
2959 myTb.state &= ~State_AutoRaise;
2960#ifndef QT_NO_ACCESSIBILITY
2961 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
2962 QRect cr = tb->rect;
2963 int shiftX = 0;
2964 int shiftY = 0;
2965 bool needText = false;
2966 int alignment = 0;
2967 bool down = tb->state & (State_Sunken | State_On);
2968 if (down) {
2970 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
2971 }
2972 // The down state is special for QToolButtons in a toolbar on the Mac
2973 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
2974 // This doesn't really fit into any particular case in QIcon, so we
2975 // do the majority of the work ourselves.
2976 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
2977 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
2978 if (tb->icon.isNull() && !tb->text.isEmpty())
2979 tbstyle = Qt::ToolButtonTextOnly;
2980
2981 switch (tbstyle) {
2983 needText = true;
2985 break; }
2989 QRect pr = cr;
2990 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
2992 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
2993 : QIcon::Off;
2994 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize),
2995 opt->window->devicePixelRatio(), iconMode,
2996 iconState);
2997
2998 // Draw the text if it's needed.
2999 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3000 needText = true;
3001 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3002 pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
3003 cr.adjust(0, pr.bottom(), 0, -3);
3005 } else {
3006 pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
3007 cr.adjust(pr.right(), 0, 0, 0);
3009 }
3010 }
3011 if (opt->state & State_Sunken) {
3012 pr.translate(shiftX, shiftY);
3014 }
3016 break; }
3017 default:
3018 Q_ASSERT(false);
3019 break;
3020 }
3021
3022 if (needText) {
3023 QPalette pal = tb->palette;
3027 if (down)
3028 cr.translate(shiftX, shiftY);
3029 if (tbstyle == Qt::ToolButtonTextOnly
3030 || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
3031 QPen pen = p->pen();
3032 QColor light = down || isDarkMode() ? Qt::black : Qt::white;
3033 light.setAlphaF(0.375f);
3034 p->setPen(light);
3035 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3036 p->setPen(pen);
3037 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3038// pal = QApplication::palette("QMenu");
3039 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3041 }
3042 }
3043 proxy()->drawItemText(p, cr, alignment, pal,
3044 tb->state & State_Enabled, tb->text, role);
3045 }
3046 } else {
3047 QCommonStyle::drawControl(ce, &myTb, p);
3048 }
3049 } else
3050#endif // QT_NO_ACCESSIBILITY
3051 {
3052 QCommonStyle::drawControl(ce, &myTb, p);
3053 }
3054 }
3055 break;
3056 case CE_ToolBoxTabShape:
3058 break;
3059 case CE_PushButtonBevel:
3060 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3061 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3062 break;
3063
3066 break;
3067 }
3068
3069 const bool hasFocus = btn->state & State_HasFocus;
3070 const bool isActive = btn->state & State_Active;
3071
3072 // a focused auto-default button within an active window
3073 // takes precedence over a normal default button
3075 && isActive && hasFocus)
3076 d->autoDefaultButton = btn->styleObject;
3077 else if (d->autoDefaultButton == btn->styleObject)
3078 d->autoDefaultButton = nullptr;
3079
3080 const bool isEnabled = btn->state & State_Enabled;
3081 const bool isPressed = btn->state & State_Sunken;
3082 const bool isHighlighted = isActive &&
3083 ((btn->state & State_On)
3086 && d->autoDefaultButton == btn->styleObject));
3087 const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3088 const auto ct = cocoaControlType(btn);
3089 const auto cs = d->effectiveAquaSizeConstrain(btn);
3090 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3091 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
3092 // Ensure same size and location as we used to have with HITheme.
3093 // This is more convoluted than we initialy thought. See for example
3094 // differences between plain and menu button frames.
3095 const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
3096 pb.frame = frameRect.toCGRect();
3097
3098 pb.enabled = isEnabled;
3099 [pb highlight:isPressed];
3100 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
3101 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
3103 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3104 });
3105 [pb highlight:NO];
3106
3107 if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
3108 // Using -[NSPopuButtonCell drawWithFrame:inView:] above won't do
3109 // it right because we don't set the text in the native button.
3111 const auto ir = frameRect.toRect();
3112 int arrowYOffset = 0;
3113 const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
3114
3115 QStyleOption arrowOpt = *opt;
3116 arrowOpt.rect = ar;
3118 }
3119 }
3120 break;
3121 case CE_PushButtonLabel:
3122 if (const QStyleOptionButton *b = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3124 // We really don't want the label to be drawn the same as on
3125 // windows style if it has an icon and text, then it should be more like a
3126 // tab. So, cheat a little here. However, if it *is* only an icon
3127 // the windows style works great, so just use that implementation.
3128 const bool isEnabled = btn.state & State_Enabled;
3129 const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
3130 const bool hasIcon = !btn.icon.isNull();
3131 const bool hasText = !btn.text.isEmpty();
3132 const bool isActive = btn.state & State_Active;
3133 const bool isPressed = btn.state & State_Sunken;
3134
3135 const auto ct = cocoaControlType(&btn);
3136
3137 if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
3138 if (isPressed
3139 || (isActive && isEnabled
3140 && ((btn.state & State_On)
3141 || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
3142 || d->autoDefaultButton == btn.styleObject)))
3144 }
3145
3146 if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
3148 } else {
3149 QRect freeContentRect = btn.rect;
3151 btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
3152 if (hasMenu) {
3153 textRect.moveTo(11, textRect.top());
3154 }
3155 // Draw the icon:
3156 if (hasIcon) {
3157 int contentW = textRect.width();
3158 if (hasMenu)
3159 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3163 // Decide if the icon is should be on or off:
3165 if (btn.state & State_On)
3166 state = QIcon::On;
3167 QPixmap pixmap = btn.icon.pixmap(btn.iconSize, opt->window->devicePixelRatio(),
3168 mode, state);
3169 int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
3170 int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
3171 contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
3172 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3173 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
3174 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
3175 QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
3176 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3177 int newOffset = iconDestRect.x() + iconDestRect.width()
3179 textRect.adjust(newOffset, 0, newOffset, 0);
3180 }
3181 // Draw the text:
3182 if (hasText) {
3183 textRect = visualRect(btn.direction, freeContentRect, textRect);
3185 isEnabled, btn.text, QPalette::ButtonText);
3186 }
3187 }
3188 }
3189 break;
3190 case CE_ComboBoxLabel:
3191 if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3192 auto comboCopy = *cb;
3193 comboCopy.direction = Qt::LeftToRight;
3194 // The rectangle will be adjusted to SC_ComboBoxEditField with comboboxEditBounds()
3196 }
3197 break;
3198 case CE_TabBarTabShape:
3199 if (const auto *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3200 if (tabOpt->documentMode) {
3201 p->save();
3202 bool isUnified = false;
3203// if (w) {
3204// QRect tabRect = tabOpt->rect;
3205// QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
3206// isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y());
3207// }
3208
3209 const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
3210 drawTabShape(p, tabOpt, isUnified, tabOverlap);
3211
3212 p->restore();
3213 return;
3214 }
3215
3216 const bool isActive = tabOpt->state & State_Active;
3217 const bool isEnabled = tabOpt->state & State_Enabled;
3218 const bool isPressed = tabOpt->state & State_Sunken;
3219 const bool isSelected = tabOpt->state & State_Selected;
3220 const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
3221 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3222 || tabDirection == QMacStylePrivate::West;
3223
3224 QStyleOptionTab::TabPosition tp = tabOpt->position;
3225 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3226 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3227 if (tp == QStyleOptionTab::Beginning)
3228 tp = QStyleOptionTab::End;
3229 else if (tp == QStyleOptionTab::End)
3230 tp = QStyleOptionTab::Beginning;
3231
3232 if (sp == QStyleOptionTab::NextIsSelected)
3233 sp = QStyleOptionTab::PreviousIsSelected;
3234 else if (sp == QStyleOptionTab::PreviousIsSelected)
3235 sp = QStyleOptionTab::NextIsSelected;
3236 }
3237
3238 // Alas, NSSegmentedControl and NSSegmentedCell are letting us down.
3239 // We're not able to draw it at will, either calling -[drawSegment:
3240 // inFrame:withView:], -[drawRect:] or anything in between. Besides,
3241 // there's no public API do draw the pressed state, AFAICS. We'll use
3242 // a push NSButton instead and clip the CGContext.
3243 // NOTE/TODO: this is not true. On 10.13 NSSegmentedControl works with
3244 // some (black?) magic/magic dances, on 10.14 it simply works (was
3245 // it fixed in AppKit?). But, indeed, we cannot make a tab 'pressed'
3246 // with NSSegmentedControl (only selected), so we stay with buttons
3247 // (mixing buttons and NSSegmentedControl for such a simple thing
3248 // is too much work).
3249
3250 const auto cs = d->effectiveAquaSizeConstrain(opt);
3251 // Extra hacks to get the proper pressed appreance when not selected or selected and inactive
3252 const bool needsInactiveHack = (!isActive && isSelected);
3253 const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
3256 const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
3257 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3258 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
3259
3260 auto vOffset = isPopupButton ? 1 : 2;
3261 if (tabDirection == QMacStylePrivate::East)
3262 vOffset -= 1;
3263 const auto outerAdjust = isPopupButton ? 1 : 4;
3264 const auto innerAdjust = isPopupButton ? 20 : 10;
3265 QRectF frameRect = tabOpt->rect;
3266 if (verticalTabs)
3267 frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
3268 // Adjust before clipping
3269 frameRect = frameRect.translated(0, vOffset);
3270 switch (tp) {
3271 case QStyleOptionTab::Beginning:
3272 // Pressed state hack: tweak adjustments in preparation for flip below
3273 if (!isSelected && tabDirection == QMacStylePrivate::West)
3274 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3275 else
3276 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3277 break;
3278 case QStyleOptionTab::Middle:
3279 frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
3280 break;
3281 case QStyleOptionTab::End:
3282 // Pressed state hack: tweak adjustments in preparation for flip below
3283 if (isSelected || tabDirection == QMacStylePrivate::West)
3284 frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
3285 else
3286 frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
3287 break;
3288 case QStyleOptionTab::OnlyOneTab:
3289 frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
3290 break;
3291 }
3292 pb.frame = frameRect.toCGRect();
3293
3294 pb.enabled = isEnabled;
3295 [pb highlight:isPressed];
3296 // Set off state when inactive. See needsInactiveHack for when it's selected
3297 pb.state = (isActive && isSelected && !isPressed) ? NSControlStateValueOn : NSControlStateValueOff;
3298
3299 const auto drawBezelBlock = ^(CGContextRef ctx, const CGRect &r) {
3301 CGContextClipToRect(ctx, opt->rect.toCGRect());
3302 if (!isSelected || needsInactiveHack) {
3303 // Final stage of the pressed state hack: flip NSPopupButton rendering
3304 if (!verticalTabs && tp == QStyleOptionTab::End) {
3305 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3306 CGContextScaleCTM(ctx, -1, 1);
3307 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3308 } else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
3309 CGContextTranslateCTM(ctx, 0, opt->rect.top());
3310 CGContextScaleCTM(ctx, 1, -1);
3311 CGContextTranslateCTM(ctx, 0, -frameRect.right());
3312 } else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
3313 CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
3314 CGContextScaleCTM(ctx, 1, -1);
3315 CGContextTranslateCTM(ctx, 0, -frameRect.left());
3316 }
3317 }
3318
3319 // Rotate and translate CTM when vertical
3320 // On macOS: positive angle is CW, negative is CCW
3321 if (tabDirection == QMacStylePrivate::West) {
3322 CGContextTranslateCTM(ctx, 0, frameRect.right());
3323 CGContextRotateCTM(ctx, -M_PI_2);
3324 CGContextTranslateCTM(ctx, -frameRect.left(), 0);
3325 } else if (tabDirection == QMacStylePrivate::East) {
3326 CGContextTranslateCTM(ctx, opt->rect.right(), 0);
3327 CGContextRotateCTM(ctx, M_PI_2);
3328 }
3329
3330 // Now, if it's a trick with a popup button, it has an arrow
3331 // which makes no sense on tabs.
3332 NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
3333 NSPopUpButtonCell *pbCell = nil;
3334 if (isPopupButton) {
3335 pbCell = static_cast<NSPopUpButtonCell *>(pb.cell);
3336 oldPosition = pbCell.arrowPosition;
3337 pbCell.arrowPosition = NSPopUpNoArrow;
3338 }
3339
3340 [pb.cell drawBezelWithFrame:r inView:pb.superview];
3341
3342 if (pbCell) // Restore, we may reuse it for a ComboBox.
3343 pbCell.arrowPosition = oldPosition;
3344 };
3345
3346 if (needsInactiveHack) {
3347 // First, render tab as non-selected tab on a pixamp
3348 const qreal pixelRatio = p->device()->devicePixelRatioF();
3349 QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
3350 tabPixmap.setDevicePixelRatio(pixelRatio);
3351 tabPixmap.fill(Qt::transparent);
3352 QPainter tabPainter(&tabPixmap);
3353 d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx, const CGRect &r) {
3355 CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
3356 drawBezelBlock(ctx, r);
3357 });
3358 tabPainter.end();
3359
3360 // Then, darken it with the proper shade of gray
3361 const qreal inactiveGray = 0.898; // As measured
3362 const int inactiveGray8 = qRound(inactiveGray * 255.0);
3363 const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
3364 for (int l = 0; l < tabPixmap.height(); ++l) {
3365 auto *line = reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
3366 for (int i = 0; i < tabPixmap.width(); ++i) {
3367 if (qAlpha(line[i]) == 255) {
3368 line[i] = inactiveGrayRGB;
3369 } else if (qAlpha(line[i]) > 128) {
3370 const int g = qRound(inactiveGray * qRed(line[i]));
3371 line[i] = qRgba(g, g, g, qAlpha(line[i]));
3372 }
3373 }
3374 }
3375
3376 // Finally, draw the tab pixmap on the current painter
3377 p->drawImage(opt->rect, tabPixmap);
3378 } else {
3379 d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
3380 }
3381
3382 if (!isSelected && sp != QStyleOptionTab::NextIsSelected
3383 && tp != QStyleOptionTab::End
3384 && tp != QStyleOptionTab::OnlyOneTab) {
3385 static const QPen separatorPen(Qt::black, 1.0);
3386 p->save();
3387 p->setOpacity(isEnabled ? 0.105 : 0.06); // As measured
3388 p->setPen(separatorPen);
3389 if (tabDirection == QMacStylePrivate::West) {
3390 p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
3391 opt->rect.right() - 0.5, opt->rect.bottom()));
3392 } else if (tabDirection == QMacStylePrivate::East) {
3393 p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
3394 opt->rect.right() - 0.5, opt->rect.bottom()));
3395 } else {
3396 p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
3397 opt->rect.right(), opt->rect.bottom() - 0.5));
3398 }
3399 p->restore();
3400 }
3401 }
3402 break;
3403 case CE_TabBarTabLabel:
3404 if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3405 QStyleOptionTab myTab = *tab;
3406 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
3407 const bool verticalTabs = tabDirection == QMacStylePrivate::East
3408 || tabDirection == QMacStylePrivate::West;
3409
3410 // Check to see if we use have the same as the system font
3411 // (QComboMenuItem is internal and should never be seen by the
3412 // outside world, unless they read the source, in which case, it's
3413 // their own fault).
3414// const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
3415 const bool nonDefaultFont = false;
3416
3417// if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
3418// if (const auto *tabBar = qobject_cast<const QTabBar *>(w))
3419// if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
3420// myTab.palette.setColor(QPalette::WindowText, Qt::white);
3421
3422 if (myTab.documentMode && isDarkMode()) {
3423 bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
3424 myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
3425 }
3426
3427 int heightOffset = 0;
3428 if (verticalTabs) {
3429 heightOffset = -1;
3430 } else if (nonDefaultFont) {
3431 if (p->fontMetrics().height() == myTab.rect.height())
3432 heightOffset = 2;
3433 }
3434 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3435
3436 QCommonStyle::drawControl(ce, &myTab, p);
3437 }
3438 break;
3439 case CE_DockWidgetTitle:
3440 if (const auto *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
3441 const bool isVertical = dwOpt->verticalTitleBar;
3442 const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
3443 p->save();
3444 if (isVertical) {
3445 p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
3446 p->rotate(-90);
3447 p->translate(-effectiveRect.left(), -effectiveRect.top());
3448 }
3449
3450 // fill title bar background
3451 p->fillRect(effectiveRect, opt->palette.window());
3452
3453 // draw horizontal line at bottom
3454 p->setPen(opt->palette.dark().color());
3455 p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
3456
3457 if (!dwOpt->title.isEmpty()) {
3458 auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
3459 if (isVertical)
3460 titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
3461 effectiveRect.top() + titleRect.left() - opt->rect.left(),
3462 titleRect.height(),
3463 titleRect.width());
3464
3465 const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
3466 proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
3467 dwOpt->state & State_Enabled, text, QPalette::WindowText);
3468 }
3469 p->restore();
3470 }
3471 break;
3472 case CE_FocusFrame: {
3473// const auto *ff = qobject_cast<const QFocusFrame *>(w);
3474// const auto *ffw = ff ? ff->widget() : nullptr;
3475// const auto ct = [=] {
3476// if (ffw) {
3477// if (ffw->inherits("QCheckBox"))
3478// return QMacStylePrivate::Button_CheckBox;
3479// if (ffw->inherits("QRadioButton"))
3480// return QMacStylePrivate::Button_RadioButton;
3481// if (ffw->inherits("QLineEdit") || ffw->inherits("QTextEdit"))
3482// return QMacStylePrivate::TextField;
3483// }
3484//
3485// return QMacStylePrivate::Box; // Not really, just make it the default
3486// } ();
3487// const auto cs = ffw ? (ffw->testAttribute(Qt::WA_MacMiniSize) ? QStyleHelper::SizeMini :
3488// ffw->testAttribute(Qt::WA_MacSmallSize) ? QStyleHelper::SizeSmall :
3489// QStyleHelper::SizeLarge) :
3490// QStyleHelper::SizeLarge;
3491// const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt);
3492// const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt);
3493// d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
3494 break; }
3495 case CE_MenuEmptyArea:
3496 // Skip: PE_PanelMenu fills in everything
3497 break;
3498 case CE_MenuItem:
3499 case CE_MenuHMargin:
3500 case CE_MenuVMargin:
3501 case CE_MenuTearoff:
3502 case CE_MenuScroller:
3503 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3504 const bool active = mi->state & State_Selected;
3505 if (active)
3506 p->fillRect(mi->rect, mi->palette.highlight());
3507
3508 const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
3509
3510 if (ce == CE_MenuTearoff) {
3511 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
3512 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
3513 mi->rect.x() + mi->rect.width() - 4,
3514 mi->rect.y() + mi->rect.height() / 2 - 1);
3515 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
3516 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
3517 mi->rect.x() + mi->rect.width() - 4,
3518 mi->rect.y() + mi->rect.height() / 2);
3519 } else if (ce == CE_MenuScroller) {
3520 const QSize scrollerSize = QSize(10, 8);
3521 const int scrollerVOffset = 5;
3522 const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
3523 const int right = left + scrollerSize.width();
3524 int top;
3525 int bottom;
3526 if (opt->state & State_DownArrow) {
3527 bottom = mi->rect.y() + scrollerVOffset;
3528 top = bottom + scrollerSize.height();
3529 } else {
3530 bottom = mi->rect.bottom() - scrollerVOffset;
3531 top = bottom - scrollerSize.height();
3532 }
3533 p->save();
3534 p->setRenderHint(QPainter::Antialiasing);
3536 path.moveTo(left, bottom);
3537 path.lineTo(right, bottom);
3538 path.lineTo((left + right) / 2, top);
3539 p->fillPath(path, opt->palette.buttonText());
3540 p->restore();
3541 } else if (ce != CE_MenuItem) {
3542 break;
3543 }
3544
3545 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
3546 CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
3547 const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
3548 p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
3549 break;
3550 }
3551
3552 const int maxpmw = mi->maxIconWidth;
3553 const bool enabled = mi->state & State_Enabled;
3554
3555 int xpos = mi->rect.x() + 18;
3556 int checkcol = maxpmw;
3557 if (!enabled)
3558 p->setPen(mi->palette.text().color());
3559 else if (active)
3560 p->setPen(mi->palette.highlightedText().color());
3561 else
3562 p->setPen(mi->palette.buttonText().color());
3563
3564 if (mi->checked) {
3565 QStyleOption checkmarkOpt;
3566// checkmarkOpt.initFrom(w);
3567
3568 const int mw = checkcol + macItemFrame;
3569 const int mh = mi->rect.height() + macItemFrame;
3570 const int xp = mi->rect.x() + macItemFrame;
3571 checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
3572
3573 checkmarkOpt.state.setFlag(State_On, active);
3574 checkmarkOpt.state.setFlag(State_Enabled, enabled);
3575 if (widgetSize == QStyleHelper::SizeMini)
3576 checkmarkOpt.state |= State_Mini;
3577 else if (widgetSize == QStyleHelper::SizeSmall)
3578 checkmarkOpt.state |= State_Small;
3579
3580 // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color
3581 checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
3582 checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
3583
3584 proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
3585 }
3586 if (!mi->icon.isNull()) {
3589 // Always be normal or disabled to follow the Mac style.
3590 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
3591 QSize iconSize(smallIconSize, smallIconSize);
3592//#if QT_CONFIG(combobox)
3593// if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
3594// iconSize = comboBox->iconSize();
3595// }
3596//#endif
3597 QPixmap pixmap = mi->icon.pixmap(iconSize, opt->window->devicePixelRatio(), mode);
3598 int pixw = pixmap.width() / pixmap.devicePixelRatio();
3599 int pixh = pixmap.height() / pixmap.devicePixelRatio();
3600 QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
3601 QRect pmr(0, 0, pixw, pixh);
3602 pmr.moveCenter(cr.center());
3603 p->drawPixmap(pmr.topLeft(), pixmap);
3604 xpos += pixw + 6;
3605 }
3606
3607 QString s = mi->text;
3608 const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
3610 int yPos = mi->rect.y();
3611 if (widgetSize == QStyleHelper::SizeMini)
3612 yPos += 1;
3613
3614 const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
3615 const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
3616
3617 QString rightMarginText;
3618 if (isSubMenu)
3619 rightMarginText = QStringLiteral("\u25b6\ufe0e"); // U+25B6 U+FE0E: BLACK RIGHT-POINTING TRIANGLE
3620
3621 // If present, save and remove embedded shorcut from text
3622 const int tabIndex = s.indexOf(QLatin1Char('\t'));
3623 if (tabIndex >= 0) {
3624 if (!isSubMenu) // ... but ignore it if it's a submenu.
3625 rightMarginText = s.mid(tabIndex + 1);
3626 s = s.left(tabIndex);
3627 }
3628
3629 p->save();
3630 if (!rightMarginText.isEmpty()) {
3631// p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
3632 int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
3633 if (!isSubMenu)
3634 xp -= macItemHMargin + macItemFrame + 3; // Adjust for shortcut
3635 p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
3636 }
3637
3638 if (!s.isEmpty()) {
3639 const int xm = macItemFrame + maxpmw + macItemHMargin;
3640 QFont myFont = mi->font;
3641 // myFont may not have any "hard" flags set. We override
3642 // the point size so that when it is resolved against the device, this font will win.
3643 // This is mainly to handle cases where someone sets the font on the window
3644 // and then the combo inherits it and passes it onward. At that point the resolve mask
3645 // is very, very weak. This makes it stonger.
3646 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
3647
3648 // QTBUG-65653: Our own text rendering doesn't look good enough, especially on non-retina
3649 // displays. Worked around here while waiting for a proper fix in QCoreTextFontEngine.
3650 // Only if we're not using QCoreTextFontEngine we do fallback to our own text rendering.
3651 const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
3652 Q_ASSERT(fontEngine);
3653 if (fontEngine->type() == QFontEngine::Multi) {
3654 fontEngine = static_cast<const QFontEngineMulti *>(fontEngine)->engine(0);
3655 Q_ASSERT(fontEngine);
3656 }
3657 if (fontEngine->type() == QFontEngine::Mac) {
3658 NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
3659
3660 // Respect the menu item palette as set in the style option.
3661 const auto pc = p->pen().color();
3662 NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
3663 green:pc.greenF()
3664 blue:pc.blueF()
3665 alpha:pc.alphaF()];
3666
3668
3669 QMacCGContext cgCtx(p);
3670 d->setupNSGraphicsContext(cgCtx, YES);
3671
3672 // Draw at point instead of in rect, as the rect we've computed for the menu item
3673 // is based on the font metrics we got from HarfBuzz, so we may risk having CoreText
3674 // line-break the string if it doesn't fit the given rect. It's better to draw outside
3675 // the rect and possibly overlap something than to have part of the text disappear.
3676 [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
3677 withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
3678 NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
3679
3680 d->restoreNSGraphicsContext(cgCtx);
3681 } else {
3682 p->setFont(myFont);
3683 p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
3684 mi->rect.height(), text_flags, s);
3685 }
3686 }
3687 p->restore();
3688 }
3689 break;
3690 case CE_MenuBarItem:
3692 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3693 const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
3694 const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
3695 p->fillRect(mi->rect, bg);
3696
3697 if (ce != CE_MenuBarItem)
3698 break;
3699
3700 if (!mi->icon.isNull()) {
3701 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
3702 drawItemPixmap(p, mi->rect,
3705 mi->icon.pixmap(QSize(iconExtent, iconExtent),
3706 opt->window->devicePixelRatio(),
3707 (mi->state & State_Enabled) ? QIcon::Normal
3708 : QIcon::Disabled));
3709 } else {
3710 drawItemText(p, mi->rect,
3713 mi->palette, mi->state & State_Enabled,
3714 mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
3715 }
3716 }
3717 break;
3720 break;
3722 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
3723 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
3724 const bool inverted = pb->invertedAppearance;
3725 bool reverse = pb->direction == Qt::RightToLeft;
3726 if (inverted)
3727 reverse = !reverse;
3728
3729 QRect rect = pb->rect;
3730 const CGRect cgRect = rect.toCGRect();
3731
3732 const auto aquaSize = d->aquaSizeConstrain(opt);
3733
3734// const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
3736// if (isIndeterminate || animation)
3737 ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
3738 if (isIndeterminate) {
3739 // QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
3740 // instance that we start animating as soon as one of the progress bars is indeterminate.
3741 // Since they will be in sync (as it's the case in Cocoa), we just need to draw it with
3742 // the right geometry when the animation triggers an update. However, we can't hide it
3743 // entirely between frames since that would stop the animation, so we just set its alpha
3744 // value to 0. Same if we remove it from its superview. See QIndeterminateProgressIndicator
3745 // implementation for details.
3746 //
3747 // Quick: consider implementing this animation by using Quick/QML instead.
3748 //
3749// if (!animation && opt->styleObject) {
3750// auto *animation = new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
3751// // NSProgressIndicator is heavier to draw than the HITheme API, so we reduce the frame rate a couple notches.
3752// animation->setFrameRate(QStyleAnimation::FifteenFps);
3753// d->startAnimation(animation);
3754// [ipi startAnimation];
3755// }
3756
3757 d->setupNSGraphicsContext(cg, NO);
3758 d->setupVerticalInvertedXform(cg, reverse, false, cgRect);
3759 [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
3760 d->restoreNSGraphicsContext(cg);
3761 } else {
3762// if (animation) {
3763// d->stopAnimation(opt->styleObject);
3764// [ipi stopAnimation];
3765// }
3766
3768 auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
3769 d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx, const CGRect &rect) {
3771 d->setupVerticalInvertedXform(ctx, reverse, false, rect);
3772 pi.minValue = pb->minimum;
3773 pi.maxValue = pb->maximum;
3774 pi.doubleValue = pb->progress;
3775 [pi drawRect:rect];
3776 });
3777 }
3778 }
3779 break;
3780 case CE_SizeGrip: {
3781 // This is not HIG kosher: Fall back to the old stuff until we decide what to do.
3782//#ifndef QT_NO_MDIAREA
3783// if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
3784//#endif
3785// break;
3786
3787// if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
3788// p->fillRect(opt->rect, opt->palette.window());
3789
3790// QPen lineColor = QColor(82, 82, 82, 192);
3791// lineColor.setWidth(1);
3792// p->save();
3793// p->setRenderHint(QPainter::Antialiasing);
3794// p->setPen(lineColor);
3795// const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
3796// const int NumLines = 3;
3797// for (int l = 0; l < NumLines; ++l) {
3798// const int offset = (l * 4 + 3);
3799// QPoint start, end;
3800// if (layoutDirection == Qt::LeftToRight) {
3801// start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
3802// end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
3803// } else {
3804// start = QPoint(offset, opt->rect.height() - 1);
3805// end = QPoint(1, opt->rect.height() - offset);
3806// }
3807// p->drawLine(start, end);
3808// }
3809// p->restore();
3810 break;
3811 }
3812 case CE_Splitter:
3813 if (opt->rect.width() > 1 && opt->rect.height() > 1) {
3814 const bool isVertical = !(opt->state & QStyle::State_Horizontal);
3815 // Qt refers to the layout orientation, while Cocoa refers to the divider's.
3818 auto *sv = static_cast<NSSplitView *>(d->cocoaControl(cw));
3819 sv.frame = opt->rect.toCGRect();
3820 d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
3822 [sv drawDividerInRect:rect];
3823 });
3824 } else {
3825 QPen oldPen = p->pen();
3826 p->setPen(opt->palette.dark().color());
3828 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3829 else
3830 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3831 p->setPen(oldPen);
3832 }
3833 break;
3834 case CE_RubberBand:
3835 if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
3837 if (!rubber->opaque) {
3838 QColor strokeColor;
3839 // I retrieved these colors from the Carbon-Dev mailing list
3840 strokeColor.setHsvF(0, 0, 0.86, 1.0);
3841 fillColor.setHsvF(0, 0, 0.53, 0.25);
3842 if (opt->rect.width() * opt->rect.height() <= 3) {
3843 p->fillRect(opt->rect, strokeColor);
3844 } else {
3845 QPen oldPen = p->pen();
3846 QBrush oldBrush = p->brush();
3847 QPen pen(strokeColor);
3848 p->setPen(pen);
3849 p->setBrush(fillColor);
3850 QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
3851 if (adjusted.isValid())
3852 p->drawRect(adjusted);
3853 p->setPen(oldPen);
3854 p->setBrush(oldBrush);
3855 }
3856 } else {
3857 p->fillRect(opt->rect, fillColor);
3858 }
3859 }
3860 break;
3861 case CE_ToolBar: {
3862 const bool isDarkMode = qt_mac_applicationIsInDarkMode();
3863
3864 // Unified title and toolbar drawing. In this mode the cocoa platform plugin will
3865 // fill the top toolbar area part with a background gradient that "unifies" with
3866 // the title bar. The following code fills the toolBar area with transparent pixels
3867 // to make that gradient visible.
3868// if (w) {
3869//#if QT_CONFIG(mainwindow)
3870// if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
3871// if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
3872// // fill with transparent pixels.
3873// p->save();
3874// p->setCompositionMode(QPainter::CompositionMode_Source);
3875// p->fillRect(opt->rect, Qt::transparent);
3876// p->restore();
3877
3878// // Draw a horizontal separator line at the toolBar bottom if the "unified" area ends here.
3879// // There might be additional toolbars or other widgets such as tab bars in document
3880// // mode below. Determine this by making a unified toolbar area test for the row below
3881// // this toolbar.
3882// const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
3883// const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowToolbarEnd.y() + 1);
3884// if (isEndOfUnifiedArea) {
3885// const int margin = qt_mac_aqua_get_metric(SeparatorSize);
3886// const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
3887// p->fillRect(separatorRect, isDarkMode ? darkModeSeparatorLine : opt->palette.dark().color());
3888// }
3889// break;
3890// }
3891// }
3892//#endif
3893// }
3894
3895 // draw background gradient
3896 QLinearGradient linearGrad;
3897 if (opt->state & State_Horizontal)
3898 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
3899 else
3900 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
3901
3904
3905 linearGrad.setColorAt(0, mainWindowGradientBegin);
3906 linearGrad.setColorAt(1, mainWindowGradientEnd);
3907 p->fillRect(opt->rect, linearGrad);
3908
3909 p->save();
3910 QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
3911 if (opt->state & State_Horizontal) {
3912 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3913 p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
3914 p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
3915 p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
3916 } else {
3917 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
3918 p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
3919 p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
3920 p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
3921 }
3922 p->restore();
3923
3924 break; }
3925 default:
3927 break;
3928 }
3929}
3930
3932{
3933 if (dir == Qt::RightToLeft) {
3934 rect->adjust(-right, top, -left, bottom);
3935 } else {
3936 rect->adjust(left, top, right, bottom);
3937 }
3938}
3939
3941{
3942 Q_D(const QMacStyle);
3943 QRect rect;
3944 const int controlSize = getControlSize(opt);
3945
3946 switch (sr) {
3948 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
3950 // We add the focusframeargin between icon and text in commonstyle
3952 if (vopt->features & QStyleOptionViewItem::HasDecoration)
3953 rect.adjust(-fw, 0, 0, 0);
3954 }
3955 break;
3958 break;
3960 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3961 // Comment from the old HITheme days:
3962 // "Unlike Carbon, we want the button to always be drawn inside its bounds.
3963 // Therefore, the button is a bit smaller, so that even if it got focus,
3964 // the focus 'shadow' will be inside. Adjust the content rect likewise."
3965 // In the future, we should consider using -[NSCell titleRectForBounds:].
3966 // Since it requires configuring the NSButton fully, i.e. frame, image,
3967 // title and font, we keep things more manual until we are more familiar
3968 // with side effects when changing NSButton state.
3969 const auto ct = cocoaControlType(btn);
3970 const auto cs = d->effectiveAquaSizeConstrain(btn);
3971 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
3972 auto frameRect = cw.adjustedControlFrame(btn->rect);
3973 frameRect -= cw.titleMargins();
3974 rect = frameRect.toRect();
3975 }
3976 break;
3977 case SE_HeaderLabel: {
3978 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3979 rect.setRect(opt->rect.x() + margin, opt->rect.y(),
3980 opt->rect.width() - margin * 2, opt->rect.height() - 2);
3981 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3982 // Subtract width needed for arrow, if there is one
3983 if (header->sortIndicator != QStyleOptionHeader::None) {
3984 if (opt->state & State_Horizontal)
3985 rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
3986 else
3987 rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
3988 }
3989 }
3991 break;
3992 }
3993 case SE_HeaderArrow: {
3994 int h = opt->rect.height();
3995 int w = opt->rect.width();
3996 int x = opt->rect.x();
3997 int y = opt->rect.y();
3998 int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
3999
4000 if (opt->state & State_Horizontal) {
4001 rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
4002 headerSectionArrowHeight, h - margin * 2 - 5);
4003 } else {
4004 rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
4005 w - margin * 2 - 5, headerSectionArrowHeight);
4006 }
4008 break;
4009 }
4011 // Wrong in the secondary dimension, but accurate enough in the main dimension.
4012 rect = opt->rect;
4013 break;
4015 break;
4017 rect = opt->rect;
4018 break;
4020 rect = opt->rect;
4021 // As previously returned by HIThemeGetButtonContentBounds
4022 rect.setLeft(rect.left() + 2 + DisclosureOffset);
4023 break;
4024 }
4026 if (const QStyleOptionTabWidgetFrame *twf
4027 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4028 switch (twf->shape) {
4029 case QStyleOptionTab::RoundedNorth:
4030 case QStyleOptionTab::TriangularNorth:
4031 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4032 break;
4033 case QStyleOptionTab::RoundedSouth:
4034 case QStyleOptionTab::TriangularSouth:
4035 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4036 twf->leftCornerWidgetSize);
4037 break;
4038 default:
4039 break;
4040 }
4041 rect = visualRect(twf->direction, twf->rect, rect);
4042 }
4043 break;
4045 if (const QStyleOptionTabWidgetFrame *twf
4046 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4047 switch (twf->shape) {
4048 case QStyleOptionTab::RoundedNorth:
4049 case QStyleOptionTab::TriangularNorth:
4050 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4051 twf->rightCornerWidgetSize);
4052 break;
4053 case QStyleOptionTab::RoundedSouth:
4054 case QStyleOptionTab::TriangularSouth:
4055 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4056 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4057 twf->rightCornerWidgetSize);
4058 break;
4059 default:
4060 break;
4061 }
4062 rect = visualRect(twf->direction, twf->rect, rect);
4063 }
4064 break;
4067 if (const auto *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4068 if (twf->lineWidth != 0) {
4069 switch (QMacStylePrivate::tabDirection(twf->shape)) {
4071 rect.adjust(+1, +14, -1, -1);
4072 break;
4074 rect.adjust(+1, +1, -1, -14);
4075 break;
4077 rect.adjust(+14, +1, -1, -1);
4078 break;
4080 rect.adjust(+1, +1, -14, -1);
4081 }
4082 }
4083 }
4084 break;
4085 case SE_TabBarTabText:
4086 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4087 QRect dummyIconRect;
4088 d->tabLayout(tab, &rect, &dummyIconRect);
4089 }
4090 break;
4093 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4094 bool selected = tab->state & State_Selected;
4095 int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
4096 int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
4097 int hpadding = 5;
4098
4099 bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
4100 || tab->shape == QStyleOptionTab::RoundedWest
4101 || tab->shape == QStyleOptionTab::TriangularEast
4102 || tab->shape == QStyleOptionTab::TriangularWest;
4103
4104 QRect tr = tab->rect;
4105 if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
4106 verticalShift = -verticalShift;
4107 if (verticalTabs) {
4108 qSwap(horizontalShift, verticalShift);
4109 horizontalShift *= -1;
4110 verticalShift *= -1;
4111 }
4112 if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
4113 horizontalShift = -horizontalShift;
4114
4115 tr.adjust(0, 0, horizontalShift, verticalShift);
4116 if (selected)
4117 {
4118 tr.setBottom(tr.bottom() - verticalShift);
4119 tr.setRight(tr.right() - horizontalShift);
4120 }
4121
4122 QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
4123 int w = size.width();
4124 int h = size.height();
4125 int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2));
4126 int midWidth = ((tr.width() - w) / 2);
4127
4128 bool atTheTop = true;
4129 switch (tab->shape) {
4130 case QStyleOptionTab::RoundedWest:
4131 case QStyleOptionTab::TriangularWest:
4132 atTheTop = (sr == SE_TabBarTabLeftButton);
4133 break;
4134 case QStyleOptionTab::RoundedEast:
4135 case QStyleOptionTab::TriangularEast:
4136 atTheTop = (sr == SE_TabBarTabRightButton);
4137 break;
4138 default:
4139 if (sr == SE_TabBarTabLeftButton)
4140 rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
4141 else
4142 rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
4143 rect = visualRect(tab->direction, tab->rect, rect);
4144 }
4145 if (verticalTabs) {
4146 if (atTheTop)
4147 rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
4148 else
4149 rect = QRect(midWidth, tr.y() + hpadding, w, h);
4150 }
4151 }
4152 break;
4153 case SE_LineEditContents: {
4154 // From using pixelTool with XCode/NSTextTextField
4155 int leftPadding = 4;
4156 int rightPadding = 4;
4157 int topPadding = 4;
4158 int bottomPadding = 0;
4159
4160 if (opt->state & QStyle::State_Small) {
4161 topPadding = 3;
4162 } else if (opt->state & QStyle::State_Mini) {
4163 topPadding = 2;
4164 }
4165
4166 rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
4167 opt->rect.height() - topPadding - bottomPadding);
4168 break; }
4170 rect = opt->rect;
4171 if (controlSize == QStyleHelper::SizeLarge) {
4172 setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
4173 } else if (controlSize == QStyleHelper::SizeSmall) {
4174 setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
4175 } else {
4176 setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
4177 }
4178 break;
4180 if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4181 //#ifndef QT_NO_TOOLBAR
4182 // if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4183 // // Do nothing, because QToolbar needs the entire widget rect.
4184 // // Otherwise it will be clipped. Equivalent to
4185 // // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4186 // // all the hassle.
4187 // } else
4188 //#endif
4189 if (combo->editable)
4191 opt->rect.adjusted(5, 6, -6, -7),
4192 opt->rect.adjusted(4, 4, -5, -7),
4193 opt->rect.adjusted(5, 4, -4, -6));
4194 else
4196 opt->rect.adjusted(6, 4, -7, -7),
4197 opt->rect.adjusted(6, 7, -6, -5),
4198 opt->rect.adjusted(9, 5, -5, -7));
4199 }
4200 break;
4201 case SE_LabelLayoutItem:
4202 rect = opt->rect;
4203 setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4204 break;
4206 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4207 const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4208 rect = opt->rect;
4209
4210 if (isIndeterminate) {
4211 rect.adjust(1, 2, -1, -2);
4212 } else {
4213 rect.adjust(1, 1, -1, -2);
4214 }
4215 }
4216 break;
4218 rect = opt->rect;
4219 if (const QStyleOptionButton *buttonOpt = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4220 if ((buttonOpt->features & QStyleOptionButton::Flat))
4221 break;
4222 }
4224 opt->rect.adjusted(7, 5, -7, -7),
4225 opt->rect.adjusted(6, 6, -6, -6),
4226 opt->rect.adjusted(6, 5, -6, -6));
4227 break;
4230 opt->rect.adjusted(2, 3, -2, -2),
4231 opt->rect.adjusted(2, 3, -2, -2),
4232 opt->rect.adjusted(2, 3, -2, -2));
4233 break;
4236 opt->rect.adjusted(2, 2, -3, -2),
4237 opt->rect.adjusted(2, 2, -3, -2),
4238 opt->rect.adjusted(1, 2, -3, -2));
4239 break;
4241 if (const QStyleOptionSlider *sliderOpt
4242 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4243 rect = opt->rect;
4244 if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
4245 if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
4246 rect.adjust(3, 3, -3, -3);
4247 } else {
4248 rect.adjust(3, 0, -3, 0);
4249 }
4250 }
4251 break;
4252 case SE_ScrollBarLayoutItem:
4253 if (const QStyleOptionSlider *sliderOpt = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4254 rect = opt->rect;
4255 }
4256 case SE_FrameLayoutItem:
4257 // hack because QStyleOptionFrame doesn't have a frameStyle member
4258// if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4259// rect = opt->rect;
4260// switch (frame->frameStyle() & QFrame::Shape_Mask) {
4261// case QFrame::HLine:
4262// rect.adjust(0, +1, 0, -1);
4263// break;
4264// case QFrame::VLine:
4265// rect.adjust(+1, 0, -1, 0);
4266// break;
4267// default:
4268// ;
4269// }
4270// }
4271 break;
4273 rect = opt->rect;
4274 if (const QStyleOptionGroupBox *groupBoxOpt =
4275 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4276 /*
4277 AHIG is very inconsistent when it comes to group boxes.
4278 Basically, we make sure that (non-checkable) group boxes
4279 and tab widgets look good when laid out side by side.
4280 */
4281 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4283 int delta;
4284 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4285 delta = SIZE(8, 4, 4); // guess
4286 } else {
4287 delta = SIZE(15, 12, 12); // guess
4288 }
4289 rect.setTop(rect.top() + delta);
4290 }
4291 }
4292 rect.setBottom(rect.bottom() - 1);
4293 break;
4295 if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4296 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4297 /*
4298 AHIG specifies "12 or 14" as the distance from the window
4299 edge. We choose 14 and since the default top margin is 20,
4300 the overlap is 6.
4301 */
4302 rect = tabWidgetOpt->rect;
4303 if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
4304 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4305 }
4306 break;
4310 case SE_DockWidgetIcon: {
4313 QRect srect = opt->rect;
4314
4315 const QStyleOptionDockWidget *dwOpt
4316 = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
4317 bool canClose = dwOpt == 0 ? true : dwOpt->closable;
4318 bool canFloat = dwOpt == 0 ? false : dwOpt->floatable;
4319
4320 const bool verticalTitleBar = dwOpt->verticalTitleBar;
4321
4322 // If this is a vertical titlebar, we transpose and work as if it was
4323 // horizontal, then transpose again.
4324 if (verticalTitleBar)
4325 srect = srect.transposed();
4326
4327 do {
4328 int right = srect.right();
4329 int left = srect.left();
4330
4331 QRect closeRect;
4332 if (canClose) {
4334 opt).actualSize(QSize(iconSize, iconSize));
4335 sz += QSize(buttonMargin, buttonMargin);
4336 if (verticalTitleBar)
4337 sz = sz.transposed();
4338 closeRect = QRect(left,
4339 srect.center().y() - sz.height()/2,
4340 sz.width(), sz.height());
4341 left = closeRect.right() + 1;
4342 }
4343 if (sr == SE_DockWidgetCloseButton) {
4344 rect = closeRect;
4345 break;
4346 }
4347
4348 QRect floatRect;
4349 if (canFloat) {
4351 opt).actualSize(QSize(iconSize, iconSize));
4352 sz += QSize(buttonMargin, buttonMargin);
4353 if (verticalTitleBar)
4354 sz = sz.transposed();
4355 floatRect = QRect(left,
4356 srect.center().y() - sz.height()/2,
4357 sz.width(), sz.height());
4358 left = floatRect.right() + 1;
4359 }
4360 if (sr == SE_DockWidgetFloatButton) {
4361 rect = floatRect;
4362 break;
4363 }
4364
4365 QRect iconRect;
4366// if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(widget)) {
4367// QIcon icon;
4368// if (dw->isFloating())
4369// icon = dw->windowIcon();
4370// if (!icon.isNull()
4371// && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
4372// QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
4373// if (verticalTitleBar)
4374// sz = sz.transposed();
4375// iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
4376// sz.width(), sz.height());
4377// right = iconRect.left() - 1;
4378// }
4379// }
4380 if (sr == SE_DockWidgetIcon) {
4381 rect = iconRect;
4382 break;
4383 }
4384
4385 QRect textRect = QRect(left, srect.top(),
4386 right - left, srect.height());
4387 if (sr == SE_DockWidgetTitleBarText) {
4388 rect = textRect;
4389 break;
4390 }
4391 } while (false);
4392
4393 if (verticalTitleBar) {
4394 rect = QRect(srect.left() + rect.top() - srect.top(),
4395 srect.top() + srect.right() - rect.right(),
4396 rect.height(), rect.width());
4397 } else {
4398 rect = visualRect(opt->direction, srect, rect);
4399 }
4400 break;
4401 }
4402 default:
4404 break;
4405 }
4406 return rect;
4407}
4408
4410{
4411 Q_Q(const QMacStyle);
4412 QStyleOption arrowOpt = *opt;
4417 q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
4418}
4419
4420void QMacStylePrivate::setupNSGraphicsContext(CGContextRef cg, bool flipped) const
4421{
4422 CGContextSaveGState(cg);
4423 [NSGraphicsContext saveGraphicsState];
4424
4425 [NSGraphicsContext setCurrentContext:
4426 [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
4427}
4428
4430{
4431 [NSGraphicsContext restoreGraphicsState];
4432 CGContextRestoreGState(cg);
4433}
4434
4436{
4437 Q_D(const QMacStyle);
4438 const AppearanceSync sync;
4439
4440 QMacCGContext cg(p);
4441 d->resolveCurrentNSView(opt->window);
4442
4443 switch (cc) {
4444 case CC_ScrollBar:
4445 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4446
4447 const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
4448 const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
4449 if (!drawTrack && !drawKnob)
4450 break;
4451
4452 const bool isHorizontal = sb->orientation == Qt::Horizontal;
4453
4455 QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
4456
4457 static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
4458 const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
4459
4461// if (!isTransient)
4462// d->stopAnimation(opt->styleObject);
4463 bool wasActive = false;
4464 CGFloat opacity = 0.0;
4465 CGFloat expandScale = 1.0;
4466 CGFloat expandOffset = 0.0;
4467 bool shouldExpand = false;
4468
4470 const int oldPos = styleObject->property("_q_stylepos").toInt();
4471 const int oldMin = styleObject->property("_q_stylemin").toInt();
4472 const int oldMax = styleObject->property("_q_stylemax").toInt();
4473 const QRect oldRect = styleObject->property("_q_stylerect").toRect();
4474 const QStyle::State oldState = static_cast<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
4475 const uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
4476
4477 // a scrollbar is transient when the scrollbar itself and
4478 // its sibling are both inactive (ie. not pressed/hovered/moved)
4479 const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
4480
4481 if (!transient ||
4482 oldPos != sb->sliderPosition ||
4483 oldMin != sb->minimum ||
4484 oldMax != sb->maximum ||
4485 oldRect != sb->rect ||
4486 oldState != sb->state ||
4487 oldActiveControls != sb->activeSubControls) {
4488
4489 // if the scrollbar is transient or its attributes, geometry or
4490 // state has changed, the opacity is reset back to 100% opaque
4491 opacity = 1.0;
4492
4493 styleObject->setProperty("_q_stylepos", sb->sliderPosition);
4494 styleObject->setProperty("_q_stylemin", sb->minimum);
4495 styleObject->setProperty("_q_stylemax", sb->maximum);
4496 styleObject->setProperty("_q_stylerect", sb->rect);
4497 styleObject->setProperty("_q_stylestate", static_cast<QStyle::State::Int>(sb->state));
4498 styleObject->setProperty("_q_stylecontrols", static_cast<uint>(sb->activeSubControls));
4499
4500// QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
4501// if (transient) {
4502// if (!anim) {
4503// anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
4504// d->startAnimation(anim);
4505// } else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
4506// // the scrollbar was already fading out while the
4507// // state changed -> restart the fade out animation
4508// anim->setCurrentTime(0);
4509// }
4510// } else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
4511// d->stopAnimation(styleObject);
4512// }
4513 }
4514
4515// QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
4516// if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
4517// // once a scrollbar was active (hovered/pressed), it retains
4518// // the active look even if it's no longer active while fading out
4519// if (oldActiveControls)
4520// anim->setActive(true);
4521
4522// wasActive = anim->wasActive();
4523// opacity = anim->currentValue();
4524// }
4525
4526 shouldExpand = isTransient && (opt->activeSubControls || wasActive);
4527 if (shouldExpand) {
4528// if (!anim && !oldActiveControls) {
4529// // Start expand animation only once and when entering
4530// anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
4531// d->startAnimation(anim);
4532// }
4533// if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
4534// expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
4535// expandOffset = 5.5 * (1.0 - anim->currentValue());
4536// } else {
4537// // Keep expanded state after the animation ends, and when fading out
4538// expandScale = maxExpandScale;
4539// expandOffset = 0.0;
4540// }
4541 }
4542 }
4543
4544 d->setupNSGraphicsContext(cg, NO /* flipped */);
4545
4546 const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
4547 const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
4548 NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
4549
4551 const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
4552 if (isTransient) {
4553 // macOS behavior: as soon as one color channel is >= 128,
4554 // the background is considered bright, scroller is dark.
4555 scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
4556 } else {
4557 scroller.knobStyle = NSScrollerKnobStyleDefault;
4558 }
4559
4560 scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
4561
4562 if (!setupScroller(scroller, sb))
4563 break;
4564
4565 if (isTransient) {
4566 CGContextBeginTransparencyLayerWithRect(cg, scroller.frame, nullptr);
4567 CGContextSetAlpha(cg, opacity);
4568 }
4569
4570 if (drawTrack) {
4571 // Draw the track when hovering. Expand by shifting the track rect.
4572 if (!isTransient || opt->activeSubControls || wasActive) {
4573 CGRect trackRect = scroller.bounds;
4574 if (isHorizontal)
4575 trackRect.origin.y += expandOffset;
4576 else
4577 trackRect.origin.x += expandOffset;
4578 [scroller drawKnobSlotInRect:trackRect highlight:NO];
4579 }
4580 }
4581
4582 if (drawKnob) {
4583 if (shouldExpand) {
4584 // -[NSScroller drawKnob] is not useful here because any scaling applied
4585 // will only be used to draw the hi-DPI artwork. And even if did scale,
4586 // the stretched knob would look wrong, actually. So we need to draw the
4587 // scroller manually when it's being hovered.
4588 const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
4589 const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
4590 // Cocoa can help get the exact knob length in the current orientation
4591 const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
4592 const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
4593 const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
4594 const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
4595 const CGFloat knobRadius = knobWidth / 2.0;
4596 CGRect knobRect;
4597 if (isHorizontal)
4598 knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
4599 else
4600 knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
4601 QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius, nullptr);
4602 CGContextAddPath(cg, knobPath);
4603 CGContextSetAlpha(cg, 0.5);
4604 CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
4605 CGContextSetFillColorWithColor(cg, knobColor);
4606 CGContextFillPath(cg);
4607 } else {
4608 [scroller drawKnob];
4609
4610 if (!isTransient && opt->state & State_Sunken) {
4611 // The knob should appear darker (going from 0.76 down to 0.49).
4612 // But no blending mode can help darken enough in a single pass,
4613 // so we resort to drawing the knob twice with a small help from
4614 // blending. This brings the gray level to a close enough 0.53.
4615 CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
4616 [scroller drawKnob];
4617 }
4618 }
4619 }
4620
4621 if (isTransient)
4622 CGContextEndTransparencyLayer(cg);
4623
4624 d->restoreNSGraphicsContext(cg);
4625 }
4626 break;
4627 case CC_Slider:
4628 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4629 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4631 const auto cs = d->effectiveAquaSizeConstrain(opt);
4632 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4633 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
4634 if (!setupSlider(slider, sl))
4635 break;
4636
4637 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4638 const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
4639 const bool drawKnob = sl->subControls & SC_SliderHandle;
4640 const bool drawBar = sl->subControls & SC_SliderGroove;
4641 const bool drawTicks = sl->subControls & SC_SliderTickmarks;
4642 const bool isPressed = sl->state & State_Sunken;
4643
4644 CGPoint pressPoint;
4645 if (isPressed && drawKnob) {
4646 const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
4647 pressPoint.x = CGRectGetMidX(knobRect);
4648 pressPoint.y = CGRectGetMidY(knobRect);
4649 [slider.cell startTrackingAt:pressPoint inView:slider];
4650 }
4651
4652 d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef, const CGRect &) {
4653 // Note that we don't support drawing the slider upside down. When this
4654 // is needed, simply set scale = -1 on the QML control / style item instead.
4655 NSSliderCell *cell = slider.cell;
4656
4657 if (drawBar) {
4658 const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
4659 // "flipped" will only make a difference when NSSliderCell is vertical. And then
4660 // flipped means fill the groove from bottom-to-top instead of top-to-bottom.
4661 // Bottom-to-top is QSlider's normal mode, which means that we always need to flip
4662 // in vertical mode. (In case NSSlider can also be flipped horizontally in the future,
4663 // we stay on the safe side, and only flip when in vertical mode).
4664 [cell drawBarInside:barRect flipped:!isHorizontal];
4665 }
4666
4667 if (drawBar && hasTicks && drawTicks) {
4668 if (!hasDoubleTicks) {
4669 [cell drawTickMarks];
4670 } else {
4671 if (sl->orientation == Qt::Horizontal) {
4672 slider.tickMarkPosition = NSTickMarkPositionAbove;
4673 [slider layoutSubtreeIfNeeded];
4674 [cell drawTickMarks];
4675 slider.tickMarkPosition = NSTickMarkPositionBelow;
4676 [slider layoutSubtreeIfNeeded];
4677 [cell drawTickMarks];
4678 } else {
4679 slider.tickMarkPosition = NSTickMarkPositionLeading;
4680 [slider layoutSubtreeIfNeeded];
4681 [cell drawTickMarks];
4682 slider.tickMarkPosition = NSTickMarkPositionTrailing;
4683 [slider layoutSubtreeIfNeeded];
4684 [cell drawTickMarks];
4685 }
4686 }
4687 }
4688
4689 if (drawKnob)
4690 [cell drawKnob];
4691 });
4692
4693 if (isPressed && drawKnob)
4694 [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
4695 }
4696 break;
4697 case CC_SpinBox:
4698 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
4699 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4700 const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
4702 static_cast<QStyleOption &>(frame) = *opt;
4703 frame.rect = lineEditRect;
4704 frame.state |= State_Sunken;
4705 frame.lineWidth = 1;
4706 frame.midLineWidth = 0;
4707 frame.features = QStyleOptionFrame::None;
4708 frame.frameShape = QStyleOptionFrame::Box;
4710 }
4711 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4712 const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
4714
4715 d->setupNSGraphicsContext(cg, NO);
4716
4717 const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
4719 NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
4720 cell.enabled = (sb->state & State_Enabled);
4721
4722 const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
4723
4724 const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
4725 const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
4726 const CGFloat x = CGRectGetMidX(newRect);
4727 const CGFloat y = upPressed ? -3 : 3; // Weird coordinate shift going on. Verified with Hopper
4728 const CGPoint pressPoint = CGPointMake(x, y);
4729 // Pretend we're pressing the mouse on the right button. Unfortunately, NSStepperCell has no
4730 // API to highlight a specific button. The highlighted property works only on the down button.
4731 if (upPressed || downPressed)
4732 [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
4733
4734 [cell drawWithFrame:newRect inView:d->backingStoreNSView];
4735
4736 if (upPressed || downPressed)
4737 [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
4738
4739 d->restoreNSGraphicsContext(cg);
4740 }
4741 }
4742 break;
4743 case CC_ComboBox:
4744 if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4745 const bool isEnabled = combo->state & State_Enabled;
4746 const bool isPressed = combo->state & State_Sunken;
4747
4748 const auto ct = cocoaControlType(combo);
4749 const auto cs = d->effectiveAquaSizeConstrain(combo);
4750 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4751 auto *cc = static_cast<NSControl *>(d->cocoaControl(cw));
4752 cc.enabled = isEnabled;
4753 QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
4755 // Non-editable QComboBox
4756 auto *pb = static_cast<NSPopUpButton *>(cc);
4757 // FIXME Old offsets. Try to move to adjustedControlFrame()
4758 if (cw.size == QStyleHelper::SizeSmall) {
4759 frameRect = frameRect.translated(0, 1);
4760 } else if (cw.size == QStyleHelper::SizeMini) {
4761 // Same 0.5 pt misalignment as AppKit and fit the focus ring
4762 frameRect = frameRect.translated(2, -0.5);
4763 }
4764 pb.frame = frameRect.toCGRect();
4765 [pb highlight:isPressed];
4766 d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
4768 [pb.cell drawBezelWithFrame:r inView:pb.superview];
4769 });
4770 } else if (cw.type == QMacStylePrivate::ComboBox) {
4771 // Editable QComboBox
4772 auto *cb = static_cast<NSComboBox *>(cc);
4773 const auto frameRect = cw.adjustedControlFrame(combo->rect);
4774 cb.frame = frameRect.toCGRect();
4775
4776 // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3
4777 if (NSButtonCell *cell = static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) {
4778 cell.highlighted = isPressed;
4779 } else {
4780 // TODO Render to pixmap and darken the button manually
4781 }
4782
4783 d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef, const CGRect &r) {
4784 // FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case
4786 [cb.cell drawWithFrame:r inView:cb];
4787 });
4788 }
4789 }
4790 break;
4791 case CC_TitleBar:
4792 if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
4793 const bool isActive = (titlebar->state & State_Active)
4794 && (titlebar->titleBarState & State_Active);
4795
4796 p->fillRect(opt->rect, Qt::transparent);
4797 p->setRenderHint(QPainter::Antialiasing);
4798 p->setClipRect(opt->rect, Qt::IntersectClip);
4799
4800 // FIXME A single drawPath() with 0-sized pen
4801 // doesn't look as good as this double fillPath().
4802 const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
4803 QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
4804 p->fillPath(outerFramePath, opt->palette.dark());
4805
4806 const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
4807 const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
4808 QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
4809 p->fillPath(innerFramePath, opt->palette.button());
4810
4811 if (titlebar->subControls & (SC_TitleBarCloseButton
4815 const bool isHovered = (titlebar->state & State_MouseOver);
4816 static const SubControl buttons[] = {
4818 };
4819 for (const auto sc : buttons) {
4820 const auto ct = d->windowButtonCocoaControl(sc);
4822 auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
4823 wb.enabled = (sc & titlebar->subControls) && isActive;
4824 [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
4825 Q_UNUSED(isHovered); // FIXME No public API for this
4826
4827 const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
4828 d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
4830 auto *wbCell = static_cast<NSButtonCell *>(wb.cell);
4831 [wbCell drawWithFrame:rect inView:wb];
4832 });
4833 }
4834 }
4835
4836 if (titlebar->subControls & SC_TitleBarLabel) {
4837 const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
4838 if (!titlebar->icon.isNull()) {
4839 const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
4840 const auto iconSize = QSize(iconExtent, iconExtent);
4841 const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
4842 // Only render the icon if it'll be fully visible
4843 if (iconPos < tr.right() - titleBarIconTitleSpacing)
4844 p->drawPixmap(iconPos, tr.y(),
4845 titlebar->icon.pixmap(iconSize,
4846 opt->window->devicePixelRatio(),
4847 QIcon::Normal));
4848 }
4849
4850 if (!titlebar->text.isEmpty())
4852 }
4853 }
4854 break;
4855 case CC_GroupBox:
4856 if (const QStyleOptionGroupBox *gb
4857 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4858
4860 const bool flat = groupBox.features & QStyleOptionFrame::Flat;
4861 if (!flat)
4862 groupBox.state |= QStyle::State_Mini; // Force mini-sized checkbox to go with small-sized label
4863 else
4864 groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame; // We don't like frames and ugly lines
4865
4866// const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
4867// const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
4868// if (didModifySubControls)
4869// groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
4871// if (didModifySubControls) {
4872// const QRect rect = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel);
4873// const bool rtl = groupBox.direction == Qt::RightToLeft;
4874// const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
4875// const QFont savedFont = p->font();
4876// if (!flat)
4877// p->setFont(d->smallSystemFont);
4878// proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
4879// if (!flat)
4880// p->setFont(savedFont);
4881// }
4882 }
4883 break;
4884 case CC_ToolButton:
4885 if (const QStyleOptionToolButton *tb
4886 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
4887#ifndef QT_NO_ACCESSIBILITY
4888 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
4889 if (tb->subControls & SC_ToolButtonMenu) {
4890 QStyleOption arrowOpt = *tb;
4891 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4892 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
4893 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
4895 } else if ((tb->features & QStyleOptionToolButton::HasMenu)
4896 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
4897 d->drawToolbarButtonArrow(tb, p);
4898 }
4899 if (tb->state & State_On) {
4900 NSView *view = reinterpret_cast<NSView *>(opt->window->winId());
4901 bool isKey = false;
4902 if (view)
4903 isKey = [view.window isKeyWindow];
4904
4907 path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
4908 p->setRenderHint(QPainter::Antialiasing);
4909 p->fillPath(path, brush);
4910 }
4912 } else
4913#endif // QT_NO_ACCESSIBILITY
4914 {
4915 auto bflags = tb->state;
4916 if (tb->subControls & SC_ToolButton)
4917 bflags |= State_Sunken;
4918 auto mflags = tb->state;
4919 if (tb->subControls & SC_ToolButtonMenu)
4920 mflags |= State_Sunken;
4921
4922 if (tb->subControls & SC_ToolButton) {
4923 if (bflags & (State_Sunken | State_On | State_Raised)) {
4924 const bool isEnabled = tb->state & State_Enabled;
4925 const bool isPressed = tb->state & State_Sunken;
4926 const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
4928 const auto cs = d->effectiveAquaSizeConstrain(opt);
4929 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4930 auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
4931 pb.bezelStyle = NSBezelStyleShadowlessSquare; // TODO Use NSTexturedRoundedBezelStyle in the future.
4932 pb.frame = opt->rect.toCGRect();
4933 pb.buttonType = NSButtonTypePushOnPushOff;
4934 pb.enabled = isEnabled;
4935 [pb highlight:isPressed];
4936 pb.state = isHighlighted && !isPressed ? NSControlStateValueOn : NSControlStateValueOff;
4937 const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
4938 d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
4940 [pb.cell drawBezelWithFrame:rect inView:pb];
4941 });
4942 }
4943 }
4944
4945 if (tb->subControls & SC_ToolButtonMenu) {
4946 const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
4947 QStyleOption arrowOpt = *tb;
4948 arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
4949 menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
4953 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
4954 d->drawToolbarButtonArrow(tb, p);
4955 }
4959 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
4961 }
4962 }
4963 break;
4964 case CC_Dial:
4965 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
4966 QStyleHelper::drawDial(dial, p);
4967 break;
4968 default:
4970 break;
4971 }
4972}
4973
4975{
4976 Q_D(const QMacStyle);
4977
4979
4980 switch (cc) {
4981 case CC_ComboBox:
4982 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
4983 sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
4984 if (!cmb->editable && sc != QStyle::SC_None)
4985 sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
4986 }
4987 break;
4988 case CC_Slider:
4989 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4990 if (!sl->rect.contains(pt))
4991 break;
4992
4993 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
4994 const bool isHorizontal = sl->orientation == Qt::Horizontal;
4996 const auto cs = d->effectiveAquaSizeConstrain(opt);
4997 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
4998 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
4999 if (!setupSlider(slider, sl))
5000 break;
5001
5002 NSSliderCell *cell = slider.cell;
5003 const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
5004 const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
5005 if (knobRect.contains(pt)) {
5006 sc = SC_SliderHandle;
5007 } else if (barRect.contains(pt)) {
5008 sc = SC_SliderGroove;
5009 } else if (hasTicks) {
5010 sc = SC_SliderTickmarks;
5011 }
5012 }
5013 break;
5014 case CC_ScrollBar:
5015 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5016 if (!sb->rect.contains(pt)) {
5017 sc = SC_None;
5018 break;
5019 }
5020
5021 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5023 const auto cs = d->effectiveAquaSizeConstrain(opt);
5024 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5025 auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
5026 if (!setupScroller(scroller, sb)) {
5027 sc = SC_None;
5028 break;
5029 }
5030
5031 // Since -[NSScroller testPart:] doesn't want to cooperate, we do it the
5032 // straightforward way. In any case, macOS doesn't return line-sized changes
5033 // with NSScroller since 10.7, according to the aforementioned method's doc.
5034 const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
5035 if (isHorizontal) {
5036 const bool isReverse = sb->direction == Qt::RightToLeft;
5037 if (pt.x() < knobRect.left())
5038 sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
5039 else if (pt.x() > knobRect.right())
5040 sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
5041 else
5042 sc = SC_ScrollBarSlider;
5043 } else {
5044 if (pt.y() < knobRect.top())
5046 else if (pt.y() > knobRect.bottom())
5048 else
5049 sc = SC_ScrollBarSlider;
5050 }
5051 }
5052 break;
5053 default:
5055 break;
5056 }
5057 return sc;
5058}
5059
5061{
5062 Q_D(const QMacStyle);
5063
5064 QRect ret;
5065
5066 switch (cc) {
5067 case CC_ScrollBar:
5068 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5069 const bool isHorizontal = sb->orientation == Qt::Horizontal;
5070 const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
5071
5072 NSScrollerPart part = NSScrollerNoPart;
5073 if (sc == SC_ScrollBarSlider) {
5074 part = NSScrollerKnob;
5075 } else if (sc == SC_ScrollBarGroove) {
5076 part = NSScrollerKnobSlot;
5077 } else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5078 if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
5079 || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
5080 part = NSScrollerDecrementPage;
5081 else
5082 part = NSScrollerIncrementPage;
5083 }
5084 // And nothing else since 10.7
5085
5086 if (part != NSScrollerNoPart) {
5088 const auto cs = d->effectiveAquaSizeConstrain(opt);
5089 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5090 auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
5091 if (setupScroller(scroller, sb))
5092 ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
5093 }
5094 }
5095 break;
5096 case CC_Slider:
5097 if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5098 const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
5099 const bool isHorizontal = sl->orientation == Qt::Horizontal;
5101 const auto cs = d->effectiveAquaSizeConstrain(opt);
5102 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5103 auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
5104 if (!setupSlider(slider, sl))
5105 break;
5106
5107 NSSliderCell *cell = slider.cell;
5108 if (sc == SC_SliderHandle) {
5109 ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
5110 } else if (sc == SC_SliderGroove) {
5111 ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
5112 } else if (hasTicks && sc == SC_SliderTickmarks) {
5113 const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
5114 if (isHorizontal)
5115 ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
5116 else
5117 ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
5118 }
5119
5120// if (sl->upsideDown) {
5121// if isHorizontal) {
5122// } else {
5123// }
5124// }
5125 }
5126 break;
5127 case CC_TitleBar:
5128 if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5129 // The title bar layout is as follows: close, min, zoom, icon, title
5130 // [ x _ + @ Window Title ]
5131 // Center the icon and title until it starts to overlap with the buttons.
5132 // The icon doesn't count towards SC_TitleBarLabel, but it's still rendered
5133 // next to the title text. See drawComplexControl().
5134 if (sc == SC_TitleBarLabel) {
5135 qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1; // FIXME Rounding error?
5136 qreal labelHeight = titlebar->fontMetrics.height();
5137
5138 const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
5139 qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
5140 if (!titlebar->icon.isNull()) {
5141 const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
5142 const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
5143 controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
5144 }
5145
5146 const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
5147 labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
5148 ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
5149 labelWidth, labelHeight);
5150 } else {
5151 const auto currentButton = d->windowButtonCocoaControl(sc);
5152 if (currentButton == QMacStylePrivate::NoControl)
5153 break;
5154
5155 QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
5156 QSizeF buttonSize;
5157 for (int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
5160 auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
5161 if (ct == currentButton)
5162 buttonSize = QSizeF::fromCGSize(wb.frame.size);
5163 else
5164 buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
5165 }
5166
5167 const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
5168 ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
5169 }
5170 }
5171 break;
5172 case CC_ComboBox:
5173 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5174 const auto ct = cocoaControlType(combo);
5175 const auto cs = d->effectiveAquaSizeConstrain(combo);
5176 const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
5177
5178 // Old widget path. Current not understood why it's needed:
5179 //const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
5180
5181 // New path:
5182 QRectF editRect;
5183 switch (cs) {
5185 editRect = combo->rect.adjusted(15, 7, -25, -9);
5186 break;
5188 if (combo->editable)
5189 editRect = combo->rect.adjusted(15, 6, -22, -9);
5190 else
5191 editRect = combo->rect.adjusted(15, 8, -22, -6);
5192 break;
5193 default:
5194 if (combo->editable)
5195 editRect = combo->rect.adjusted(15, 6, -20, -7);
5196 else
5197 editRect = combo->rect.adjusted(15, 5, -22, -6);
5198 break;
5199 }
5200
5201 switch (sc) {
5203 ret = editRect.toAlignedRect();
5204 break; }
5205 case SC_ComboBoxArrow:{
5206 ret = editRect.toAlignedRect();
5207 ret.setX(ret.x() + ret.width());
5208 ret.setWidth(combo->rect.right() - ret.right());
5209 break; }
5211 if (combo->editable) {
5212 const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
5213 const int comboTop = combo->rect.top();
5214 ret = QRect(qRound(inner.origin.x),
5215 comboTop,
5216 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5217 editRect.bottom() - comboTop + 2);
5218 } else {
5219 ret = QRect(combo->rect.x() + 4 - 11,
5220 combo->rect.y() + 1,
5221 editRect.width() + 10 + 11,
5222 1);
5223 }
5224 break; }
5225 default:
5226 break;
5227 }
5228 }
5229 break;
5230 case CC_GroupBox:
5231 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5232 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5233 const bool flat = groupBox->features & QStyleOptionFrame::Flat;
5234 bool hasNoText = !checkable && groupBox->text.isEmpty();
5235 switch (sc) {
5236 case SC_GroupBoxLabel:
5237 case SC_GroupBoxCheckBox: {
5238 // Cheat and use the smaller font if we need to
5239 const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5240 const bool fontIsSet = false;
5241// const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
5242// || !QApplication::desktopSettingsAware();
5243 const int margin = flat || hasNoText ? 0 : 9;
5244 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5245
5246 const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
5247 const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0, nullptr);
5248 const int tw = qCeil(s.width());
5249 const int h = qCeil(fm.height());
5250 ret.setHeight(h);
5251
5252 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5253 QSize(tw, h), ret);
5254 if (flat && checkable)
5255 labelRect.moveLeft(labelRect.left() + 4);
5256 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
5257 bool rtl = groupBox->direction == Qt::RightToLeft;
5258 if (sc == SC_GroupBoxLabel) {
5259 if (checkable) {
5260 int newSum = indicatorWidth + 1;
5261 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5262 labelRect.moveLeft(newLeft);
5263 if (flat)
5264 labelRect.moveTop(labelRect.top() + 3);
5265 else
5266 labelRect.moveTop(labelRect.top() + 4);
5267 } else if (flat) {
5268 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5269 labelRect.moveLeft(newLeft);
5270 labelRect.moveTop(labelRect.top() + 3);
5271 } else {
5272 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5273 labelRect.moveLeft(newLeft);
5274 labelRect.moveTop(labelRect.top() + 4);
5275 }
5276 ret = labelRect;
5277 }
5278
5279 if (sc == SC_GroupBoxCheckBox) {
5280 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
5281 int top = flat ? ret.top() + 1 : ret.top() + 5;
5282 ret.setRect(left, top,
5283 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
5284 }
5285 break;
5286 }
5288 case SC_GroupBoxFrame: {
5290 int yOffset = 3;
5291 if (!flat)
5292 yOffset = 5;
5293
5294 if (hasNoText)
5295 yOffset = -qCeil(QFontMetricsF(fm).height());
5296 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5297 if (sc == SC_GroupBoxContents) {
5298 if (flat)
5299 ret.adjust(3, -5, -3, -4); // guess too
5300 else
5301 ret.adjust(3, 3, -3, -4); // guess
5302 }
5303 }
5304 break;
5305 default:
5307 break;
5308 }
5309 }
5310 break;
5311 case CC_SpinBox:
5312 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5313 QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
5314 const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
5315 int spinner_w;
5316 int spinner_h;
5317 int adjust_y;
5318 int spinBoxSep;
5319 switch (aquaSize) {
5321 spinner_w = 14;
5322 spinner_h = 24;
5323 adjust_y = -1;
5324 spinBoxSep = 2;
5325 break;
5327 spinner_w = 12;
5328 spinner_h = 20;
5329 adjust_y = -1;
5330 spinBoxSep = 2;
5331 break;
5333 spinner_w = 10;
5334 spinner_h = 16;
5335 adjust_y = -1;
5336 spinBoxSep = 1;
5337 break;
5338 default:
5339 Q_UNREACHABLE();
5340 }
5341
5342 switch (sc) {
5343 case SC_SpinBoxUp:
5344 case SC_SpinBoxDown: {
5345 if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
5346 break;
5347
5348 const int y = fw;
5349 const int x = spin->rect.width() - spinner_w;
5350 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
5351
5353 NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
5354 const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
5355 ret = QRectF::fromCGRect(outRect).toRect();
5356
5357 switch (sc) {
5358 case SC_SpinBoxUp:
5359 ret.setHeight(ret.height() / 2);
5360 break;
5361 case SC_SpinBoxDown:
5362 ret.setY(ret.y() + ret.height() / 2);
5363 break;
5364 default:
5365 Q_ASSERT(0);
5366 break;
5367 }
5368 // The buttons are drawn with a top-margin (for some reason) into
5369 // the rect. So undo that margin here:
5370 ret.translate(0, adjust_y);
5371 ret = visualRect(spin->direction, spin->rect, ret);
5372 break;
5373 }
5375 ret = spin->rect.adjusted(fw, fw, -fw, -fw);
5376 if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
5377 ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
5378 ret = visualRect(spin->direction, spin->rect, ret);
5379 }
5380 break;
5381 default:
5382 ret = QCommonStyle::subControlRect(cc, spin, sc);
5383 break;
5384 }
5385 }
5386 break;
5387 case CC_ToolButton:
5389 if (sc == SC_ToolButtonMenu) {
5390#ifndef QT_NO_ACCESSIBILITY
5391 if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
5392 ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
5393#endif
5394 ret.adjust(-1, 0, 0, 0);
5395 }
5396 break;
5397 default:
5399 break;
5400 }
5401 return ret;
5402}
5403
5405{
5406 Q_D(const QMacStyle);
5407
5408 QSize sz(csz);
5409 bool useAquaGuideline = true;
5410
5411 switch (ct) {
5412 case CT_SpinBox:
5413 if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5414 if (vopt->subControls == SC_SpinBoxFrame) {
5415 const QSize minimumSize(20, 24);
5416 if (sz.width() < minimumSize.width())
5417 sz.setWidth(minimumSize.width());
5418 if (sz.height() < minimumSize.height())
5419 sz.setHeight(minimumSize.height());
5420 } else {
5421 const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
5422 const int upAndDownTogetherHeight = buttonSize.height() * 2;
5423 sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
5424 }
5425 }
5426 break;
5428 // the size between the pane and the "contentsRect" (+4,+4)
5429 // (the "contentsRect" is on the inside of the pane)
5430 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5461 // then add the size between the stackwidget and the "contentsRect"
5462 if (const QStyleOptionTabWidgetFrame *twf
5463 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
5464 QSize extra(0,0);
5465 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
5466 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5467
5468 const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
5469 if (tabDirection == QMacStylePrivate::North
5470 || tabDirection == QMacStylePrivate::South) {
5471 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5472 } else {
5473 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5474 }
5475 sz+= extra;
5476 }
5477 break;
5479 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
5480// const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
5481// || !QApplication::desktopSettingsAware();
5482 const bool differentFont = false;
5483 const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
5484 const bool verticalTabs = tabDirection == QMacStylePrivate::East
5485 || tabDirection == QMacStylePrivate::West;
5486 if (verticalTabs)
5487 sz = sz.transposed();
5488
5489 int defaultTabHeight;
5490 const auto cs = d->effectiveAquaSizeConstrain(opt);
5491 switch (cs) {
5493 if (tab->documentMode)
5494 defaultTabHeight = 24;
5495 else
5496 defaultTabHeight = 21;
5497 break;
5499 defaultTabHeight = 18;
5500 break;
5502 defaultTabHeight = 16;
5503 break;
5504 default:
5505 break;
5506 }
5507
5508 const bool widthSet = !differentFont && tab->icon.isNull();
5509 if (widthSet) {
5510 const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
5511 sz.rwidth() = textSize.width();
5512 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5513 } else {
5514 sz.rheight() = qMax(defaultTabHeight, sz.height());
5515 }
5516 sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
5517
5518 if (verticalTabs)
5519 sz = sz.transposed();
5520
5521 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5522 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5523
5524 int widgetWidth = 0;
5525 int widgetHeight = 0;
5526 int padding = 0;
5527 if (tab->leftButtonSize.isValid()) {
5528 padding += 8;
5529 widgetWidth += tab->leftButtonSize.width();
5530 widgetHeight += tab->leftButtonSize.height();
5531 }
5532 if (tab->rightButtonSize.isValid()) {
5533 padding += 8;
5534 widgetWidth += tab->rightButtonSize.width();
5535 widgetHeight += tab->rightButtonSize.height();
5536 }
5537
5538 if (verticalTabs) {
5539 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5540 sz.setHeight(sz.height() + widgetHeight + padding);
5541 } else {
5542 if (widthSet)
5543 sz.setWidth(sz.width() + widgetWidth + padding);
5544 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5545 }
5546 }
5547 break;
5548 case CT_LineEdit:
5549 if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
5550 // Minimum size (with padding: 18x24)
5551 if (sz.width() < 10)
5552 sz.setWidth(10);
5553 if (sz.height() < 20)
5554 sz.setHeight(20);
5555
5556 // From using pixelTool with XCode/NSTextTextField
5557 int leftPadding = 4;
5558 int rightPadding = 4;
5559 int topPadding = 4;
5560 int bottomPadding = 0;
5561
5562 if (opt->state & QStyle::State_Small) {
5563 topPadding = 3;
5564 } else if (opt->state & QStyle::State_Mini) {
5565 topPadding = 2;
5566 }
5567
5568 sz.rwidth() += leftPadding + rightPadding;
5569 sz.rheight() += topPadding + bottomPadding;
5570 }
5571 break;
5572 case QStyle::CT_PushButton: {
5573 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt))
5575 return QCommonStyle::sizeFromContents(ct, opt, sz);
5576
5577 // By default, we fit the contents inside a normal rounded push button.
5578 // Do this by add enough space around the contents so that rounded
5579 // borders (including highlighting when active) will show.
5580 // TODO Use QFocusFrame and get rid of these horrors.
5581 QSize macsz;
5582 const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
5583 // FIXME See comment in CT_PushButton case in qt_aqua_get_known_size().
5584 if (macsz.width() != -1)
5585 sz.setWidth(macsz.width());
5586 else
5588 // All values as measured from HIThemeGetButtonBackgroundBounds()
5589 if (controlSize != QStyleHelper::SizeMini)
5590 sz.rwidth() += 12; // We like 12 over here.
5591 if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
5592 sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
5593 else if (controlSize == QStyleHelper::SizeMini)
5594 sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this.
5595 else
5596 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5597 break;
5598 }
5600 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5601 int maxpmw = mi->maxIconWidth;
5602 int w = sz.width();
5603 int h = sz.height();
5604
5605//#if QT_CONFIG(combobox)
5606// const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
5607//#endif
5608
5609 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5610 w = 10;
5612 } else {
5613 h = mi->fontMetrics.height() + 2;
5614 if (!mi->icon.isNull()) {
5615//#if QT_CONFIG(combobox)
5616// if (comboBox) {
5617// const QSize &iconSize = comboBox->iconSize();
5618// h = qMax(h, iconSize.height() + 4);
5619// maxpmw = qMax(maxpmw, iconSize.width());
5620// } else
5621//#endif
5622 {
5623 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5624 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5625 }
5626 }
5627 }
5628 if (mi->text.contains(QLatin1Char('\t')))
5629 w += 12;
5630 else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5631 w += 35; // Not quite exactly as it seems to depend on other factors
5632 if (maxpmw)
5633 w += maxpmw + 6;
5634 // add space for a check. All items have place for a check too.
5635 w += 20;
5636// if (comboBox && comboBox->isVisible()) {
5637// QStyleOptionComboBox cmb;
5638// cmb.initFrom(comboBox);
5639// cmb.editable = false;
5640// cmb.subControls = QStyle::SC_ComboBoxEditField;
5641// cmb.activeSubControls = QStyle::SC_None;
5642// w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
5643// QStyle::SC_ComboBoxEditField,
5644// comboBox).width());
5645// } else {
5646// w += 12;
5647 sz = QSize(w, h);
5648 } break;
5649 case CT_MenuBarItem:
5650 if (!sz.isEmpty())
5651 sz += QSize(12, 4); // Constants from QWindowsStyle
5652 break;
5653 case CT_ToolButton:
5654 sz.rwidth() += 10;
5655 sz.rheight() += 10;
5656 if (const auto *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt))
5657 if (tb->features & QStyleOptionToolButton::Menu)
5659 return sz;
5660 case CT_ComboBox:
5661 if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5662 const int controlSize = getControlSize(opt);
5663
5664 // Set a sensible minimum width
5665 if (sz.width() < 10)
5666 sz.setWidth(10);
5667
5668 if (!cb->editable) {
5669 // Same as CT_PushButton, because we have to fit the focus
5670 // ring and a non-editable combo box is a NSPopUpButton.
5672
5673 if (controlSize == QStyleHelper::SizeLarge) {
5674 sz.rwidth() += 30;
5675 } else if (controlSize == QStyleHelper::SizeSmall) {
5676 sz.rwidth() += 26;
5677 } else {
5678 sz.rwidth() += 21;
5679 }
5680 } else {
5681 sz.rwidth() += 50; // FIXME Double check this
5682 }
5683
5684 // This should be enough to fit the focus ring
5685 if (controlSize == QStyleHelper::SizeMini)
5686 sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this for CT_PushButton.
5687 else
5688 sz.setHeight(pushButtonDefaultHeight[controlSize]);
5689
5690 return sz;
5691 }
5692 break;
5693 case CT_Menu: {
5694 if (proxy() == this) {
5695 sz = csz;
5696 } else {
5697 QStyleHintReturnMask menuMask;
5698 QStyleOption myOption = *opt;
5699 myOption.rect.setSize(sz);
5700 if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
5701 sz = menuMask.region.boundingRect().size();
5702 }
5703 break; }
5704 case CT_HeaderSection:{
5705 const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
5706 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5707 if (header->text.contains(QLatin1Char('\n')))
5708 useAquaGuideline = false;
5709 break; }
5710 case CT_ScrollBar :
5711 // Make sure that the scroll bar is large enough to display the thumb indicator.
5712 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5713 const int minimumWidth = 24;
5714 const int absoluteHeight = 14;
5715 if (slider->orientation == Qt::Horizontal) {
5716 sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
5717 sz.setHeight(absoluteHeight);
5718 } else {
5719 sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
5720 sz.setWidth(absoluteHeight);
5721 }
5722 }
5723 break;
5724 case CT_ItemViewItem:
5725 if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
5726 sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
5727 sz.setHeight(sz.height() + 2);
5728 }
5729 break;
5730 default:
5731 sz = QCommonStyle::sizeFromContents(ct, opt, csz);
5732 }
5733
5734 if (useAquaGuideline && ct != CT_PushButton) {
5735 // TODO Probably going away at some point
5736 QSize macsz;
5737 if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
5738 if (macsz.width() != -1)
5739 sz.setWidth(macsz.width());
5740 if (macsz.height() != -1)
5741 sz.setHeight(macsz.height());
5742 }
5743 }
5744
5745 // The sizes that Carbon and the guidelines gives us excludes the focus frame.
5746 // We compensate for this by adding some extra space here to make room for the frame when drawing:
5747 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
5748 if (combo->editable) {
5749 const auto widgetSize = d->aquaSizeConstrain(opt);
5752 cw.size = widgetSize;
5753 const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
5754 sz.rwidth() -= qRound(diffRect.size.width);
5755 sz.rheight() -= qRound(diffRect.size.height);
5756 }
5757 }
5758 return sz;
5759}
5760
5761QFont QMacStyle::font(QStyle::ControlElement element, const QStyle::State state) const
5762{
5763 QFont font = QCommonStyle::font(element, state);
5764
5765 if (state & QStyle::State_Small) {
5766 font.setPixelSize(11);
5767 } else if (state & QStyle::State_Mini) {
5768 font.setPixelSize(9);
5769 }
5770
5771 return font;
5772}
5773
5774QMargins QMacStyle::ninePatchMargins(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const
5775{
5776 QMargins margins;
5777
5778 switch (cc) {
5779 case CC_ComboBox: {
5781 margins = QMargins(10, 0, arrow.width() + 1, -1);
5782 break; }
5783 default:
5784 margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
5785 break;
5786 }
5787
5788 return margins;
5789}
5790
5791void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
5792 bool enabled, const QString &text, QPalette::ColorRole textRole) const
5793{
5796 QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
5797}
5798
5800{
5801 switch (standardIcon) {
5802 default:
5806 QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
5808 QPixmap pix2(pixmap.height(), pixmap.width());
5809 pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
5810 pix2.fill(Qt::transparent);
5811 QPainter p(&pix2);
5812 p.translate(pix2.width(), 0);
5813 p.rotate(90);
5814 p.drawPixmap(0, 0, pixmap);
5815 return pix2;
5816 }
5817 return pixmap;
5818 }
5819 }
5820}
5821
5822} // QQC2_NAMESPACE
5823
bool isActive
\inmodule QtGui
Definition qbitmap.h:16
static QBitmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Returns a copy of the given image converted to a bitmap using the specified image conversion flags.
Definition qbitmap.cpp:170
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
void setAlphaF(float alpha)
Sets the alpha of this color to alpha.
Definition qcolor.cpp:1511
QColor darker(int f=200) const noexcept
Definition qcolor.cpp:2857
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
QRgb rgba() const noexcept
Returns the RGB value of the color, including its alpha.
Definition qcolor.cpp:1376
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
void setHsvF(float h, float s, float v, float a=1.0)
Sets a HSV color value; h is the hue, s is the saturation, v is the value and a is the alpha componen...
Definition qcolor.cpp:1071
The 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
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
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.
\inmodule QtCore
Definition qcoreevent.h:45
@ StyleChange
Definition qcoreevent.h:136
@ MouseButtonPress
Definition qcoreevent.h:60
@ MouseButtonRelease
Definition qcoreevent.h:61
\reentrant
Definition qfontinfo.h:16
qreal pointSizeF() const
Returns the point size of the matched window system font.
Definition qfont.cpp:3131
\reentrant \inmodule QtGui
\reentrant \inmodule QtGui
int height() const
Returns the height of the font.
QRect boundingRect(QChar) const
Returns the rectangle that is covered by ink if character ch were to be drawn at the origin of the co...
QSize size(int flags, const QString &str, int tabstops=0, int *tabarray=nullptr) const
Returns the size in pixels of text.
static QFontPrivate * get(const QFont &font)
Definition qfont_p.h:193
\reentrant
Definition qfont.h:22
void setPixelSize(int)
Sets the font size to pixelSize pixels, with a maxiumum size of an unsigned 16-bit integer.
Definition qfont.cpp:1049
void setPointSizeF(qreal)
Sets the point size to pointSize.
Definition qfont.cpp:1010
int midLineWidth
the width of the mid-line
Definition qframe.h:23
int lineWidth
the line width
Definition qframe.h:22
Shape frameShape
the frame shape value from the frame style
Definition qframe.h:20
static QPlatformTheme * platformTheme()
static QPlatformNativeInterface * platformNativeInterface()
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:1019
Mode
This enum type describes the mode for which a pixmap is intended to be used.
Definition qicon.h:22
@ Disabled
Definition qicon.h:22
@ Normal
Definition qicon.h:22
@ Active
Definition qicon.h:22
State
This enum describes the state for which a pixmap is intended to be used.
Definition qicon.h:23
@ Off
Definition qicon.h:23
@ On
Definition qicon.h:23
QSize actualSize(const QSize &size, Mode mode=Normal, State state=Off) const
Returns the actual size of the icon for the requested size, mode, and state.
Definition qicon.cpp:926
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition qicon.cpp:834
\inmodule QtGui
Definition qimage.h:37
int height() const
Returns the height of the image.
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:125
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
\inmodule QtGui
Definition qbrush.h:394
void drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, __attribute__((noescape)) DrawRectBlock drawRectBlock=nil) const
static const int PushButtonRightOffset
QHash< CocoaControl, NSCell * > cocoaCells
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
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
\inmodule QtCore
Definition qmargins.h:270
\inmodule QtCore
Definition qmargins.h:24
\inmodule QtCore
Definition qobject.h:103
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
static constexpr QOperatingSystemVersionBase MacOSMojave
\variable QOperatingSystemVersion::MacOSMojave
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ Antialiasing
Definition qpainter.h:52
@ CompositionMode_Source
Definition qpainter.h:101
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
const QBrush & button() const
Returns the button brush of the current color group.
Definition qpalette.h:84
const QBrush & text() const
Returns the text foreground brush of the current color group.
Definition qpalette.h:88
const QBrush & dark() const
Returns the dark brush of the current color group.
Definition qpalette.h:86
const QBrush & brush(ColorGroup cg, ColorRole cr) const
Returns the brush in the specified color group, used for the given color role.
Definition qpalette.cpp:748
void setCurrentColorGroup(ColorGroup cg)
Set the palette's current color group to cg.
Definition qpalette.h:65
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition qpalette.h:67
@ Disabled
Definition qpalette.h:49
void setColor(ColorGroup cg, ColorRole cr, const QColor &color)
Sets the color in the specified color group, used for the given color role, to the specified solid co...
Definition qpalette.h:146
const QBrush & window() const
Returns the window (general background) brush of the current color group.
Definition qpalette.h:93
@ HighlightedText
Definition qpalette.h:53
@ ToolTipBase
Definition qpalette.h:57
@ ButtonText
Definition qpalette.h:52
@ WindowText
Definition qpalette.h:51
@ Highlight
Definition qpalette.h:53
const QBrush & buttonText() const
Returns the button text foreground brush of the current color group.
Definition qpalette.h:96
const QBrush & highlightedText() const
Returns the highlighted text brush of the current color group.
Definition qpalette.h:99
\inmodule QtGui
Definition qpen.h:28
void setWidth(int width)
Sets the pen width to the given width in pixels with integer precision.
Definition qpen.cpp:592
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QImage toImage() const
Converts the pixmap to a QImage.
Definition qpixmap.cpp:408
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:468
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
Definition qpixmap.cpp:604
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:850
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
Definition qpixmap.cpp:1437
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
int styleHint(StyleHint sh, const QStyleOption *opt=0, QStyleHintReturn *shret=0) const override
int pixelMetric(PixelMetric pm, const QStyleOption *opt=0) const override
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr QRectF translated(qreal dx, qreal dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:762
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:859
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:499
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QPoint bottomLeft() const noexcept
Returns the position of the rectangle's bottom-left corner.
Definition qrect.h:230
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr bool isValid() const noexcept
Returns true if the rectangle is valid, otherwise returns false.
Definition qrect.h:170
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:182
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr void setSize(const QSize &s) noexcept
Sets the size of the rectangle to the given size.
Definition qrect.h:387
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr QPoint topRight() const noexcept
Returns the position of the rectangle's top-right corner.
Definition qrect.h:227
constexpr void setLeft(int pos) noexcept
Sets the left edge of the rectangle to the given x coordinate.
Definition qrect.h:191
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr void setRect(int x, int y, int w, int h) noexcept
Sets the coordinates of the rectangle's top-left corner to ({x}, {y}), and its size to the given widt...
Definition qrect.h:346
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr QRect transposed() const noexcept
Definition qrect.h:267
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
Definition qrect.h:245
constexpr QPoint bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
Definition qrect.h:224
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
constexpr void moveTo(int x, int t) noexcept
Moves the rectangle, leaving the top-left corner at the given position (x, y).
Definition qrect.h:270
constexpr QPoint center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:233
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:179
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr QSize expandedTo(const QSize &) const noexcept
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition qsize.h:192
constexpr void setWidth(int w) noexcept
Sets the width to the given width.
Definition qsize.h:136
constexpr QSize transposed() const noexcept
Definition qsize.h:142
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:139
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
The QStyleHintReturnMask class provides style hints that return a QRegion.
\variable QStyleOptionGraphicsItem::exposedRect
\variable QStyleOptionHeaderV2::textElideMode
ButtonFeatures features
\variable QStyleOptionToolButton::features
\variable QStyleOptionMenuItem::menuItemType
\variable QStyleOptionComplex::subControls
\variable QStyleOptionFocusRect::backgroundColor
\variable QStyleOptionFrame::features
The QStyleOptionHeader class is used to describe the parameters for drawing a header.
\variable QStyleOptionProgressBar::minimum
\variable QStyleOptionButton::features
\variable QStyleOptionDockWidget::title
The QStyleOption class stores the parameters used by QStyle functions.
QFontMetrics fontMetrics
QStyle::State state
QPalette palette
QObject * styleObject
Qt::LayoutDirection direction
@ State_Window
Definition qstyle.h:84
@ State_MouseOver
Definition qstyle.h:80
@ State_Sunken
Definition qstyle.h:69
@ State_HasFocus
Definition qstyle.h:75
@ State_Active
Definition qstyle.h:83
@ State_Children
Definition qstyle.h:86
@ State_Mini
Definition qstyle.h:96
@ State_Small
Definition qstyle.h:95
@ State_NoChange
Definition qstyle.h:71
@ State_Enabled
Definition qstyle.h:67
@ State_DownArrow
Definition qstyle.h:73
@ State_ReadOnly
Definition qstyle.h:94
@ State_Horizontal
Definition qstyle.h:74
@ State_On
Definition qstyle.h:72
@ State_Raised
Definition qstyle.h:68
@ State_Selected
Definition qstyle.h:82
ContentsType
This enum describes the available contents types.
Definition qstyle.h:546
@ CT_Menu
Definition qstyle.h:557
@ CT_ItemViewItem
Definition qstyle.h:569
@ CT_SpinBox
Definition qstyle.h:562
@ CT_ToolButton
Definition qstyle.h:550
@ CT_MenuBar
Definition qstyle.h:556
@ CT_PushButton
Definition qstyle.h:547
@ CT_MenuItem
Definition qstyle.h:554
@ CT_CustomBase
Definition qstyle.h:571
@ CT_MenuBarItem
Definition qstyle.h:555
@ CT_SizeGrip
Definition qstyle.h:563
@ CT_TabBarTab
Definition qstyle.h:558
@ CT_LineEdit
Definition qstyle.h:561
@ CT_ScrollBar
Definition qstyle.h:560
@ CT_HeaderSection
Definition qstyle.h:566
@ CT_TabWidget
Definition qstyle.h:564
@ CT_Slider
Definition qstyle.h:559
@ CT_ComboBox
Definition qstyle.h:551
virtual QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget=nullptr) const =0
Returns the rectangle containing the specified subControl of the given complex control (with the styl...
virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option=nullptr, const QWidget *widget=nullptr) const =0
StyleHint
This enum describes the available style hints.
Definition qstyle.h:584
@ SH_TitleBar_ShowToolTipsOnButtons
Definition qstyle.h:699
@ SH_TabBar_ElideMode
Definition qstyle.h:652
@ SH_ComboBox_ListMouseTracking
Definition qstyle.h:604
@ SH_TabBar_CloseButtonPosition
Definition qstyle.h:677
@ SH_Slider_PageSetButtons
Definition qstyle.h:650
@ SH_TitleBar_NoBorder
Definition qstyle.h:611
@ SH_Menu_Scrollable
Definition qstyle.h:615
@ SH_ScrollView_FrameOnlyAroundContents
Definition qstyle.h:602
@ SH_MainWindow_SpaceBelowMenuBar
Definition qstyle.h:597
@ SH_Menu_Mask
Definition qstyle.h:665
@ SH_ComboBox_Popup
Definition qstyle.h:610
@ SH_EtchDisabledText
Definition qstyle.h:585
@ SH_TabBar_Alignment
Definition qstyle.h:590
@ SH_ItemView_PaintAlternatingRowColorsForEmptyArea
Definition qstyle.h:669
@ SH_ItemView_ChangeHighlightOnFocus
Definition qstyle.h:607
@ SH_ItemView_MovementWithoutUpdatingSelection
Definition qstyle.h:659
@ SH_MenuBar_AltKeyNavigation
Definition qstyle.h:603
@ SH_Menu_SubMenuUniDirection
Definition qstyle.h:692
@ SH_ScrollBar_RollBetweenButtons
Definition qstyle.h:648
@ SH_Menu_MouseTracking
Definition qstyle.h:605
@ SH_ScrollBar_Transient
Definition qstyle.h:681
@ SH_Table_GridLineColor
Definition qstyle.h:619
@ SH_Menu_FlashTriggeredItem
Definition qstyle.h:666
@ SH_Menu_SubMenuPopupDelay
Definition qstyle.h:601
@ SH_ItemView_ArrowKeysNavigateIntoChildren
Definition qstyle.h:664
@ SH_Slider_AbsoluteSetButtons
Definition qstyle.h:649
@ SH_Menu_SubMenuResetWhenReenteringParent
Definition qstyle.h:696
@ SH_Header_ArrowAlignment
Definition qstyle.h:591
@ SH_ToolBox_SelectedPageTitleBold
Definition qstyle.h:622
@ SH_TabBar_PreferNoArrows
Definition qstyle.h:623
@ SH_Menu_KeyboardSearch
Definition qstyle.h:651
@ SH_Button_FocusPolicy
Definition qstyle.h:634
@ SH_Menu_SubMenuSloppySelectOtherActions
Definition qstyle.h:694
@ SH_Menu_SelectionWrap
Definition qstyle.h:658
@ SH_Widget_ShareActivation
Definition qstyle.h:608
@ SH_ComboBox_LayoutDirection
Definition qstyle.h:643
@ SH_ComboBox_AllowWheelScrolling
Definition qstyle.h:701
@ SH_Menu_AllowActiveAndDisabled
Definition qstyle.h:599
@ SH_TabBar_SelectMouseType
Definition qstyle.h:589
@ SH_Menu_FillScreenWithScroll
Definition qstyle.h:630
@ SH_FontDialog_SelectAssociatedText
Definition qstyle.h:598
@ SH_ToolTipLabel_Opacity
Definition qstyle.h:631
@ SH_ScrollBar_LeftClickAbsolutePosition
Definition qstyle.h:624
@ SH_DialogButtonBox_ButtonsHaveIcons
Definition qstyle.h:656
@ SH_MenuBar_MouseTracking
Definition qstyle.h:606
@ SH_UnderlineShortcut
Definition qstyle.h:626
@ SH_ScrollBar_ContextMenu
Definition qstyle.h:647
@ SH_FormLayoutFormAlignment
Definition qstyle.h:674
@ SH_Menu_SubMenuDontStartSloppyOnLeave
Definition qstyle.h:697
@ SH_MessageBox_CenterButtons
Definition qstyle.h:657
@ SH_TitleBar_ModifyNotification
Definition qstyle.h:633
@ SH_Slider_StopMouseOverSlider
Definition qstyle.h:612
@ SH_Slider_SnapToValue
Definition qstyle.h:592
@ SH_SpinBox_ButtonsInsideFrame
Definition qstyle.h:702
@ SH_Menu_FadeOutOnHide
Definition qstyle.h:667
@ SH_GroupBox_TextLabelVerticalAlignment
Definition qstyle.h:616
@ SH_PrintDialog_RightAlignButtons
Definition qstyle.h:596
@ SH_BlinkCursorWhenTextSelected
Definition qstyle.h:613
@ SH_TitleBar_AutoRaise
Definition qstyle.h:636
@ SH_ListViewExpand_SelectMouseType
Definition qstyle.h:625
@ SH_ItemView_EllipsisLocation
Definition qstyle.h:644
@ SH_MessageBox_TextInteractionFlags
Definition qstyle.h:655
@ SH_WindowFrame_Mask
Definition qstyle.h:640
@ SH_RichText_FullWidthSelection
Definition qstyle.h:614
@ SH_RubberBand_Mask
Definition qstyle.h:639
@ SH_FormLayoutLabelAlignment
Definition qstyle.h:675
@ SH_ItemView_ShowDecorationSelected
Definition qstyle.h:645
@ SH_DockWidget_ButtonsHaveFrame
Definition qstyle.h:678
@ SH_Menu_SpaceActivatesItem
Definition qstyle.h:600
@ SH_FocusFrame_AboveWidget
Definition qstyle.h:661
@ SH_FocusFrame_Mask
Definition qstyle.h:638
@ SH_Workspace_FillSpaceOnMaximize
Definition qstyle.h:609
virtual 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:716
@ SP_TitleBarCloseButton
Definition qstyle.h:720
@ SP_TitleBarNormalButton
Definition qstyle.h:721
@ SP_MessageBoxQuestion
Definition qstyle.h:729
@ SP_MessageBoxCritical
Definition qstyle.h:728
@ SP_MessageBoxInformation
Definition qstyle.h:726
@ SP_ToolBarVerticalExtensionButton
Definition qstyle.h:745
@ SP_ToolBarHorizontalExtensionButton
Definition qstyle.h:744
@ SP_MessageBoxWarning
Definition qstyle.h:727
ControlElement
This enum represents a control element.
Definition qstyle.h:170
@ CE_ProgressBarLabel
Definition qstyle.h:188
@ CE_MenuItem
Definition qstyle.h:190
@ CE_MenuEmptyArea
Definition qstyle.h:195
@ CE_DockWidgetTitle
Definition qstyle.h:210
@ CE_MenuVMargin
Definition qstyle.h:192
@ CE_TabBarTabLabel
Definition qstyle.h:183
@ CE_Splitter
Definition qstyle.h:208
@ CE_ToolButtonLabel
Definition qstyle.h:200
@ CE_RubberBand
Definition qstyle.h:209
@ CE_HeaderSection
Definition qstyle.h:203
@ CE_TabBarTabShape
Definition qstyle.h:182
@ CE_ProgressBarContents
Definition qstyle.h:187
@ CE_ToolBar
Definition qstyle.h:223
@ CE_MenuBarItem
Definition qstyle.h:197
@ CE_FocusFrame
Definition qstyle.h:220
@ CE_MenuHMargin
Definition qstyle.h:193
@ CE_ToolBoxTabShape
Definition qstyle.h:224
@ CE_HeaderLabel
Definition qstyle.h:204
@ CE_MenuTearoff
Definition qstyle.h:194
@ CE_PushButtonBevel
Definition qstyle.h:172
@ CE_ComboBoxLabel
Definition qstyle.h:221
@ CE_MenuBarEmptyArea
Definition qstyle.h:198
@ CE_SizeGrip
Definition qstyle.h:207
@ CE_ProgressBarGroove
Definition qstyle.h:186
@ CE_MenuScroller
Definition qstyle.h:191
@ CE_PushButtonLabel
Definition qstyle.h:173
static QRect alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
Returns a new rectangle of the specified size that is aligned to the given rectangle according to the...
Definition qstyle.cpp:2173
virtual QRect subElementRect(SubElement subElement, const QStyleOption *option, const QWidget *widget=nullptr) const =0
Returns the sub-area for the given element as described in the provided style option.
static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
Returns the given logicalRectangle converted to screen coordinates based on the specified direction.
Definition qstyle.cpp:2143
PixelMetric
This enum describes the various available pixel metrics.
Definition qstyle.h:413
@ PM_MenuVMargin
Definition qstyle.h:452
@ PM_LayoutBottomMargin
Definition qstyle.h:515
@ PM_MenuBarHMargin
Definition qstyle.h:460
@ PM_FocusFrameVMargin
Definition qstyle.h:498
@ PM_MenuPanelWidth
Definition qstyle.h:453
@ PM_ScrollBarExtent
Definition qstyle.h:426
@ PM_DockWidgetFrameWidth
Definition qstyle.h:437
@ PM_TitleBarHeight
Definition qstyle.h:448
@ PM_SizeGripSize
Definition qstyle.h:504
@ PM_DockWidgetTitleMargin
Definition qstyle.h:505
@ PM_ExclusiveIndicatorHeight
Definition qstyle.h:465
@ PM_TabBarTabHSpace
Definition qstyle.h:440
@ PM_LayoutLeftMargin
Definition qstyle.h:512
@ PM_DefaultFrameWidth
Definition qstyle.h:420
@ PM_MaximumDragDistance
Definition qstyle.h:424
@ PM_ToolBarHandleExtent
Definition qstyle.h:484
@ PM_ButtonShiftHorizontal
Definition qstyle.h:417
@ PM_MdiSubWindowFrameWidth
Definition qstyle.h:473
@ PM_ToolBarItemSpacing
Definition qstyle.h:485
@ PM_DockWidgetTitleBarButtonMargin
Definition qstyle.h:509
@ PM_IndicatorWidth
Definition qstyle.h:462
@ PM_TabBarBaseOverlap
Definition qstyle.h:443
@ PM_ScrollView_ScrollBarOverlap
Definition qstyle.h:526
@ PM_DockWidgetSeparatorExtent
Definition qstyle.h:435
@ PM_TabCloseIndicatorWidth
Definition qstyle.h:522
@ PM_CheckBoxLabelSpacing
Definition qstyle.h:502
@ PM_LayoutVerticalSpacing
Definition qstyle.h:517
@ PM_TabBarTabShiftVertical
Definition qstyle.h:480
@ PM_LayoutHorizontalSpacing
Definition qstyle.h:516
@ PM_TabBarBaseHeight
Definition qstyle.h:442
@ PM_ButtonShiftVertical
Definition qstyle.h:418
@ PM_IndicatorHeight
Definition qstyle.h:463
@ PM_ButtonDefaultIndicator
Definition qstyle.h:415
@ PM_LayoutTopMargin
Definition qstyle.h:513
@ PM_SliderControlThickness
Definition qstyle.h:430
@ PM_MenuBarPanelWidth
Definition qstyle.h:457
@ PM_ToolBarItemMargin
Definition qstyle.h:486
@ PM_ToolBarIconSize
Definition qstyle.h:492
@ PM_MenuButtonIndicator
Definition qstyle.h:416
@ PM_MenuDesktopFrameWidth
Definition qstyle.h:455
@ PM_HeaderMargin
Definition qstyle.h:476
@ PM_TabBarTabVSpace
Definition qstyle.h:441
@ PM_MenuHMargin
Definition qstyle.h:451
@ PM_SmallIconSize
Definition qstyle.h:495
@ PM_LargeIconSize
Definition qstyle.h:496
@ PM_IconViewIconSize
Definition qstyle.h:494
@ PM_ToolBarExtensionExtent
Definition qstyle.h:488
@ PM_TabCloseIndicatorHeight
Definition qstyle.h:523
@ PM_SliderLength
Definition qstyle.h:431
@ PM_SplitterWidth
Definition qstyle.h:447
@ PM_RadioButtonLabelSpacing
Definition qstyle.h:511
@ PM_TabBarTabShiftHorizontal
Definition qstyle.h:479
@ PM_SpinBoxFrameWidth
Definition qstyle.h:421
@ PM_LayoutRightMargin
Definition qstyle.h:514
@ PM_FocusFrameHMargin
Definition qstyle.h:499
@ PM_ExclusiveIndicatorWidth
Definition qstyle.h:464
@ PM_ToolTipLabelFrameWidth
Definition qstyle.h:501
@ PM_MenuScrollerHeight
Definition qstyle.h:450
@ PM_TabBarTabOverlap
Definition qstyle.h:439
@ PM_ScrollBarSliderMin
Definition qstyle.h:427
@ PM_MenuBarVMargin
Definition qstyle.h:459
@ PM_ToolBarFrameWidth
Definition qstyle.h:483
ComplexControl
This enum describes the available complex controls.
Definition qstyle.h:331
@ CC_ComboBox
Definition qstyle.h:333
@ CC_GroupBox
Definition qstyle.h:339
@ CC_Slider
Definition qstyle.h:335
@ CC_Dial
Definition qstyle.h:338
@ CC_ToolButton
Definition qstyle.h:336
@ CC_TitleBar
Definition qstyle.h:337
@ CC_SpinBox
Definition qstyle.h:332
@ CC_ScrollBar
Definition qstyle.h:334
PrimitiveElement
This enum describes the various primitive elements.
Definition qstyle.h:102
@ PE_IndicatorToolBarHandle
Definition qstyle.h:141
@ PE_PanelMenu
Definition qstyle.h:159
@ PE_IndicatorArrowLeft
Definition qstyle.h:125
@ PE_IndicatorArrowRight
Definition qstyle.h:126
@ PE_FrameLineEdit
Definition qstyle.h:108
@ PE_PanelLineEdit
Definition qstyle.h:122
@ PE_IndicatorHeaderArrow
Definition qstyle.h:133
@ PE_PanelStatusBar
Definition qstyle.h:156
@ PE_PanelScrollAreaCorner
Definition qstyle.h:146
@ PE_FrameTabWidget
Definition qstyle.h:111
@ PE_FrameGroupBox
Definition qstyle.h:107
@ PE_IndicatorDockWidgetResizeHandle
Definition qstyle.h:132
@ PE_IndicatorArrowDown
Definition qstyle.h:124
@ PE_FrameWindow
Definition qstyle.h:112
@ PE_IndicatorCheckBox
Definition qstyle.h:131
@ PE_PanelTipLabel
Definition qstyle.h:143
@ PE_Frame
Definition qstyle.h:103
@ PE_IndicatorRadioButton
Definition qstyle.h:136
@ PE_IndicatorToolBarSeparator
Definition qstyle.h:142
@ PE_FrameTabBarBase
Definition qstyle.h:115
@ PE_IndicatorArrowUp
Definition qstyle.h:127
@ PE_IndicatorMenuCheckMark
Definition qstyle.h:134
@ PE_IndicatorBranch
Definition qstyle.h:128
@ PE_FrameFocusRect
Definition qstyle.h:106
@ PE_FrameStatusBarItem
Definition qstyle.h:110
@ PE_IndicatorItemViewItemCheck
Definition qstyle.h:130
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_SpinBoxLayoutItem
Definition qstyle.h:297
@ 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_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_DockWidgetCloseButton
Definition qstyle.h:284
@ SE_TabWidgetLeftCorner
Definition qstyle.h:272
@ SE_ToolBoxTabContents
Definition qstyle.h:264
@ SE_TabWidgetTabContents
Definition qstyle.h:271
virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w=nullptr) const =0
Draws the given primitive element with the provided painter using the style options specified by opti...
const QStyle * proxy() const
Definition qstyle.cpp:2400
SubControl
This enum describes the available sub controls.
Definition qstyle.h:347
@ SC_SliderGroove
Definition qstyle.h:369
@ SC_TitleBarMinButton
Definition qstyle.h:377
@ SC_ScrollBarAddPage
Definition qstyle.h:352
@ SC_TitleBarLabel
Definition qstyle.h:384
@ SC_TitleBarNormalButton
Definition qstyle.h:380
@ SC_ToolButton
Definition qstyle.h:373
@ SC_ScrollBarGroove
Definition qstyle.h:357
@ SC_ScrollBarSlider
Definition qstyle.h:356
@ SC_GroupBoxContents
Definition qstyle.h:392
@ SC_ScrollBarSubPage
Definition qstyle.h:353
@ SC_SpinBoxDown
Definition qstyle.h:360
@ SC_ComboBoxListBoxPopup
Definition qstyle.h:367
@ SC_SpinBoxUp
Definition qstyle.h:359
@ SC_GroupBoxCheckBox
Definition qstyle.h:390
@ SC_GroupBoxLabel
Definition qstyle.h:391
@ SC_None
Definition qstyle.h:348
@ SC_ComboBoxEditField
Definition qstyle.h:365
@ SC_SliderTickmarks
Definition qstyle.h:371
@ SC_TitleBarMaxButton
Definition qstyle.h:378
@ SC_TitleBarCloseButton
Definition qstyle.h:379
@ SC_SpinBoxFrame
Definition qstyle.h:361
@ SC_ComboBoxArrow
Definition qstyle.h:366
@ SC_GroupBoxFrame
Definition qstyle.h:393
@ SC_SpinBoxEditField
Definition qstyle.h:362
@ SC_SliderHandle
Definition qstyle.h:370
@ SC_ToolButtonMenu
Definition qstyle.h:374
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
T value() const &
Definition qvariant.h:516
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
uint toUInt(bool *ok=nullptr) const
Returns the variant as an unsigned int if the variant has userType() \l QMetaType::UInt,...
QRect toRect() const
Returns the variant as a QRect if the variant has userType() \l QMetaType::QRect; otherwise returns a...
QFontMetrics fontMetrics() const
Returns the font metrics for the widget's current font.
Definition qwidget.h:847
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
\inmodule QtGui
Definition qwindow.h:63
EGLContext ctx
QString text
QPushButton * button
[2]
opt iconSize
rect
[4]
QPixmap pix
uint alignment
direction
QStyleOptionButton opt
else opt state
[0]
QRect textRect
const QStyleOptionButton * btn
[3]
static const QColor darkTabBarTabBackgroundActiveHovered(32, 32, 32)
static const QColor tabBarTabLineActiveHovered()
static const QColor darkTabBarTabLineActive(90, 90, 90)
static const QColor darkTabBarTabBackground(38, 38, 38)
static const QColor tabBarTabBackgroundActiveHovered()
static const QColor lightTabBarTabBackgroundSelected(246, 246, 246)
static const QColor lightTabBarTabLineActiveHovered(150, 150, 150)
static const QColor lightTabBarTabBackground(227, 227, 227)
static const QColor lightTabBarTabLineSelected(189, 189, 189)
static const QColor tabBarTabBackgroundSelected()
static const QColor lightTabBarTabLineActive(160, 160, 160)
static const QColor darkTabBarTabLineActiveHovered(90, 90, 90)
QBrush brushForToolButton(bool isOnKeyWindow)
static const QColor darkTabBarTabLineSelected(90, 90, 90)
static const QColor darkTabBarTabBackgroundActive(38, 38, 38)
static const QColor lightTabBarTabBackgroundActiveSelected(211, 211, 211)
static const QColor lightTabBarTabBackgroundActive(190, 190, 190)
static const QColor lightTabBarTabLine(210, 210, 210)
static const QColor tabBarTabLineActive()
static const QColor tabBarTabBackgroundActiveSelected()
QRect rotateTabPainter(QPainter *p, QStyleOptionTab::Shape shape, QRect tabRect)
static const QColor tabBarTabBackgroundActive()
static const int closeButtonSize
static const QColor darkTabBarTabLine(90, 90, 90)
static const QColor tabBarTabLine()
static const QColor darkTabBarTabBackgroundSelected(52, 52, 52)
static const QColor tabBarTabBackground()
static const QColor tabBarTabLineSelected()
void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb)
static const QColor darkTabBarTabBackgroundActiveSelected(52, 52, 52)
static const QColor lightTabBarTabBackgroundActiveHovered(178, 178, 178)
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:146
@ AlignVCenter
Definition qnamespace.h:155
@ AlignTop
Definition qnamespace.h:153
@ AlignHCenter
Definition qnamespace.h:148
@ AlignCenter
Definition qnamespace.h:163
@ AlignAbsolute
Definition qnamespace.h:150
@ AlignLeft
Definition qnamespace.h:144
@ LeftButton
Definition qnamespace.h:58
@ MiddleButton
Definition qnamespace.h:60
@ TextSelectableByMouse
@ LinksAccessibleByMouse
@ TextSelectableByKeyboard
@ IntersectClip
LayoutDirection
@ LeftToRight
@ RightToLeft
@ TabFocus
Definition qnamespace.h:108
@ Horizontal
Definition qnamespace.h:99
@ TextSingleLine
Definition qnamespace.h:170
@ TextDontClip
Definition qnamespace.h:171
@ TextHideMnemonic
Definition qnamespace.h:178
@ TextShowMnemonic
Definition qnamespace.h:173
@ gray
Definition qnamespace.h:33
@ white
Definition qnamespace.h:31
@ transparent
Definition qnamespace.h:47
@ black
Definition qnamespace.h:30
@ SolidLine
@ DashLine
@ NoPen
@ RoundJoin
@ ElideRight
Definition qnamespace.h:190
ToolButtonStyle
@ ToolButtonTextOnly
@ ToolButtonTextUnderIcon
@ ToolButtonTextBesideIcon
@ ToolButtonIconOnly
@ RoundCap
@ FlatCap
Definition brush.cpp:5
QString self
Definition language.cpp:58
static int fontType(const QString &androidControl)
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
float CGFloat
long NSInteger
unsigned long NSUInteger
#define Q_FALLTHROUGH()
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
Definition qcore_mac_p.h:58
QColor qt_mac_toQColor(CGColorRef color)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QString header(const QString &name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qDebug
[1]
Definition qlogging.h:164
const int macRightBorder
static const QColor darkModeSeparatorLine(88, 88, 88)
static QStyleHelper::WidgetSizePolicy getControlSize(const QStyleOption *option, const QWidget *widget)
const int macItemFrame
static const qreal focusRingWidth
static const int toolButtonArrowSize
static const QColor darkMainWindowGradientBegin(47, 47, 47)
static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QStyleOption *opt, const QWidget *widg, QSize szHint, QStyleHelper::WidgetSizePolicy sz)
static const QColor lightMainWindowGradientEnd(200, 200, 200)
static const QColor lightMainWindowGradientBegin(240, 240, 240)
bool isDarkMode()
static const QColor titlebarSeparatorLineInactive(131, 131, 131)
static const int headerSectionArrowHeight
static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
static const qreal titleBarIconTitleSpacing
return ret
static QPixmap darkenPixmap(const QPixmap &pixmap)
static const int qt_mac_aqua_metrics[]
static const QColor titlebarSeparatorLineActive(111, 111, 111)
static const qreal titleBarButtonSpacing
static const int toolButtonArrowMargin
@ 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 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 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 return_SIZE(large, small, mini)
#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
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
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
GLboolean GLboolean g
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLsizei const GLint * box
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
GLint y
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
GLuint GLenum GLenum transform
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLint void * img
Definition qopenglext.h:233
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLuint GLenum option
struct CGContext * CGContextRef
static constexpr QSize frameSize(const T &frame)
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(name)
#define LargeSmallMini(option, large, small, mini)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr QRgb qRgba(int r, int g, int b, int a)
Definition qrgb.h:33
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
static const struct TessellationWindingOrderTab cw[]
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define sp
constexpr bool verticalTabs(QTabBar::Shape shape) noexcept
Definition qtabbar_p.h:248
#define tr(X)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
QObject * styleObject(const QStyleOption *option)
static bool isTransient(const QWindow *w)
if(qFloatDistance(a, b)<(1<< 7))
[0]
QFile defaults(defaultsPath)
QStringList keys
sem release()
QPoint oldPosition
[6]
QSharedPointer< T > other(t)
[5]
QString dir
[11]
widget render & pixmap
aWidget window() -> setWindowTitle("New Window Title")
[2]
QFrame frame
[0]
QNetworkProxy proxy
[0]
QQuickView * view
[0]
QJSEngine engine
[0]
QScroller * scroller
\inmodule QtCore \reentrant
Definition qchar.h:18
QRectF adjustedControlFrame(const QRectF &rect) const
bool operator==(const CocoaControl &other) const
bool getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const
QStyleHelper::WidgetSizePolicy size