1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 Note: The qdoc comments for QMacStyle are contained in
44 .../doc/src/qstyles.qdoc.
47 #include "qmacstyle_mac.h"
48 #include "qmacstyle_mac_p.h"
49 #include "qmacstylepixmaps_mac_p.h"
51 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
52 //#define DEBUG_SIZE_CONSTRAINT
54 #include <private/qcore_mac_p.h>
55 #include <private/qcombobox_p.h>
56 #include <private/qpainter_p.h>
57 #include <qapplication.h>
59 #include <qcheckbox.h>
60 #include <qcombobox.h>
61 #include <qdialogbuttonbox.h>
62 #include <qdockwidget.h>
64 #include <qfocusframe.h>
65 #include <qformlayout.h>
66 #include <qgroupbox.h>
68 #include <qheaderview.h>
70 #include <qlineedit.h>
71 #include <qlistview.h>
72 #include <qmainwindow.h>
75 #include <qpaintdevice.h>
77 #include <qpixmapcache.h>
79 #include <qprogressbar.h>
80 #include <qpushbutton.h>
81 #include <qradiobutton.h>
82 #include <qrubberband.h>
83 #include <qsizegrip.h>
85 #include <qsplitter.h>
86 #include <qstyleoption.h>
87 #include <qtextedit.h>
88 #include <qtextstream.h>
90 #include <qtoolbutton.h>
91 #include <qtreeview.h>
92 #include <qtableview.h>
96 #include <qdatetimeedit.h>
98 #include <QtWidgets/qgraphicsproxywidget.h>
99 #include <QtWidgets/qgraphicsview.h>
100 #include <private/qstylehelper_p.h>
101 #include <QtGui/QPlatformFontDatabase>
105 // The following constants are used for adjusting the size
106 // of push buttons so that they are drawn inside their bounds.
107 const int QMacStylePrivate::PushButtonLeftOffset = 6;
108 const int QMacStylePrivate::PushButtonTopOffset = 4;
109 const int QMacStylePrivate::PushButtonRightOffset = 12;
110 const int QMacStylePrivate::PushButtonBottomOffset = 12;
111 const int QMacStylePrivate::MiniButtonH = 26;
112 const int QMacStylePrivate::SmallButtonH = 30;
113 const int QMacStylePrivate::BevelButtonW = 50;
114 const int QMacStylePrivate::BevelButtonH = 22;
115 const int QMacStylePrivate::PushButtonContentPadding = 6;
117 // These colors specify the titlebar gradient colors on
118 // Leopard. Ideally we should get them from the system.
119 static const QColor titlebarGradientActiveBegin(220, 220, 220);
120 static const QColor titlebarGradientActiveEnd(151, 151, 151);
121 static const QColor titlebarSeparatorLineActive(111, 111, 111);
122 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
123 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
124 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
126 // Gradient colors used for the dock widget title bar and
127 // non-unifed tool bar bacground.
128 static const QColor mainWindowGradientBegin(240, 240, 240);
129 static const QColor mainWindowGradientEnd(200, 200, 200);
131 static const int DisclosureOffset = 4;
133 // Resolve these at run-time, since the functions was moved in Leopard.
134 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
135 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
137 static int closeButtonSize = 12;
138 static bool isVerticalTabs(const QTabBar::Shape shape) {
139 return (shape == QTabBar::RoundedEast
140 || shape == QTabBar::TriangularEast
141 || shape == QTabBar::RoundedWest
142 || shape == QTabBar::TriangularWest);
145 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
147 // draw background circle
148 p->setRenderHints(QPainter::Antialiasing);
149 QRect rect(0, 0, closeButtonSize, closeButtonSize);
152 background = QColor(124, 124, 124);
156 background = QColor(104, 104, 104);
158 background = QColor(83, 83, 83);
161 background = QColor(144, 144, 144);
163 background = QColor(114, 114, 114);
166 p->setPen(Qt::transparent);
167 p->setBrush(background);
168 p->drawEllipse(rect);
174 crossPen.setColor(QColor(194, 194, 194));
175 crossPen.setWidthF(1.3);
176 crossPen.setCapStyle(Qt::FlatCap);
178 p->drawLine(min, min, max, max);
179 p->drawLine(min, max, max, min);
182 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
184 if (isVerticalTabs(shape)) {
185 int newX, newY, newRot;
186 if (shape == QTabBar::RoundedEast
187 || shape == QTabBar::TriangularEast) {
188 newX = tabRect.width();
193 newY = tabRect.y() + tabRect.height();
196 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
198 m.translate(newX, newY);
200 p->setMatrix(m, true);
205 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt)
207 QRect r = tabOpt->rect;
208 p->translate(tabOpt->rect.x(), tabOpt->rect.y());
211 QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
213 int width = tabRect.width();
215 bool active = (tabOpt->state & QStyle::State_Active);
216 bool selected = (tabOpt->state & QStyle::State_Selected);
219 QRect rect(1, 0, width - 2, height);
223 int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 16 : 0;
224 p->fillRect(rect, QColor(151 + d, 151 + d, 151 + d));
226 int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 9 : 0;
227 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
228 gradient.setColorAt(0, QColor(207 + d, 207 + d, 207 + d));
229 gradient.setColorAt(0.5, QColor(206 + d, 206 + d, 206 + d));
230 gradient.setColorAt(1, QColor(201 + d, 201 + d, 201 + d));
231 p->fillRect(rect, gradient);
238 borderSides = QColor(88, 88, 88);
239 borderBottom = QColor(88, 88, 88);
241 borderSides = QColor(121, 121, 121);
242 borderBottom = QColor(116, 116, 116);
245 p->setPen(borderSides);
249 p->drawLine(0, 1, 0, bottom-2);
251 p->drawLine(width-1, 1, width-1, bottom-2);
255 p->setPen(QColor(168, 168, 168));
256 p->drawLine(3, bottom-1, width-3, bottom-1);
258 p->setPen(borderBottom);
259 p->drawLine(2, bottom, width-2, bottom);
262 QRectF rectangleLeft(1, height - w, w, w);
263 QRectF rectangleRight(width - 2, height - 1, w, w);
264 int startAngle = 180 * 16;
265 int spanAngle = 90 * 16;
266 p->setRenderHint(QPainter::Antialiasing);
267 p->drawArc(rectangleLeft, startAngle, spanAngle);
268 p->drawArc(rectangleRight, startAngle, -spanAngle);
270 // when the mouse is over non selected tabs they get a new color
271 bool hover = (tabOpt->state & QStyle::State_MouseOver);
273 QRect rect(1, 2, width - 1, height - 1);
274 p->fillRect(rect, QColor(110, 110, 110));
277 // seperator lines between tabs
278 bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
279 bool drawOnRight = !west;
280 if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
281 || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
283 QColor borderHighlightColor;
285 borderColor = QColor(64, 64, 64);
286 borderHighlightColor = QColor(140, 140, 140);
288 borderColor = QColor(135, 135, 135);
289 borderHighlightColor = QColor(178, 178, 178);
292 int x = drawOnRight ? width : 0;
294 // tab seperator line
295 p->setPen(borderColor);
296 p->drawLine(x, 2, x, height + 1);
298 // tab seperator highlight
299 p->setPen(borderHighlightColor);
300 p->drawLine(x-1, 2, x-1, height + 1);
301 p->drawLine(x+1, 2, x+1, height + 1);
306 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
309 if (isVerticalTabs(tbb->shape)) {
310 r.setWidth(w->width());
312 r.setHeight(w->height());
314 QRect tabRect = rotateTabPainter(p, tbb->shape, r);
315 int width = tabRect.width();
316 int height = tabRect.height();
317 bool active = (tbb->state & QStyle::State_Active);
320 QColor borderHighlightTop;
323 borderTop = QColor(64, 64, 64);
324 borderHighlightTop = QColor(174, 174, 174);
326 borderTop = QColor(135, 135, 135);
327 borderHighlightTop = QColor(207, 207, 207);
329 p->setPen(borderHighlightTop);
330 p->drawLine(tabRect.x(), 0, width, 0);
331 p->setPen(borderTop);
332 p->drawLine(tabRect.x(), 1, width, 1);
335 QRect centralRect(tabRect.x(), 2, width, height - 2);
337 QColor mainColor = QColor(120, 120, 120);
338 p->fillRect(centralRect, mainColor);
340 QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
341 gradient.setColorAt(0, QColor(165, 165, 165));
342 gradient.setColorAt(0.5, QColor(164, 164, 164));
343 gradient.setColorAt(1, QColor(158, 158, 158));
344 p->fillRect(centralRect, gradient);
347 // bottom border lines
348 QColor borderHighlightBottom;
351 borderHighlightBottom = QColor(153, 153, 153);
352 borderBottom = QColor(64, 64, 64);
354 borderHighlightBottom = QColor(177, 177, 177);
355 borderBottom = QColor(127, 127, 127);
357 p->setPen(borderHighlightBottom);
358 p->drawLine(tabRect.x(), height - 2, width, height - 2);
359 p->setPen(borderBottom);
360 p->drawLine(tabRect.x(), height - 1, width, height - 1);
363 static int getControlSize(const QStyleOption *option, const QWidget *widget)
366 if (option->state & (QStyle::State_Small | QStyle::State_Mini))
367 return (option->state & QStyle::State_Mini) ? QAquaSizeMini : QAquaSizeSmall;
369 switch (QMacStyle::widgetSizePolicy(widget)) {
370 case QMacStyle::SizeSmall:
371 return QAquaSizeSmall;
372 case QMacStyle::SizeMini:
373 return QAquaSizeMini;
378 return QAquaSizeLarge;
382 static inline bool isTreeView(const QWidget *widget)
384 return (widget && widget->parentWidget() &&
385 (qobject_cast<const QTreeView *>(widget->parentWidget())
389 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
391 ThemeTabDirection ttd;
393 case QTabBar::RoundedSouth:
394 case QTabBar::TriangularSouth:
395 ttd = kThemeTabSouth;
397 default: // Added to remove the warning, since all values are taken care of, really!
398 case QTabBar::RoundedNorth:
399 case QTabBar::TriangularNorth:
400 ttd = kThemeTabNorth;
402 case QTabBar::RoundedWest:
403 case QTabBar::TriangularWest:
406 case QTabBar::RoundedEast:
407 case QTabBar::TriangularEast:
414 static QString qt_mac_removeMnemonics(const QString &original)
416 QString returnText(original.size(), 0);
419 int l = original.length();
421 if (original.at(currPos) == QLatin1Char('&')
422 && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) {
428 returnText[finalDest] = original.at(currPos);
433 returnText.truncate(finalDest);
439 CGContextRef context;
441 QMacCGContext(QPainter *p); //qpaintengine_mac.cpp
442 inline QMacCGContext() { context = 0; }
443 inline QMacCGContext(const QPaintDevice *pdev) {
444 extern CGContextRef qt_mac_cg_context(const QPaintDevice *);
445 context = qt_mac_cg_context(pdev);
447 inline QMacCGContext(CGContextRef cg, bool takeOwnership=false) {
450 CGContextRetain(context);
452 inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; }
453 inline ~QMacCGContext() {
455 CGContextRelease(context);
457 inline bool isNull() const { return context; }
458 inline operator CGContextRef() { return context; }
459 inline QMacCGContext &operator=(const QMacCGContext ©) {
461 CGContextRelease(context);
462 context = copy.context;
463 CGContextRetain(context);
466 inline QMacCGContext &operator=(CGContextRef cg) {
468 CGContextRelease(context);
470 CGContextRetain(context); //we do not take ownership
475 static QColor qcolorFromCGColor(CGColorRef cgcolor)
478 CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor));
479 const CGFloat *components = CGColorGetComponents(cgcolor);
480 if (model == kCGColorSpaceModelRGB) {
481 pc.setRgbF(components[0], components[1], components[2], components[3]);
482 } else if (model == kCGColorSpaceModelCMYK) {
483 pc.setCmykF(components[0], components[1], components[2], components[3]);
484 } else if (model == kCGColorSpaceModelMonochrome) {
485 pc.setRgbF(components[0], components[0], components[0], components[1]);
487 // Colorspace we can't deal with.
488 qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model);
494 static inline QColor leopardBrush(ThemeBrush brush)
496 QCFType<CGColorRef> cgClr = 0;
497 HIThemeBrushCreateCGColor(brush, &cgClr);
498 return qcolorFromCGColor(cgClr);
501 QColor qcolorForTheme(ThemeBrush brush)
503 return leopardBrush(brush);
506 OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon)
508 QRegion *region = static_cast<QRegion *>(inRefcon);
513 case kHIShapeEnumerateRect:
514 *region += QRect(inRect->origin.x, inRect->origin.y,
515 inRect->size.width, inRect->size.height);
517 case kHIShapeEnumerateInit:
518 // Assume the region is already setup correctly
519 case kHIShapeEnumerateTerminate:
529 Create's a mutable shape, it's the caller's responsibility to release.
530 WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below.
532 HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion ®ion)
534 HIMutableShapeRef shape = HIShapeCreateMutable();
535 if (region.rectCount() < 2 ) {
536 QRect qtRect = region.boundingRect();
537 CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
538 HIShapeUnionWithRect(shape, &cgRect);
540 foreach (const QRect &qtRect, region.rects()) {
541 CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
542 HIShapeUnionWithRect(shape, &cgRect);
548 QRegion qt_mac_fromHIShapeRef(HIShapeRef shape)
550 QRegion returnRegion;
551 //returnRegion.detach();
552 HIShapeEnumerate(shape, kHIShapeParseFromTopLeft, qt_mac_shape2QRegionHelper, &returnRegion);
556 CGColorSpaceRef m_genericColorSpace = 0;
557 QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
558 bool m_postRoutineRegistered = false;
560 CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget);
561 CGColorSpaceRef qt_mac_genericColorSpace()
564 if (!m_genericColorSpace) {
565 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
566 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
567 m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
571 m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
573 if (!m_postRoutineRegistered) {
574 m_postRoutineRegistered = true;
575 qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
578 return m_genericColorSpace;
580 // Just return the main display colorspace for the moment.
581 return qt_mac_displayColorSpace(0);
586 Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc.
587 to support multiple displays correctly.
589 CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget)
591 CGColorSpaceRef colorSpace;
593 CGDirectDisplayID displayID;
594 CMProfileRef displayProfile = 0;
596 displayID = CGMainDisplayID();
598 displayID = CGMainDisplayID();
600 ### get correct display
601 const QRect &qrect = widget->window()->geometry();
602 CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height());
603 CGDisplayCount throwAway;
604 CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway);
605 if (dErr != kCGErrorSuccess)
606 return macDisplayColorSpace(0); // fall back on main display
609 if ((colorSpace = m_displayColorSpaceHash.value(displayID)))
612 CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile);
614 colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile);
616 return qt_mac_displayColorSpace(0); // fall back on main display
620 colorSpace = CGColorSpaceCreateDeviceRGB();
622 m_displayColorSpaceHash.insert(displayID, colorSpace);
623 CMCloseProfile(displayProfile);
624 if (!m_postRoutineRegistered) {
625 m_postRoutineRegistered = true;
626 void qt_mac_cleanUpMacColorSpaces();
627 qAddPostRoutine(qt_mac_cleanUpMacColorSpaces);
632 void qt_mac_cleanUpMacColorSpaces()
634 if (m_genericColorSpace) {
635 CFRelease(m_genericColorSpace);
636 m_genericColorSpace = 0;
638 QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin();
639 while (it != m_displayColorSpaceHash.constEnd()) {
641 CFRelease(it.value());
644 m_displayColorSpaceHash.clear();
647 bool qt_macWindowIsTextured(const QWidget *window)
649 NSWindow *nswindow = static_cast<NSWindow*>(
650 QApplication::platformNativeInterface()->nativeResourceForWindow("NSWindow", window->windowHandle()));
653 return ([nswindow styleMask] & NSTexturedBackgroundWindowMask) ? true : false;
656 /*****************************************************************************
658 *****************************************************************************/
659 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
660 const int macItemFrame = 2; // menu item frame width
661 const int macItemHMargin = 3; // menu item hor text margin
662 const int macItemVMargin = 2; // menu item ver text margin
663 const int macRightBorder = 12; // right border on mac
664 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
665 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
667 /*****************************************************************************
668 QMacCGStyle utility functions
669 *****************************************************************************/
670 static inline int qt_mac_hitheme_tab_version()
675 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
677 return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
678 convertRect.width() - rect.width(), convertRect.height() - rect.height());
681 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
683 return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
684 QSize(int(hirect.size.width), int(hirect.size.height)));
687 inline bool qt_mac_is_metal(const QWidget *w)
689 for (; w; w = w->parentWidget()) {
690 if (w->testAttribute(Qt::WA_MacBrushedMetal))
692 if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) { // If not created will fall through to the opaque check and be fine anyway.
693 return qt_macWindowIsTextured(w);
695 if (w->d_func()->isOpaque)
701 static int qt_mac_aqua_get_metric(ThemeMetric met)
704 GetThemeMetric(met, &ret);
708 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
712 if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
713 qDebug("Not sure how to return this...");
716 if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
717 // If you're using a custom font and it's bigger than the default font,
718 // then no constraints for you. If you are smaller, we can try to help you out
719 QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
720 if (widg->font().pointSize() > font.pointSize())
724 if (ct == QStyle::CT_CustomBase && widg) {
725 if (qobject_cast<const QPushButton *>(widg))
726 ct = QStyle::CT_PushButton;
727 else if (qobject_cast<const QRadioButton *>(widg))
728 ct = QStyle::CT_RadioButton;
729 else if (qobject_cast<const QCheckBox *>(widg))
730 ct = QStyle::CT_CheckBox;
731 else if (qobject_cast<const QComboBox *>(widg))
732 ct = QStyle::CT_ComboBox;
733 else if (qobject_cast<const QToolButton *>(widg))
734 ct = QStyle::CT_ToolButton;
735 else if (qobject_cast<const QSlider *>(widg))
736 ct = QStyle::CT_Slider;
737 else if (qobject_cast<const QProgressBar *>(widg))
738 ct = QStyle::CT_ProgressBar;
739 else if (qobject_cast<const QLineEdit *>(widg))
740 ct = QStyle::CT_LineEdit;
741 else if (qobject_cast<const QHeaderView *>(widg))
742 ct = QStyle::CT_HeaderSection;
743 else if (qobject_cast<const QMenuBar *>(widg))
744 ct = QStyle::CT_MenuBar;
745 else if (qobject_cast<const QSizeGrip *>(widg))
746 ct = QStyle::CT_SizeGrip;
752 case QStyle::CT_PushButton: {
753 const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
754 // If this comparison is false, then the widget was not a push button.
755 // This is bad and there's very little we can do since we were requested to find a
756 // sensible size for a widget that pretends to be a QPushButton but is not.
758 QString buttonText = qt_mac_removeMnemonics(psh->text());
759 if (buttonText.contains(QLatin1Char('\n')))
761 else if (sz == QAquaSizeLarge)
762 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
763 else if (sz == QAquaSizeSmall)
764 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
765 else if (sz == QAquaSizeMini)
766 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
768 if (!psh->icon().isNull()){
769 // If the button got an icon, and the icon is larger than the
770 // button, we can't decide on a default size
772 if (ret.height() < psh->iconSize().height())
775 else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
776 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
777 // However, this doesn't work for German, therefore only do it for English,
778 // I suppose it would be better to do some sort of lookups for languages
779 // that like to have really long words.
780 ret.setWidth(77 - 8);
783 // The only sensible thing to do is to return whatever the style suggests...
784 if (sz == QAquaSizeLarge)
785 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
786 else if (sz == QAquaSizeSmall)
787 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
788 else if (sz == QAquaSizeMini)
789 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
791 // Since there's no default size we return the large size...
792 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
794 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
795 } else if (ct == QStyle::CT_RadioButton) {
796 QRadioButton *rdo = static_cast<QRadioButton *>(widg);
797 // Exception for case where multiline radio button text requires no size constrainment
798 if (rdo->text().find('\n') != -1)
800 if (sz == QAquaSizeLarge)
801 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
802 else if (sz == QAquaSizeSmall)
803 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
804 else if (sz == QAquaSizeMini)
805 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
806 } else if (ct == QStyle::CT_CheckBox) {
807 if (sz == QAquaSizeLarge)
808 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
809 else if (sz == QAquaSizeSmall)
810 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
811 else if (sz == QAquaSizeMini)
812 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
816 case QStyle::CT_SizeGrip:
817 if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
819 HIPoint p = { 0, 0 };
820 HIThemeGrowBoxDrawInfo gbi;
822 gbi.state = kThemeStateActive;
823 gbi.kind = kHIThemeGrowBoxKindNormal;
824 gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
825 : kThemeGrowRight | kThemeGrowDown;
826 gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
827 if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr)
828 ret = QSize(r.size.width, r.size.height);
831 case QStyle::CT_ComboBox:
834 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
837 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
840 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
846 case QStyle::CT_ToolButton:
847 if (sz == QAquaSizeSmall) {
848 int width = 0, height = 0;
849 if (szHint == QSize(-1, -1)) { //just 'guess'..
850 const QToolButton *bt = qobject_cast<const QToolButton *>(widg);
851 // If this conversion fails then the widget was not what it claimed to be.
853 if (!bt->icon().isNull()) {
854 QSize iconSize = bt->iconSize();
855 QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
856 width = qMax(width, qMax(iconSize.width(), pmSize.width()));
857 height = qMax(height, qMax(iconSize.height(), pmSize.height()));
859 if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
860 int text_width = bt->fontMetrics().width(bt->text()),
861 text_height = bt->fontMetrics().height();
862 if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
863 width = qMax(width, text_width);
864 height += text_height;
867 width = qMax(height, text_height);
871 // Let's return the size hint...
872 width = szHint.width();
873 height = szHint.height();
876 width = szHint.width();
877 height = szHint.height();
879 width = qMax(20, width + 5); //border
880 height = qMax(20, height + 5); //border
881 ret = QSize(width, height);
884 case QStyle::CT_Slider: {
886 const QSlider *sld = qobject_cast<const QSlider *>(widg);
887 // If this conversion fails then the widget was not what it claimed to be.
889 if (sz == QAquaSizeLarge) {
890 if (sld->orientation() == Qt::Horizontal) {
891 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
892 if (sld->tickPosition() != QSlider::NoTicks)
893 w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
895 w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
896 if (sld->tickPosition() != QSlider::NoTicks)
897 w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
899 } else if (sz == QAquaSizeSmall) {
900 if (sld->orientation() == Qt::Horizontal) {
901 w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
902 if (sld->tickPosition() != QSlider::NoTicks)
903 w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
905 w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
906 if (sld->tickPosition() != QSlider::NoTicks)
907 w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
909 } else if (sz == QAquaSizeMini) {
910 if (sld->orientation() == Qt::Horizontal) {
911 w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
912 if (sld->tickPosition() != QSlider::NoTicks)
913 w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
915 w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
916 if (sld->tickPosition() != QSlider::NoTicks)
917 w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
921 // This is tricky, we were requested to find a size for a slider which is not
922 // a slider. We don't know if this is vertical or horizontal or if we need to
923 // have tick marks or not.
924 // For this case we will return an horizontal slider without tick marks.
925 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
926 w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
928 if (sld->orientation() == Qt::Horizontal)
934 case QStyle::CT_ProgressBar: {
936 Qt::Orientation orient = Qt::Horizontal;
937 if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
938 orient = pb->orientation();
940 if (sz == QAquaSizeLarge)
941 finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
942 + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
944 finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
945 + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
946 if (orient == Qt::Horizontal)
947 ret.setHeight(finalValue);
949 ret.setWidth(finalValue);
952 case QStyle::CT_LineEdit:
953 if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
954 //should I take into account the font dimentions of the lineedit? -Sam
955 if (sz == QAquaSizeLarge)
961 case QStyle::CT_HeaderSection:
962 if (isTreeView(widg))
963 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
965 case QStyle::CT_MenuBar:
966 if (sz == QAquaSizeLarge) {
967 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
968 // In the qt_mac_set_native_menubar(false) case,
969 // we come it here with a zero-height main menu,
970 // preventing the in-window menu from displaying.
971 // Use 22 pixels for the height, by observation.
972 if (ret.height() <= 0)
983 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
984 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
986 if (large == QSize(-1, -1)) {
987 if (small != QSize(-1, -1))
988 return QAquaSizeSmall;
989 if (mini != QSize(-1, -1))
990 return QAquaSizeMini;
991 return QAquaSizeUnknown;
992 } else if (small == QSize(-1, -1)) {
993 if (mini != QSize(-1, -1))
994 return QAquaSizeMini;
995 return QAquaSizeLarge;
996 } else if (mini == QSize(-1, -1)) {
997 return QAquaSizeLarge;
1000 #ifndef QT_NO_MAINWINDOW
1001 if (qobject_cast<QDockWidget *>(widg->window()) || !qgetenv("QWIDGET_ALL_SMALL").isNull()) {
1002 //if (small.width() != -1 || small.height() != -1)
1003 return QAquaSizeSmall;
1004 } else if (!qgetenv("QWIDGET_ALL_MINI").isNull()) {
1005 return QAquaSizeMini;
1010 /* Figure out which size we're closer to, I just hacked this in, I haven't
1011 tested it as it would probably look pretty strange to have some widgets
1012 big and some widgets small in the same window?? -Sam */
1014 if (large.width() != -1) {
1015 int delta = large.width() - widg->width();
1016 large_delta += delta * delta;
1018 if (large.height() != -1) {
1019 int delta = large.height() - widg->height();
1020 large_delta += delta * delta;
1023 if (small.width() != -1) {
1024 int delta = small.width() - widg->width();
1025 small_delta += delta * delta;
1027 if (small.height() != -1) {
1028 int delta = small.height() - widg->height();
1029 small_delta += delta * delta;
1032 if (mini.width() != -1) {
1033 int delta = mini.width() - widg->width();
1034 mini_delta += delta * delta;
1036 if (mini.height() != -1) {
1037 int delta = mini.height() - widg->height();
1038 mini_delta += delta * delta;
1040 if (mini_delta < small_delta && mini_delta < large_delta)
1041 return QAquaSizeMini;
1042 else if (small_delta < large_delta)
1043 return QAquaSizeSmall;
1045 return QAquaSizeLarge;
1049 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
1050 QStyle::ContentsType ct, QSize szHint, QSize *insz) const
1052 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1054 if (option->state & QStyle::State_Small)
1055 return QAquaSizeSmall;
1056 if (option->state & QStyle::State_Mini)
1057 return QAquaSizeMini;
1063 if (!qgetenv("QWIDGET_ALL_SMALL").isNull())
1064 return QAquaSizeSmall;
1065 if (!qgetenv("QWIDGET_ALL_MINI").isNull())
1066 return QAquaSizeMini;
1067 return QAquaSizeUnknown;
1069 QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
1070 small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
1071 mini = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
1072 bool guess_size = false;
1073 QAquaWidgetSize ret = QAquaSizeUnknown;
1074 QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
1075 if (wsp == QMacStyle::SizeDefault)
1077 else if (wsp == QMacStyle::SizeMini)
1078 ret = QAquaSizeMini;
1079 else if (wsp == QMacStyle::SizeSmall)
1080 ret = QAquaSizeSmall;
1081 else if (wsp == QMacStyle::SizeLarge)
1082 ret = QAquaSizeLarge;
1084 ret = qt_aqua_guess_size(widg, large, small, mini);
1087 if (ret == QAquaSizeSmall)
1089 else if (ret == QAquaSizeLarge)
1091 else if (ret == QAquaSizeMini)
1094 *insz = sz ? *sz : QSize(-1, -1);
1095 #ifdef DEBUG_SIZE_CONSTRAINT
1097 const char *size_desc = "Unknown";
1099 size_desc = "Small";
1100 else if (sz == &large)
1101 size_desc = "Large";
1102 else if (sz == &mini)
1104 qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
1105 widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
1106 widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
1107 sz->width(), sz->height());
1117 return QAquaSizeUnknown;
1122 Returns the free space awailable for contents inside the
1123 button (and not the size of the contents itself)
1125 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
1126 const HIThemeButtonDrawInfo *bdi) const
1128 HIRect outerBounds = qt_hirectForQRect(btn->rect);
1129 // Adjust the bounds to correct for
1130 // carbon not calculating the content bounds fully correct
1131 if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
1132 outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1133 outerBounds.size.height -= QMacStylePrivate::PushButtonBottomOffset;
1134 } else if (bdi->kind == kThemePushButtonMini) {
1135 outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1138 HIRect contentBounds;
1139 HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
1140 return contentBounds;
1144 Calculates the size of the button contents.
1145 This includes both the text and the icon.
1147 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
1150 QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
1151 : (btn->iconSize + QSize(QMacStylePrivate::PushButtonContentPadding, 0));
1152 QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
1153 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
1154 csz.setWidth(iconSize.width() + textRect.width()
1155 + ((btn->features & QStyleOptionButton::HasMenu)
1156 ? q->proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
1157 csz.setHeight(qMax(iconSize.height(), textRect.height()));
1162 Checks if the actual contents of btn fits inside the free content bounds of
1163 'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
1164 for determining which button kind to use for drawing.
1166 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
1167 HIThemeButtonDrawInfo *bdi,
1168 ThemeButtonKind buttonKindToCheck) const
1170 ThemeButtonKind tmp = bdi->kind;
1171 bdi->kind = buttonKindToCheck;
1172 QSize contentSize = pushButtonSizeFromContents(btn);
1173 QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
1175 return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
1176 contentSize.width(), contentSize.height()));
1180 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1181 kind and other details to use for drawing the given push button. Which
1182 button kind depends on the size of the button, the size of the contents,
1183 explicit user style settings, etc.
1185 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1186 const QWidget *widget,
1187 const ThemeDrawState tds,
1188 HIThemeButtonDrawInfo *bdi) const
1190 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
1191 ThemeDrawState tdsModified = tds;
1192 if (btn->state & QStyle::State_On)
1193 tdsModified = kThemeStatePressed;
1194 bdi->version = qt_mac_hitheme_version;
1195 bdi->state = tdsModified;
1196 bdi->value = kThemeButtonOff;
1198 if (drawColorless && tdsModified == kThemeStateInactive)
1199 bdi->state = kThemeStateActive;
1200 if (btn->state & QStyle::State_HasFocus)
1201 bdi->adornment = kThemeAdornmentFocus;
1203 bdi->adornment = kThemeAdornmentNone;
1206 if (btn->features & (QStyleOptionButton::Flat)) {
1207 bdi->kind = kThemeBevelButton;
1209 switch (aquaSizeConstrain(btn, widget)) {
1210 case QAquaSizeSmall:
1211 bdi->kind = kThemePushButtonSmall;
1214 bdi->kind = kThemePushButtonMini;
1216 case QAquaSizeLarge:
1217 // ... We should honor if the user is explicit about using the
1218 // large button. But right now Qt will specify the large button
1219 // as default rather than QAquaSizeUnknown.
1220 // So we treat it like QAquaSizeUnknown
1221 // to get the dynamic choosing of button kind.
1222 case QAquaSizeUnknown:
1223 // Choose the button kind that closest match the button rect, but at the
1224 // same time displays the button contents without clipping.
1225 bdi->kind = kThemeBevelButton;
1226 if (btn->rect.width() >= QMacStylePrivate::BevelButtonW && btn->rect.height() >= QMacStylePrivate::BevelButtonH){
1227 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1228 if (btn->rect.height() <= QMacStylePrivate::MiniButtonH){
1229 if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1230 bdi->kind = kThemePushButtonMini;
1231 } else if (btn->rect.height() <= QMacStylePrivate::SmallButtonH){
1232 if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1233 bdi->kind = kThemePushButtonSmall;
1234 } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1235 bdi->kind = kThemePushButton;
1238 bdi->kind = kThemePushButton;
1245 bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
1247 QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
1250 HIThemeButtonDrawInfo bdi;
1251 macStyle->d->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
1252 return bdi.kind == kThemeBevelButton;
1256 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1257 kind and other details to use for drawing the given combobox. Which button
1258 kind depends on the size of the combo, wether or not it is editable,
1259 explicit user style settings, etc.
1261 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1262 const QWidget *widget, const ThemeDrawState &tds)
1264 bdi->version = qt_mac_hitheme_version;
1265 bdi->adornment = kThemeAdornmentArrowLeftArrow;
1266 bdi->value = kThemeButtonOff;
1267 if (combo->state & QStyle::State_HasFocus)
1268 bdi->adornment = kThemeAdornmentFocus;
1269 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
1270 if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1271 bdi->state = kThemeStatePressed;
1272 else if (drawColorless)
1273 bdi->state = kThemeStateActive;
1277 QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1280 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1281 : ThemeButtonKind(kThemePopupButtonMini);
1283 case QAquaSizeSmall:
1284 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1285 : ThemeButtonKind(kThemePopupButtonSmall);
1287 case QAquaSizeUnknown:
1288 case QAquaSizeLarge:
1289 // Unless the user explicitly specified large buttons, determine the
1290 // kind by looking at the combox size.
1291 // ... specifying small and mini-buttons it not a current feature of
1292 // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1293 // an extra check here before using the mini and small buttons.
1294 int h = combo->rect.size().height();
1295 if (combo->editable){
1297 bdi->kind = kThemeComboBoxMini;
1299 bdi->kind = kThemeComboBoxSmall;
1301 bdi->kind = kThemeComboBox;
1303 // Even if we specify that we want the kThemePopupButton, Carbon
1304 // will use the kThemePopupButtonSmall if the size matches. So we
1305 // do the same size check explicit to have the size of the inner
1306 // text field be correct. Therefore, do this even if the user specifies
1307 // the use of LargeButtons explicit.
1309 bdi->kind = kThemePopupButtonMini;
1311 bdi->kind = kThemePopupButtonSmall;
1313 bdi->kind = kThemePopupButton;
1320 Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1321 the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1323 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1325 HIRect innerBounds = outerBounds;
1326 // Carbon draw parts of the view outside the rect.
1327 // So make the rect a bit smaller to compensate
1328 // (I wish HIThemeGetButtonBackgroundBounds worked)
1329 switch (buttonKind){
1330 case kThemePopupButton:
1331 innerBounds.origin.x += 2;
1332 innerBounds.origin.y += 3;
1333 innerBounds.size.width -= 5;
1334 innerBounds.size.height -= 6;
1336 case kThemePopupButtonSmall:
1337 innerBounds.origin.x += 3;
1338 innerBounds.origin.y += 3;
1339 innerBounds.size.width -= 6;
1340 innerBounds.size.height -= 7;
1342 case kThemePopupButtonMini:
1343 innerBounds.origin.x += 2;
1344 innerBounds.origin.y += 2;
1345 innerBounds.size.width -= 5;
1346 innerBounds.size.height -= 6;
1348 case kThemeComboBox:
1349 innerBounds.origin.x += 3;
1350 innerBounds.origin.y += 3;
1351 innerBounds.size.width -= 6;
1352 innerBounds.size.height -= 6;
1354 case kThemeComboBoxSmall:
1355 innerBounds.origin.x += 3;
1356 innerBounds.origin.y += 3;
1357 innerBounds.size.width -= 7;
1358 innerBounds.size.height -= 8;
1360 case kThemeComboBoxMini:
1361 innerBounds.origin.x += 3;
1362 innerBounds.origin.y += 3;
1363 innerBounds.size.width -= 4;
1364 innerBounds.size.height -= 8;
1373 Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1374 of combobox we choose to draw. This function calculates and returns this size.
1376 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1378 QRect ret = outerBounds;
1380 case kThemeComboBox:
1381 ret.adjust(5, 8, -21, -4);
1383 case kThemeComboBoxSmall:
1384 ret.adjust(4, 5, -18, 0);
1387 case kThemeComboBoxMini:
1388 ret.adjust(4, 5, -16, 0);
1391 case kThemePopupButton:
1392 ret.adjust(10, 3, -23, -3);
1394 case kThemePopupButtonSmall:
1395 ret.adjust(9, 3, -20, -3);
1397 case kThemePopupButtonMini:
1398 ret.adjust(8, 3, -19, 0);
1406 Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1407 create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1408 it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1410 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1412 if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1413 // We have an unscaled combobox, or popup-button; use Carbon directly.
1414 HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1415 HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1418 QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1419 if (!QPixmapCache::find(key, buffer)) {
1420 HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1421 buffer = QPixmap(35, 28);
1422 buffer.fill(Qt::transparent);
1423 QPainter buffPainter(&buffer);
1424 HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1426 QPixmapCache::insert(key, buffer);
1429 const int bwidth = 20;
1430 const int fwidth = 10;
1431 const int fheight = 10;
1432 int w = qRound(outerBounds.size.width);
1433 int h = qRound(outerBounds.size.height);
1434 int bstart = w - bwidth;
1435 int blower = fheight + 1;
1436 int flower = h - fheight;
1437 int sheight = flower - fheight;
1438 int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1440 // Draw upper and lower gap
1441 p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1442 p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1443 // Draw left and right gap. Right gap is drawn top and bottom separatly
1444 p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1445 p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1446 p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1448 p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1450 p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1451 p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1452 p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1453 p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1458 Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1459 onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1461 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1462 bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1464 static SInt32 headerHeight = 0;
1465 static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1469 QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1470 if (!QPixmapCache::find(key, buffer)) {
1471 HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1472 buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1473 buffer.fill(Qt::transparent);
1474 QPainter buffPainter(&buffer);
1475 HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1477 QPixmapCache::insert(key, buffer);
1479 const int buttonw = qRound(outerBounds.size.width);
1480 const int buttonh = qRound(outerBounds.size.height);
1481 const int framew = 1;
1482 const int frameh_n = 4;
1483 const int frameh_s = 3;
1484 const int transh = buffer.height() - frameh_n - frameh_s;
1485 int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1487 int skipTopBorder = 0;
1491 p->translate(outerBounds.origin.x, outerBounds.origin.y);
1493 p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1494 p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1495 // Draw upper and lower center blocks
1496 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1497 p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1498 // Draw right center block borders
1499 p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1500 p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1501 // Draw right corners
1502 p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1503 p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1504 // Draw center transition block
1505 p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh));
1506 // Draw right center transition block border
1507 p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh));
1508 if (drawLeftBorder){
1509 // Draw left center block borders
1510 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1511 p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1512 // Draw left corners
1513 p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1514 p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1515 // Draw left center transition block border
1516 p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1519 p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1523 Returns cutoff sizes for scroll bars.
1524 thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1525 scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1527 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1528 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1530 // Mini scroll bars do not exist as of version 10.4.
1531 if (widgetSize == QMacStyle::SizeMini)
1534 const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1535 static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1536 return sizeTable[sizeIndex][cutoffType];
1539 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1540 HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe)
1542 memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1543 tdi->version = qt_mac_hitheme_version;
1546 bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1547 switch (aquaSizeConstrain(0, needToRemoveMe)) {
1548 case QAquaSizeUnknown:
1549 case QAquaSizeLarge:
1551 tdi->kind = kThemeMediumScrollBar;
1553 tdi->kind = kThemeMediumSlider;
1557 tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1559 tdi->kind = kThemeMiniSlider;
1561 case QAquaSizeSmall:
1563 tdi->kind = kThemeSmallScrollBar;
1565 tdi->kind = kThemeSmallSlider;
1568 tdi->bounds = qt_hirectForQRect(slider->rect);
1569 tdi->min = slider->minimum;
1570 tdi->max = slider->maximum;
1571 tdi->value = slider->sliderPosition;
1572 tdi->attributes = kThemeTrackShowThumb;
1573 if (slider->upsideDown)
1574 tdi->attributes |= kThemeTrackRightToLeft;
1575 if (slider->orientation == Qt::Horizontal) {
1576 tdi->attributes |= kThemeTrackHorizontal;
1577 if (isScrollbar && slider->direction == Qt::RightToLeft) {
1578 if (!slider->upsideDown)
1579 tdi->attributes |= kThemeTrackRightToLeft;
1581 tdi->attributes &= ~kThemeTrackRightToLeft;
1585 // Tiger broke reverse scroll bars so put them back and "fake it"
1586 if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)) {
1587 tdi->attributes &= ~kThemeTrackRightToLeft;
1588 tdi->value = tdi->max - slider->sliderPosition;
1591 tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1592 : kThemeTrackDisabled;
1593 if (!(slider->state & QStyle::State_Active))
1594 tdi->enableState = kThemeTrackInactive;
1596 if (slider->state & QStyle::QStyle::State_HasFocus)
1597 tdi->attributes |= kThemeTrackHasFocus;
1598 if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1599 tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1600 else if (slider->tickPosition == QSlider::TicksAbove)
1601 tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1603 tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1605 tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1609 QMacStylePrivate::QMacStylePrivate(QMacStyle *style)
1610 : timerID(-1), progressFrame(0), q(style), mouseDown(false)
1612 defaultButtonStart = CFAbsoluteTimeGetCurrent();
1613 memset(&buttonState, 0, sizeof(ButtonState));
1615 if (ptrHIShapeGetBounds == 0) {
1616 QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1617 library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1618 ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1623 bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QWidget *w) const
1628 if (as == AquaPushButton) {
1629 QPushButton *pb = const_cast<QPushButton *>(static_cast<const QPushButton *>(w));
1630 if (w->window()->isActiveWindow() && pb && !mouseDown) {
1631 if (static_cast<const QPushButton *>(w) != defaultButton) {
1632 // Changed on its own, update the value.
1633 const_cast<QMacStylePrivate *>(this)->stopAnimate(as, defaultButton);
1634 const_cast<QMacStylePrivate *>(this)->startAnimate(as, pb);
1638 } else if (as == AquaProgressBar) {
1639 if (progressBars.contains((const_cast<QWidget *>(w))))
1645 void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QWidget *w)
1647 if (as == AquaPushButton && defaultButton) {
1648 QPushButton *tmp = defaultButton;
1651 } else if (as == AquaProgressBar) {
1652 progressBars.removeAll(w);
1656 void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QWidget *w)
1658 if (as == AquaPushButton)
1659 defaultButton = static_cast<QPushButton *>(w);
1660 else if (as == AquaProgressBar)
1661 progressBars.append(w);
1662 startAnimationTimer();
1665 void QMacStylePrivate::startAnimationTimer()
1667 if ((defaultButton || !progressBars.isEmpty()) && timerID <= -1)
1668 timerID = startTimer(animateSpeed(AquaListViewItemOpen));
1671 bool QMacStylePrivate::addWidget(QWidget *w)
1673 //already knew of it
1674 if (static_cast<QPushButton*>(w) == defaultButton
1675 || progressBars.contains(static_cast<QProgressBar*>(w)))
1678 if (QPushButton *btn = qobject_cast<QPushButton *>(w)) {
1679 btn->installEventFilter(this);
1680 if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus()))
1681 startAnimate(AquaPushButton, btn);
1684 bool isProgressBar = (qobject_cast<QProgressBar *>(w));
1685 if (isProgressBar) {
1686 w->installEventFilter(this);
1687 startAnimate(AquaProgressBar, w);
1691 if (w->isWindow()) {
1692 w->installEventFilter(this);
1698 void QMacStylePrivate::removeWidget(QWidget *w)
1700 QPushButton *btn = qobject_cast<QPushButton *>(w);
1701 if (btn && btn == defaultButton) {
1702 stopAnimate(AquaPushButton, btn);
1703 } else if (qobject_cast<QProgressBar *>(w)) {
1704 stopAnimate(AquaProgressBar, w);
1708 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1710 ThemeDrawState tds = kThemeStateActive;
1711 if (flags & QStyle::State_Sunken) {
1712 tds = kThemeStatePressed;
1713 } else if (flags & QStyle::State_Active) {
1714 if (!(flags & QStyle::State_Enabled))
1715 tds = kThemeStateUnavailable;
1717 if (flags & QStyle::State_Enabled)
1718 tds = kThemeStateInactive;
1720 tds = kThemeStateUnavailableInactive;
1725 void QMacStylePrivate::timerEvent(QTimerEvent *)
1728 if (defaultButton && defaultButton->isEnabled() && defaultButton->window()->isActiveWindow()
1729 && defaultButton->isVisibleTo(0) && (defaultButton->isDefault()
1730 || (defaultButton->autoDefault() && defaultButton->hasFocus()))
1731 && doAnimate(AquaPushButton)) {
1733 defaultButton->update();
1735 if (!progressBars.isEmpty()) {
1737 while (i < progressBars.size()) {
1738 QWidget *maybeProgress = progressBars.at(i);
1739 if (!maybeProgress) {
1740 progressBars.removeAt(i);
1742 if (QProgressBar *pb = qobject_cast<QProgressBar *>(maybeProgress)) {
1743 if (pb->maximum() == 0 || (pb->value() > 0 && pb->value() < pb->maximum())) {
1744 if (doAnimate(AquaProgressBar))
1756 if (animated <= 0) {
1762 bool QMacStylePrivate::eventFilter(QObject *o, QEvent *e)
1765 if (QProgressBar *pb = qobject_cast<QProgressBar *>(o)) {
1766 switch (e->type()) {
1770 if (!progressBars.contains(pb))
1771 startAnimate(AquaProgressBar, pb);
1773 case QEvent::Destroy:
1775 progressBars.removeAll(pb);
1777 } else if (QPushButton *btn = qobject_cast<QPushButton *>(o)) {
1778 switch (e->type()) {
1781 case QEvent::FocusIn:
1782 if (btn->autoDefault())
1783 startAnimate(AquaPushButton, btn);
1785 case QEvent::Destroy:
1787 if (btn == defaultButton)
1788 stopAnimate(AquaPushButton, btn);
1790 case QEvent::MouseButtonPress:
1791 // It is very confusing to keep the button pulsing, so just stop the animation.
1792 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1794 stopAnimate(AquaPushButton, btn);
1796 case QEvent::MouseButtonRelease:
1797 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1800 case QEvent::FocusOut:
1802 case QEvent::WindowActivate: {
1803 QList<QPushButton *> list = btn->window()->findChildren<QPushButton *>();
1804 for (int i = 0; i < list.size(); ++i) {
1805 QPushButton *pBtn = list.at(i);
1806 if ((e->type() == QEvent::FocusOut
1807 && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus()))
1809 || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease
1810 || e->type() == QEvent::WindowActivate)
1811 && pBtn->isDefault())) {
1812 if (pBtn->window()->isActiveWindow()) {
1813 startAnimate(AquaPushButton, pBtn);
1824 bool QMacStylePrivate::doAnimate(QMacStylePrivate::Animates as)
1826 if (as == AquaPushButton) {
1827 } else if (as == AquaProgressBar) {
1828 // something for later...
1829 } else if (as == AquaListViewItemOpen) {
1830 // To be revived later...
1835 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1836 QPainter *p, const QStyleOption *opt) const
1844 const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
1845 int width = int(macRect.size.width) + extraWidth;
1846 int height = int(macRect.size.height) + extraHeight;
1848 if (width <= 0 || height <= 0)
1849 return; // nothing to draw
1851 QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1852 + QString::number(bdi->value) + QLatin1Char('_') + QString::number(width)
1853 + QLatin1Char('_') + QString::number(height);
1855 if (!QPixmapCache::find(key, pm)) {
1856 QPixmap activePixmap(width, height);
1857 activePixmap.fill(Qt::transparent);
1860 // Carbon combos don't scale. Therefore we draw it
1861 // ourselves, if a scaled version is needed.
1862 QPainter tmpPainter(&activePixmap);
1863 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1866 QMacCGContext cg(&activePixmap);
1867 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1868 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1872 if (!combo && bdi->value == kThemeButtonOff) {
1875 QImage image = activePixmap.toImage();
1877 for (int y = 0; y < height; ++y) {
1878 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1880 for (int x = 0; x < width; ++x) {
1881 QRgb &pixel = scanLine[x];
1883 int darkest = qRed(pixel);
1884 int mid = qGreen(pixel);
1885 int lightest = qBlue(pixel);
1888 qSwap(darkest, mid);
1890 qSwap(mid, lightest);
1892 qSwap(darkest, mid);
1894 int gray = (mid + 2 * lightest) / 3;
1895 pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1898 pm = QPixmap::fromImage(image);
1900 QImage activeImage = activePixmap.toImage();
1901 QImage colorlessImage;
1903 QPixmap colorlessPixmap(width, height);
1904 colorlessPixmap.fill(Qt::transparent);
1906 QMacCGContext cg(&colorlessPixmap);
1907 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1908 int oldValue = bdi->value;
1909 bdi->value = kThemeButtonOff;
1910 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1911 bdi->value = oldValue;
1912 colorlessImage = colorlessPixmap.toImage();
1915 for (int y = 0; y < height; ++y) {
1916 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1917 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1919 for (int x = 0; x < width; ++x) {
1920 QRgb &colorlessPixel = colorlessScanLine[x];
1921 QRgb activePixel = activeScanLine[x];
1923 if (activePixel != colorlessPixel) {
1924 int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1925 qBlue(activePixel));
1926 QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1927 if (qGray(newPixel) < qGray(colorlessPixel)
1928 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1929 colorlessPixel = newPixel;
1933 pm = QPixmap::fromImage(colorlessImage);
1935 QPixmapCache::insert(key, pm);
1937 p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm);
1940 QMacStyle::QMacStyle()
1943 d = new QMacStylePrivate(this);
1946 QMacStyle::~QMacStyle()
1948 delete qt_mac_backgroundPattern;
1949 qt_mac_backgroundPattern = 0;
1954 Generates the standard widget background pattern.
1956 QPixmap QMacStylePrivate::generateBackgroundPattern() const
1959 QMacCGContext cg(&px);
1960 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
1961 const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
1962 CGContextFillRect(cg, cgRect);
1967 Fills the given \a rect with the pattern stored in \a brush. As an optimization,
1968 HIThemeSetFill us used directly if we are filling with the standard background.
1970 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
1973 const QPaintDevice *target = painter->device();
1974 const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
1975 //const bool usePainter = redirected && redirected != target;
1978 if (!usePainter && qt_mac_backgroundPattern
1979 && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
1981 painter->setClipRegion(rgn);
1983 QCFType<CGContextRef> cg = qt_mac_cg_context(target);
1984 CGContextSaveGState(cg);
1985 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
1987 const QVector<QRect> &rects = rgn.rects();
1988 for (int i = 0; i < rects.size(); ++i) {
1989 const QRect rect(rects.at(i));
1990 // Anchor the pattern to the top so it stays put when the window is resized.
1991 CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
1992 CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1993 CGContextFillRect(cg, mac_rect);
1996 CGContextRestoreGState(cg);
1999 const QRect rect(rgn.boundingRect());
2000 painter->setClipRegion(rgn);
2001 painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
2005 void QMacStyle::polish(QPalette &pal)
2007 if (!qt_mac_backgroundPattern) {
2010 qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
2013 QColor pc(Qt::black);
2014 pc = qcolorForTheme(kThemeBrushDialogBackgroundActive);
2015 QBrush background(pc, *qt_mac_backgroundPattern);
2016 pal.setBrush(QPalette::All, QPalette::Window, background);
2017 pal.setBrush(QPalette::All, QPalette::Button, background);
2020 const OSErr err = CopyThemeIdentifier(&theme);
2021 if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
2022 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
2024 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
2028 void QMacStyle::polish(QApplication *)
2032 void QMacStyle::unpolish(QApplication *)
2036 void QMacStyle::polish(QWidget* w)
2039 if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
2040 // Set a clear brush so that the metal shines through.
2041 QPalette pal = w->palette();
2042 QBrush background(Qt::transparent);
2043 pal.setBrush(QPalette::All, QPalette::Window, background);
2044 pal.setBrush(QPalette::All, QPalette::Button, background);
2046 w->setAttribute(Qt::WA_SetPalette, false);
2049 if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
2050 w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
2051 if (!w->testAttribute(Qt::WA_SetPalette)) {
2054 HIThemeMenuDrawInfo mtinfo;
2055 mtinfo.version = qt_mac_hitheme_version;
2056 mtinfo.menuType = kThemeMenuTypePopUp;
2057 HIRect rect = CGRectMake(0, 0, px.width(), px.height());
2059 //HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
2060 // kHIThemeOrientationNormal);
2061 QPalette pal = w->palette();
2062 QBrush background(px);
2063 pal.setBrush(QPalette::All, QPalette::Window, background);
2064 pal.setBrush(QPalette::All, QPalette::Button, background);
2066 w->setAttribute(Qt::WA_SetPalette, false);
2070 if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
2071 if (tb->documentMode()) {
2072 w->setAttribute(Qt::WA_Hover);
2073 w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2074 QPalette p = w->palette();
2075 p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2080 QWindowsStyle::polish(w);
2082 if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2083 rubber->setWindowOpacity(0.25);
2084 rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2085 rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2089 void QMacStyle::unpolish(QWidget* w)
2092 if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
2093 QPalette pal = qApp->palette(w);
2095 w->setAttribute(Qt::WA_SetPalette, false);
2096 w->setWindowOpacity(1.0);
2099 if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2100 if (!combo->isEditable()) {
2101 if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
2102 widget->setWindowOpacity(1.0);
2106 if (QRubberBand *rubber = ::qobject_cast<QRubberBand*>(w)) {
2107 rubber->setWindowOpacity(1.0);
2108 rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2109 rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2112 if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
2113 frame->setAttribute(Qt::WA_NoSystemBackground, true);
2115 QWindowsStyle::unpolish(w);
2118 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
2120 int controlSize = getControlSize(opt, widget);
2124 case PM_TabCloseIndicatorWidth:
2125 case PM_TabCloseIndicatorHeight:
2126 ret = closeButtonSize;
2128 case PM_ToolBarIconSize:
2129 ret = proxy()->pixelMetric(PM_LargeIconSize);
2131 case PM_FocusFrameVMargin:
2132 case PM_FocusFrameHMargin:
2133 GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
2135 case PM_DialogButtonsSeparator:
2138 case PM_DialogButtonsButtonHeight: {
2140 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2141 if (sz == QSize(-1, -1))
2146 case PM_CheckListButtonSize: {
2147 switch (d->aquaSizeConstrain(opt, widget)) {
2148 case QAquaSizeUnknown:
2149 case QAquaSizeLarge:
2150 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2153 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2155 case QAquaSizeSmall:
2156 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2160 case PM_DialogButtonsButtonWidth: {
2162 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2163 if (sz == QSize(-1, -1))
2169 case PM_MenuBarHMargin:
2173 case PM_MenuBarVMargin:
2177 case QStyle::PM_MenuDesktopFrameWidth:
2181 case PM_CheckBoxLabelSpacing:
2182 case PM_RadioButtonLabelSpacing:
2185 case PM_MenuScrollerHeight:
2188 GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2191 ret = 15; // I hate having magic numbers in here...
2194 case PM_DefaultFrameWidth:
2195 #ifndef QT_NO_MAINWINDOW
2196 if (widget && (widget->isWindow() || !widget->parentWidget()
2197 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2198 && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2199 && (qobject_cast<const QAbstractScrollArea *>(widget)
2200 || widget->inherits("QWorkspaceChild")))
2204 // The combo box popup has no frame.
2205 if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2207 // Frame of mac style line edits is two pixels on top and one on the bottom
2208 else if (qobject_cast<const QLineEdit *>(widget) != 0)
2213 case PM_MaximumDragDistance:
2216 case PM_ScrollBarSliderMin:
2219 case PM_SpinBoxFrameWidth:
2220 GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2221 switch (d->aquaSizeConstrain(opt, widget)) {
2230 case PM_ButtonShiftHorizontal:
2231 case PM_ButtonShiftVertical:
2234 case PM_SliderLength:
2237 case PM_ButtonDefaultIndicator:
2240 case PM_TitleBarHeight:
2241 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2242 HIThemeWindowDrawInfo wdi;
2243 wdi.version = qt_mac_hitheme_version;
2244 wdi.state = kThemeStateActive;
2245 wdi.windowType = QtWinType;
2246 if (tb->titleBarState)
2247 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2248 | kThemeWindowHasCollapseBox;
2249 else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2250 wdi.attributes = kThemeWindowHasCloseBox;
2253 wdi.titleHeight = tb->rect.height();
2254 wdi.titleWidth = tb->rect.width();
2255 QCFType<HIShapeRef> region;
2256 HIRect hirect = qt_hirectForQRect(tb->rect);
2257 if (hirect.size.width <= 0)
2258 hirect.size.width = 100;
2259 if (hirect.size.height <= 0)
2260 hirect.size.height = 30;
2262 HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, ®ion);
2264 ptrHIShapeGetBounds(region, &rect);
2265 ret = int(rect.size.height);
2269 case PM_TabBarTabVSpace:
2272 case PM_TabBarTabShiftHorizontal:
2273 case PM_TabBarTabShiftVertical:
2276 case PM_TabBarBaseHeight:
2279 case PM_TabBarTabOverlap:
2282 case PM_TabBarBaseOverlap:
2283 switch (d->aquaSizeConstrain(opt, widget)) {
2284 case QAquaSizeUnknown:
2285 case QAquaSizeLarge:
2288 case QAquaSizeSmall:
2296 case PM_ScrollBarExtent: {
2297 switch (d->aquaSizeConstrain(opt, widget)) {
2298 case QAquaSizeUnknown:
2299 case QAquaSizeLarge:
2300 GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2303 case QAquaSizeSmall:
2304 GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2308 case PM_IndicatorHeight: {
2309 switch (d->aquaSizeConstrain(opt, widget)) {
2310 case QAquaSizeUnknown:
2311 case QAquaSizeLarge:
2312 GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2315 GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2317 case QAquaSizeSmall:
2318 GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2322 case PM_IndicatorWidth: {
2323 switch (d->aquaSizeConstrain(opt, widget)) {
2324 case QAquaSizeUnknown:
2325 case QAquaSizeLarge:
2326 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2329 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2331 case QAquaSizeSmall:
2332 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2337 case PM_ExclusiveIndicatorHeight: {
2338 switch (d->aquaSizeConstrain(opt, widget)) {
2339 case QAquaSizeUnknown:
2340 case QAquaSizeLarge:
2341 GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2344 GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2346 case QAquaSizeSmall:
2347 GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2351 case PM_ExclusiveIndicatorWidth: {
2352 switch (d->aquaSizeConstrain(opt, widget)) {
2353 case QAquaSizeUnknown:
2354 case QAquaSizeLarge:
2355 GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2358 GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2360 case QAquaSizeSmall:
2361 GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2366 case PM_MenuVMargin:
2369 case PM_MenuPanelWidth:
2372 case PM_ToolTipLabelFrameWidth:
2375 case PM_SizeGripSize: {
2376 QAquaWidgetSize aSize;
2377 if (widget && widget->window()->windowType() == Qt::Tool)
2378 aSize = QAquaSizeSmall;
2380 aSize = QAquaSizeLarge;
2381 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2384 case PM_MdiSubWindowFrameWidth:
2387 case PM_DockWidgetFrameWidth:
2390 case PM_DockWidgetTitleMargin:
2393 case PM_DockWidgetSeparatorExtent:
2396 case PM_ToolBarHandleExtent:
2399 case PM_ToolBarItemMargin:
2402 case PM_ToolBarItemSpacing:
2405 case PM_SplitterWidth:
2406 ret = qMax(7, QApplication::globalStrut().width());
2408 case PM_LayoutLeftMargin:
2409 case PM_LayoutTopMargin:
2410 case PM_LayoutRightMargin:
2411 case PM_LayoutBottomMargin:
2413 bool isWindow = false;
2415 isWindow = (opt->state & State_Window);
2416 } else if (widget) {
2417 isWindow = widget->isWindow();
2421 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2423 if (metric == PM_LayoutTopMargin) {
2424 return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2425 } else if (metric == PM_LayoutBottomMargin) {
2426 return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2428 return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2432 AHIG would have (20, 8, 10) here but that makes
2433 no sense. It would also have 14 for the top margin
2434 but this contradicts both Builder and most
2437 return_SIZE(20, 10, 10); // AHIG
2440 // hack to detect QTabWidget
2441 if (widget && widget->parentWidget()
2442 && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2443 if (metric == PM_LayoutTopMargin) {
2445 Builder would have 14 (= 20 - 6) instead of 12,
2446 but that makes the tab look disproportionate.
2448 return_SIZE(12, 6, 6); // guess
2450 return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2454 Child margins are highly inconsistent in AHIG and Builder.
2456 return_SIZE(12, 8, 6); // guess
2460 case PM_LayoutHorizontalSpacing:
2461 case PM_LayoutVerticalSpacing:
2463 case QStyle::PM_TabBarTabHSpace:
2464 switch (d->aquaSizeConstrain(opt, widget)) {
2465 case QAquaSizeLarge:
2466 case QAquaSizeUnknown:
2467 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2469 case QAquaSizeSmall:
2477 case PM_MenuHMargin:
2480 case PM_ToolBarFrameWidth:
2483 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->parent()))
2484 if (mainWindow->unifiedTitleAndToolBarOnMac())
2489 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2495 QPalette QMacStyle::standardPalette() const
2497 QPalette pal = QWindowsStyle::standardPalette();
2498 pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2499 pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2500 pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2504 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2505 QStyleHintReturn *hret) const
2509 case SH_Menu_SelectionWrap:
2512 case SH_Menu_KeyboardSearch:
2515 case SH_Menu_SpaceActivatesItem:
2518 case SH_Slider_AbsoluteSetButtons:
2519 ret = Qt::LeftButton|Qt::MidButton;
2521 case SH_Slider_PageSetButtons:
2524 case SH_ScrollBar_ContextMenu:
2527 case SH_TitleBar_AutoRaise:
2530 case SH_Menu_AllowActiveAndDisabled:
2533 case SH_Menu_SubMenuPopupDelay:
2536 case SH_ScrollBar_LeftClickAbsolutePosition: {
2537 if(QApplication::keyboardModifiers() & Qt::AltModifier)
2539 //ret = !qt_scrollbar_jump_to_pos;
2542 //ret = qt_scrollbar_jump_to_pos;
2544 case SH_TabBar_PreferNoArrows:
2547 case SH_LineEdit_PasswordCharacter:
2548 ret = kBulletUnicode;
2551 case SH_DialogButtons_DefaultButton:
2552 ret = QDialogButtons::Reject;
2555 case SH_Menu_SloppySubMenus:
2558 case SH_GroupBox_TextLabelVerticalAlignment:
2561 case SH_ScrollView_FrameOnlyAroundContents:
2562 if (w && (w->isWindow() || !w->parentWidget() || w->parentWidget()->isWindow())
2563 && (w->inherits("QWorkspaceChild")
2567 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2569 case SH_Menu_FillScreenWithScroll:
2572 case SH_Menu_Scrollable:
2575 case SH_RichText_FullWidthSelection:
2578 case SH_BlinkCursorWhenTextSelected:
2581 case SH_ScrollBar_StopMouseOverSlider:
2584 case SH_Q3ListViewExpand_SelectMouseType:
2585 ret = QEvent::MouseButtonRelease;
2587 case SH_TabBar_SelectMouseType:
2588 if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2589 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2591 ret = QEvent::MouseButtonRelease;
2594 case SH_ComboBox_Popup:
2595 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2596 ret = !cmb->editable;
2600 case SH_Workspace_FillSpaceOnMaximize:
2603 case SH_Widget_ShareActivation:
2606 case SH_Header_ArrowAlignment:
2607 ret = Qt::AlignRight;
2609 case SH_TabBar_Alignment: {
2610 if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2611 if (tab->documentMode()) {
2612 ret = Qt::AlignLeft;
2616 if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2617 if (tab->documentMode()) {
2618 ret = Qt::AlignLeft;
2622 ret = Qt::AlignCenter;
2624 case SH_UnderlineShortcut:
2627 case SH_ToolTipLabel_Opacity:
2628 ret = 242; // About 95%
2630 case SH_Button_FocusPolicy:
2633 case SH_EtchDisabledText:
2636 case SH_FocusFrame_Mask: {
2638 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2639 const uchar fillR = 192, fillG = 191, fillB = 190;
2642 QSize pixmapSize = opt->rect.size();
2643 if (pixmapSize.isValid()) {
2644 QPixmap pix(pixmapSize);
2645 pix.fill(QColor(fillR, fillG, fillB));
2646 QPainter pix_paint(&pix);
2647 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w);
2649 img = pix.toImage();
2652 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2653 const int sbpl = img.bytesPerLine();
2654 const int w = sbpl/4, h = img.height();
2656 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2657 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2658 const int dbpl = img_mask.bytesPerLine();
2660 for (int y = 0; y < h; ++y) {
2661 srow = sptr+((y*sbpl)/4);
2662 drow = dptr+((y*dbpl)/4);
2663 for (int x = 0; x < w; ++x) {
2664 const int diff = (((qRed(*srow)-fillR)*(qRed(*srow)-fillR)) +
2665 ((qGreen(*srow)-fillG)*((qGreen(*srow)-fillG))) +
2666 ((qBlue(*srow)-fillB)*((qBlue(*srow)-fillB))));
2667 (*drow++) = (diff < 100) ? 0xffffffff : 0xff000000;
2671 QBitmap qmask = QBitmap::fromImage(img_mask);
2672 mask->region = QRegion(qmask);
2675 case SH_TitleBar_NoBorder:
2678 case SH_RubberBand_Mask:
2681 case SH_ComboBox_LayoutDirection:
2682 ret = Qt::LeftToRight;
2684 case SH_ItemView_EllipsisLocation:
2685 ret = Qt::AlignHCenter;
2687 case SH_ItemView_ShowDecorationSelected:
2690 case SH_TitleBar_ModifyNotification:
2693 case SH_ScrollBar_RollBetweenButtons:
2696 case SH_WindowFrame_Mask:
2698 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2699 mask->region = opt->rect;
2700 mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2701 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2702 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2703 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2705 mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2706 mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2707 mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2708 mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2711 case SH_TabBar_ElideMode:
2712 ret = Qt::ElideRight;
2714 case SH_DialogButtonLayout:
2715 ret = QDialogButtonBox::MacLayout;
2717 case SH_FormLayoutWrapPolicy:
2718 ret = QFormLayout::DontWrapRows;
2720 case SH_FormLayoutFieldGrowthPolicy:
2721 ret = QFormLayout::FieldsStayAtSizeHint;
2723 case SH_FormLayoutFormAlignment:
2724 ret = Qt::AlignHCenter | Qt::AlignTop;
2726 case SH_FormLayoutLabelAlignment:
2727 ret = Qt::AlignRight;
2729 case SH_ComboBox_PopupFrameStyle:
2730 ret = QFrame::NoFrame | QFrame::Plain;
2732 case SH_MessageBox_TextInteractionFlags:
2733 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2735 case SH_SpellCheckUnderlineStyle:
2736 ret = QTextCharFormat::DashUnderline;
2738 case SH_MessageBox_CenterButtons:
2741 case SH_MenuBar_AltKeyNavigation:
2744 case SH_ItemView_MovementWithoutUpdatingSelection:
2747 case SH_FocusFrame_AboveWidget:
2750 case SH_WizardStyle:
2751 ret = QWizard::MacStyle;
2753 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2756 case SH_Menu_FlashTriggeredItem:
2759 case SH_Menu_FadeOutOnHide:
2764 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2766 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2767 opt->rect.width(), opt->rect.height() - 8);
2768 HIThemeMenuDrawInfo mdi;
2770 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2771 mdi.menuType = kThemeMenuTypeHierarchical;
2773 mdi.menuType = kThemeMenuTypePopUp;
2774 QCFType<HIShapeRef> shape;
2775 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2777 mask->region = qt_mac_fromHIShapeRef(shape);
2781 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2784 case SH_TabBar_CloseButtonPosition:
2785 ret = QTabBar::LeftSide;
2787 case SH_DockWidget_ButtonsHaveFrame:
2791 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2797 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2798 const QStyleOption *opt) const
2801 case QIcon::Disabled: {
2802 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2803 int imgh = img.height();
2804 int imgw = img.width();
2806 for (int y = 0; y < imgh; ++y) {
2807 for (int x = 0; x < imgw; ++x) {
2808 pixel = img.pixel(x, y);
2809 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2810 qAlpha(pixel) / 2));
2813 return QPixmap::fromImage(img);
2818 return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt);
2822 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2823 const QWidget *widget) const
2825 // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2826 // I don't want infinite recursion so if we do get in that situation, just return the Window's
2827 // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2828 // someone changes how Windows standard
2830 static bool recursionGuard = false;
2833 return QWindowsStyle::standardPixmap(standardPixmap, opt, widget);
2835 recursionGuard = true;
2836 QIcon icon = standardIconImplementation(standardPixmap, opt, widget);
2837 recursionGuard = false;
2839 switch (standardPixmap) {
2843 case SP_MessageBoxCritical:
2844 case SP_MessageBoxQuestion:
2845 case SP_MessageBoxInformation:
2846 case SP_MessageBoxWarning:
2850 return icon.pixmap(size, size);
2853 void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
2860 w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
2865 QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
2867 return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
2870 void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
2872 QWidget *wadget = const_cast<QWidget *>(widget);
2873 wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge);
2874 wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall);
2875 wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini);
2878 QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget)
2881 if (widget->testAttribute(Qt::WA_MacMiniSize)) {
2883 } else if (widget->testAttribute(Qt::WA_MacSmallSize)) {
2885 } else if (widget->testAttribute(Qt::WA_MacNormalSize)) {
2888 widget = widget->parentWidget();
2893 void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
2894 const QWidget *w) const
2896 ThemeDrawState tds = d->getDrawState(opt->state);
2897 QMacCGContext cg(p);
2899 case PE_IndicatorArrowUp:
2900 case PE_IndicatorArrowDown:
2901 case PE_IndicatorArrowRight:
2902 case PE_IndicatorArrowLeft: {
2904 p->setRenderHint(QPainter::Antialiasing);
2905 int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
2907 matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2911 case PE_IndicatorArrowDown:
2913 case PE_IndicatorArrowUp:
2916 case PE_IndicatorArrowLeft:
2919 case PE_IndicatorArrowRight:
2924 path.lineTo(-4, -3);
2926 p->setMatrix(matrix);
2927 p->setPen(Qt::NoPen);
2928 p->setBrush(QColor(0, 0, 0, 135));
2932 case PE_FrameTabBarBase:
2933 if (const QStyleOptionTabBarBaseV2 *tbb
2934 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2935 if (tbb->documentMode) {
2937 drawTabBase(p, tbb, w);
2942 QRegion region(tbb->rect);
2943 region -= tbb->tabBarRect;
2945 p->setClipRegion(region);
2946 QStyleOptionTabWidgetFrame twf;
2947 twf.QStyleOption::operator=(*tbb);
2948 twf.shape = tbb->shape;
2949 switch (getTabDirection(twf.shape)) {
2950 case kThemeTabNorth:
2951 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2953 case kThemeTabSouth:
2954 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2957 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2960 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2963 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
2967 case PE_PanelTipLabel:
2968 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2970 case PE_FrameGroupBox:
2971 if (const QStyleOptionFrame *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2972 const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt);
2973 if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) {
2974 QWindowsStyle::drawPrimitive(pe, groupBox, p, w);
2976 HIThemeGroupBoxDrawInfo gdi;
2977 gdi.version = qt_mac_hitheme_version;
2979 if (w && qobject_cast<QGroupBox *>(w->parentWidget()))
2980 gdi.kind = kHIThemeGroupBoxKindSecondary;
2982 gdi.kind = kHIThemeGroupBoxKindPrimary;
2983 HIRect hirect = qt_hirectForQRect(opt->rect);
2984 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
2988 case PE_IndicatorToolBarSeparator: {
2990 if (opt->state & State_Horizontal) {
2991 int xpoint = opt->rect.center().x();
2992 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2993 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2995 int ypoint = opt->rect.center().y();
2996 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2997 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2999 QPainterPathStroker theStroker;
3000 theStroker.setCapStyle(Qt::FlatCap);
3001 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3002 path = theStroker.createStroke(path);
3003 p->fillPath(path, QColor(0, 0, 0, 119));
3006 case PE_FrameWindow:
3008 case PE_IndicatorDockWidgetResizeHandle: {
3009 // The docwidget resize handle is drawn as a one-pixel wide line.
3011 if (opt->state & State_Horizontal) {
3012 p->setPen(QColor(160, 160, 160));
3013 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3015 p->setPen(QColor(145, 145, 145));
3016 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3020 case PE_IndicatorToolBarHandle: {
3023 int x = opt->rect.x() + 6;
3024 int y = opt->rect.y() + 5;
3025 static const int RectHeight = 2;
3026 if (opt->state & State_Horizontal) {
3027 while (y < opt->rect.height() - RectHeight - 6) {
3029 path.addRect(x, y, RectHeight, RectHeight);
3033 while (x < opt->rect.width() - RectHeight - 6) {
3035 path.addRect(x, y, RectHeight, RectHeight);
3039 p->setPen(Qt::NoPen);
3040 QColor dark = opt->palette.dark().color();
3041 dark.setAlphaF(0.75);
3042 QColor light = opt->palette.light().color();
3043 light.setAlphaF(0.6);
3044 p->fillPath(path, light);
3047 p->fillPath(path, dark);
3050 p->fillPath(path, light);
3052 p->fillPath(path, dark);
3057 case PE_IndicatorHeaderArrow:
3058 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3059 // In HITheme, up is down, down is up and hamburgers eat people.
3060 if (header->sortIndicator != QStyleOptionHeader::None)
3061 proxy()->drawPrimitive(
3062 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3063 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3066 case PE_IndicatorMenuCheckMark: {
3067 const int checkw = 8;
3068 const int checkh = 8;
3069 const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
3070 const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
3071 const int x1 = xoff + opt->rect.x();
3072 const int y1 = yoff + opt->rect.y() + checkw/2;
3073 const int x2 = xoff + opt->rect.x() + checkw/4;
3074 const int y2 = yoff + opt->rect.y() + checkh;
3075 const int x3 = xoff + opt->rect.x() + checkw;
3076 const int y3 = yoff + opt->rect.y();
3078 QVector<QLineF> a(2);
3079 a << QLineF(x1, y1, x2, y2);
3080 a << QLineF(x2, y2, x3, y3);
3081 if (opt->palette.currentColorGroup() == QPalette::Active) {
3082 if (opt->state & State_On)
3083 p->setPen(QPen(opt->palette.highlightedText().color(), 3));
3085 p->setPen(QPen(opt->palette.text().color(), 3));
3087 p->setPen(QPen(QColor(100, 100, 100), 3));
3090 p->setRenderHint(QPainter::Antialiasing);
3094 case PE_IndicatorViewItemCheck:
3095 case PE_Q3CheckListExclusiveIndicator:
3096 case PE_Q3CheckListIndicator:
3097 case PE_IndicatorRadioButton:
3098 case PE_IndicatorCheckBox: {
3099 bool drawColorless = (!(opt->state & State_Active))
3100 && opt->palette.currentColorGroup() == QPalette::Active;
3101 HIThemeButtonDrawInfo bdi;
3102 bdi.version = qt_mac_hitheme_version;
3104 if (drawColorless && tds == kThemeStateInactive)
3105 bdi.state = kThemeStateActive;
3106 bdi.adornment = kThemeDrawIndicatorOnly;
3107 if (opt->state & State_HasFocus)
3108 bdi.adornment |= kThemeAdornmentFocus;
3109 bool isRadioButton = (pe == PE_Q3CheckListExclusiveIndicator
3110 || pe == PE_IndicatorRadioButton);
3111 switch (d->aquaSizeConstrain(opt, w)) {
3112 case QAquaSizeUnknown:
3113 case QAquaSizeLarge:
3115 bdi.kind = kThemeRadioButton;
3117 bdi.kind = kThemeCheckBox;
3121 bdi.kind = kThemeMiniRadioButton;
3123 bdi.kind = kThemeMiniCheckBox;
3125 case QAquaSizeSmall:
3127 bdi.kind = kThemeSmallRadioButton;
3129 bdi.kind = kThemeSmallCheckBox;
3132 if (opt->state & State_NoChange)
3133 bdi.value = kThemeButtonMixed;
3134 else if (opt->state & State_On)
3135 bdi.value = kThemeButtonOn;
3137 bdi.value = kThemeButtonOff;
3139 if (pe == PE_Q3CheckListExclusiveIndicator || pe == PE_Q3CheckListIndicator)
3140 macRect = qt_hirectForQRect(opt->rect);
3142 macRect = qt_hirectForQRect(opt->rect);
3144 HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3146 d->drawColorlessButton(macRect, &bdi, p, opt);
3148 case PE_FrameFocusRect:
3149 // Use the our own focus widget stuff.
3151 case PE_IndicatorBranch: {
3152 if (!(opt->state & State_Children))
3154 HIThemeButtonDrawInfo bi;
3155 bi.version = qt_mac_hitheme_version;
3157 if (tds == kThemeStateInactive && opt->palette.currentColorGroup() == QPalette::Active)
3158 bi.state = kThemeStateActive;
3159 if (opt->state & State_Sunken)
3160 bi.state |= kThemeStatePressed;
3161 bi.kind = kThemeDisclosureButton;
3162 if (opt->state & State_Open)
3163 bi.value = kThemeDisclosureDown;
3165 bi.value = opt->direction == Qt::LeftToRight ? kThemeDisclosureRight : kThemeDisclosureLeft;
3166 bi.adornment = kThemeAdornmentNone;
3167 HIRect hirect = qt_hirectForQRect(opt->rect.adjusted(DisclosureOffset,0,-DisclosureOffset,0));
3168 HIThemeDrawButton(&hirect, &bi, cg, kHIThemeOrientationNormal, 0);
3172 QPen oldPen = p->pen();
3173 p->setPen(opt->palette.base().color().darker(140));
3174 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3175 p->setPen(opt->palette.base().color().darker(180));
3176 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3180 case PE_FrameLineEdit:
3181 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3182 if (frame->state & State_Sunken) {
3183 QColor baseColor(frame->palette.background().color());
3184 HIThemeFrameDrawInfo fdi;
3185 fdi.version = qt_mac_hitheme_version;
3188 if (pe == PE_FrameLineEdit) {
3189 fdi.kind = kHIThemeFrameTextFieldSquare;
3190 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
3191 if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled))
3192 fdi.state = kThemeStateInactive;
3194 baseColor = QColor(150, 150, 150); //hardcoded since no query function --Sam
3195 fdi.kind = kHIThemeFrameListBox;
3196 GetThemeMetric(kThemeMetricListBoxFrameOutset, &frame_size);
3198 fdi.isFocused = (frame->state & State_HasFocus);
3199 int lw = frame->lineWidth;
3201 lw = proxy()->pixelMetric(PM_DefaultFrameWidth, frame, w);
3202 { //clear to base color
3204 p->setPen(QPen(baseColor, lw));
3205 p->setBrush(Qt::NoBrush);
3206 p->drawRect(frame->rect);
3209 HIRect hirect = qt_hirectForQRect(frame->rect,
3210 QRect(frame_size, frame_size,
3211 frame_size * 2, frame_size * 2));
3213 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
3215 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3219 case PE_PanelLineEdit:
3220 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3221 // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit).
3222 // Focus frame is drawn outside the rectangle passed in the option-rect.
3223 if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3224 if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(w)) {
3225 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3226 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3227 QStyleOptionFrame focusFrame = *panel;
3228 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3229 drawControl(CE_FocusFrame, &focusFrame, p, w);
3234 case PE_FrameTabWidget:
3235 if (const QStyleOptionTabWidgetFrame *twf
3236 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
3237 HIRect hirect = qt_hirectForQRect(twf->rect);
3238 HIThemeTabPaneDrawInfo tpdi;
3239 tpdi.version = qt_mac_hitheme_tab_version();
3241 tpdi.direction = getTabDirection(twf->shape);
3242 tpdi.size = kHIThemeTabSizeNormal;
3243 tpdi.kind = kHIThemeTabKindNormal;
3244 tpdi.adornment = kHIThemeTabPaneAdornmentNormal;
3245 HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal);
3248 case PE_PanelScrollAreaCorner: {
3249 const QBrush brush(opt->palette.brush(QPalette::Base));
3250 p->fillRect(opt->rect, brush);
3251 p->setPen(QPen(QColor(217, 217, 217)));
3252 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3253 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3255 case PE_FrameStatusBarItem:
3257 case PE_IndicatorTabClose: {
3258 bool hover = (opt->state & State_MouseOver);
3259 bool selected = (opt->state & State_Selected);
3260 bool active = (opt->state & State_Active);
3261 drawTabCloseButton(p, hover, active, selected);
3263 case PE_PanelStatusBar: {
3264 if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) {
3265 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3268 // Use the Leopard style only if the status bar is the status bar for a
3269 // QMainWindow with a unifed toolbar.
3270 if (w == 0 || w->parent() == 0 || qobject_cast<QMainWindow *>(w->parent()) == 0 ||
3271 qobject_cast<QMainWindow *>(w->parent())->unifiedTitleAndToolBarOnMac() == false ) {
3272 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3276 // Fill the status bar with the titlebar gradient.
3277 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3278 if (opt->state & QStyle::State_Active) {
3279 linearGrad.setColorAt(0, titlebarGradientActiveBegin);
3280 linearGrad.setColorAt(1, titlebarGradientActiveEnd);
3282 linearGrad.setColorAt(0, titlebarGradientInactiveBegin);
3283 linearGrad.setColorAt(1, titlebarGradientInactiveEnd);
3285 p->fillRect(opt->rect, linearGrad);
3287 // Draw the black separator line at the top of the status bar.
3288 if (opt->state & QStyle::State_Active)
3289 p->setPen(titlebarSeparatorLineActive);
3291 p->setPen(titlebarSeparatorLineInactive);
3292 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3298 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3303 static inline QPixmap darkenPixmap(const QPixmap &pixmap)
3305 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
3306 int imgh = img.height();
3307 int imgw = img.width();
3310 for (int y = 0; y < imgh; ++y) {
3311 for (int x = 0; x < imgw; ++x) {
3312 pixel = img.pixel(x, y);
3314 QColor hsvColor(pixel);
3315 hsvColor.getHsv(&h, &s, &v);
3316 s = qMin(100, s * 2);
3318 hsvColor.setHsv(h, s, v);
3319 pixel = hsvColor.rgb();
3320 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3323 return QPixmap::fromImage(img);
3328 void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3329 const QWidget *w) const
3331 ThemeDrawState tds = d->getDrawState(opt->state);
3332 QMacCGContext cg(p);
3334 case CE_HeaderSection:
3335 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3336 HIThemeButtonDrawInfo bdi;
3337 bdi.version = qt_mac_hitheme_version;
3338 State flags = header->state;
3339 QRect ir = header->rect;
3340 bdi.kind = kThemeListHeaderButton;
3341 bdi.adornment = kThemeAdornmentNone;
3342 bdi.state = kThemeStateActive;
3344 if (flags & State_On)
3345 bdi.value = kThemeButtonOn;
3347 bdi.value = kThemeButtonOff;
3349 if (header->orientation == Qt::Horizontal){
3350 switch (header->position) {
3351 case QStyleOptionHeader::Beginning:
3352 ir.adjust(-1, -1, 0, 0);
3354 case QStyleOptionHeader::Middle:
3355 ir.adjust(-1, -1, 0, 0);
3357 case QStyleOptionHeader::OnlyOneSection:
3358 case QStyleOptionHeader::End:
3359 ir.adjust(-1, -1, 1, 0);
3365 if (header->position != QStyleOptionHeader::Beginning
3366 && header->position != QStyleOptionHeader::OnlyOneSection) {
3367 bdi.adornment = header->direction == Qt::LeftToRight
3368 ? kThemeAdornmentHeaderButtonLeftNeighborSelected
3369 : kThemeAdornmentHeaderButtonRightNeighborSelected;
3373 if (flags & State_Active) {
3374 if (!(flags & State_Enabled))
3375 bdi.state = kThemeStateUnavailable;
3376 else if (flags & State_Sunken)
3377 bdi.state = kThemeStatePressed;
3379 if (flags & State_Enabled)
3380 bdi.state = kThemeStateInactive;
3382 bdi.state = kThemeStateUnavailableInactive;
3385 if (header->sortIndicator != QStyleOptionHeader::None) {
3386 bdi.value = kThemeButtonOn;
3387 if (header->sortIndicator == QStyleOptionHeader::SortDown)
3388 bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
3390 if (flags & State_HasFocus)
3391 bdi.adornment = kThemeAdornmentFocus;
3393 ir = visualRect(header->direction, header->rect, ir);
3394 HIRect bounds = qt_hirectForQRect(ir);
3396 bool noVerticalHeader = true;
3398 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3399 noVerticalHeader = !table->verticalHeader()->isVisible();
3401 bool drawTopBorder = header->orientation == Qt::Horizontal;
3402 bool drawLeftBorder = header->orientation == Qt::Vertical
3403 || header->position == QStyleOptionHeader::OnlyOneSection
3404 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3405 d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
3408 case CE_HeaderLabel:
3409 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3410 QRect textr = header->rect;
3411 if (!header->icon.isNull()) {
3412 QIcon::Mode mode = QIcon::Disabled;
3413 if (opt->state & State_Enabled)
3414 mode = QIcon::Normal;
3415 QPixmap pixmap = header->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), mode);
3417 QRect pixr = header->rect;
3418 pixr.setY(header->rect.center().y() - (pixmap.height() - 1) / 2);
3419 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
3420 textr.translate(pixmap.width() + 2, 0);
3423 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
3424 header->state & State_Enabled, header->text, QPalette::ButtonText);
3427 case CE_ToolButtonLabel:
3428 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3429 QStyleOptionToolButton myTb = *tb;
3430 myTb.state &= ~State_AutoRaise;
3431 if (w && qobject_cast<QToolBar *>(w->parentWidget())) {
3432 QRect cr = tb->rect;
3435 bool needText = false;
3437 bool down = tb->state & (State_Sunken | State_On);
3439 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3440 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3442 // The down state is special for QToolButtons in a toolbar on the Mac
3443 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3444 // This doesn't really fit into any particular case in QIcon, so we
3445 // do the majority of the work ourselves.
3446 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3447 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3448 if (tb->icon.isNull() && !tb->text.isEmpty())
3449 tbstyle = Qt::ToolButtonTextOnly;
3452 case Qt::ToolButtonTextOnly: {
3454 alignment = Qt::AlignCenter;
3456 case Qt::ToolButtonIconOnly:
3457 case Qt::ToolButtonTextBesideIcon:
3458 case Qt::ToolButtonTextUnderIcon: {
3460 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3462 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3464 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), iconMode, iconState);
3466 // Draw the text if it's needed.
3467 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3469 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3470 QMainWindow *mw = qobject_cast<QMainWindow *>(w->window());
3471 if (mw && mw->unifiedTitleAndToolBarOnMac()) {
3472 pr.setHeight(pixmap.size().height());
3473 cr.adjust(0, pr.bottom() + 1, 0, 1);
3475 pr.setHeight(pixmap.size().height() + 6);
3476 cr.adjust(0, pr.bottom(), 0, -3);
3478 alignment |= Qt::AlignCenter;
3480 pr.setWidth(pixmap.width() + 8);
3481 cr.adjust(pr.right(), 0, 0, 0);
3482 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3485 if (opt->state & State_Sunken) {
3486 pr.translate(shiftX, shiftY);
3487 pixmap = darkenPixmap(pixmap);
3489 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3497 QPalette pal = tb->palette;
3498 QPalette::ColorRole role = QPalette::NoRole;
3499 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3500 alignment |= Qt::TextHideMnemonic;
3502 cr.translate(shiftX, shiftY);
3503 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5
3504 && (tbstyle == Qt::ToolButtonTextOnly
3505 || (tbstyle != Qt::ToolButtonTextOnly && !down))) {
3506 QPen pen = p->pen();
3507 QColor light = down ? Qt::black : Qt::white;
3508 light.setAlphaF(0.375f);
3510 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3512 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3513 pal = QApplication::palette("QMenu");
3514 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3515 role = QPalette::HighlightedText;
3518 proxy()->drawItemText(p, cr, alignment, pal,
3519 tb->state & State_Enabled, tb->text, role);
3520 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 &&
3521 (tb->state & State_Sunken)) {
3522 // Draw a "drop shadow" in earlier versions.
3523 proxy()->drawItemText(p, cr.adjusted(0, 1, 0, 1), alignment,
3524 tb->palette, tb->state & State_Enabled, tb->text);
3528 QWindowsStyle::drawControl(ce, &myTb, p, w);
3531 QWindowsStyle::drawControl(ce, &myTb, p, w);
3535 case CE_ToolBoxTabShape:
3536 QCommonStyle::drawControl(ce, opt, p, w);
3538 case CE_PushButtonBevel:
3539 if (const QStyleOptionButton *btn = ::qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3540 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3543 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3544 QWindowsStyle::drawControl(ce, opt, p, w);
3548 HIThemeButtonDrawInfo bdi;
3549 d->initHIThemePushButton(btn, w, tds, &bdi);
3550 if (btn->features & QStyleOptionButton::DefaultButton
3551 && d->animatable(QMacStylePrivate::AquaPushButton, w)) {
3552 bdi.adornment |= kThemeAdornmentDefault;
3553 bdi.animation.time.start = d->defaultButtonStart;
3554 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
3555 if (d->timerID <= -1)
3556 QMetaObject::invokeMethod(d, "startAnimationTimer", Qt::QueuedConnection);
3558 // Unlike Carbon, we want the button to always be drawn inside its bounds.
3559 // Therefore, make the button a bit smaller, so that even if it got focus,
3560 // the focus 'shadow' will be inside.
3561 HIRect newRect = qt_hirectForQRect(btn->rect);
3562 if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) {
3563 newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset;
3564 newRect.origin.y += QMacStylePrivate::PushButtonTopOffset;
3565 newRect.size.width -= QMacStylePrivate::PushButtonRightOffset;
3566 newRect.size.height -= QMacStylePrivate::PushButtonBottomOffset;
3567 } else if (bdi.kind == kThemePushButtonMini) {
3568 newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset - 2;
3569 newRect.origin.y += QMacStylePrivate::PushButtonTopOffset;
3570 newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4;
3572 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3574 if (btn->features & QStyleOptionButton::HasMenu) {
3575 int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3576 QRect ir = btn->rect;
3577 HIRect arrowRect = CGRectMake(ir.right() - mbi - QMacStylePrivate::PushButtonRightOffset,
3578 ir.height() / 2 - 4, mbi, ir.height() / 2);
3579 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
3580 if (drawColorless && tds == kThemeStateInactive)
3581 tds = kThemeStateActive;
3583 HIThemePopupArrowDrawInfo pdi;
3584 pdi.version = qt_mac_hitheme_version;
3586 pdi.orientation = kThemeArrowDown;
3587 if (arrowRect.size.width < 8.)
3588 pdi.size = kThemeArrow5pt;
3590 pdi.size = kThemeArrow9pt;
3591 HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal);
3595 case CE_PushButtonLabel:
3596 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3597 // We really don't want the label to be drawn the same as on
3598 // windows style if it has an icon and text, then it should be more like a
3599 // tab. So, cheat a little here. However, if it *is* only an icon
3600 // the windows style works great, so just use that implementation.
3601 bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3602 bool hasIcon = !btn->icon.isNull();
3603 bool hasText = !btn->text.isEmpty();
3604 if (!hasIcon && !hasMenu) {
3605 // ### this is really overly difficult, simplify.
3606 // It basically tries to get the right font for "small" and "mini" icons.
3607 QFont oldFont = p->font();
3608 QFont newFont = qt_app_fonts_hash()->value("QPushButton", QFont());
3609 ThemeFontID themeId = kThemePushButtonFont;
3610 if (oldFont == newFont) { // Yes, use HITheme to draw the text for small sizes.
3611 switch (d->aquaSizeConstrain(opt, w)) {
3614 case QAquaSizeSmall:
3615 themeId = kThemeSmallSystemFont;
3618 themeId = kThemeMiniSystemFont;
3622 if (themeId == kThemePushButtonFont) {
3623 QWindowsStyle::drawControl(ce, btn, p, w);
3626 CGContextSetShouldAntialias(cg, true);
3627 CGContextSetShouldSmoothFonts(cg, true);
3628 HIThemeTextInfo tti;
3629 tti.version = qt_mac_hitheme_version;
3631 QColor textColor = btn->palette.buttonText().color();
3632 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3633 textColor.blueF(), textColor.alphaF() };
3634 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
3635 CGContextSetFillColor(cg, colorComp);
3636 tti.fontID = themeId;
3637 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3638 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3639 tti.options = kHIThemeTextBoxOptionNone;
3640 tti.truncationPosition = kHIThemeTextTruncationNone;
3641 tti.truncationMaxLines = 1 + btn->text.count(QLatin1Char('\n'));
3642 QCFString buttonText = qt_mac_removeMnemonics(btn->text);
3643 QRect r = btn->rect;
3644 HIRect bounds = qt_hirectForQRect(r);
3645 HIThemeDrawTextBox(buttonText, &bounds, &tti,
3646 cg, kHIThemeOrientationNormal);
3650 if (hasIcon && !hasText) {
3651 QWindowsStyle::drawControl(ce, btn, p, w);
3653 QRect freeContentRect = btn->rect;
3654 QRect textRect = itemTextRect(
3655 btn->fontMetrics, freeContentRect, Qt::AlignCenter, btn->state & State_Enabled, btn->text);
3657 textRect.adjust(-1, 0, -1, 0);
3660 int contentW = textRect.width();
3662 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3663 QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3664 if (mode == QIcon::Normal && btn->state & State_HasFocus)
3665 mode = QIcon::Active;
3666 // Decide if the icon is should be on or off:
3667 QIcon::State state = QIcon::Off;
3668 if (btn->state & State_On)
3670 QPixmap pixmap = btn->icon.pixmap(btn->iconSize, mode, state);
3671 contentW += pixmap.width() + QMacStylePrivate::PushButtonContentPadding;
3672 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3673 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmap.height()) / 2;
3674 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmap.width(), pixmap.height());
3675 QRect visualIconDestRect = visualRect(btn->direction, freeContentRect, iconDestRect);
3676 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3677 int newOffset = iconDestRect.x() + iconDestRect.width()
3678 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
3679 textRect.adjust(newOffset, 0, newOffset, 0);
3683 textRect = visualRect(btn->direction, freeContentRect, textRect);
3684 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn->palette,
3685 (btn->state & State_Enabled), btn->text, QPalette::ButtonText);
3691 case CE_ComboBoxLabel:
3692 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3693 QStyleOptionComboBox comboCopy = *cb;
3694 comboCopy.direction = Qt::LeftToRight;
3695 QWindowsStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
3698 case CE_TabBarTabShape:
3699 if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3701 if (const QStyleOptionTabV3 *tabOptV3 = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
3702 if (tabOptV3->documentMode) {
3704 QRect tabRect = tabOptV3->rect;
3705 drawTabShape(p, tabOptV3);
3710 HIThemeTabDrawInfo tdi;
3712 tdi.style = kThemeTabNonFront;
3713 tdi.direction = getTabDirection(tabOpt->shape);
3714 switch (d->aquaSizeConstrain(opt, w)) {
3716 case QAquaSizeUnknown:
3717 case QAquaSizeLarge:
3718 tdi.size = kHIThemeTabSizeNormal;
3720 case QAquaSizeSmall:
3721 tdi.size = kHIThemeTabSizeSmall;
3724 tdi.size = kHIThemeTabSizeMini;
3727 bool verticalTabs = tdi.direction == kThemeTabWest || tdi.direction == kThemeTabEast;
3728 QRect tabRect = tabOpt->rect;
3730 bool selected = tabOpt->state & State_Selected;
3732 if (!(tabOpt->state & State_Active))
3733 tdi.style = kThemeTabFrontUnavailable;
3734 else if (!(tabOpt->state & State_Enabled))
3735 tdi.style = kThemeTabFrontInactive;
3737 tdi.style = kThemeTabFront;
3738 } else if (!(tabOpt->state & State_Active)) {
3739 tdi.style = kThemeTabNonFrontUnavailable;
3740 } else if (!(tabOpt->state & State_Enabled)) {
3741 tdi.style = kThemeTabNonFrontInactive;
3742 } else if (tabOpt->state & State_Sunken) {
3743 tdi.style = kThemeTabFrontInactive; // (should be kThemeTabNonFrontPressed)
3745 if (tabOpt->state & State_HasFocus)
3746 tdi.adornment = kHIThemeTabAdornmentFocus;
3748 tdi.adornment = kHIThemeTabAdornmentNone;
3749 tdi.kind = kHIThemeTabKindNormal;
3751 tabRect.setY(tabRect.y() - 1);
3753 tabRect.setX(tabRect.x() - 1);
3754 QStyleOptionTab::TabPosition tp = tabOpt->position;
3755 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3756 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3757 if (sp == QStyleOptionTab::NextIsSelected)
3758 sp = QStyleOptionTab::PreviousIsSelected;
3759 else if (sp == QStyleOptionTab::PreviousIsSelected)
3760 sp = QStyleOptionTab::NextIsSelected;
3762 case QStyleOptionTab::Beginning:
3763 tp = QStyleOptionTab::End;
3765 case QStyleOptionTab::End:
3766 tp = QStyleOptionTab::Beginning;
3772 bool stretchTabs = (!verticalTabs && tabRect.height() > 22) || (verticalTabs && tabRect.width() > 22);
3775 case QStyleOptionTab::Beginning:
3776 tdi.position = kHIThemeTabPositionFirst;
3777 if (sp != QStyleOptionTab::NextIsSelected || stretchTabs)
3778 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3780 case QStyleOptionTab::Middle:
3781 tdi.position = kHIThemeTabPositionMiddle;
3783 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3784 if (sp != QStyleOptionTab::NextIsSelected || stretchTabs) // Also when we're selected.
3785 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3787 case QStyleOptionTab::End:
3788 tdi.position = kHIThemeTabPositionLast;
3790 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3792 case QStyleOptionTab::OnlyOneTab:
3793 tdi.position = kHIThemeTabPositionOnly;
3796 // HITheme doesn't stretch its tabs. Therefore we have to cheat and do the job ourselves.
3798 HIRect hirect = CGRectMake(0, 0, 23, 23);
3800 pm.fill(Qt::transparent);
3802 QMacCGContext pmcg(&pm);
3803 HIThemeDrawTab(&hirect, &tdi, pmcg, kHIThemeOrientationNormal, 0);
3805 QStyleHelper::drawBorderPixmap(pm, p, tabRect, 7, 7, 7, 7);
3807 HIRect hirect = qt_hirectForQRect(tabRect);
3808 HIThemeDrawTab(&hirect, &tdi, cg, kHIThemeOrientationNormal, 0);
3812 case CE_TabBarTabLabel:
3813 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3814 QStyleOptionTabV3 myTab = *tab;
3815 ThemeTabDirection ttd = getTabDirection(myTab.shape);
3816 bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
3818 // Check to see if we use have the same as the system font
3819 // (QComboMenuItem is internal and should never be seen by the
3820 // outside world, unless they read the source, in which case, it's
3821 // their own fault).
3822 bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
3823 if (verticalTabs || nonDefaultFont || !tab->icon.isNull()
3824 || !myTab.leftButtonSize.isNull() || !myTab.rightButtonSize.isNull()) {
3825 int heightOffset = 0;
3828 } else if (nonDefaultFont) {
3829 if (p->fontMetrics().height() == myTab.rect.height())
3832 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3834 if (myTab.documentMode) {
3836 rotateTabPainter(p, myTab.shape, myTab.rect);
3838 QPalette np = tab->palette;
3839 np.setColor(QPalette::WindowText, QColor(255, 255, 255, 75));
3840 QRect nr = subElementRect(SE_TabBarTabText, opt, w);
3842 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic;
3843 proxy()->drawItemText(p, nr, alignment, np, tab->state & State_Enabled,
3844 tab->text, QPalette::WindowText);
3848 QCommonStyle::drawControl(ce, &myTab, p, w);
3851 CGContextSetShouldAntialias(cg, true);
3852 CGContextSetShouldSmoothFonts(cg, true);
3853 HIThemeTextInfo tti;
3854 tti.version = qt_mac_hitheme_version;
3856 QColor textColor = myTab.palette.windowText().color();
3857 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3858 textColor.blueF(), textColor.alphaF() };
3859 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
3860 CGContextSetFillColor(cg, colorComp);
3861 switch (d->aquaSizeConstrain(opt, w)) {
3863 case QAquaSizeUnknown:
3864 case QAquaSizeLarge:
3865 tti.fontID = kThemeSystemFont;
3867 case QAquaSizeSmall:
3868 tti.fontID = kThemeSmallSystemFont;
3871 tti.fontID = kThemeMiniSystemFont;
3874 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3875 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3876 tti.options = verticalTabs ? kHIThemeTextBoxOptionStronglyVertical : kHIThemeTextBoxOptionNone;
3877 tti.truncationPosition = kHIThemeTextTruncationNone;
3878 tti.truncationMaxLines = 1 + myTab.text.count(QLatin1Char('\n'));
3879 QCFString tabText = qt_mac_removeMnemonics(myTab.text);
3880 QRect r = myTab.rect.adjusted(0, 0, 0, -1);
3881 HIRect bounds = qt_hirectForQRect(r);
3882 HIThemeDrawTextBox(tabText, &bounds, &tti, cg, kHIThemeOrientationNormal);
3887 case CE_DockWidgetTitle:
3888 if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(w)) {
3889 bool floating = dockWidget->isFloating();
3891 ThemeDrawState tds = d->getDrawState(opt->state);
3892 HIThemeWindowDrawInfo wdi;
3893 wdi.version = qt_mac_hitheme_version;
3895 wdi.windowType = kThemeMovableDialogWindow;
3896 wdi.titleHeight = opt->rect.height();
3897 wdi.titleWidth = opt->rect.width();
3900 HIRect titleBarRect;
3901 HIRect tmpRect = qt_hirectForQRect(opt->rect);
3903 QCFType<HIShapeRef> titleRegion;
3904 QRect newr = opt->rect.adjusted(0, 0, 2, 0);
3905 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
3906 ptrHIShapeGetBounds(titleRegion, &tmpRect);
3907 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
3908 titleBarRect = qt_hirectForQRect(newr);
3910 QMacCGContext cg(p);
3911 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
3913 // fill title bar background
3914 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3915 linearGrad.setColorAt(0, mainWindowGradientBegin);
3916 linearGrad.setColorAt(1, mainWindowGradientEnd);
3917 p->fillRect(opt->rect, linearGrad);
3919 // draw horizontal lines at top and bottom
3921 p->setPen(mainWindowGradientBegin.lighter(114));
3922 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3923 p->setPen(mainWindowGradientEnd.darker(114));
3924 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
3930 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
3931 if (!dwOpt->title.isEmpty()) {
3932 const QStyleOptionDockWidgetV2 *v2
3933 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt);
3934 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
3936 QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w);
3937 if (verticalTitleBar) {
3938 QRect rect = dwOpt->rect;
3944 titleRect = QRect(r.left() + rect.bottom()
3945 - titleRect.bottom(),
3946 r.top() + titleRect.left() - rect.left(),
3947 titleRect.height(), titleRect.width());
3949 p->translate(r.left(), r.top() + r.width());
3951 p->translate(-r.left(), -r.top());
3954 QFont oldFont = p->font();
3955 p->setFont(qt_app_fonts_hash()->value("QToolButton", p->font()));
3956 QString text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
3958 drawItemText(p, titleRect,
3959 Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette,
3960 dwOpt->state & State_Enabled, text,
3961 QPalette::WindowText);
3962 p->setFont(oldFont);
3966 case CE_FocusFrame: {
3967 int xOff = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, w) + 1;
3968 int yOff = proxy()->pixelMetric(PM_FocusFrameVMargin, opt, w) + 1;
3969 HIRect hirect = CGRectMake(xOff+opt->rect.x(), yOff+opt->rect.y(), opt->rect.width() - 2 * xOff,
3970 opt->rect.height() - 2 * yOff);
3971 HIThemeDrawFocusRect(&hirect, true, QMacCGContext(p), kHIThemeOrientationNormal);
3974 case CE_MenuEmptyArea:
3975 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3976 p->fillRect(mi->rect, opt->palette.background());
3977 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, w);
3978 int tabwidth = mi->tabWidth;
3979 int maxpmw = mi->maxIconWidth;
3980 bool active = mi->state & State_Selected;
3981 bool enabled = mi->state & State_Enabled;
3982 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
3983 HIRect itemRect = qt_hirectForQRect(mi->rect);
3984 HIThemeMenuItemDrawInfo mdi;
3985 mdi.version = qt_mac_hitheme_version;
3986 mdi.itemType = kThemeMenuItemPlain;
3987 if (!mi->icon.isNull())
3988 mdi.itemType |= kThemeMenuItemHasIcon;
3989 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
3990 mdi.itemType |= kThemeMenuItemHierarchical | kThemeMenuItemHierBackground;
3992 mdi.itemType |= kThemeMenuItemPopUpBackground;
3994 mdi.state = kThemeMenuActive;
3996 mdi.state = kThemeMenuDisabled;
3998 mdi.state |= kThemeMenuSelected;
4000 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4001 // First arg should be &menurect, but wacky stuff happens then.
4002 HIThemeDrawMenuSeparator(&itemRect, &itemRect, &mdi,
4003 cg, kHIThemeOrientationNormal);
4007 bool needAlpha = mi->palette.color(QPalette::Button) == Qt::transparent;
4010 CGContextSaveGState(cg);
4011 CGContextSetAlpha(cg, 0.0);
4013 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4014 cg, kHIThemeOrientationNormal, &cr);
4016 CGContextRestoreGState(cg);
4017 if (ce == CE_MenuEmptyArea)
4019 contentRect = qt_qrectForHIRect(cr);
4021 int xpos = contentRect.x() + 18;
4022 int checkcol = maxpmw;
4024 p->setPen(mi->palette.text().color());
4026 p->setPen(mi->palette.highlightedText().color());
4028 p->setPen(mi->palette.buttonText().color());
4031 // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it,
4032 // we somehow need to use a special encoding as it doesn't look right with our
4035 CGContextSetShouldAntialias(cg, true);
4036 CGContextSetShouldSmoothFonts(cg, true);
4037 QColor textColor = p->pen().color();
4038 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4039 textColor.blueF(), textColor.alphaF() };
4040 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
4041 CGContextSetFillColor(cg, colorComp);
4042 HIThemeTextInfo tti;
4043 tti.version = qt_mac_hitheme_version;
4045 if (active && enabled)
4046 tti.state = kThemeStatePressed;
4047 switch (widgetSize) {
4048 case QAquaSizeUnknown:
4049 case QAquaSizeLarge:
4050 tti.fontID = kThemeMenuItemMarkFont;
4052 case QAquaSizeSmall:
4053 tti.fontID = kThemeSmallSystemFont;
4056 tti.fontID = kThemeMiniSystemFont;
4059 tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft;
4060 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4061 tti.options = kHIThemeTextBoxOptionNone;
4062 tti.truncationPosition = kHIThemeTextTruncationNone;
4063 tti.truncationMaxLines = 1;
4064 QCFString checkmark;
4066 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
4067 checkmark = QString(QChar(kDiamondUnicode));
4070 checkmark = QString(QChar(kCheckUnicode));
4071 int mw = checkcol + macItemFrame;
4072 int mh = contentRect.height() - 2 * macItemFrame;
4073 int xp = contentRect.x();
4075 CGFloat outWidth, outHeight, outBaseline;
4076 HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight,
4078 if (widgetSize == QAquaSizeMini)
4080 QRect r(xp, contentRect.y(), mw, mh);
4081 r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1);
4082 HIRect bounds = qt_hirectForQRect(r);
4083 HIThemeDrawTextBox(checkmark, &bounds, &tti,
4084 cg, kHIThemeOrientationNormal);
4087 if (!mi->icon.isNull()) {
4088 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4090 // Always be normal or disabled to follow the Mac style.
4091 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4092 QSize iconSize(smallIconSize, smallIconSize);
4093 if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
4094 iconSize = comboBox->iconSize();
4096 QPixmap pixmap = mi->icon.pixmap(iconSize, mode);
4097 int pixw = pixmap.width();
4098 int pixh = pixmap.height();
4099 QRect cr(xpos, contentRect.y(), checkcol, contentRect.height());
4100 QRect pmr(0, 0, pixw, pixh);
4101 pmr.moveCenter(cr.center());
4102 p->drawPixmap(pmr.topLeft(), pixmap);
4106 QString s = mi->text;
4108 int t = s.indexOf(QLatin1Char('\t'));
4109 int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic
4110 | Qt::TextSingleLine | Qt::AlignAbsolute;
4111 int yPos = contentRect.y();
4112 if (widgetSize == QAquaSizeMini)
4116 p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
4117 int xp = contentRect.right() - tabwidth - macRightBorder
4118 - macItemHMargin - macItemFrame + 1;
4119 p->drawText(xp, yPos, tabwidth, contentRect.height(), text_flags,
4124 const int xm = macItemFrame + maxpmw + macItemHMargin;
4125 QFont myFont = mi->font;
4126 // myFont may not have any "hard" flags set. We override
4127 // the point size so that when it is resolved against the device, this font will win.
4128 // This is mainly to handle cases where someone sets the font on the window
4129 // and then the combo inherits it and passes it onward. At that point the resolve mask
4130 // is very, very weak. This makes it stonger.
4131 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4133 p->drawText(xpos, yPos, contentRect.width() - xm - tabwidth + 1,
4134 contentRect.height(), text_flags ^ Qt::AlignRight, s);
4139 case CE_MenuHMargin:
4140 case CE_MenuVMargin:
4141 case CE_MenuTearoff:
4142 case CE_MenuScroller:
4143 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4144 p->fillRect(mi->rect, opt->palette.background());
4146 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4147 HIRect itemRect = qt_hirectForQRect(mi->rect);
4148 HIThemeMenuItemDrawInfo mdi;
4149 mdi.version = qt_mac_hitheme_version;
4150 if (!(opt->state & State_Enabled))
4151 mdi.state = kThemeMenuDisabled;
4152 else if (opt->state & State_Selected)
4153 mdi.state = kThemeMenuSelected;
4155 mdi.state = kThemeMenuActive;
4156 if (ce == CE_MenuScroller) {
4157 if (opt->state & State_DownArrow)
4158 mdi.itemType = kThemeMenuItemScrollDownArrow;
4160 mdi.itemType = kThemeMenuItemScrollUpArrow;
4162 mdi.itemType = kThemeMenuItemPlain;
4164 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4166 kHIThemeOrientationNormal, 0);
4167 if (ce == CE_MenuTearoff) {
4168 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4169 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4170 mi->rect.x() + mi->rect.width() - 4,
4171 mi->rect.y() + mi->rect.height() / 2 - 1);
4172 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4173 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4174 mi->rect.x() + mi->rect.width() - 4,
4175 mi->rect.y() + mi->rect.height() / 2);
4179 case CE_MenuBarItem:
4180 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4181 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4182 HIRect itemRect = qt_hirectForQRect(mi->rect);
4184 if ((opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken)){
4185 // Draw a selected menu item background:
4186 HIThemeMenuItemDrawInfo mdi;
4187 mdi.version = qt_mac_hitheme_version;
4188 mdi.state = kThemeMenuSelected;
4189 mdi.itemType = kThemeMenuItemPlain;
4190 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, cg, kHIThemeOrientationNormal, 0);
4192 // Draw the toolbar background:
4193 HIThemeMenuBarDrawInfo bdi;
4194 bdi.version = qt_mac_hitheme_version;
4195 bdi.state = kThemeMenuBarNormal;
4197 HIThemeDrawMenuBarBackground(&menuRect, &bdi, cg, kHIThemeOrientationNormal);
4200 if (!mi->icon.isNull()) {
4201 drawItemPixmap(p, mi->rect,
4202 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4203 | Qt::TextSingleLine,
4204 mi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize),
4205 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4207 drawItemText(p, mi->rect,
4208 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4209 | Qt::TextSingleLine,
4210 mi->palette, mi->state & State_Enabled,
4211 mi->text, QPalette::ButtonText);
4215 case CE_MenuBarEmptyArea:
4216 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4217 HIThemeMenuBarDrawInfo bdi;
4218 bdi.version = qt_mac_hitheme_version;
4219 bdi.state = kThemeMenuBarNormal;
4221 HIRect hirect = qt_hirectForQRect(mi->rect);
4222 HIThemeDrawMenuBarBackground(&hirect, &bdi, cg,
4223 kHIThemeOrientationNormal);
4226 case CE_ProgressBarContents:
4227 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4228 HIThemeTrackDrawInfo tdi;
4229 tdi.version = qt_mac_hitheme_version;
4231 bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4232 bool vertical = false;
4233 bool inverted = false;
4234 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
4235 vertical = (pb2->orientation == Qt::Vertical);
4236 inverted = pb2->invertedAppearance;
4238 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4241 switch (d->aquaSizeConstrain(opt, w)) {
4242 case QAquaSizeUnknown:
4243 case QAquaSizeLarge:
4244 tdi.kind = !isIndeterminate ? kThemeLargeProgressBar
4245 : kThemeLargeIndeterminateBar;
4248 case QAquaSizeSmall:
4249 tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar;
4252 tdi.bounds = qt_hirectForQRect(pb->rect);
4253 tdi.max = pb->maximum;
4254 tdi.min = pb->minimum;
4255 tdi.value = pb->progress;
4256 tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
4257 tdi.trackInfo.progress.phase = d->progressFrame;
4258 if (!(pb->state & State_Active))
4259 tdi.enableState = kThemeTrackInactive;
4260 else if (!(pb->state & State_Enabled))
4261 tdi.enableState = kThemeTrackDisabled;
4263 tdi.enableState = kThemeTrackActive;
4264 HIThemeOrientation drawOrientation = kHIThemeOrientationNormal;
4267 drawOrientation = kHIThemeOrientationInverted;
4269 CGContextSaveGState(cg);
4270 CGContextTranslateCTM(cg, pb->rect.width(), 0);
4271 CGContextScaleCTM(cg, -1, 1);
4274 HIThemeDrawTrack(&tdi, 0, cg, drawOrientation);
4275 if (reverse && !vertical)
4276 CGContextRestoreGState(cg);
4279 case CE_ProgressBarLabel:
4280 case CE_ProgressBarGroove:
4283 if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) {
4284 HIThemeGrowBoxDrawInfo gdi;
4285 gdi.version = qt_mac_hitheme_version;
4287 gdi.kind = kHIThemeGrowBoxKindNormal;
4288 gdi.direction = kThemeGrowRight | kThemeGrowDown;
4289 gdi.size = kHIThemeGrowBoxSizeNormal;
4290 HIPoint pt = CGPointMake(opt->rect.x(), opt->rect.y());
4291 HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal);
4293 // It isn't possible to draw a transparent size grip with the
4294 // native API, so we do it ourselves here.
4295 const bool metal = qt_mac_is_metal(w);
4296 QPen lineColor = metal ? QColor(236, 236, 236) : QColor(82, 82, 82, 192);
4297 QPen metalHighlight = QColor(5, 5, 5, 192);
4298 lineColor.setWidth(1);
4300 p->setRenderHint(QPainter::Antialiasing);
4301 p->setPen(lineColor);
4302 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4303 const int NumLines = metal ? 4 : 3;
4304 for (int l = 0; l < NumLines; ++l) {
4305 const int offset = (l * 4 + (metal ? 2 : 3));
4307 if (layoutDirection == Qt::LeftToRight) {
4308 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4309 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4311 start = QPoint(offset, opt->rect.height() - 1);
4312 end = QPoint(1, opt->rect.height() - offset);
4314 p->drawLine(start, end);
4316 p->setPen(metalHighlight);
4317 p->setRenderHint(QPainter::Antialiasing, false);
4318 p->drawLine(start + QPoint(0, -1), end + QPoint(0, -1));
4319 p->setRenderHint(QPainter::Antialiasing, true);
4320 p->setPen(lineColor);
4328 HIThemeSplitterDrawInfo sdi;
4329 sdi.version = qt_mac_hitheme_version;
4331 sdi.adornment = qt_mac_is_metal(w) ? kHIThemeSplitterAdornmentMetal
4332 : kHIThemeSplitterAdornmentNone;
4333 HIRect hirect = qt_hirectForQRect(opt->rect);
4334 HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal);
4337 if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
4338 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4339 if (!rubber->opaque) {
4341 // I retrieved these colors from the Carbon-Dev mailing list
4342 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4343 fillColor.setHsvF(0, 0, 0.53, 0.25);
4344 if (opt->rect.width() * opt->rect.height() <= 3) {
4345 p->fillRect(opt->rect, strokeColor);
4347 QPen oldPen = p->pen();
4348 QBrush oldBrush = p->brush();
4349 QPen pen(strokeColor);
4351 p->setBrush(fillColor);
4352 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
4354 p->setBrush(oldBrush);
4357 p->fillRect(opt->rect, fillColor);
4362 // For unified tool bars, draw nothing.
4364 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4365 if (mainWindow->unifiedTitleAndToolBarOnMac())
4370 // draw background gradient
4371 QLinearGradient linearGrad;
4372 if (opt->state & State_Horizontal)
4373 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4375 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
4377 linearGrad.setColorAt(0, mainWindowGradientBegin);
4378 linearGrad.setColorAt(1, mainWindowGradientEnd);
4379 p->fillRect(opt->rect, linearGrad);
4382 if (opt->state & State_Horizontal) {
4383 p->setPen(mainWindowGradientBegin.lighter(114));
4384 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4385 p->setPen(mainWindowGradientEnd.darker(114));
4386 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4389 p->setPen(mainWindowGradientBegin.lighter(114));
4390 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4391 p->setPen(mainWindowGradientEnd.darker(114));
4392 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
4399 QWindowsStyle::drawControl(ce, opt, p, w);
4404 static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
4406 if (dir == Qt::RightToLeft) {
4407 rect->adjust(-right, top, -left, bottom);
4409 rect->adjust(left, top, right, bottom);
4413 QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
4414 const QWidget *widget) const
4417 int controlSize = getControlSize(opt, widget);
4420 case SE_ItemViewItemText:
4421 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
4422 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget);
4423 // We add the focusframeargin between icon and text in commonstyle
4424 rect = QCommonStyle::subElementRect(sr, opt, widget);
4425 if (vopt->features & QStyleOptionViewItemV2::HasDecoration)
4426 rect.adjust(-fw, 0, 0, 0);
4429 case SE_ToolBoxTabContents:
4430 rect = QCommonStyle::subElementRect(sr, opt, widget);
4432 case SE_PushButtonContents:
4433 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4434 // Unlike Carbon, we want the button to always be drawn inside its bounds.
4435 // Therefore, the button is a bit smaller, so that even if it got focus,
4436 // the focus 'shadow' will be inside. Adjust the content rect likewise.
4437 HIThemeButtonDrawInfo bdi;
4438 d->initHIThemePushButton(btn, widget, d->getDrawState(opt->state), &bdi);
4439 HIRect contentRect = d->pushButtonContentBounds(btn, &bdi);
4440 rect = qt_qrectForHIRect(contentRect);
4443 case SE_HeaderLabel:
4444 if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4445 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4446 if (widget && widget->height() <= 22){
4447 // We need to allow the text a bit more space when the header is
4448 // small, otherwise it gets clipped:
4450 rect.setHeight(widget->height());
4454 case SE_ProgressBarGroove:
4455 case SE_ProgressBarLabel:
4457 case SE_ProgressBarContents:
4460 case SE_TreeViewDisclosureItem: {
4461 HIRect inRect = CGRectMake(opt->rect.x(), opt->rect.y(),
4462 opt->rect.width(), opt->rect.height());
4463 HIThemeButtonDrawInfo bdi;
4464 bdi.version = qt_mac_hitheme_version;
4465 bdi.state = kThemeStateActive;
4466 bdi.kind = kThemeDisclosureButton;
4467 bdi.value = kThemeDisclosureRight;
4468 bdi.adornment = kThemeAdornmentNone;
4470 HIThemeGetButtonContentBounds(&inRect, &bdi, &contentRect);
4471 QCFType<HIShapeRef> shape;
4473 HIThemeGetButtonShape(&inRect, &bdi, &shape);
4474 ptrHIShapeGetBounds(shape, &outRect);
4475 rect = QRect(int(outRect.origin.x + DisclosureOffset), int(outRect.origin.y),
4476 int(contentRect.origin.x - outRect.origin.x + DisclosureOffset),
4477 int(outRect.size.height));
4480 case SE_TabWidgetLeftCorner:
4481 if (const QStyleOptionTabWidgetFrame *twf
4482 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4483 switch (twf->shape) {
4484 case QTabBar::RoundedNorth:
4485 case QTabBar::TriangularNorth:
4486 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4488 case QTabBar::RoundedSouth:
4489 case QTabBar::TriangularSouth:
4490 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4491 twf->leftCornerWidgetSize);
4496 rect = visualRect(twf->direction, twf->rect, rect);
4499 case SE_TabWidgetRightCorner:
4500 if (const QStyleOptionTabWidgetFrame *twf
4501 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4502 switch (twf->shape) {
4503 case QTabBar::RoundedNorth:
4504 case QTabBar::TriangularNorth:
4505 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4506 twf->rightCornerWidgetSize);
4508 case QTabBar::RoundedSouth:
4509 case QTabBar::TriangularSouth:
4510 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4511 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4512 twf->rightCornerWidgetSize);
4517 rect = visualRect(twf->direction, twf->rect, rect);
4520 case SE_TabWidgetTabContents:
4521 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4522 if (const QStyleOptionTabWidgetFrame *twf
4523 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4524 if (twf->lineWidth != 0) {
4525 switch (getTabDirection(twf->shape)) {
4526 case kThemeTabNorth:
4527 rect.adjust(+1, +14, -1, -1);
4529 case kThemeTabSouth:
4530 rect.adjust(+1, +1, -1, -14);
4533 rect.adjust(+14, +1, -1, -1);
4536 rect.adjust(+1, +1, -14, -1);
4541 case SE_LineEditContents:
4542 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4543 if(widget->parentWidget() && qobject_cast<const QComboBox*>(widget->parentWidget()))
4544 rect.adjust(-1, -2, 0, 0);
4546 rect.adjust(-1, 0, 0, +1);
4548 case SE_CheckBoxLayoutItem:
4550 if (controlSize == QAquaSizeLarge) {
4551 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4552 } else if (controlSize == QAquaSizeSmall) {
4553 setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction);
4555 setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction);
4558 case SE_ComboBoxLayoutItem:
4559 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4560 // Do nothing, because QToolbar needs the entire widget rect.
4561 // Otherwise it will be clipped. Equivalent to
4562 // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4566 if (controlSize == QAquaSizeLarge) {
4567 rect.adjust(+3, +2, -3, -4);
4568 } else if (controlSize == QAquaSizeSmall) {
4569 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4571 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4575 case SE_LabelLayoutItem:
4577 setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4579 case SE_ProgressBarLayoutItem: {
4581 int bottom = SIZE(3, 8, 8);
4582 if (opt->state & State_Horizontal) {
4583 rect.adjust(0, +1, 0, -bottom);
4585 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
4589 case SE_PushButtonLayoutItem:
4590 if (const QStyleOptionButton *buttonOpt
4591 = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4592 if ((buttonOpt->features & QStyleOptionButton::Flat))
4593 break; // leave rect alone
4596 if (controlSize == QAquaSizeLarge) {
4597 rect.adjust(+6, +4, -6, -8);
4598 } else if (controlSize == QAquaSizeSmall) {
4599 rect.adjust(+5, +4, -5, -6);
4601 rect.adjust(+1, 0, -1, -2);
4604 case SE_RadioButtonLayoutItem:
4606 if (controlSize == QAquaSizeLarge) {
4607 setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */,
4608 0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction);
4609 } else if (controlSize == QAquaSizeSmall) {
4610 rect.adjust(0, +6, 0 /* fix */, -5);
4612 rect.adjust(0, +6, 0 /* fix */, -7);
4615 case SE_SliderLayoutItem:
4616 if (const QStyleOptionSlider *sliderOpt
4617 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4619 if (sliderOpt->tickPosition == QSlider::NoTicks) {
4620 int above = SIZE(3, 0, 2);
4621 int below = SIZE(4, 3, 0);
4622 if (sliderOpt->orientation == Qt::Horizontal) {
4623 rect.adjust(0, +above, 0, -below);
4625 rect.adjust(+above, 0, -below, 0); //### Seems that QSlider flip the position of the ticks in reverse mode.
4627 } else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4628 int below = SIZE(3, 2, 0);
4629 if (sliderOpt->orientation == Qt::Horizontal) {
4630 rect.setHeight(rect.height() - below);
4632 rect.setWidth(rect.width() - below);
4634 } else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4635 int above = SIZE(3, 2, 0);
4636 if (sliderOpt->orientation == Qt::Horizontal) {
4637 rect.setTop(rect.top() + above);
4639 rect.setLeft(rect.left() + above);
4644 case SE_FrameLayoutItem:
4645 // hack because QStyleOptionFrameV2 doesn't have a frameStyle member
4646 if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4648 switch (frame->frameStyle() & QFrame::Shape_Mask) {
4650 rect.adjust(0, +1, 0, -1);
4653 rect.adjust(+1, 0, -1, 0);
4660 case SE_GroupBoxLayoutItem:
4662 if (const QStyleOptionGroupBox *groupBoxOpt =
4663 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4665 AHIG is very inconsistent when it comes to group boxes.
4666 Basically, we make sure that (non-checkable) group boxes
4667 and tab widgets look good when laid out side by side.
4669 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4670 | QStyle::SC_GroupBoxLabel)) {
4672 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4673 delta = SIZE(8, 4, 4); // guess
4675 delta = SIZE(15, 12, 12); // guess
4677 rect.setTop(rect.top() + delta);
4680 rect.setBottom(rect.bottom() - 1);
4682 case SE_TabWidgetLayoutItem:
4683 if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4684 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4686 AHIG specifies "12 or 14" as the distance from the window
4687 edge. We choose 14 and since the default top margin is 20,
4690 rect = tabWidgetOpt->rect;
4691 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4692 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4695 #ifndef QT_NO_DOCKWIDGET
4696 case SE_DockWidgetCloseButton:
4697 case SE_DockWidgetFloatButton:
4698 case SE_DockWidgetTitleBarText:
4699 case SE_DockWidgetIcon: {
4700 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
4701 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget);
4702 QRect srect = opt->rect;
4704 const QStyleOptionDockWidget *dwOpt
4705 = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
4706 bool canClose = dwOpt == 0 ? true : dwOpt->closable;
4707 bool canFloat = dwOpt == 0 ? false : dwOpt->floatable;
4708 const QStyleOptionDockWidgetV2 *v2
4709 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(opt);
4710 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
4712 // If this is a vertical titlebar, we transpose and work as if it was
4713 // horizontal, then transpose again.
4714 if (verticalTitleBar) {
4715 QSize size = srect.size();
4717 srect.setSize(size);
4721 int right = srect.right();
4722 int left = srect.left();
4726 QSize sz = standardIcon(QStyle::SP_TitleBarCloseButton,
4727 opt, widget).actualSize(QSize(iconSize, iconSize));
4728 sz += QSize(buttonMargin, buttonMargin);
4729 if (verticalTitleBar)
4731 closeRect = QRect(left,
4732 srect.center().y() - sz.height()/2,
4733 sz.width(), sz.height());
4734 left = closeRect.right() + 1;
4736 if (sr == SE_DockWidgetCloseButton) {
4743 QSize sz = standardIcon(QStyle::SP_TitleBarNormalButton,
4744 opt, widget).actualSize(QSize(iconSize, iconSize));
4745 sz += QSize(buttonMargin, buttonMargin);
4746 if (verticalTitleBar)
4748 floatRect = QRect(left,
4749 srect.center().y() - sz.height()/2,
4750 sz.width(), sz.height());
4751 left = floatRect.right() + 1;
4753 if (sr == SE_DockWidgetFloatButton) {
4759 if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(widget)) {
4761 if (dw->isFloating())
4762 icon = dw->windowIcon();
4764 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
4765 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
4766 if (verticalTitleBar)
4768 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
4769 sz.width(), sz.height());
4770 right = iconRect.left() - 1;
4773 if (sr == SE_DockWidgetIcon) {
4778 QRect textRect = QRect(left, srect.top(),
4779 right - left, srect.height());
4780 if (sr == SE_DockWidgetTitleBarText) {
4786 if (verticalTitleBar) {
4787 rect = QRect(srect.left() + rect.top() - srect.top(),
4788 srect.top() + srect.right() - rect.right(),
4789 rect.height(), rect.width());
4791 rect = visualRect(opt->direction, srect, rect);
4797 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4803 static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDrawState tds, CGContextRef cg)
4805 QRect arrowRect = QRect(toolButtonRect.right() - 9, toolButtonRect.bottom() - 9, 7, 5);
4806 HIThemePopupArrowDrawInfo padi;
4807 padi.version = qt_mac_hitheme_version;
4809 padi.orientation = kThemeArrowDown;
4810 padi.size = kThemeArrow7pt;
4811 HIRect hirect = qt_hirectForQRect(arrowRect);
4812 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
4815 void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
4816 const QWidget *widget) const
4818 ThemeDrawState tds = d->getDrawState(opt->state);
4819 QMacCGContext cg(p);
4823 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4824 HIThemeTrackDrawInfo tdi;
4825 d->getSliderInfo(cc, slider, &tdi, widget);
4826 if (slider->state & State_Sunken) {
4827 if (cc == CC_Slider) {
4828 if (slider->activeSubControls == SC_SliderHandle)
4829 tdi.trackInfo.slider.pressState = kThemeThumbPressed;
4830 else if (slider->activeSubControls == SC_SliderGroove)
4831 tdi.trackInfo.slider.pressState = kThemeLeftTrackPressed;
4833 if (slider->activeSubControls == SC_ScrollBarSubLine
4834 || slider->activeSubControls == SC_ScrollBarAddLine) {
4835 // This test looks complex but it basically boils down
4836 // to the following: The "RTL look" on the mac also
4837 // changed the directions of the controls, that's not
4838 // what people expect (an arrow is an arrow), so we
4839 // kind of fake and say the opposite button is hit.
4840 // This works great, up until 10.4 which broke the
4841 // scroll bars, so I also have actually do something
4842 // similar when I have an upside down scroll bar
4843 // because on Tiger I only "fake" the reverse stuff.
4844 bool reverseHorizontal = (slider->direction == Qt::RightToLeft
4845 && slider->orientation == Qt::Horizontal);
4846 if ((reverseHorizontal
4847 && slider->activeSubControls == SC_ScrollBarAddLine)
4848 || (!reverseHorizontal
4849 && slider->activeSubControls == SC_ScrollBarSubLine)) {
4850 tdi.trackInfo.scrollbar.pressState = kThemeRightInsideArrowPressed
4851 | kThemeLeftOutsideArrowPressed;
4853 tdi.trackInfo.scrollbar.pressState = kThemeLeftInsideArrowPressed
4854 | kThemeRightOutsideArrowPressed;
4856 } else if (slider->activeSubControls == SC_ScrollBarAddPage) {
4857 tdi.trackInfo.scrollbar.pressState = kThemeRightTrackPressed;
4858 } else if (slider->activeSubControls == SC_ScrollBarSubPage) {
4859 tdi.trackInfo.scrollbar.pressState = kThemeLeftTrackPressed;
4860 } else if (slider->activeSubControls == SC_ScrollBarSlider) {
4861 tdi.trackInfo.scrollbar.pressState = kThemeThumbPressed;
4866 bool tracking = slider->sliderPosition == slider->sliderValue;
4868 // Small optimization, the same as q->subControlRect
4869 QCFType<HIShapeRef> shape;
4870 HIThemeGetTrackThumbShape(&tdi, &shape);
4871 ptrHIShapeGetBounds(shape, &macRect);
4872 tdi.value = slider->sliderValue;
4875 // Remove controls from the scroll bar if it is to short to draw them correctly.
4876 // This is done in two stages: first the thumb indicator is removed when it is
4877 // no longer possible to move it, second the up/down buttons are removed when
4878 // there is not enough space for them.
4879 if (cc == CC_ScrollBar) {
4880 const int scrollBarLength = (slider->orientation == Qt::Horizontal)
4881 ? slider->rect.width() : slider->rect.height();
4882 const QMacStyle::WidgetSizePolicy sizePolicy = widgetSizePolicy(widget);
4883 if (scrollBarLength < scrollButtonsCutoffSize(thumbIndicatorCutoff, sizePolicy))
4884 tdi.attributes &= ~kThemeTrackShowThumb;
4885 if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, sizePolicy))
4886 tdi.enableState = kThemeTrackNothingToScroll;
4888 if (!(slider->subControls & SC_SliderHandle))
4889 tdi.attributes &= ~kThemeTrackShowThumb;
4890 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4891 if (!(slider->subControls & SC_SliderGroove))
4892 tdi.attributes |= kThemeTrackHideTrack;
4896 HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg,
4897 kHIThemeOrientationNormal);
4898 if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
4899 if (qt_mac_is_metal(widget)) {
4900 if (tdi.enableState == kThemeTrackInactive)
4901 tdi.enableState = kThemeTrackActive; // Looks more Cocoa-like
4903 int interval = slider->tickInterval;
4904 if (interval == 0) {
4905 interval = slider->pageStep;
4907 interval = slider->singleStep;
4911 int numMarks = 1 + ((slider->maximum - slider->minimum) / interval);
4913 if (tdi.trackInfo.slider.thumbDir == kThemeThumbPlain) {
4914 // They asked for both, so we'll give it to them.
4915 tdi.trackInfo.slider.thumbDir = kThemeThumbDownward;
4916 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4918 kHIThemeOrientationNormal);
4919 tdi.trackInfo.slider.thumbDir = kThemeThumbUpward;
4920 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4922 kHIThemeOrientationNormal);
4924 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4926 kHIThemeOrientationNormal);
4933 if (const QStyleOptionQ3ListView *lv = qstyleoption_cast<const QStyleOptionQ3ListView *>(opt)) {
4934 if (lv->subControls & SC_Q3ListView)
4935 QWindowsStyle::drawComplexControl(cc, lv, p, widget);
4936 if (lv->subControls & (SC_Q3ListViewBranch | SC_Q3ListViewExpand)) {
4937 int y = lv->rect.y();
4938 int h = lv->rect.height();
4939 int x = lv->rect.right() - 10;
4940 for (int i = 1; i < lv->items.size() && y < h; ++i) {
4941 QStyleOptionQ3ListViewItem item = lv->items.at(i);
4942 if (y + item.height > 0 && (item.childCount > 0
4943 || (item.features & (QStyleOptionQ3ListViewItem::Expandable
4944 | QStyleOptionQ3ListViewItem::Visible))
4945 == (QStyleOptionQ3ListViewItem::Expandable
4946 | QStyleOptionQ3ListViewItem::Visible))) {
4947 QStyleOption treeOpt(0);
4948 treeOpt.rect.setRect(x, y + item.height / 2 - 4, 9, 9);
4949 treeOpt.palette = lv->palette;
4950 treeOpt.state = lv->state;
4951 treeOpt.state |= State_Children;
4952 if (item.state & State_Open)
4953 treeOpt.state |= State_Open;
4954 proxy()->drawPrimitive(PE_IndicatorBranch, &treeOpt, p, widget);
4956 y += item.totalHeight;
4962 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
4963 QStyleOptionSpinBox newSB = *sb;
4964 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4966 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
4968 QRect lineeditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
4969 lineeditRect.adjust(-frame_size, -frame_size, +frame_size, +frame_size);
4971 HIThemeFrameDrawInfo fdi;
4972 fdi.version = qt_mac_hitheme_version;
4974 fdi.kind = kHIThemeFrameTextFieldSquare;
4975 fdi.isFocused = false;
4976 HIRect hirect = qt_hirectForQRect(lineeditRect);
4977 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
4979 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4980 HIThemeButtonDrawInfo bdi;
4981 bdi.version = qt_mac_hitheme_version;
4982 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
4984 case QAquaSizeUnknown:
4985 case QAquaSizeLarge:
4986 bdi.kind = kThemeIncDecButton;
4989 bdi.kind = kThemeIncDecButtonMini;
4991 case QAquaSizeSmall:
4992 bdi.kind = kThemeIncDecButtonSmall;
4995 if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled
4996 | QAbstractSpinBox::StepDownEnabled)))
4997 tds = kThemeStateUnavailable;
4998 if (sb->activeSubControls == SC_SpinBoxDown
4999 && (sb->state & State_Sunken))
5000 tds = kThemeStatePressedDown;
5001 else if (sb->activeSubControls == SC_SpinBoxUp
5002 && (sb->state & State_Sunken))
5003 tds = kThemeStatePressedUp;
5005 if (!(sb->state & State_Active)
5006 && sb->palette.currentColorGroup() == QPalette::Active
5007 && tds == kThemeStateInactive)
5008 bdi.state = kThemeStateActive;
5009 bdi.value = kThemeButtonOff;
5010 bdi.adornment = kThemeAdornmentNone;
5012 QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget);
5014 updown |= proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5015 HIRect newRect = qt_hirectForQRect(updown);
5018 HIThemeGetButtonBackgroundBounds(&newRect, &bdi, &outRect);
5019 off_rct.setRect(int(newRect.origin.x - outRect.origin.x),
5020 int(newRect.origin.y - outRect.origin.y),
5021 int(outRect.size.width - newRect.size.width),
5022 int(outRect.size.height - newRect.size.height));
5024 newRect = qt_hirectForQRect(updown, off_rct);
5025 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5030 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
5031 HIThemeButtonDrawInfo bdi;
5032 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5033 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
5035 QMacStylePrivate::drawCombobox(qt_hirectForQRect(combo->rect), bdi, p);
5037 d->drawColorlessButton(qt_hirectForQRect(combo->rect), &bdi, p, opt);
5041 if (const QStyleOptionTitleBar *titlebar
5042 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5043 if (titlebar->state & State_Active) {
5044 if (titlebar->titleBarState & State_Active)
5045 tds = kThemeStateActive;
5047 tds = kThemeStateInactive;
5049 tds = kThemeStateInactive;
5052 HIThemeWindowDrawInfo wdi;
5053 wdi.version = qt_mac_hitheme_version;
5055 wdi.windowType = QtWinType;
5056 wdi.titleHeight = titlebar->rect.height();
5057 wdi.titleWidth = titlebar->rect.width();
5058 wdi.attributes = kThemeWindowHasTitleText;
5059 // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty
5060 // close button, so use HIThemeDrawWindowFrame instead.
5061 if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton)
5062 wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty;
5064 HIRect titleBarRect;
5065 HIRect tmpRect = qt_hirectForQRect(titlebar->rect);
5067 QCFType<HIShapeRef> titleRegion;
5068 QRect newr = titlebar->rect.adjusted(0, 0, 2, 0);
5069 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
5070 ptrHIShapeGetBounds(titleRegion, &tmpRect);
5071 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
5072 titleBarRect = qt_hirectForQRect(newr);
5074 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
5075 if (titlebar->subControls & (SC_TitleBarCloseButton
5076 | SC_TitleBarMaxButton
5077 | SC_TitleBarMinButton
5078 | SC_TitleBarNormalButton)) {
5079 HIThemeWindowWidgetDrawInfo wwdi;
5080 wwdi.version = qt_mac_hitheme_version;
5081 wwdi.widgetState = tds;
5082 if (titlebar->state & State_MouseOver)
5083 wwdi.widgetState = kThemeStateRollover;
5084 wwdi.windowType = QtWinType;
5085 wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox;
5086 wwdi.windowState = wdi.state;
5087 wwdi.titleHeight = wdi.titleHeight;
5088 wwdi.titleWidth = wdi.titleWidth;
5089 ThemeDrawState savedControlState = wwdi.widgetState;
5090 uint sc = SC_TitleBarMinButton;
5091 ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox;
5092 bool active = titlebar->state & State_Active;
5093 if (qMacVersion() < QSysInfo::MV_10_6) {
5095 titleBarRect.origin.x += border;
5096 titleBarRect.origin.y -= border;
5099 while (sc <= SC_TitleBarCloseButton) {
5100 if (sc & titlebar->subControls) {
5102 wwdi.widgetState = savedControlState;
5103 wwdi.widgetType = tbw;
5104 if (sc == SC_TitleBarMinButton)
5105 tmp |= SC_TitleBarNormalButton;
5106 if (active && (titlebar->activeSubControls & tmp)
5107 && (titlebar->state & State_Sunken))
5108 wwdi.widgetState = kThemeStatePressed;
5109 // Draw all sub controllers except the dirty close button
5110 // (it is already handled by HIThemeDrawWindowFrame).
5111 if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) {
5112 HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal);
5113 p->paintEngine()->syncState();
5120 p->paintEngine()->syncState();
5121 if (titlebar->subControls & SC_TitleBarLabel) {
5123 if (!titlebar->icon.isNull()) {
5124 QCFType<HIShapeRef> titleRegion2;
5125 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn,
5127 ptrHIShapeGetBounds(titleRegion2, &tmpRect);
5128 if (tmpRect.size.width != 1) {
5129 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5130 iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width();
5133 if (!titlebar->text.isEmpty()) {
5135 QCFType<HIShapeRef> titleRegion3;
5136 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3);
5137 ptrHIShapeGetBounds(titleRegion3, &tmpRect);
5138 p->setClipRect(qt_qrectForHIRect(tmpRect));
5139 QRect br = p->clipRegion().boundingRect();
5141 y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2);
5142 if (br.width() <= (p->fontMetrics().width(titlebar->text) + iw * 2))
5145 x += br.width() / 2 - p->fontMetrics().width(titlebar->text) / 2;
5147 p->drawPixmap(x - iw, y,
5148 titlebar->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), QIcon::Normal));
5149 drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive,
5150 titlebar->text, QPalette::Text);
5157 if (const QStyleOptionGroupBox *groupBox
5158 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5160 QStyleOptionGroupBox groupBoxCopy(*groupBox);
5161 if ((widget && !widget->testAttribute(Qt::WA_SetFont))
5162 && QApplication::desktopSettingsAware())
5163 groupBoxCopy.subControls = groupBoxCopy.subControls & ~SC_GroupBoxLabel;
5164 QWindowsStyle::drawComplexControl(cc, &groupBoxCopy, p, widget);
5165 if (groupBoxCopy.subControls != groupBox->subControls) {
5166 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5168 CGContextSetShouldAntialias(cg, true);
5169 CGContextSetShouldSmoothFonts(cg, true);
5170 HIThemeTextInfo tti;
5171 tti.version = qt_mac_hitheme_version;
5173 QColor textColor = groupBox->palette.windowText().color();
5174 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
5175 textColor.blueF(), textColor.alphaF() };
5176 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
5177 CGContextSetFillColor(cg, colorComp);
5178 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5179 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5180 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5181 tti.options = kHIThemeTextBoxOptionNone;
5182 tti.truncationPosition = kHIThemeTextTruncationNone;
5183 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5184 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5185 QRect r = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget);
5186 HIRect bounds = qt_hirectForQRect(r);
5187 HIThemeDrawTextBox(groupText, &bounds, &tti, cg, kHIThemeOrientationNormal);
5193 if (const QStyleOptionToolButton *tb
5194 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5195 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5196 if (tb->subControls & SC_ToolButtonMenu) {
5197 QStyleOption arrowOpt(0);
5198 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5199 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5200 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5201 arrowOpt.state = tb->state;
5202 arrowOpt.palette = tb->palette;
5203 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5204 } else if ((tb->features & QStyleOptionToolButton::HasMenu)
5205 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
5206 drawToolbarButtonArrow(tb->rect, tds, cg);
5208 if (tb->state & State_On) {
5209 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
5210 static QPixmap pm(QLatin1String(":/trolltech/mac/style/images/leopard-unified-toolbar-on.png"));
5211 p->setRenderHint(QPainter::SmoothPixmapTransform);
5212 QStyleHelper::drawBorderPixmap(pm, p, tb->rect, 2, 2, 2, 2);
5214 QPen oldPen = p->pen();
5215 p->setPen(QColor(0, 0, 0, 0x3a));
5216 p->fillRect(tb->rect.adjusted(1, 1, -1, -1), QColor(0, 0, 0, 0x12));
5217 p->drawLine(tb->rect.left() + 1, tb->rect.top(),
5218 tb->rect.right() - 1, tb->rect.top());
5219 p->drawLine(tb->rect.left() + 1, tb->rect.bottom(),
5220 tb->rect.right() - 1, tb->rect.bottom());
5221 p->drawLine(tb->rect.topLeft(), tb->rect.bottomLeft());
5222 p->drawLine(tb->rect.topRight(), tb->rect.bottomRight());
5226 proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
5228 ThemeButtonKind bkind = kThemeBevelButton;
5229 switch (d->aquaSizeConstrain(opt, widget)) {
5230 case QAquaSizeUnknown:
5231 case QAquaSizeLarge:
5232 bkind = kThemeBevelButton;
5235 case QAquaSizeSmall:
5236 bkind = kThemeSmallBevelButton;
5240 QRect button, menuarea;
5241 button = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
5242 menuarea = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5243 State bflags = tb->state,
5245 if (tb->subControls & SC_ToolButton)
5246 bflags |= State_Sunken;
5247 if (tb->subControls & SC_ToolButtonMenu)
5248 mflags |= State_Sunken;
5250 if (tb->subControls & SC_ToolButton) {
5251 if (bflags & (State_Sunken | State_On | State_Raised)) {
5252 HIThemeButtonDrawInfo bdi;
5253 bdi.version = qt_mac_hitheme_version;
5255 bdi.adornment = kThemeAdornmentNone;
5257 bdi.value = kThemeButtonOff;
5258 if (tb->state & State_HasFocus)
5259 bdi.adornment = kThemeAdornmentFocus;
5260 if (tb->state & State_Sunken)
5261 bdi.state = kThemeStatePressed;
5262 if (tb->state & State_On)
5263 bdi.value = kThemeButtonOn;
5265 QRect off_rct(0, 0, 0, 0);
5266 HIRect myRect, macRect;
5267 myRect = CGRectMake(tb->rect.x(), tb->rect.y(),
5268 tb->rect.width(), tb->rect.height());
5269 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
5270 off_rct.setRect(int(myRect.origin.x - macRect.origin.x),
5271 int(myRect.origin.y - macRect.origin.y),
5272 int(macRect.size.width - myRect.size.width),
5273 int(macRect.size.height - myRect.size.height));
5275 myRect = qt_hirectForQRect(button, off_rct);
5276 HIThemeDrawButton(&myRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5280 if (tb->subControls & SC_ToolButtonMenu) {
5281 HIThemeButtonDrawInfo bdi;
5282 bdi.version = qt_mac_hitheme_version;
5284 bdi.value = kThemeButtonOff;
5285 bdi.adornment = kThemeAdornmentNone;
5287 if (tb->state & State_HasFocus)
5288 bdi.adornment = kThemeAdornmentFocus;
5289 if (tb->state & (State_On | State_Sunken)
5290 || (tb->activeSubControls & SC_ToolButtonMenu))
5291 bdi.state = kThemeStatePressed;
5292 HIRect hirect = qt_hirectForQRect(menuarea);
5293 HIThemeDrawButton(&hirect, &bdi, cg, kHIThemeOrientationNormal, 0);
5294 QRect r(menuarea.x() + ((menuarea.width() / 2) - 3), menuarea.height() - 8, 8, 8);
5295 HIThemePopupArrowDrawInfo padi;
5296 padi.version = qt_mac_hitheme_version;
5298 padi.orientation = kThemeArrowDown;
5299 padi.size = kThemeArrow7pt;
5300 hirect = qt_hirectForQRect(r);
5301 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
5302 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5303 drawToolbarButtonArrow(tb->rect, tds, cg);
5305 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
5306 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
5307 QStyleOptionToolButton label = *tb;
5308 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5309 proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
5314 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5315 QStyleHelper::drawDial(dial, p);
5318 QWindowsStyle::drawComplexControl(cc, opt, p, widget);
5323 QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
5324 const QStyleOptionComplex *opt,
5325 const QPoint &pt, const QWidget *widget) const
5327 SubControl sc = QStyle::SC_None;
5330 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5331 sc = QWindowsStyle::hitTestComplexControl(cc, cmb, pt, widget);
5332 if (!cmb->editable && sc != QStyle::SC_None)
5333 sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
5337 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5338 HIThemeTrackDrawInfo tdi;
5339 d->getSliderInfo(cc, slider, &tdi, widget);
5340 ControlPartCode part;
5341 HIPoint pos = CGPointMake(pt.x(), pt.y());
5342 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5343 if (part == kControlPageUpPart || part == kControlPageDownPart)
5344 sc = SC_SliderGroove;
5346 sc = SC_SliderHandle;
5351 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5352 HIScrollBarTrackInfo sbi;
5353 sbi.version = qt_mac_hitheme_version;
5354 if (!(sb->state & State_Active))
5355 sbi.enableState = kThemeTrackInactive;
5356 else if (sb->state & State_Enabled)
5357 sbi.enableState = kThemeTrackActive;
5359 sbi.enableState = kThemeTrackDisabled;
5361 // The arrow buttons are not drawn if the scroll bar is to short,
5362 // exclude them from the hit test.
5363 const int scrollBarLength = (sb->orientation == Qt::Horizontal)
5364 ? sb->rect.width() : sb->rect.height();
5365 if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, widgetSizePolicy(widget)))
5366 sbi.enableState = kThemeTrackNothingToScroll;
5368 sbi.viewsize = sb->pageStep;
5369 HIPoint pos = CGPointMake(pt.x(), pt.y());
5371 HIRect macSBRect = qt_hirectForQRect(sb->rect);
5372 ControlPartCode part;
5373 bool reverseHorizontal = (sb->direction == Qt::RightToLeft
5374 && sb->orientation == Qt::Horizontal
5375 && (!sb->upsideDown ||
5376 (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5377 && sb->upsideDown)));
5378 if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal,
5380 if (part == kControlUpButtonPart)
5381 sc = reverseHorizontal ? SC_ScrollBarAddLine : SC_ScrollBarSubLine;
5382 else if (part == kControlDownButtonPart)
5383 sc = reverseHorizontal ? SC_ScrollBarSubLine : SC_ScrollBarAddLine;
5385 HIThemeTrackDrawInfo tdi;
5386 d->getSliderInfo(cc, sb, &tdi, widget);
5387 if(tdi.enableState == kThemeTrackInactive)
5388 tdi.enableState = kThemeTrackActive;
5389 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5390 if (part == kControlPageUpPart)
5391 sc = reverseHorizontal ? SC_ScrollBarAddPage
5392 : SC_ScrollBarSubPage;
5393 else if (part == kControlPageDownPart)
5394 sc = reverseHorizontal ? SC_ScrollBarSubPage
5395 : SC_ScrollBarAddPage;
5397 sc = SC_ScrollBarSlider;
5403 I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all.
5404 It would be very nice if this would work.
5405 case QStyle::CC_TitleBar:
5406 if (const QStyleOptionTitleBar *tbar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5407 HIThemeWindowDrawInfo wdi;
5408 memset(&wdi, 0, sizeof(wdi));
5409 wdi.version = qt_mac_hitheme_version;
5410 wdi.state = kThemeStateActive;
5411 wdi.windowType = QtWinType;
5412 wdi.titleWidth = tbar->rect.width();
5413 wdi.titleHeight = tbar->rect.height();
5414 if (tbar->titleBarState)
5415 wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
5416 | kThemeWindowHasCollapseBox;
5417 else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint)
5418 wdi.attributes |= kThemeWindowHasCloseBox;
5419 QRect tmpRect = tbar->rect;
5420 tmpRect.setHeight(tmpRect.height() + 100);
5421 HIRect hirect = qt_hirectForQRect(tmpRect);
5422 WindowRegionCode hit;
5423 HIPoint hipt = CGPointMake(pt.x(), pt.y());
5424 if (HIThemeGetWindowRegionHit(&hirect, &wdi, &hipt, &hit)) {
5426 case kWindowCloseBoxRgn:
5427 sc = QStyle::SC_TitleBarCloseButton;
5429 case kWindowCollapseBoxRgn:
5430 sc = QStyle::SC_TitleBarMinButton;
5432 case kWindowZoomBoxRgn:
5433 sc = QStyle::SC_TitleBarMaxButton;
5435 case kWindowTitleTextRgn:
5436 sc = QStyle::SC_TitleBarLabel;
5439 qDebug("got something else %d", hit);
5447 sc = QWindowsStyle::hitTestComplexControl(cc, opt, pt, widget);
5453 QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5454 const QWidget *widget) const
5460 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5461 HIThemeTrackDrawInfo tdi;
5462 d->getSliderInfo(cc, slider, &tdi, widget);
5464 QCFType<HIShapeRef> shape;
5465 bool scrollBar = cc == CC_ScrollBar;
5466 if ((scrollBar && sc == SC_ScrollBarSlider)
5467 || (!scrollBar && sc == SC_SliderHandle)) {
5468 HIThemeGetTrackThumbShape(&tdi, &shape);
5469 ptrHIShapeGetBounds(shape, &macRect);
5470 } else if (!scrollBar && sc == SC_SliderGroove) {
5471 HIThemeGetTrackBounds(&tdi, &macRect);
5472 } else if (sc == SC_ScrollBarGroove) { // Only scroll bar parts available...
5473 HIThemeGetTrackDragRect(&tdi, &macRect);
5475 ControlPartCode cpc;
5476 if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5477 cpc = sc == SC_ScrollBarSubPage ? kControlPageDownPart
5478 : kControlPageUpPart;
5480 cpc = sc == SC_ScrollBarSubLine ? kControlUpButtonPart
5481 : kControlDownButtonPart;
5482 if (slider->direction == Qt::RightToLeft
5483 && slider->orientation == Qt::Horizontal) {
5484 if (cpc == kControlDownButtonPart)
5485 cpc = kControlUpButtonPart;
5486 else if (cpc == kControlUpButtonPart)
5487 cpc = kControlDownButtonPart;
5490 HIThemeGetTrackPartBounds(&tdi, cpc, &macRect);
5492 ret = qt_qrectForHIRect(macRect);
5494 // Tweak: the dark line between the sub/add line buttons belong to only one of the buttons
5495 // when doing hit-testing, but both of them have to repaint it. Extend the rect to cover
5496 // the line in the cases where HIThemeGetTrackPartBounds returns a rect that doesn't.
5497 if (slider->orientation == Qt::Horizontal) {
5498 if (slider->direction == Qt::LeftToRight && sc == SC_ScrollBarSubLine)
5499 ret.adjust(0, 0, 1, 0);
5500 else if (slider->direction == Qt::RightToLeft && sc == SC_ScrollBarAddLine)
5501 ret.adjust(-1, 0, 1, 0);
5502 } else if (sc == SC_ScrollBarAddLine) {
5503 ret.adjust(0, -1, 0, 1);
5508 if (const QStyleOptionTitleBar *titlebar
5509 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5510 HIThemeWindowDrawInfo wdi;
5511 memset(&wdi, 0, sizeof(wdi));
5512 wdi.version = qt_mac_hitheme_version;
5513 wdi.state = kThemeStateActive;
5514 wdi.windowType = QtWinType;
5515 wdi.titleHeight = titlebar->rect.height();
5516 wdi.titleWidth = titlebar->rect.width();
5517 wdi.attributes = kThemeWindowHasTitleText;
5518 if (titlebar->subControls & SC_TitleBarCloseButton)
5519 wdi.attributes |= kThemeWindowHasCloseBox;
5520 if (titlebar->subControls & SC_TitleBarMaxButton
5521 | SC_TitleBarNormalButton)
5522 wdi.attributes |= kThemeWindowHasFullZoom;
5523 if (titlebar->subControls & SC_TitleBarMinButton)
5524 wdi.attributes |= kThemeWindowHasCollapseBox;
5525 WindowRegionCode wrc = kWindowGlobalPortRgn;
5527 if (sc == SC_TitleBarCloseButton)
5528 wrc = kWindowCloseBoxRgn;
5529 else if (sc == SC_TitleBarMinButton)
5530 wrc = kWindowCollapseBoxRgn;
5531 else if (sc == SC_TitleBarMaxButton)
5532 wrc = kWindowZoomBoxRgn;
5533 else if (sc == SC_TitleBarLabel)
5534 wrc = kWindowTitleTextRgn;
5535 else if (sc == SC_TitleBarSysMenu)
5536 ret.setRect(-1024, -1024, 10, proxy()->pixelMetric(PM_TitleBarHeight,
5538 if (wrc != kWindowGlobalPortRgn) {
5539 QCFType<HIShapeRef> region;
5540 QRect tmpRect = titlebar->rect;
5541 HIRect titleRect = qt_hirectForQRect(tmpRect);
5542 HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, ®ion);
5543 ptrHIShapeGetBounds(region, &titleRect);
5545 tmpRect.translate(tmpRect.x() - int(titleRect.origin.x),
5546 tmpRect.y() - int(titleRect.origin.y));
5547 titleRect = qt_hirectForQRect(tmpRect);
5548 HIThemeGetWindowShape(&titleRect, &wdi, wrc, ®ion);
5549 ptrHIShapeGetBounds(region, &titleRect);
5550 ret = qt_qrectForHIRect(titleRect);
5555 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5556 HIThemeButtonDrawInfo bdi;
5557 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5560 case SC_ComboBoxEditField:{
5561 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5562 // hack to posistion the edit feld correctly for QDateTimeEdits
5563 // in calendarPopup mode.
5564 if (qobject_cast<const QDateTimeEdit *>(widget)) {
5565 ret.moveTop(ret.top() - 2);
5566 ret.setHeight(ret.height() +1);
5569 case SC_ComboBoxArrow:{
5570 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5571 ret.setX(ret.x() + ret.width());
5572 ret.setWidth(combo->rect.right() - ret.right());
5574 case SC_ComboBoxListBoxPopup:{
5575 if (combo->editable) {
5576 HIRect inner = QMacStylePrivate::comboboxInnerBounds(qt_hirectForQRect(combo->rect), bdi.kind);
5577 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5578 const int comboTop = combo->rect.top();
5579 ret = QRect(qRound(inner.origin.x),
5581 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5582 editRect.bottom() - comboTop + 2);
5584 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5585 ret = QRect(combo->rect.x() + 4 - 11,
5586 combo->rect.y() + 1,
5587 editRect.width() + 10 + 11,
5597 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5598 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5599 bool flat = (groupBox->features & QStyleOptionFrameV2::Flat);
5600 bool hasNoText = !checkable && groupBox->text.isEmpty();
5602 case SC_GroupBoxLabel:
5603 case SC_GroupBoxCheckBox: {
5604 // Cheat and use the smaller font if we need to
5605 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5606 bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
5607 || !QApplication::desktopSettingsAware();
5610 int margin = flat || hasNoText ? 0 : 12;
5611 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5614 HIThemeTextInfo tti;
5615 tti.version = qt_mac_hitheme_version;
5616 tti.state = kThemeStateActive;
5617 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5618 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5619 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5620 tti.options = kHIThemeTextBoxOptionNone;
5621 tti.truncationPosition = kHIThemeTextTruncationNone;
5622 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5625 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5626 HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0);
5630 QFontMetricsF fm = QFontMetricsF(groupBox->fontMetrics);
5631 h = qCeil(fm.height());
5632 tw = qCeil(fm.size(Qt::TextShowMnemonic, groupBox->text).width());
5636 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5638 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
5639 bool rtl = groupBox->direction == Qt::RightToLeft;
5640 if (sc == SC_GroupBoxLabel) {
5642 int newSum = indicatorWidth + 1;
5643 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5644 labelRect.moveLeft(newLeft);
5646 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5647 labelRect.moveLeft(newLeft);
5648 labelRect.moveTop(labelRect.top() + 3);
5650 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5651 labelRect.moveLeft(newLeft);
5652 labelRect.moveTop(labelRect.top() + 5);
5657 if (sc == SC_GroupBoxCheckBox) {
5658 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left();
5659 ret.setRect(left, ret.top(),
5660 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
5664 case SC_GroupBoxContents:
5665 case SC_GroupBoxFrame: {
5667 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5670 QFontMetrics fm = groupBox->fontMetrics;
5671 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5674 if (widget && !widget->testAttribute(Qt::WA_SetFont)
5675 && QApplication::desktopSettingsAware())
5676 fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5679 yOffset = -qCeil(QFontMetricsF(fm).height());
5682 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5683 if (sc == SC_GroupBoxContents)
5684 ret.adjust(3, 3, -3, -4); // guess
5688 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5694 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5695 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(spin, widget);
5698 int fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5701 case QAquaSizeUnknown:
5702 case QAquaSizeLarge:
5706 case QAquaSizeSmall:
5718 case SC_SpinBoxDown: {
5719 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
5723 const int x = spin->rect.width() - spinner_w;
5724 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
5725 HIThemeButtonDrawInfo bdi;
5726 bdi.version = qt_mac_hitheme_version;
5727 bdi.kind = kThemeIncDecButton;
5731 case QAquaSizeUnknown:
5732 case QAquaSizeLarge:
5733 bdi.kind = kThemeIncDecButton;
5736 case QAquaSizeSmall:
5737 bdi.kind = kThemeIncDecButtonSmall;
5738 hackTranslateX = -2;
5741 bdi.kind = kThemeIncDecButtonMini;
5742 hackTranslateX = -1;
5745 bdi.state = kThemeStateActive;
5746 bdi.value = kThemeButtonOff;
5747 bdi.adornment = kThemeAdornmentNone;
5748 HIRect hirect = qt_hirectForQRect(ret);
5751 HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect);
5752 ret = qt_qrectForHIRect(outRect);
5755 ret.setHeight(ret.height() / 2);
5757 case SC_SpinBoxDown:
5758 ret.setY(ret.y() + ret.height() / 2);
5764 ret.translate(hackTranslateX, 0); // hack: position the buttons correctly (weird that we need this)
5765 ret = visualRect(spin->direction, spin->rect, ret);
5768 case SC_SpinBoxEditField:
5769 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons) {
5771 spin->rect.width() - fw * 2,
5772 spin->rect.height() - fw * 2);
5775 spin->rect.width() - fw * 2 - spinBoxSep - spinner_w,
5776 spin->rect.height() - fw * 2);
5778 ret = visualRect(spin->direction, spin->rect, ret);
5781 ret = QWindowsStyle::subControlRect(cc, spin, sc, widget);
5787 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5788 if (sc == SC_ToolButtonMenu && widget && !qobject_cast<QToolBar*>(widget->parentWidget())) {
5789 ret.adjust(-1, 0, 0, 0);
5793 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5799 QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5800 const QSize &csz, const QWidget *widget) const
5803 bool useAquaGuideline = true;
5806 case QStyle::CT_SpinBox:
5807 // hack to work around horrible sizeHint() code in QAbstractSpinBox
5808 sz.setHeight(sz.height() - 3);
5810 case QStyle::CT_TabWidget:
5811 // the size between the pane and the "contentsRect" (+4,+4)
5812 // (the "contentsRect" is on the inside of the pane)
5813 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
5815 This is supposed to show the relationship between the tabBar and
5816 the stack widget of a QTabWidget.
5817 Unfortunately ascii is not a good way of representing graphics.....
5818 PS: The '=' line is the painted frame.
5824 | vvv just outside the painted frame is the "pane"
5825 - -|- - - - - - - - - - <-+
5826 TAB BAR +=====^============ | +2 pixels
5827 - - -|- - -|- - - - - - - <-+
5828 | | ^ ^^^ just inside the painted frame is the "contentsRect"
5832 bottom ------+ <-+ +14 pixels
5835 ------------------------------ <- top of stack widget
5839 * 2 is the distance between the pane and the contentsRect
5840 * The 14 and the 1's are the distance from the contentsRect to the stack widget.
5841 (same value as used in SE_TabWidgetTabContents)
5842 * overlap is how much the pane should overlap the tab bar
5844 // then add the size between the stackwidget and the "contentsRect"
5846 if (const QStyleOptionTabWidgetFrame *twf
5847 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
5849 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
5850 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5852 if (getTabDirection(twf->shape) == kThemeTabNorth || getTabDirection(twf->shape) == kThemeTabSouth) {
5853 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5855 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5861 case QStyle::CT_TabBarTab:
5862 if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
5863 const QAquaWidgetSize AquaSize = d->aquaSizeConstrain(opt, widget);
5864 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
5865 || !QApplication::desktopSettingsAware();
5866 ThemeTabDirection ttd = getTabDirection(tab->shape);
5867 bool vertTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
5870 int defaultTabHeight;
5871 int defaultExtraSpace = proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget); // Remove spurious gcc warning (AFAIK)
5872 QFontMetrics fm = opt->fontMetrics;
5874 case QAquaSizeUnknown:
5875 case QAquaSizeLarge:
5876 if (tab->documentMode)
5877 defaultTabHeight = 23;
5879 defaultTabHeight = 21;
5881 case QAquaSizeSmall:
5882 defaultTabHeight = 18;
5885 defaultTabHeight = 16;
5888 bool setWidth = false;
5889 if (differentFont || !tab->icon.isNull()) {
5890 sz.rheight() = qMax(defaultTabHeight, sz.height());
5892 QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text);
5893 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5894 sz.rwidth() = textSize.width() + defaultExtraSpace;
5901 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5902 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5904 int widgetWidth = 0;
5905 int widgetHeight = 0;
5907 if (tab->leftButtonSize.isValid()) {
5909 widgetWidth += tab->leftButtonSize.width();
5910 widgetHeight += tab->leftButtonSize.height();
5912 if (tab->rightButtonSize.isValid()) {
5914 widgetWidth += tab->rightButtonSize.width();
5915 widgetHeight += tab->rightButtonSize.height();
5919 sz.setHeight(sz.height() + widgetHeight + padding);
5920 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5923 sz.setWidth(sz.width() + widgetWidth + padding);
5924 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5928 case QStyle::CT_PushButton:
5929 // By default, we fit the contents inside a normal rounded push button.
5930 // Do this by add enough space around the contents so that rounded
5931 // borders (including highlighting when active) will show.
5932 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
5933 sz.rheight() += QMacStylePrivate::PushButtonTopOffset + QMacStylePrivate::PushButtonBottomOffset;
5935 case QStyle::CT_MenuItem:
5936 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5937 int maxpmw = mi->maxIconWidth;
5938 const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
5941 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5944 GetThemeMenuSeparatorHeight(&ash);
5947 h = mi->fontMetrics.height() + 2;
5948 if (!mi->icon.isNull()) {
5950 const QSize &iconSize = comboBox->iconSize();
5951 h = qMax(h, iconSize.height() + 4);
5952 maxpmw = qMax(maxpmw, iconSize.width());
5954 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5955 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5959 if (mi->text.contains(QLatin1Char('\t')))
5961 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5965 // add space for a check. All items have place for a check too.
5967 if (comboBox && comboBox->isVisible()) {
5968 QStyleOptionComboBox cmb;
5969 cmb.initFrom(comboBox);
5970 cmb.editable = false;
5971 cmb.subControls = QStyle::SC_ComboBoxEditField;
5972 cmb.activeSubControls = QStyle::SC_None;
5973 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
5974 QStyle::SC_ComboBoxEditField,
5983 if (widget && qobject_cast<const QToolBar *>(widget->parentWidget())) {
5984 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->parent())) {
5985 if (mainWindow->unifiedTitleAndToolBarOnMac()) {
5987 if (sz.height() <= 32) {
5988 // Workaround strange HIToolBar bug when getting constraints.
6002 QStyleHintReturnMask menuMask;
6003 QStyleOption myOption = *opt;
6004 myOption.rect.setSize(sz);
6005 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask)) {
6006 sz = menuMask.region.boundingRect().size();
6009 case CT_HeaderSection:{
6010 const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
6011 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6012 if (header->text.contains(QLatin1Char('\n')))
6013 useAquaGuideline = false;
6016 // Make sure that the scroll bar is large enough to display the thumb indicator.
6017 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6018 const int minimumSize = scrollButtonsCutoffSize(thumbIndicatorCutoff, widgetSizePolicy(widget));
6019 if (slider->orientation == Qt::Horizontal)
6020 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6022 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6025 case CT_ItemViewItem:
6026 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
6027 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6028 sz.setHeight(sz.height() + 2);
6033 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6036 if (useAquaGuideline){
6038 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QAquaSizeUnknown) {
6039 if (macsz.width() != -1)
6040 sz.setWidth(macsz.width());
6041 if (macsz.height() != -1)
6042 sz.setHeight(macsz.height());
6046 // The sizes that Carbon and the guidelines gives us excludes the focus frame.
6047 // We compensate for this by adding some extra space here to make room for the frame when drawing:
6048 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
6049 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6051 switch (widgetSize) {
6053 case QAquaSizeLarge:
6054 bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
6056 case QAquaSizeSmall:
6057 bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
6060 bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
6063 HIRect tmpRect = {{0, 0}, {0, 0}};
6064 HIRect diffRect = QMacStylePrivate::comboboxInnerBounds(tmpRect, bkind);
6065 sz.rwidth() -= qRound(diffRect.size.width);
6066 sz.rheight() -= qRound(diffRect.size.height);
6067 } else if (ct == CT_PushButton || ct == CT_ToolButton){
6068 ThemeButtonKind bkind;
6069 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6073 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6074 if (btn->features & QStyleOptionButton::CommandLinkButton) {
6075 return QWindowsStyle::sizeFromContents(ct, opt, sz, widget);
6079 switch (widgetSize) {
6081 case QAquaSizeLarge:
6082 bkind = kThemePushButton;
6084 case QAquaSizeSmall:
6085 bkind = kThemePushButtonSmall;
6088 bkind = kThemePushButtonMini;
6093 switch (widgetSize) {
6095 case QAquaSizeLarge:
6096 bkind = kThemeLargeBevelButton;
6099 case QAquaSizeSmall:
6100 bkind = kThemeSmallBevelButton;
6105 HIThemeButtonDrawInfo bdi;
6106 bdi.version = qt_mac_hitheme_version;
6107 bdi.state = kThemeStateActive;
6109 bdi.value = kThemeButtonOff;
6110 bdi.adornment = kThemeAdornmentNone;
6111 HIRect macRect, myRect;
6112 myRect = CGRectMake(0, 0, sz.width(), sz.height());
6113 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
6114 // Mini buttons only return their actual size in HIThemeGetButtonBackgroundBounds, so help them out a bit (guess),
6115 if (bkind == kThemePushButtonMini)
6116 macRect.size.height += 8.;
6117 else if (bkind == kThemePushButtonSmall)
6118 macRect.size.height -= 10;
6119 sz.setWidth(sz.width() + int(macRect.size.width - myRect.size.width));
6120 sz.setHeight(sz.height() + int(macRect.size.height - myRect.size.height));
6125 void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
6126 bool enabled, const QString &text, QPalette::ColorRole textRole) const
6128 if(flags & Qt::TextShowMnemonic)
6129 flags |= Qt::TextHideMnemonic;
6130 QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6133 bool QMacStyle::event(QEvent *e)
6135 if(e->type() == QEvent::FocusIn) {
6137 QWidget *focusWidget = QApplication::focusWidget();
6138 #ifndef QT_NO_GRAPHICSVIEW
6139 if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
6140 QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
6141 if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
6142 QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(focusItem);
6143 if (proxy->widget())
6144 focusWidget = proxy->widget()->focusWidget();
6148 if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) {
6150 QWidget *top = f->parentWidget();
6151 while (top && !top->isWindow() && !(top->windowType() == Qt::SubWindow))
6152 top = top->parentWidget();
6153 #ifndef QT_NO_MAINWINDOW
6154 if (qobject_cast<QMainWindow *>(top)) {
6155 QWidget *central = static_cast<QMainWindow *>(top)->centralWidget();
6156 for (const QWidget *par = f; par; par = par->parentWidget()) {
6157 if (par == central) {
6161 if (par->isWindow())
6169 d->focusWidget = new QFocusFrame(f);
6170 d->focusWidget->setWidget(f);
6171 } else if(d->focusWidget) {
6172 d->focusWidget->setWidget(0);
6174 } else if(e->type() == QEvent::FocusOut) {
6176 d->focusWidget->setWidget(0);
6181 QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt,
6182 const QWidget *widget) const
6184 switch (standardIcon) {
6186 return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget);
6187 case SP_ToolBarHorizontalExtensionButton:
6188 case SP_ToolBarVerticalExtensionButton: {
6189 QPixmap pixmap(qt_mac_toolbar_ext);
6190 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6191 QPixmap pix2(pixmap.height(), pixmap.width());
6192 pix2.fill(Qt::transparent);
6194 p.translate(pix2.width(), 0);
6196 p.drawPixmap(0, 0, pixmap);
6204 int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
6205 QSizePolicy::ControlType control2,
6206 Qt::Orientation orientation,
6207 const QStyleOption *option,
6208 const QWidget *widget) const
6210 const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton;
6211 bool isMetal = (widget && widget->testAttribute(Qt::WA_MacBrushedMetal));
6212 int controlSize = getControlSize(option, widget);
6214 if (control2 == QSizePolicy::ButtonBox) {
6216 AHIG seems to prefer a 12-pixel margin between group
6217 boxes and the row of buttons. The 20 pixel comes from
6220 if (isMetal // (AHIG, guess, guess)
6221 || (control1 & (QSizePolicy::Frame // guess
6222 | QSizePolicy::GroupBox // (AHIG, guess, guess)
6223 | QSizePolicy::TabWidget // guess
6224 | ButtonMask))) { // AHIG
6225 return_SIZE(14, 8, 8);
6226 } else if (control1 == QSizePolicy::LineEdit) {
6227 return_SIZE(8, 8, 8); // Interface Builder
6229 return_SIZE(20, 7, 7); // Interface Builder
6233 if ((control1 | control2) & ButtonMask) {
6234 if (control1 == QSizePolicy::LineEdit)
6235 return_SIZE(8, 8, 8); // Interface Builder
6236 else if (control2 == QSizePolicy::LineEdit) {
6237 if (orientation == Qt::Vertical)
6238 return_SIZE(20, 7, 7); // Interface Builder
6240 return_SIZE(20, 8, 8);
6242 return_SIZE(14, 8, 8); // Interface Builder
6245 switch (CT2(control1, control2)) {
6246 case CT1(QSizePolicy::Label): // guess
6247 case CT2(QSizePolicy::Label, QSizePolicy::DefaultType): // guess
6248 case CT2(QSizePolicy::Label, QSizePolicy::CheckBox): // AHIG
6249 case CT2(QSizePolicy::Label, QSizePolicy::ComboBox): // AHIG
6250 case CT2(QSizePolicy::Label, QSizePolicy::LineEdit): // guess
6251 case CT2(QSizePolicy::Label, QSizePolicy::RadioButton): // AHIG
6252 case CT2(QSizePolicy::Label, QSizePolicy::Slider): // guess
6253 case CT2(QSizePolicy::Label, QSizePolicy::SpinBox): // guess
6254 case CT2(QSizePolicy::Label, QSizePolicy::ToolButton): // guess
6255 return_SIZE(8, 6, 5);
6256 case CT1(QSizePolicy::ToolButton):
6258 case CT1(QSizePolicy::CheckBox):
6259 case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton):
6260 case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox):
6261 if (orientation == Qt::Vertical)
6262 return_SIZE(8, 8, 7); // AHIG and Builder
6264 case CT1(QSizePolicy::RadioButton):
6265 if (orientation == Qt::Vertical)
6266 return 5; // (Builder, guess, AHIG)
6269 if (orientation == Qt::Horizontal
6270 && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton)))
6271 return_SIZE(12, 10, 8); // guess
6273 if ((control1 | control2) & (QSizePolicy::Frame
6274 | QSizePolicy::GroupBox
6275 | QSizePolicy::TabWidget)) {
6277 These values were chosen so that nested container widgets
6278 look good side by side. Builder uses 8, which looks way
6279 too small, and AHIG doesn't say anything.
6281 return_SIZE(16, 10, 10); // guess
6284 if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider))
6285 return_SIZE(12, 10, 8); // AHIG
6287 if ((control1 | control2) & QSizePolicy::LineEdit)
6288 return_SIZE(10, 8, 8); // AHIG
6291 AHIG and Builder differ by up to 4 pixels for stacked editable
6292 comboboxes. We use some values that work fairly well in all
6295 if ((control1 | control2) & QSizePolicy::ComboBox)
6296 return_SIZE(10, 8, 7); // guess
6299 Builder defaults to 8, 6, 5 in lots of cases, but most of the time the
6300 result looks too cramped.
6302 return_SIZE(10, 8, 6); // guess
6305 void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
6307 CGAffineTransform old_xform = CGAffineTransformIdentity;
6308 if (orig_xform) { //setup xforms
6309 old_xform = CGContextGetCTM(hd);
6310 CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
6311 CGContextConcatCTM(hd, *orig_xform);
6315 CGContextBeginPath(hd);
6316 if (rgn.isEmpty()) {
6317 CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
6319 QCFType<HIMutableShapeRef> shape = qt_mac_toHIMutableShape(rgn);
6320 Q_ASSERT(!HIShapeIsEmpty(shape));
6321 HIShapeReplacePathInCGContext(shape, hd);
6325 if (orig_xform) {//reset xforms
6326 CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
6327 CGContextConcatCTM(hd, old_xform);
6331 QMacCGContext::QMacCGContext(QPainter *p)
6333 QPaintEngine *pe = p->paintEngine();
6337 int devType = p->device()->devType();
6338 if (pe->type() == QPaintEngine::Raster
6339 && (devType == QInternal::Widget ||
6340 devType == QInternal::Pixmap ||
6341 devType == QInternal::Image)) {
6343 extern CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice);
6344 CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pe->paintDevice());
6345 uint flags = kCGImageAlphaPremultipliedFirst;
6346 flags |= kCGBitmapByteOrder32Host;
6348 const QImage *image = (const QImage *) pe->paintDevice();
6350 context = CGBitmapContextCreate((void *) image->bits(), image->width(), image->height(),
6351 8, image->bytesPerLine(), colorspace, flags);
6353 CGContextTranslateCTM(context, 0, image->height());
6354 CGContextScaleCTM(context, 1, -1);
6356 if (devType == QInternal::Widget) {
6357 QRegion clip = p->paintEngine()->systemClip();
6358 QTransform native = p->deviceTransform();
6359 QTransform logical = p->combinedTransform();
6361 if (p->hasClipping()) {
6362 QRegion r = p->clipRegion();
6363 r.translate(native.dx(), native.dy());
6369 qt_mac_clip_cg(context, clip, 0);
6371 CGContextTranslateCTM(context, native.dx(), native.dy());
6374 qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType;
6378 CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice)
6380 bool isWidget = (paintDevice->devType() == QInternal::Widget);
6381 return qt_mac_displayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice) : 0);
6386 Returns the CoreGraphics CGContextRef of the paint device. 0 is
6387 returned if it can't be obtained. It is the caller's responsibility to
6388 CGContextRelease the context when finished using it.
6390 \warning This function is only available on Mac OS X.
6393 CGContextRef qt_mac_cg_context(const QPaintDevice *pdev)
6395 if (pdev->devType() == QInternal::Pixmap) {
6396 const QPixmap *pm = static_cast<const QPixmap*>(pdev);
6397 CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev);
6398 uint flags = kCGImageAlphaPremultipliedFirst;
6399 flags |= kCGBitmapByteOrder32Host;
6400 CGContextRef ret = 0;
6402 QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data();
6403 if (data->classId() == QPlatformPixmap::RasterClass) {
6404 QImage *image = data->buffer();
6405 ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(),
6406 8, image->bytesPerLine(), colorspace, flags);
6408 qDebug() << "qt_mac_cg_context: Unsupported pixmap class";
6411 CGContextTranslateCTM(ret, 0, pm->height());
6412 CGContextScaleCTM(ret, 1, -1);
6414 } else if (pdev->devType() == QInternal::Widget) {
6415 //CGContextRef ret = static_cast<CGContextRef>(static_cast<const QWidget *>(pdev)->macCGHandle());
6416 ///CGContextRetain(ret);
6418 qDebug() << "qt_mac_cg_context: not implemented: Widget class";
6425 FontHash::FontHash()
6427 QHash<QByteArray, QFont>::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts());
6430 Q_GLOBAL_STATIC(FontHash, app_fonts)
6431 FontHash *qt_app_fonts_hash()