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