Merge branch '4.5' of git@scm.dev.nokia.troll.no:qt/qt
[qt-netbsd.git] / src / gui / styles / qmacstyle_mac.mm
blobfad9995c9c297da888170f7e5c51751cf29d51ad
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file.  Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file.  Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at qt-sales@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "qmacstyle_mac.h"
44 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
45 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
46 //#define DEBUG_SIZE_CONSTRAINT
48 #include <private/qcombobox_p.h>
49 #include <private/qmacstylepixmaps_mac_p.h>
50 #include <private/qpaintengine_mac_p.h>
51 #include <private/qpainter_p.h>
52 #include <private/qprintengine_mac_p.h>
53 #include <private/qstylehelper_p.h>
54 #include <qapplication.h>
55 #include <qbitmap.h>
56 #include <qcheckbox.h>
57 #include <qcombobox.h>
58 #include <qdialogbuttonbox.h>
59 #include <qdockwidget.h>
60 #include <qevent.h>
61 #include <qfocusframe.h>
62 #include <qformlayout.h>
63 #include <qgroupbox.h>
64 #include <qhash.h>
65 #include <qheaderview.h>
66 #include <qlayout.h>
67 #include <qlineedit.h>
68 #include <qlistview.h>
69 #include <qmainwindow.h>
70 #include <qmap.h>
71 #include <qmenubar.h>
72 #include <qpaintdevice.h>
73 #include <qpainter.h>
74 #include <qpixmapcache.h>
75 #include <qpointer.h>
76 #include <qprogressbar.h>
77 #include <qpushbutton.h>
78 #include <qradiobutton.h>
79 #include <qrubberband.h>
80 #include <qsizegrip.h>
81 #include <qspinbox.h>
82 #include <qsplitter.h>
83 #include <qstyleoption.h>
84 #include <qtextedit.h>
85 #include <qtextstream.h>
86 #include <qtoolbar.h>
87 #include <qtoolbutton.h>
88 #include <qtreeview.h>
89 #include <qtableview.h>
90 #include <qwizard.h>
91 #include <qdebug.h>
92 #include <qlibrary.h>
93 #include <qdatetimeedit.h>
94 #include <QtGui/qgraphicsproxywidget.h>
95 #include <QtGui/qgraphicsview.h>
96 #include <private/qt_cocoa_helpers_mac_p.h>
98 QT_BEGIN_NAMESPACE
100 extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
101 extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp
103 // The following constants are used for adjusting the size
104 // of push buttons so that they are drawn inside their bounds.
105 static const int PushButtonLeftOffset = 6;
106 static const int PushButtonTopOffset = 4;
107 static const int PushButtonRightOffset = 12;
108 static const int PushButtonBottomOffset = 12;
109 static const int MiniButtonH = 26;
110 static const int SmallButtonH = 30;
111 static const int BevelButtonW = 50;
112 static const int BevelButtonH = 22;
113 static const int PushButtonContentPadding = 6;
115 // These colors specify the titlebar gradient colors on
116 // Leopard. Ideally we should get them from the system.
117 static const QColor titlebarGradientActiveBegin(220, 220, 220);
118 static const QColor titlebarGradientActiveEnd(151, 151, 151);
119 static const QColor titlebarSeparatorLineActive(111, 111, 111);
120 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
121 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
122 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
124 // Gradient colors used for the dock widget title bar and
125 // non-unifed tool bar bacground.
126 static const QColor mainWindowGradientBegin(240, 240, 240);
127 static const QColor mainWindowGradientEnd(200, 200, 200);
129 #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
130 enum {
131     kThemePushButtonTextured = 31,
132     kThemePushButtonTexturedSmall = 32,
133     kThemePushButtonTexturedMini = 33
135 #endif
137 // Resolve these at run-time, since the functions was moved in Leopard.
138 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
139 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
141 static bool isVerticalTabs(const QTabBar::Shape shape) {
142     return (shape == QTabBar::RoundedEast
143                 || shape == QTabBar::TriangularEast
144                 || shape == QTabBar::RoundedWest
145                 || shape == QTabBar::TriangularWest);
148 static int closeButtonSize = 12;
150 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
152     // draw background circle
153     p->setRenderHints(QPainter::Antialiasing);
154     QRect rect(0, 0, closeButtonSize, closeButtonSize);
155     QColor background;
156     if (hover) {
157         background = QColor(124, 124, 124);
158     } else {
159         if (active) {
160             if (selected)
161                 background = QColor(104, 104, 104);
162             else
163                 background = QColor(83, 83, 83);
164         } else {
165             if (selected)
166                 background = QColor(144, 144, 144);
167             else
168                 background = QColor(114, 114, 114);
169         }
170     }
171     p->setPen(Qt::transparent);
172     p->setBrush(background);
173     p->drawEllipse(rect);
175     // draw cross
176     int min = 3;
177     int max = 9;
178     QPen crossPen;
179     crossPen.setColor(QColor(194, 194, 194));
180     crossPen.setWidthF(1.3);
181     crossPen.setCapStyle(Qt::FlatCap);
182     p->setPen(crossPen);
183     p->drawLine(min, min, max, max);
184     p->drawLine(min, max, max, min);
187 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
189     if (isVerticalTabs(shape)) {
190         int newX, newY, newRot;
191         if (shape == QTabBar::RoundedEast
192             || shape == QTabBar::TriangularEast) {
193             newX = tabRect.width();
194             newY = tabRect.y();
195             newRot = 90;
196         } else {
197             newX = 0;
198             newY = tabRect.y() + tabRect.height();
199             newRot = -90;
200         }
201         tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
202         QMatrix m;
203         m.translate(newX, newY);
204         m.rotate(newRot);
205         p->setMatrix(m, true);
206     }
207     return tabRect;
210 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt)
212     QRect r = tabOpt->rect;
213     p->translate(tabOpt->rect.x(), tabOpt->rect.y());
214     r.moveLeft(0);
215     r.moveTop(0);
216     QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
218     int width = tabRect.width();
219     int height = 20;
220     bool active = (tabOpt->state & QStyle::State_Active);
221     bool selected = (tabOpt->state & QStyle::State_Selected);
223     if (selected) {
224         QRect rect(1, 0, width - 2, height);
226         // fill body
227         if (active) {
228             p->fillRect(rect, QColor(151, 151, 151));
229         } else {
230             QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
231             gradient.setColorAt(0, QColor(207, 207, 207));
232             gradient.setColorAt(0.5, QColor(206, 206, 206));
233             gradient.setColorAt(1, QColor(201, 201, 201));
234             p->fillRect(rect, gradient);
235         }
237         // draw border
238         QColor borderSides;
239         QColor borderBottom;
240         if (active) {
241             borderSides = QColor(88, 88, 88);
242             borderBottom = QColor(88, 88, 88);
243         } else {
244             borderSides = QColor(121, 121, 121);
245             borderBottom = QColor(116, 116, 116);
246         }
248         p->setPen(borderSides);
250         int bottom = height;
251         // left line
252         p->drawLine(0, 1, 0, bottom-2);
253         // right line
254         p->drawLine(width-1, 1, width-1, bottom-2);
256         // bottom line
257         if (active) {
258             p->setPen(QColor(168, 168, 168));
259             p->drawLine(3, bottom-1, width-3, bottom-1);
260         }
261         p->setPen(borderBottom);
262         p->drawLine(2, bottom, width-2, bottom);
264         int w = 3;
265         QRectF rectangleLeft(1, height - w, w, w);
266         QRectF rectangleRight(width - 2, height - 1, w, w);
267         int startAngle = 180 * 16;
268         int spanAngle = 90 * 16;
269         p->setRenderHint(QPainter::Antialiasing);
270         p->drawArc(rectangleLeft, startAngle, spanAngle);
271         p->drawArc(rectangleRight, startAngle, -spanAngle);
272     } else {
273         // when the mouse is over non selected tabs they get a new color
274         bool hover = (tabOpt->state & QStyle::State_MouseOver);
275         if (hover) {
276             QRect rect(1, 2, width - 1, height - 1);
277             p->fillRect(rect, QColor(110, 110, 110));
278         }
280         // seperator lines between tabs
281         bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
282         bool drawOnRight = !west;
283         if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
284             || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
285             QColor borderColor;
286             QColor borderHighlightColor;
287             if (active) {
288                 borderColor = QColor(64, 64, 64);
289                 borderHighlightColor = QColor(140, 140, 140);
290             } else {
291                 borderColor = QColor(135, 135, 135);
292                 borderHighlightColor = QColor(178, 178, 178);
293             }
295             int x = drawOnRight ? width : 0;
297             // tab seperator line
298             p->setPen(borderColor);
299             p->drawLine(x, 2, x, height + 1);
301             // tab seperator highlight
302             p->setPen(borderHighlightColor);
303             p->drawLine(x-1, 2, x-1, height + 1);
304             p->drawLine(x+1, 2, x+1, height + 1);
305         }
306     }
309 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
311     QRect r = tbb->rect;
312     if (isVerticalTabs(tbb->shape)) {
313         r.setWidth(w->width());
314     } else {
315         r.setHeight(w->height());
316     }
317     QRect tabRect = rotateTabPainter(p, tbb->shape, r);
318     int width = tabRect.width();
319     int height = tabRect.height();
320     bool active = (tbb->state & QStyle::State_Active);
322     // top border lines
323     QColor borderHighlightTop;
324     QColor borderTop;
325     if (active) {
326         borderTop = QColor(64, 64, 64);
327         borderHighlightTop = QColor(174, 174, 174);
328     } else {
329         borderTop = QColor(135, 135, 135);
330         borderHighlightTop = QColor(207, 207, 207);
331     }
332     p->setPen(borderHighlightTop);
333     p->drawLine(0, 0, width, 0);
334     p->setPen(borderTop);
335     p->drawLine(0, 1, width, 1);
337     // center block
338     QRect centralRect(0, 2, width, height - 2);
339     if (active) {
340         QColor mainColor = QColor(120, 120, 120);
341         p->fillRect(centralRect, mainColor);
342     } else {
343         QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
344         gradient.setColorAt(0, QColor(165, 165, 165));
345         gradient.setColorAt(0.5, QColor(164, 164, 164));
346         gradient.setColorAt(1, QColor(158, 158, 158));
347         p->fillRect(centralRect, gradient);
348     }
350     // bottom border lines
351     QColor borderHighlightBottom;
352     QColor borderBottom;
353     if (active) {
354         borderHighlightBottom = QColor(153, 153, 153);
355         borderBottom = QColor(64, 64, 64);
356     } else {
357         borderHighlightBottom = QColor(177, 177, 177);
358         borderBottom = QColor(127, 127, 127);
359     }
360     p->setPen(borderHighlightBottom);
361     p->drawLine(0, height - 2, width, height - 2);
362     p->setPen(borderBottom);
363     p->drawLine(0, height - 1, width, height - 1);
367     AHIG:
368         Apple Human Interface Guidelines
369         http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/
371     Builder:
372         Apple Interface Builder v. 3.1.1
375 // this works as long as we have at most 16 different control types
376 #define CT1(c) CT2(c, c)
377 #define CT2(c1, c2) ((uint(c1) << 16) | uint(c2))
379 enum QAquaWidgetSize { QAquaSizeLarge = 0, QAquaSizeSmall = 1, QAquaSizeMini = 2,
380                        QAquaSizeUnknown = -1 };
382 #define SIZE(large, small, mini) \
383     (controlSize == QAquaSizeLarge ? (large) : controlSize == QAquaSizeSmall ? (small) : (mini))
385 // same as return SIZE(...) but optimized
386 #define return_SIZE(large, small, mini) \
387     do { \
388         static const int sizes[] = { (large), (small), (mini) }; \
389         return sizes[controlSize]; \
390     } while (0)
392 static int getControlSize(const QStyleOption *option, const QWidget *widget)
394     if (option) {
395         if (option->state & (QStyle::State_Small | QStyle::State_Mini))
396             return (option->state & QStyle::State_Mini) ? QAquaSizeMini : QAquaSizeSmall;
397     } else if (widget) {
398         switch (QMacStyle::widgetSizePolicy(widget)) {
399         case QMacStyle::SizeSmall:
400             return QAquaSizeSmall;
401         case QMacStyle::SizeMini:
402             return QAquaSizeMini;
403         default:
404             break;
405         }
406     }
407     return QAquaSizeLarge;
411 static inline bool isTreeView(const QWidget *widget)
413     return (widget && widget->parentWidget() &&
414             (qobject_cast<const QTreeView *>(widget->parentWidget())
415 #ifdef QT3_SUPPORT
416              || widget->parentWidget()->inherits("Q3ListView")
417 #endif
418              ));
421 QString qt_mac_removeMnemonics(const QString &original)
423     // copied from qt_format_text (to be bug-for-bug compatible).
424     QString returnText(original.size(), 0);
425     int finalDest = 0;
426     int currPos = 0;
427     int l = original.length();
428     while (l) {
429         if (original.at(currPos) == QLatin1Char('&')) {
430             ++currPos;
431             --l;
432             if (l == 0)
433                 break;
434         }
435         returnText[finalDest] = original.at(currPos);
436         ++currPos;
437         ++finalDest;
438         --l;
439     }
440     returnText.truncate(finalDest);
441     return returnText;
444 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
446     ThemeTabDirection ttd;
447     switch (shape) {
448     case QTabBar::RoundedSouth:
449     case QTabBar::TriangularSouth:
450         ttd = kThemeTabSouth;
451         break;
452     default:  // Added to remove the warning, since all values are taken care of, really!
453     case QTabBar::RoundedNorth:
454     case QTabBar::TriangularNorth:
455         ttd = kThemeTabNorth;
456         break;
457     case QTabBar::RoundedWest:
458     case QTabBar::TriangularWest:
459         ttd = kThemeTabWest;
460         break;
461     case QTabBar::RoundedEast:
462     case QTabBar::TriangularEast:
463         ttd = kThemeTabEast;
464         break;
465     }
466     return ttd;
469 class QMacStylePrivate : public QObject
471     Q_OBJECT
473 public:
474     QMacStylePrivate(QMacStyle *style);
476     // Stuff from QAquaAnimate:
477     bool addWidget(QWidget *);
478     void removeWidget(QWidget *);
480     enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen };
481     bool animatable(Animates, const QWidget *) const;
482     void stopAnimate(Animates, QWidget *);
483     void startAnimate(Animates, QWidget *);
484     static ThemeDrawState getDrawState(QStyle::State flags);
485     QAquaWidgetSize aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
486                              QStyle::ContentsType ct = QStyle::CT_CustomBase,
487                              QSize szHint=QSize(-1, -1), QSize *insz = 0) const;
488     void getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
489                           HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe);
490     bool doAnimate(Animates);
491     inline int animateSpeed(Animates) const { return 33; }
493     // Utility functions
494     void drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
495                              QPainter *p, const QStyleOption *opt) const;
497     void drawPantherTab(const QStyleOptionTab *tab, QPainter *p, const QWidget *w = 0) const;
499     QSize pushButtonSizeFromContents(const QStyleOptionButton *btn) const;
501     HIRect pushButtonContentBounds(const QStyleOptionButton *btn,
502                                    const HIThemeButtonDrawInfo *bdi) const;
504     void initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
505                         const QWidget *widget, const ThemeDrawState &tds);
507     static HIRect comboboxInnerBounds(const HIRect &outerBounds, int buttonKind);
509     static QRect comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi);
511     static void drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p);
512     static void drawTableHeader(const HIRect &outerBounds, bool drawTopBorder, bool drawLeftBorder,
513                                      const HIThemeButtonDrawInfo &bdi, QPainter *p);
514     bool contentFitsInPushButton(const QStyleOptionButton *btn, HIThemeButtonDrawInfo *bdi,
515                                  ThemeButtonKind buttonKindToCheck) const;
516     void initHIThemePushButton(const QStyleOptionButton *btn, const QWidget *widget,
517                                const ThemeDrawState tds,
518                                HIThemeButtonDrawInfo *bdi) const;
519     QPixmap generateBackgroundPattern() const;
520 protected:
521     bool eventFilter(QObject *, QEvent *);
522     void timerEvent(QTimerEvent *);
524 private slots:
525     void startAnimationTimer();
527 public:
528     QPointer<QPushButton> defaultButton; //default push buttons
529     int timerID;
530     QList<QPointer<QWidget> > progressBars; //existing progress bars that need animation
532     struct ButtonState {
533         int frame;
534         enum { ButtonDark, ButtonLight } dir;
535     } buttonState;
536     UInt8 progressFrame;
537     QPointer<QFocusFrame> focusWidget;
538     CFAbsoluteTime defaultButtonStart;
539     QMacStyle *q;
540     bool mouseDown;
543 QT_BEGIN_INCLUDE_NAMESPACE
544 #include "qmacstyle_mac.moc"
545 QT_END_INCLUDE_NAMESPACE
547 /*****************************************************************************
548   External functions
549  *****************************************************************************/
550 extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
551 extern QPixmap qt_mac_convert_iconref(const IconRef, int, int); //qpixmap_mac.cpp
552 extern QRegion qt_mac_convert_mac_region(HIShapeRef); //qregion_mac.cpp
553 void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
554 extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp
556 /*****************************************************************************
557   QMacCGStyle globals
558  *****************************************************************************/
559 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
560 const int macSpinBoxSep        = 5;    // distance between spinwidget and the lineedit
561 const int macItemFrame         = 2;    // menu item frame width
562 const int macItemHMargin       = 3;    // menu item hor text margin
563 const int macItemVMargin       = 2;    // menu item ver text margin
564 const int macRightBorder       = 12;   // right border on mac
565 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
566 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
568 /*****************************************************************************
569   QMacCGStyle utility functions
570  *****************************************************************************/
571 static inline int qt_mac_hitheme_tab_version()
573 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
574     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4)
575         return 1;
576 #endif
577     return 0;
580 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
582     return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
583                       convertRect.width() - rect.width(), convertRect.height() - rect.height());
586 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
588     return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
589                  QSize(int(hirect.size.width), int(hirect.size.height)));
592 inline bool qt_mac_is_metal(const QWidget *w)
594     for (; w; w = w->parentWidget()) {
595         if (w->testAttribute(Qt::WA_MacBrushedMetal))
596             return true;
597         if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) {  // If not created will fall through to the opaque check and be fine anyway.
598                         return macWindowIsTextured(qt_mac_window_for(w));
599         }
600         if (w->d_func()->isOpaque)
601             break;
602     }
603     return false;
606 static int qt_mac_aqua_get_metric(ThemeMetric met)
608     SInt32 ret;
609     GetThemeMetric(met, &ret);
610     return ret;
613 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
614                                     QAquaWidgetSize sz)
616     QSize ret(-1, -1);
617     if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
618         qDebug("Not sure how to return this...");
619         return ret;
620     }
621     if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
622         // If you're using a custom font and it's bigger than the default font,
623         // then no constraints for you. If you are smaller, we can try to help you out
624         QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
625         if (widg->font().pointSize() > font.pointSize())
626             return ret;
627     }
629     if (ct == QStyle::CT_CustomBase && widg) {
630         if (qobject_cast<const QPushButton *>(widg))
631             ct = QStyle::CT_PushButton;
632         else if (qobject_cast<const QRadioButton *>(widg))
633             ct = QStyle::CT_RadioButton;
634         else if (qobject_cast<const QCheckBox *>(widg))
635             ct = QStyle::CT_CheckBox;
636         else if (qobject_cast<const QComboBox *>(widg))
637             ct = QStyle::CT_ComboBox;
638         else if (qobject_cast<const QToolButton *>(widg))
639             ct = QStyle::CT_ToolButton;
640         else if (qobject_cast<const QSlider *>(widg))
641             ct = QStyle::CT_Slider;
642         else if (qobject_cast<const QProgressBar *>(widg))
643             ct = QStyle::CT_ProgressBar;
644         else if (qobject_cast<const QLineEdit *>(widg))
645             ct = QStyle::CT_LineEdit;
646         else if (qobject_cast<const QHeaderView *>(widg)
647 #ifdef QT3_SUPPORT
648                  || widg->inherits("Q3Header")
649 #endif
650                 )
651             ct = QStyle::CT_HeaderSection;
652         else if (qobject_cast<const QMenuBar *>(widg)
653 #ifdef QT3_SUPPORT
654                 || widg->inherits("Q3MenuBar")
655 #endif
656                )
657             ct = QStyle::CT_MenuBar;
658         else if (qobject_cast<const QSizeGrip *>(widg))
659             ct = QStyle::CT_SizeGrip;
660         else
661             return ret;
662     }
664     switch (ct) {
665     case QStyle::CT_PushButton: {
666         const QPushButton *psh = static_cast<const QPushButton *>(widg);
667         QString buttonText = qt_mac_removeMnemonics(psh->text());
668         if (buttonText.contains(QLatin1Char('\n')))
669             ret = QSize(-1, -1);
670         else if (sz == QAquaSizeLarge)
671             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
672         else if (sz == QAquaSizeSmall)
673             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
674         else if (sz == QAquaSizeMini)
675             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
677         if (!psh->icon().isNull()){
678             // If the button got an icon, and the icon is larger than the
679             // button, we can't decide on a default size
680             ret.setWidth(-1);
681             if (ret.height() < psh->iconSize().height())
682                 ret.setHeight(-1);
683         }
684         else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
685             // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
686             // However, this doesn't work for German, therefore only do it for English,
687             // I suppose it would be better to do some sort of lookups for languages
688             // that like to have really long words.
689             ret.setWidth(77 - 8);
690         }
692 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
693     } else if (ct == QStyle::CT_RadioButton) {
694         QRadioButton *rdo = static_cast<QRadioButton *>(widg);
695         // Exception for case where multiline radio button text requires no size constrainment
696         if (rdo->text().find('\n') != -1)
697             return ret;
698         if (sz == QAquaSizeLarge)
699             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
700         else if (sz == QAquaSizeSmall)
701             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
702         else if (sz == QAquaSizeMini)
703             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
704     } else if (ct == QStyle::CT_CheckBox) {
705         if (sz == QAquaSizeLarge)
706             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
707         else if (sz == QAquaSizeSmall)
708             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
709         else if (sz == QAquaSizeMini)
710             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
711 #endif
712         break;
713     }
714     case QStyle::CT_SizeGrip:
715         if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
716             HIRect r;
717             HIPoint p = { 0, 0 };
718             HIThemeGrowBoxDrawInfo gbi;
719             gbi.version = 0;
720             gbi.state = kThemeStateActive;
721             gbi.kind = kHIThemeGrowBoxKindNormal;
722             gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
723                                                           : kThemeGrowRight | kThemeGrowDown;
724             gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
725             if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr)
726                 ret = QSize(r.size.width, r.size.height);
727         }
728         break;
729     case QStyle::CT_ComboBox:
730         switch (sz) {
731         case QAquaSizeLarge:
732             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
733             break;
734         case QAquaSizeSmall:
735             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
736             break;
737         case QAquaSizeMini:
738             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
739             break;
740         default:
741             break;
742         }
743         break;
744     case QStyle::CT_ToolButton:
745         if (sz == QAquaSizeSmall) {
746             int width = 0, height = 0;
747             if (szHint == QSize(-1, -1)) { //just 'guess'..
748                 const QToolButton *bt = static_cast<const QToolButton *>(widg);
749                 if (!bt->icon().isNull()) {
750                     QSize iconSize = bt->iconSize();
751                     QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
752                     width = qMax(width, qMax(iconSize.width(), pmSize.width()));
753                     height = qMax(height, qMax(iconSize.height(), pmSize.height()));
754                 }
755                 if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
756                     int text_width = bt->fontMetrics().width(bt->text()),
757                        text_height = bt->fontMetrics().height();
758                     if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
759                         width = qMax(width, text_width);
760                         height += text_height;
761                     } else {
762                         width += text_width;
763                         width = qMax(height, text_height);
764                     }
765                 }
766             } else {
767                 width = szHint.width();
768                 height = szHint.height();
769             }
770             width =  qMax(20, width +  5); //border
771             height = qMax(20, height + 5); //border
772             ret = QSize(width, height);
773         }
774         break;
775     case QStyle::CT_Slider: {
776         int w = -1;
777         const QSlider *sld = static_cast<const QSlider *>(widg);
778         if (sz == QAquaSizeLarge) {
779             if (sld->orientation() == Qt::Horizontal) {
780                 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
781                 if (sld->tickPosition() != QSlider::NoTicks)
782                     w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
783             } else {
784                 w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
785                 if (sld->tickPosition() != QSlider::NoTicks)
786                     w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
787             }
788         } else if (sz == QAquaSizeSmall) {
789             if (sld->orientation() == Qt::Horizontal) {
790                 w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
791                 if (sld->tickPosition() != QSlider::NoTicks)
792                     w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
793             } else {
794                 w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
795                 if (sld->tickPosition() != QSlider::NoTicks)
796                     w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
797             }
798         } else if (sz == QAquaSizeMini) {
799             if (sld->orientation() == Qt::Horizontal) {
800                 w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
801                 if (sld->tickPosition() != QSlider::NoTicks)
802                     w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
803             } else {
804                 w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
805                 if (sld->tickPosition() != QSlider::NoTicks)
806                     w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
807             }
808         }
809         if (sld->orientation() == Qt::Horizontal)
810             ret.setHeight(w);
811         else
812             ret.setWidth(w);
813         break;
814     }
815     case QStyle::CT_ProgressBar: {
816         int finalValue = -1;
817         Qt::Orientation orient = Qt::Horizontal;
818         if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
819             orient = pb->orientation();
821         if (sz == QAquaSizeLarge)
822             finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
823                             + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
824         else
825             finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
826                             + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
827         if (orient == Qt::Horizontal)
828             ret.setHeight(finalValue);
829         else
830             ret.setWidth(finalValue);
831         break;
832     }
833     case QStyle::CT_LineEdit:
834         if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
835             //should I take into account the font dimentions of the lineedit? -Sam
836             if (sz == QAquaSizeLarge)
837                 ret = QSize(-1, 22);
838             else
839                 ret = QSize(-1, 19);
840         }
841         break;
842     case QStyle::CT_HeaderSection:
843         if (sz == QAquaSizeLarge && isTreeView(widg))
844            ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
845         break;
846     case QStyle::CT_MenuBar:
847         if (sz == QAquaSizeLarge) {
848 #ifndef QT_MAC_USE_COCOA
849             SInt16 size;
850             if (!GetThemeMenuBarHeight(&size))
851                 ret = QSize(-1, size);
852 #else
853             ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
854             // In the qt_mac_set_native_menubar(false) case,
855             // we come it here with a zero-height main menu,
856             // preventing the in-window menu from displaying.
857             // Use 22 pixels for the height, by observation.
858             if (ret.height() <= 0)
859                 ret.setHeight(22);
860 #endif
861         }
862         break;
863     default:
864         break;
865     }
866     return ret;
870 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
871 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
873     if (large == QSize(-1, -1)) {
874         if (small != QSize(-1, -1))
875             return QAquaSizeSmall;
876         if (mini != QSize(-1, -1))
877             return QAquaSizeMini;
878         return QAquaSizeUnknown;
879     } else if (small == QSize(-1, -1)) {
880         if (mini != QSize(-1, -1))
881             return QAquaSizeMini;
882         return QAquaSizeLarge;
883     } else if (mini == QSize(-1, -1)) {
884         return QAquaSizeLarge;
885     }
887 #ifndef QT_NO_MAINWINDOW
888     if (qobject_cast<QDockWidget *>(widg->window()) || !qgetenv("QWIDGET_ALL_SMALL").isNull()) {
889         //if (small.width() != -1 || small.height() != -1)
890         return QAquaSizeSmall;
891     } else if (!qgetenv("QWIDGET_ALL_MINI").isNull()) {
892         return QAquaSizeMini;
893     }
894 #endif
896 #if 0
897     /* Figure out which size we're closer to, I just hacked this in, I haven't
898        tested it as it would probably look pretty strange to have some widgets
899        big and some widgets small in the same window?? -Sam */
900     int large_delta=0;
901     if (large.width() != -1) {
902         int delta = large.width() - widg->width();
903         large_delta += delta * delta;
904     }
905     if (large.height() != -1) {
906         int delta = large.height() - widg->height();
907         large_delta += delta * delta;
908     }
909     int small_delta=0;
910     if (small.width() != -1) {
911         int delta = small.width() - widg->width();
912         small_delta += delta * delta;
913     }
914     if (small.height() != -1) {
915         int delta = small.height() - widg->height();
916         small_delta += delta * delta;
917     }
918     int mini_delta=0;
919     if (mini.width() != -1) {
920         int delta = mini.width() - widg->width();
921         mini_delta += delta * delta;
922     }
923     if (mini.height() != -1) {
924         int delta = mini.height() - widg->height();
925         mini_delta += delta * delta;
926     }
927     if (mini_delta < small_delta && mini_delta < large_delta)
928         return QAquaSizeMini;
929     else if (small_delta < large_delta)
930         return QAquaSizeSmall;
931 #endif
932     return QAquaSizeLarge;
934 #endif
936 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
937                                        QStyle::ContentsType ct, QSize szHint, QSize *insz) const
939 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
940     if (option) {
941         if (option->state & QStyle::State_Small)
942             return QAquaSizeSmall;
943         if (option->state & QStyle::State_Mini)
944             return QAquaSizeMini;
945     }
947     if (!widg) {
948         if (insz)
949             *insz = QSize();
950         if (!qgetenv("QWIDGET_ALL_SMALL").isNull())
951             return QAquaSizeSmall;
952         if (!qgetenv("QWIDGET_ALL_MINI").isNull())
953             return QAquaSizeMini;
954         return QAquaSizeUnknown;
955     }
956     QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
957           small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
958           mini  = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
959     bool guess_size = false;
960     QAquaWidgetSize ret = QAquaSizeUnknown;
961     QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
962     if (wsp == QMacStyle::SizeDefault)
963         guess_size = true;
964     else if (wsp == QMacStyle::SizeMini)
965         ret = QAquaSizeMini;
966     else if (wsp == QMacStyle::SizeSmall)
967         ret = QAquaSizeSmall;
968     else if (wsp == QMacStyle::SizeLarge)
969         ret = QAquaSizeLarge;
970     if (guess_size)
971         ret = qt_aqua_guess_size(widg, large, small, mini);
973     QSize *sz = 0;
974     if (ret == QAquaSizeSmall)
975         sz = &small;
976     else if (ret == QAquaSizeLarge)
977         sz = &large;
978     else if (ret == QAquaSizeMini)
979         sz = &mini;
980     if (insz)
981         *insz = sz ? *sz : QSize(-1, -1);
982 #ifdef DEBUG_SIZE_CONSTRAINT
983     if (sz) {
984         const char *size_desc = "Unknown";
985         if (sz == &small)
986             size_desc = "Small";
987         else if (sz == &large)
988             size_desc = "Large";
989         else if (sz == &mini)
990             size_desc = "Mini";
991         qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
992                widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
993                widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
994                sz->width(), sz->height());
995     }
996 #endif
997     return ret;
998 #else
999     if (insz)
1000         *insz = QSize();
1001     Q_UNUSED(widg);
1002     Q_UNUSED(ct);
1003     Q_UNUSED(szHint);
1004     return QAquaSizeUnknown;
1005 #endif
1009     Returns the free space awailable for contents inside the
1010     button (and not the size of the contents itself)
1012 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
1013                                                  const HIThemeButtonDrawInfo *bdi) const
1015     HIRect outerBounds = qt_hirectForQRect(btn->rect);
1016     // Adjust the bounds to correct for
1017     // carbon not calculating the content bounds fully correct
1018     if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
1019         outerBounds.origin.y += PushButtonTopOffset;
1020         outerBounds.size.height -= PushButtonBottomOffset;
1021     } else if (bdi->kind == kThemePushButtonMini) {
1022         outerBounds.origin.y += PushButtonTopOffset;
1023     }
1025     HIRect contentBounds;
1026     HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
1027     return contentBounds;
1031     Calculates the size of the button contents.
1032     This includes both the text and the icon.
1034 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
1036     QSize csz(0, 0);
1037     QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
1038                 : (btn->iconSize + QSize(PushButtonContentPadding, 0));
1039     QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
1040                 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
1041     csz.setWidth(iconSize.width() + textRect.width()
1042              + ((btn->features & QStyleOptionButton::HasMenu)
1043                             ? q->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
1044     csz.setHeight(qMax(iconSize.height(), textRect.height()));
1045     return csz;
1049     Checks if the actual contents of btn fits inside the free content bounds of
1050     'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
1051     for determining which button kind to use for drawing.
1053 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
1054                                                HIThemeButtonDrawInfo *bdi,
1055                                                ThemeButtonKind buttonKindToCheck) const
1057     ThemeButtonKind tmp = bdi->kind;
1058     bdi->kind = buttonKindToCheck;
1059     QSize contentSize = pushButtonSizeFromContents(btn);
1060     QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
1061     bdi->kind = tmp;
1062     return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
1063                                     contentSize.width(), contentSize.height()));
1067     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1068     kind and other details to use for drawing the given push button. Which
1069     button kind depends on the size of the button, the size of the contents,
1070     explicit user style settings, etc.
1072 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1073                                              const QWidget *widget,
1074                                              const ThemeDrawState tds,
1075                                              HIThemeButtonDrawInfo *bdi) const
1077     bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
1078     ThemeDrawState tdsModified = tds;
1079     if (btn->state & QStyle::State_On)
1080         tdsModified = kThemeStatePressed;
1081     bdi->version = qt_mac_hitheme_version;
1082     bdi->state = tdsModified;
1083     bdi->value = kThemeButtonOff;
1085     if (drawColorless && tdsModified == kThemeStateInactive)
1086         bdi->state = kThemeStateActive;
1087     if (btn->state & QStyle::State_HasFocus)
1088         bdi->adornment = kThemeAdornmentFocus;
1089     else
1090         bdi->adornment = kThemeAdornmentNone;
1093     if (btn->features & (QStyleOptionButton::Flat)) {
1094         bdi->kind = kThemeBevelButton;
1095     } else {
1096         switch (aquaSizeConstrain(btn, widget)) {
1097         case QAquaSizeSmall:
1098             bdi->kind = kThemePushButtonSmall;
1099             break;
1100         case QAquaSizeMini:
1101             bdi->kind = kThemePushButtonMini;
1102             break;
1103         case QAquaSizeLarge:
1104             // ... We should honor if the user is explicit about using the
1105             // large button. But right now Qt will specify the large button
1106             // as default rather than QAquaSizeUnknown.
1107             // So we treat it like QAquaSizeUnknown
1108             // to get the dynamic choosing of button kind.
1109         case QAquaSizeUnknown:
1110             // Choose the button kind that closest match the button rect, but at the
1111             // same time displays the button contents without clipping.
1112             bdi->kind = kThemeBevelButton;
1113             if (btn->rect.width() >= BevelButtonW && btn->rect.height() >= BevelButtonH){
1114                 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1115                     if (btn->rect.height() <= MiniButtonH){
1116                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1117                             bdi->kind = kThemePushButtonMini;
1118                     } else if (btn->rect.height() <= SmallButtonH){
1119                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1120                             bdi->kind = kThemePushButtonSmall;
1121                     } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1122                         bdi->kind = kThemePushButton;
1123                     }
1124                 } else {
1125                     bdi->kind = kThemePushButton;
1126                 }
1127             }
1128         }
1129     }
1133     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1134     kind and other details to use for drawing the given combobox. Which button
1135     kind depends on the size of the combo, wether or not it is editable,
1136     explicit user style settings, etc.
1138 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1139                                     const QWidget *widget, const ThemeDrawState &tds)
1141     bdi->version = qt_mac_hitheme_version;
1142     bdi->adornment = kThemeAdornmentArrowLeftArrow;
1143     bdi->value = kThemeButtonOff;
1144     if (combo->state & QStyle::State_HasFocus)
1145         bdi->adornment = kThemeAdornmentFocus;
1146     bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
1147     if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1148         bdi->state = kThemeStatePressed;
1149     else if (drawColorless)
1150         bdi->state = kThemeStateActive;
1151     else
1152         bdi->state = tds;
1154     QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1155     switch (aSize) {
1156     case QAquaSizeMini:
1157         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1158             : ThemeButtonKind(kThemePopupButtonMini);
1159         break;
1160     case QAquaSizeSmall:
1161         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1162             : ThemeButtonKind(kThemePopupButtonSmall);
1163         break;
1164     case QAquaSizeUnknown:
1165     case QAquaSizeLarge:
1166         // Unless the user explicitly specified large buttons, determine the
1167         // kind by looking at the combox size.
1168         // ... specifying small and mini-buttons it not a current feature of
1169         // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1170         // an extra check here before using the mini and small buttons.
1171         int h = combo->rect.size().height();
1172         if (combo->editable){
1173             if (h < 21)
1174                 bdi->kind = kThemeComboBoxMini;
1175             else if (h < 26)
1176                 bdi->kind = kThemeComboBoxSmall;
1177             else
1178                 bdi->kind = kThemeComboBox;
1179         } else {
1180             // Even if we specify that we want the kThemePopupButton, Carbon
1181             // will use the kThemePopupButtonSmall if the size matches. So we
1182             // do the same size check explicit to have the size of the inner
1183             // text field be correct. Therefore, do this even if the user specifies
1184             // the use of LargeButtons explicit.
1185             if (h < 21)
1186                 bdi->kind = kThemePopupButtonMini;
1187             else if (h < 26)
1188                 bdi->kind = kThemePopupButtonSmall;
1189             else
1190                 bdi->kind = kThemePopupButton;
1191         }
1192         break;
1193     }
1197     Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1198     the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1200 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1202     HIRect innerBounds = outerBounds;
1203     // Carbon draw parts of the view outside the rect.
1204     // So make the rect a bit smaller to compensate
1205     // (I wish HIThemeGetButtonBackgroundBounds worked)
1206     switch (buttonKind){
1207     case kThemePopupButton:
1208         innerBounds.origin.x += 2;
1209         innerBounds.origin.y += 3;
1210         innerBounds.size.width -= 5;
1211         innerBounds.size.height -= 6;
1212         break;
1213     case kThemePopupButtonSmall:
1214         innerBounds.origin.x += 3;
1215         innerBounds.origin.y += 3;
1216         innerBounds.size.width -= 6;
1217         innerBounds.size.height -= 7;
1218         break;
1219     case kThemePopupButtonMini:
1220         innerBounds.origin.x += 2;
1221         innerBounds.origin.y += 2;
1222         innerBounds.size.width -= 5;
1223         innerBounds.size.height -= 6;
1224         break;
1225     case kThemeComboBox:
1226         innerBounds.origin.x += 3;
1227         innerBounds.origin.y += 3;
1228         innerBounds.size.width -= 6;
1229         innerBounds.size.height -= 6;
1230         break;
1231     case kThemeComboBoxSmall:
1232         innerBounds.origin.x += 3;
1233         innerBounds.origin.y += 3;
1234         innerBounds.size.width -= 7;
1235         innerBounds.size.height -= 8;
1236         break;
1237     case kThemeComboBoxMini:
1238         innerBounds.origin.x += 3;
1239         innerBounds.origin.y += 3;
1240         innerBounds.size.width -= 4;
1241         innerBounds.size.height -= 8;
1242         break;
1243     default:
1244         break;
1245     }
1246     return innerBounds;
1250     Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1251     of combobox we choose to draw. This function calculates and returns this size.
1253 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1255     QRect ret = outerBounds;
1256     switch (bdi.kind){
1257     case kThemeComboBox:
1258         ret.adjust(5, 8, -21, -4);
1259         break;
1260     case kThemeComboBoxSmall:
1261         ret.adjust(4, 5, -18, 0);
1262         ret.setHeight(16);
1263         break;
1264     case kThemeComboBoxMini:
1265         ret.adjust(4, 5, -16, 0);
1266         ret.setHeight(13);
1267         break;
1268     case kThemePopupButton:
1269         ret.adjust(10, 3, -23, -3);
1270         break;
1271     case kThemePopupButtonSmall:
1272         ret.adjust(9, 3, -20, -3);
1273         break;
1274     case kThemePopupButtonMini:
1275         ret.adjust(8, 3, -19, 0);
1276         ret.setHeight(13);
1277         break;
1278     }
1279     return ret;
1283     Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1284     create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1285     it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1287 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1289     if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1290         // We have an unscaled combobox, or popup-button; use Carbon directly.
1291         HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1292         HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1293     } else {
1294         QPixmap buffer;
1295         QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1296         if (!QPixmapCache::find(key, buffer)) {
1297             HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1298             buffer = QPixmap(35, 28);
1299             buffer.fill(Qt::transparent);
1300             QPainter buffPainter(&buffer);
1301             HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1302             buffPainter.end();
1303             QPixmapCache::insert(key, buffer);
1304         }
1306         const int bwidth = 20;
1307         const int fwidth = 10;
1308         const int fheight = 10;
1309         int w = qRound(outerBounds.size.width);
1310         int h = qRound(outerBounds.size.height);
1311         int bstart = w - bwidth;
1312         int blower = fheight + 1;
1313         int flower = h - fheight;
1314         int sheight = flower - fheight;
1315         int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1317         // Draw upper and lower gap
1318         p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1319         p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1320         // Draw left and right gap. Right gap is drawn top and bottom separatly
1321         p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1322         p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1323         p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1324         // Draw arrow
1325         p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1326         // Draw corners
1327         p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1328         p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1329         p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1330         p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1331     }
1335     Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1336     onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1338 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1339     bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1341     static SInt32 headerHeight = 0;
1342     static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1343     Q_UNUSED(err);
1345     QPixmap buffer;
1346     QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1347     if (!QPixmapCache::find(key, buffer)) {
1348         HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1349         buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1350         buffer.fill(Qt::transparent);
1351         QPainter buffPainter(&buffer);
1352         HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1353         buffPainter.end();
1354         QPixmapCache::insert(key, buffer);
1355     }
1356     const int buttonw = qRound(outerBounds.size.width);
1357     const int buttonh = qRound(outerBounds.size.height);
1358     const int framew = 1;
1359     const int frameh_n = 4;
1360     const int frameh_s = 3;
1361     const int transh = buffer.height() - frameh_n - frameh_s;
1362     int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1364     int skipTopBorder = 0;
1365     if (!drawTopBorder)
1366         skipTopBorder = 1;
1368     p->translate(outerBounds.origin.x, outerBounds.origin.y);
1370     p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1371     p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1372     // Draw upper and lower center blocks
1373     p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1374     p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1375     // Draw right center block borders
1376     p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1377     p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1378     // Draw right corners
1379     p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1380     p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1381     // Draw center transition block
1382     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));
1383     // Draw right center transition block border
1384     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));
1385     if (drawLeftBorder){
1386         // Draw left center block borders
1387         p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1388         p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1389         // Draw left corners
1390         p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1391         p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1392         // Draw left center transition block border
1393         p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1394     }
1396     p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1400     Returns cutoff sizes for scroll bars.
1401     thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1402     scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1404 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1405 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1407     // Mini scroll bars do not exist as of version 10.4.
1408     if (widgetSize ==  QMacStyle::SizeMini)
1409         return 0;
1411     const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1412     static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1413     return sizeTable[sizeIndex][cutoffType];
1416 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1417                           HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe)
1419     memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1420     tdi->version = qt_mac_hitheme_version;
1421     tdi->reserved = 0;
1422     tdi->filler1 = 0;
1423     bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1424     switch (aquaSizeConstrain(0, needToRemoveMe)) {
1425     case QAquaSizeUnknown:
1426     case QAquaSizeLarge:
1427         if (isScrollbar)
1428             tdi->kind = kThemeMediumScrollBar;
1429         else
1430             tdi->kind = kThemeMediumSlider;
1431         break;
1432     case QAquaSizeMini:
1433         if (isScrollbar)
1434             tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1435         else
1436             tdi->kind = kThemeMiniSlider;
1437         break;
1438     case QAquaSizeSmall:
1439         if (isScrollbar)
1440             tdi->kind = kThemeSmallScrollBar;
1441         else
1442             tdi->kind = kThemeSmallSlider;
1443         break;
1444     }
1445     tdi->bounds = qt_hirectForQRect(slider->rect);
1446     tdi->min = slider->minimum;
1447     tdi->max = slider->maximum;
1448     tdi->value = slider->sliderPosition;
1449     tdi->attributes = kThemeTrackShowThumb;
1450     if (slider->upsideDown)
1451         tdi->attributes |= kThemeTrackRightToLeft;
1452     if (slider->orientation == Qt::Horizontal) {
1453         tdi->attributes |= kThemeTrackHorizontal;
1454         if (isScrollbar && slider->direction == Qt::RightToLeft) {
1455             if (!slider->upsideDown)
1456                 tdi->attributes |= kThemeTrackRightToLeft;
1457             else
1458                 tdi->attributes &= ~kThemeTrackRightToLeft;
1459         }
1460     }
1462     // Tiger broke reverse scroll bars so put them back and "fake it"
1463     if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)
1464         && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
1465         tdi->attributes &= ~kThemeTrackRightToLeft;
1466         tdi->value = tdi->max - slider->sliderPosition;
1467     }
1469     tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1470                                                              : kThemeTrackDisabled;
1471     if (!(slider->state & QStyle::State_Active))
1472         tdi->enableState = kThemeTrackInactive;
1473     if (!isScrollbar) {
1474         if (slider->state & QStyle::QStyle::State_HasFocus)
1475             tdi->attributes |= kThemeTrackHasFocus;
1476         if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1477             tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1478         else if (slider->tickPosition == QSlider::TicksAbove)
1479             tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1480         else
1481             tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1482     } else {
1483         tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1484     }
1486 #endif
1488 QMacStylePrivate::QMacStylePrivate(QMacStyle *style)
1489     : timerID(-1), progressFrame(0), q(style), mouseDown(false)
1491     defaultButtonStart = CFAbsoluteTimeGetCurrent();
1492     memset(&buttonState, 0, sizeof(ButtonState));
1494     if (ptrHIShapeGetBounds == 0) {
1495         QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1496         library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1497                 ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1498     }
1502 bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QWidget *w) const
1504     if (as == AquaPushButton) {
1505         QPushButton *pb = const_cast<QPushButton *>(static_cast<const QPushButton *>(w));
1506         if (w->window()->isActiveWindow() && pb && !mouseDown) {
1507             if (static_cast<const QPushButton *>(w) != defaultButton) {
1508                 // Changed on its own, update the value.
1509                 const_cast<QMacStylePrivate *>(this)->stopAnimate(as, defaultButton);
1510                 const_cast<QMacStylePrivate *>(this)->startAnimate(as, pb);
1511             }
1512             return true;
1513         }
1514     } else if (as == AquaProgressBar) {
1515         if (progressBars.contains((const_cast<QWidget *>(w))))
1516             return true;
1517     }
1518     return false;
1521 void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QWidget *w)
1523     if (as == AquaPushButton && defaultButton) {
1524         QPushButton *tmp = defaultButton;
1525         defaultButton = 0;
1526         tmp->update();
1527     } else if (as == AquaProgressBar) {
1528         progressBars.removeAll(w);
1529     }
1532 void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QWidget *w)
1534     if (as == AquaPushButton)
1535         defaultButton = static_cast<QPushButton *>(w);
1536     else if (as == AquaProgressBar)
1537         progressBars.append(w);
1538     startAnimationTimer();
1541 void QMacStylePrivate::startAnimationTimer()
1543     if ((defaultButton || !progressBars.isEmpty()) && timerID <= -1)
1544         timerID = startTimer(animateSpeed(AquaListViewItemOpen));
1547 enum { TabNormalLeft, TabNormalMid, TabNormalRight, TabSelectedActiveLeft,
1548        TabSelectedActiveMid, TabSelectedActiveRight, TabSelectedInactiveLeft,
1549        TabSelectedInactiveMid, TabSelectedInactiveRight, TabSelectedActiveGraphiteLeft,
1550        TabSelectedActiveGraphiteMid, TabSelectedActiveGraphiteRight,
1551        TabPressedLeft, TabPressedMid, TabPressedRight };
1553 static const char * const * const PantherTabXpms[] = {
1554                                     qt_mac_tabnrm_left,
1555                                     qt_mac_tabnrm_mid,
1556                                     qt_mac_tabnrm_right,
1557                                     qt_mac_tabselected_active_left,
1558                                     qt_mac_tabselected_active_mid,
1559                                     qt_mac_tabselected_active_right,
1560                                     qt_mac_tabselected_inactive_left,
1561                                     qt_mac_tabselected_inactive_mid,
1562                                     qt_mac_tabselected_inactive_right,
1563                                     qt_mac_tab_selected_active_graph_left,
1564                                     qt_mac_tab_selected_active_graph_mid,
1565                                     qt_mac_tab_selected_active_graph_right,
1566                                     qt_mac_tab_press_left,
1567                                     qt_mac_tab_press_mid,
1568                                     qt_mac_tab_press_right};
1570 void QMacStylePrivate::drawPantherTab(const QStyleOptionTab *tabOpt, QPainter *p,
1571                                       const QWidget *) const
1573     QString tabKey = QLatin1String("$qt_mac_style_tab_");
1574     int pantherTabStart;
1575     int pantherTabMid;
1576     int pantherTabEnd;
1578     ThemeTabDirection ttd = getTabDirection(tabOpt->shape);
1580     if (tabOpt->state & QStyle::State_Selected) {
1581         if (!(tabOpt->state & QStyle::State_Active)) {
1582             pantherTabStart = TabSelectedInactiveLeft;
1583         } else {
1584             // Draw into a pixmap to determine which version we use, Aqua or Graphite.
1585             QPixmap tabPix(20, 20);
1586             QPainter pixPainter(&tabPix);
1587             HIThemeTabDrawInfo tdi;
1588             tdi.version = 0;
1589             tdi.style = kThemeTabFront;
1590             tdi.direction = kThemeTabNorth;
1591             tdi.size = kHIThemeTabSizeNormal;
1592             tdi.adornment = kHIThemeTabAdornmentNone;
1593             HIRect inRect = CGRectMake(0.0f, 0.0f, 20.0f, 20.0f);
1594             HIThemeDrawTab(&inRect, &tdi, QMacCGContext(&pixPainter), kHIThemeOrientationNormal, 0);
1595             pixPainter.end();
1596             const QRgb GraphiteColor = 0xffa7b0ba;
1597             QRgb pmColor = tabPix.toImage().pixel(10, 10);
1598             if (qAbs(qRed(pmColor) - qRed(GraphiteColor)) < 3 &&
1599                 qAbs(qGreen(pmColor) - qGreen(GraphiteColor)) < 3
1600                 && qAbs(qBlue(pmColor) - qBlue(GraphiteColor)) < 3)
1601                 pantherTabStart = TabSelectedActiveGraphiteLeft;
1602             else
1603                 pantherTabStart = TabSelectedActiveLeft;
1604         }
1605     } else if (tabOpt->state & QStyle::State_Sunken) {
1606         pantherTabStart = TabPressedLeft;
1607     } else {
1608         pantherTabStart = TabNormalLeft;
1609     }
1612     bool doLine;
1613     bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
1615     QStyleOptionTab::TabPosition tp = tabOpt->position;
1616     if (ttd == kThemeTabWest
1617         || ((ttd == kThemeTabNorth || ttd == kThemeTabSouth)
1618             && tabOpt->direction == Qt::RightToLeft)) {
1619         if (tp == QStyleOptionTab::Beginning)
1620             tp = QStyleOptionTab::End;
1621         else if (tp == QStyleOptionTab::End)
1622             tp = QStyleOptionTab::Beginning;
1623     }
1625     switch (tp) {
1626     default:  // Stupid GCC, being overly pedantic
1627     case QStyleOptionTab::Beginning:
1628         doLine = false;
1629         pantherTabMid = pantherTabEnd = pantherTabStart + 1;
1630         break;
1631     case QStyleOptionTab::Middle:
1632         doLine = true;
1633         pantherTabMid = pantherTabEnd = ++pantherTabStart;
1634         break;
1635     case QStyleOptionTab::End:
1636         doLine = true;
1637         pantherTabMid = ++pantherTabStart;
1638         pantherTabEnd = pantherTabMid + 1;
1639         break;
1640     case QStyleOptionTab::OnlyOneTab:
1641         doLine = false;
1642         pantherTabMid = pantherTabStart + 1;
1643         pantherTabEnd = pantherTabMid + 1;
1644         break;
1645     }
1647     QPixmap pmStart;
1648     if (!QPixmapCache::find(tabKey + QString::number(pantherTabStart), pmStart)) {
1649         pmStart = QPixmap(PantherTabXpms[pantherTabStart]);
1650         QPixmapCache::insert(tabKey + QString::number(pantherTabStart), pmStart);
1651     }
1653     QPixmap pmMid;
1654     if (!QPixmapCache::find(tabKey + QString::number(pantherTabMid), pmMid)) {
1655         pmMid = QPixmap(PantherTabXpms[pantherTabMid]);
1656         QPixmapCache::insert(tabKey + QString::number(pantherTabMid), pmMid);
1657     }
1659     QPixmap pmEnd;
1660     if (!QPixmapCache::find(tabKey + QString::number(pantherTabEnd), pmEnd)) {
1661         pmEnd = QPixmap(PantherTabXpms[pantherTabEnd]);
1662         QPixmapCache::insert(tabKey + QString::number(pantherTabEnd), pmEnd);
1663     }
1664     QRect tr = tabOpt->rect;
1665     if (verticalTabs) {
1666         p->save();
1667         int newX, newY, newRot;
1668         if (tabOpt->shape == QTabBar::RoundedEast || tabOpt->shape == QTabBar::TriangularEast) {
1669             newX = tr.width();
1670             newY = tr.y();
1671             newRot = 90;
1672         } else {
1673             newX = 0;
1674             newY = tr.y() + tr.height();
1675             newRot = -90;
1676         }
1677         tr.setRect(0, 0, tr.height(), tr.width());
1678         QMatrix m;
1679         if (ttd == kThemeTabEast) {
1680             // It's lame but Apple inverts these on the East side.
1681             m.scale(-1, 1);
1682             m.translate(-tabOpt->rect.width(), 0);
1683         }
1684         m.translate(newX, newY);
1685         m.rotate(newRot);
1686         p->setMatrix(m, true);
1687     }
1689     int x = tr.x();
1690     int y = tr.y();
1691     int endX = x + tr.width() - pmEnd.width();
1693     p->drawPixmap(x, y, pmStart.width(), tr.height(), pmStart);
1694     if (doLine) {
1695         QPen oldPen = p->pen();
1696         p->setPen(QColor(0, 0, 0, 0x35));
1697         p->drawLine(x, y + (verticalTabs ? 0 : 1), x, tr.height() - 2);
1698     }
1700     for (x = x + pmStart.width(); x < endX; x += pmMid.width())
1701         p->drawPixmap(x, y, pmMid.width(), tr.height(), pmMid);
1702     p->drawPixmap(endX, y, pmEnd.width(), tr.height(), pmEnd);
1703     if (verticalTabs)
1704         p->restore();
1707 bool QMacStylePrivate::addWidget(QWidget *w)
1709     //already knew of it
1710     if (static_cast<QPushButton*>(w) == defaultButton
1711             || progressBars.contains(static_cast<QProgressBar*>(w)))
1712         return false;
1714     if (QPushButton *btn = qobject_cast<QPushButton *>(w)) {
1715         btn->installEventFilter(this);
1716         if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus()))
1717             startAnimate(AquaPushButton, btn);
1718         return true;
1719     } else {
1720         bool isProgressBar = (qobject_cast<QProgressBar *>(w)
1721 #ifdef QT3_SUPPORT
1722                 || w->inherits("Q3ProgressBar")
1723 #endif
1724             );
1725         if (isProgressBar) {
1726             w->installEventFilter(this);
1727             startAnimate(AquaProgressBar, w);
1728             return true;
1729         }
1730     }
1731     if (w->isWindow()) {
1732         w->installEventFilter(this);
1733         return true;
1734     }
1735     return false;
1738 void QMacStylePrivate::removeWidget(QWidget *w)
1740     QPushButton *btn = qobject_cast<QPushButton *>(w);
1741     if (btn && btn == defaultButton) {
1742         stopAnimate(AquaPushButton, btn);
1743     } else if (qobject_cast<QProgressBar *>(w)
1744 #ifdef QT3_SUPPORT
1745             || w->inherits("Q3ProgressBar")
1746 #endif
1747             ) {
1748         stopAnimate(AquaProgressBar, w);
1749     }
1752 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1754     ThemeDrawState tds = kThemeStateActive;
1755     if (flags & QStyle::State_Sunken) {
1756         tds = kThemeStatePressed;
1757     } else if (flags & QStyle::State_Active) {
1758         if (!(flags & QStyle::State_Enabled))
1759             tds = kThemeStateUnavailable;
1760     } else {
1761         if (flags & QStyle::State_Enabled)
1762             tds = kThemeStateInactive;
1763         else
1764             tds = kThemeStateUnavailableInactive;
1765     }
1766     return tds;
1769 void QMacStylePrivate::timerEvent(QTimerEvent *)
1771     int animated = 0;
1772     if (defaultButton && defaultButton->isEnabled() && defaultButton->window()->isActiveWindow()
1773         && defaultButton->isVisibleTo(0) && (defaultButton->isDefault()
1774         || (defaultButton->autoDefault() && defaultButton->hasFocus()))
1775         && doAnimate(AquaPushButton)) {
1776         ++animated;
1777         defaultButton->update();
1778     }
1779     if (!progressBars.isEmpty()) {
1780         int i = 0;
1781         while (i < progressBars.size()) {
1782             QWidget *maybeProgress = progressBars.at(i);
1783             if (!maybeProgress) {
1784                 progressBars.removeAt(i);
1785             } else {
1786                 if (QProgressBar *pb = qobject_cast<QProgressBar *>(maybeProgress)) {
1787                     if (pb->maximum() == 0 || pb->value() > 0
1788                         && pb->value() < pb->maximum()) {
1789                         if (doAnimate(AquaProgressBar))
1790                             pb->update();
1791                     }
1792                 }
1793 #ifdef QT3_SUPPORT
1794                 else {
1795                     // Watch me now...
1796                     QVariant progress = maybeProgress->property("progress");
1797                     QVariant totalSteps = maybeProgress->property("totalSteps");
1798                     if (progress.isValid() && totalSteps.isValid()) {
1799                         int intProgress = progress.toInt();
1800                         int intTotalSteps = totalSteps.toInt();
1801                         if (intTotalSteps == 0 || intProgress > 0 && intProgress < intTotalSteps) {
1802                             if (doAnimate(AquaProgressBar))
1803                                 maybeProgress->update();
1804                         }
1805                     }
1806                 }
1807 #endif
1808                 ++i;
1809             }
1810         }
1811         if (i > 0) {
1812             ++progressFrame;
1813             animated += i;
1814         }
1815     }
1816     if (animated <= 0) {
1817         killTimer(timerID);
1818         timerID = -1;
1819     }
1822 bool QMacStylePrivate::eventFilter(QObject *o, QEvent *e)
1824     //animate
1825     if (QProgressBar *pb = qobject_cast<QProgressBar *>(o)) {
1826         switch (e->type()) {
1827         default:
1828             break;
1829         case QEvent::Show:
1830             if (!progressBars.contains(pb))
1831                 startAnimate(AquaProgressBar, pb);
1832             break;
1833         case QEvent::Destroy:
1834         case QEvent::Hide:
1835             progressBars.removeAll(pb);
1836         }
1837     } else if (QPushButton *btn = qobject_cast<QPushButton *>(o)) {
1838         switch (e->type()) {
1839         default:
1840             break;
1841         case QEvent::FocusIn:
1842             if (btn->autoDefault())
1843                 startAnimate(AquaPushButton, btn);
1844             break;
1845         case QEvent::Destroy:
1846         case QEvent::Hide:
1847             if (btn == defaultButton)
1848                 stopAnimate(AquaPushButton, btn);
1849             break;
1850         case QEvent::MouseButtonPress:
1851             // It is very confusing to keep the button pulsing, so just stop the animation.
1852             if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1853                 mouseDown = true;
1854             stopAnimate(AquaPushButton, btn);
1855             break;
1856         case QEvent::MouseButtonRelease:
1857             if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1858                 mouseDown = false;
1859             // fall through
1860         case QEvent::FocusOut:
1861         case QEvent::Show:
1862         case QEvent::WindowActivate: {
1863             QList<QPushButton *> list = qFindChildren<QPushButton *>(btn->window());
1864             for (int i = 0; i < list.size(); ++i) {
1865                 QPushButton *pBtn = list.at(i);
1866                 if ((e->type() == QEvent::FocusOut
1867                      && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus()))
1868                      && pBtn != btn)
1869                     || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease
1870                          || e->type() == QEvent::WindowActivate)
1871                         && pBtn->isDefault())) {
1872                     if (pBtn->window()->isActiveWindow()) {
1873                         startAnimate(AquaPushButton, pBtn);
1874                     }
1875                     break;
1876                 }
1877             }
1878             break; }
1879         }
1880     }
1881     return false;
1884 bool QMacStylePrivate::doAnimate(QMacStylePrivate::Animates as)
1886     if (as == AquaPushButton) {
1887     } else if (as == AquaProgressBar) {
1888         // something for later...
1889     } else if (as == AquaListViewItemOpen) {
1890         // To be revived later...
1891     }
1892     return true;
1895 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1896                                            QPainter *p, const QStyleOption *opt) const
1898     int xoff = 0,
1899         yoff = 0,
1900         extraWidth = 0,
1901         extraHeight = 0,
1902         finalyoff = 0;
1904     const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
1905     int width = int(macRect.size.width) + extraWidth;
1906     int height = int(macRect.size.height) + extraHeight;
1908     if (width <= 0 || height <= 0)
1909         return;   // nothing to draw
1911     QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1912                   + QString::number(bdi->value) + QLatin1Char('_') + QString::number(width)
1913                   + QLatin1Char('_') + QString::number(height);
1914     QPixmap pm;
1915     if (!QPixmapCache::find(key, pm)) {
1916         QPixmap activePixmap(width, height);
1917         activePixmap.fill(Qt::transparent);
1918         {
1919             if (combo){
1920                 // Carbon combos don't scale. Therefore we draw it
1921                 // ourselves, if a scaled version is needed.
1922                 QPainter tmpPainter(&activePixmap);
1923                 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1924             }
1925             else {
1926                 QMacCGContext cg(&activePixmap);
1927                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1928                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1929             }
1930         }
1932         if (!combo && bdi->value == kThemeButtonOff) {
1933             pm = activePixmap;
1934         } else if (combo) {
1935             QImage image = activePixmap.toImage();
1937             for (int y = 0; y < height; ++y) {
1938                 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1940                 for (int x = 0; x < width; ++x) {
1941                     QRgb &pixel = scanLine[x];
1943                     int darkest = qRed(pixel);
1944                     int mid = qGreen(pixel);
1945                     int lightest = qBlue(pixel);
1947                     if (darkest > mid)
1948                         qSwap(darkest, mid);
1949                     if (mid > lightest)
1950                         qSwap(mid, lightest);
1951                     if (darkest > mid)
1952                         qSwap(darkest, mid);
1954                     int gray = (mid + 2 * lightest) / 3;
1955                     pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1956                 }
1957             }
1958             pm = QPixmap::fromImage(image);
1959         } else {
1960             QImage activeImage = activePixmap.toImage();
1961             QImage colorlessImage;
1962             {
1963                 QPixmap colorlessPixmap(width, height);
1964                 colorlessPixmap.fill(Qt::transparent);
1966                 QMacCGContext cg(&colorlessPixmap);
1967                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1968                 int oldValue = bdi->value;
1969                 bdi->value = kThemeButtonOff;
1970                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1971                 bdi->value = oldValue;
1972                 colorlessImage = colorlessPixmap.toImage();
1973             }
1975             for (int y = 0; y < height; ++y) {
1976                 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1977                 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1979                 for (int x = 0; x < width; ++x) {
1980                     QRgb &colorlessPixel = colorlessScanLine[x];
1981                     QRgb activePixel = activeScanLine[x];
1983                     if (activePixel != colorlessPixel) {
1984                         int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1985                                        qBlue(activePixel));
1986                         QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1987                         if (qGray(newPixel) < qGray(colorlessPixel)
1988                                 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1989                             colorlessPixel = newPixel;
1990                     }
1991                 }
1992             }
1993             pm = QPixmap::fromImage(colorlessImage);
1994         }
1995         QPixmapCache::insert(key, pm);
1996     }
1997     p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm);
2001     \class QMacStyle
2002     \brief The QMacStyle class provides a Mac OS X style using the Apple Appearance Manager.
2004     \ingroup appearance
2006     This class is implemented as a wrapper to the HITheme
2007     APIs, allowing applications to be styled according to the current
2008     theme in use on Mac OS X. This is done by having primitives
2009     in QStyle implemented in terms of what Mac OS X would normally theme.
2011     \warning This style is only available on Mac OS X because it relies on the
2012     HITheme APIs.
2014     There are additional issues that should be taken
2015     into consideration to make an application compatible with the
2016     \link http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html
2017     Apple Human Interface Guidelines \endlink. Some of these issues are outlined
2018     below.
2020     \list
2022     \i Layout - The restrictions on window layout are such that some
2023     aspects of layout that are style-dependent cannot be achieved
2024     using QLayout. Changes are being considered (and feedback would be
2025     appreciated) to make layouts QStyle-able. Some of the restrictions
2026     involve horizontal and vertical widget alignment and widget size
2027     (covered below).
2029     \i Widget size - Mac OS X allows widgets to have specific fixed sizes.  Qt
2030     does not fully implement this behavior so as to maintain cross-platform
2031     compatibility. As a result some widgets sizes may be inappropriate (and
2032     subsequently not rendered correctly by the HITheme APIs).The
2033     QWidget::sizeHint() will return the appropriate size for many
2034     managed widgets (widgets enumerated in \l QStyle::ContentsType).
2036     \i Effects - QMacStyle uses HITheme for performing most of the drawing, but
2037     also uses emulation in a few cases where HITheme does not provide the
2038     required functionality (for example, tab bars on Panther, the toolbar
2039     separator, etc). We tried to make the emulation as close to the original as
2040     possible. Please report any issues you see in effects or non-standard
2041     widgets.
2043     \endlist
2045     There are other issues that need to be considered in the feel of
2046     your application (including the general color scheme to match the
2047     Aqua colors). The Guidelines mentioned above will remain current
2048     with new advances and design suggestions for Mac OS X.
2050     Note that the functions provided by QMacStyle are
2051     reimplementations of QStyle functions; see QStyle for their
2052     documentation.
2054     \img qmacstyle.png
2055     \sa QWindowsXPStyle, QWindowsStyle, QPlastiqueStyle, QCDEStyle, QMotifStyle
2060     \enum QMacStyle::WidgetSizePolicy
2062     \value SizeSmall
2063     \value SizeLarge
2064     \value SizeMini
2065     \value SizeDefault
2066     \omitvalue SizeNone
2070     Constructs a QMacStyle object.
2072 QMacStyle::QMacStyle()
2073     : QWindowsStyle()
2075     d = new QMacStylePrivate(this);
2079     Destructs a QMacStyle object.
2081 QMacStyle::~QMacStyle()
2083     delete qt_mac_backgroundPattern;
2084     qt_mac_backgroundPattern = 0;
2085     delete d;
2088 /*! \internal
2089     Generates the standard widget background pattern.
2091 QPixmap QMacStylePrivate::generateBackgroundPattern() const
2093     QPixmap px(4, 4);
2094 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
2095     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
2096         QMacCGContext cg(&px);
2097         HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
2098         const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
2099         CGContextFillRect(cg, cgRect);
2100     } else
2101 #endif
2102     {
2103 #ifndef QT_MAC_NO_QUICKDRAW
2104         QMacSavedPortInfo port(&px);
2105         SetThemeBackground(kThemeBrushDialogBackgroundActive, px.depth(), true);
2106         const Rect qdRect = { 0, 0, px.width(), px.height() };
2107         EraseRect(&qdRect);
2108 #endif
2109     }
2110     return px;
2113 /*! \internal
2114     Fills the given \a rect with the pattern stored in \a brush. As an optimization,
2115     HIThemeSetFill us used directly if we are filling with the standard background.
2117 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush)
2119 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
2120     QPoint dummy;
2121     const QPaintDevice *target = painter->device();
2122     const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
2123     const bool usePainter = redirected && redirected != target;
2124     const QRegion translated = rgn.translated(offset);
2126     if (!usePainter && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 && qt_mac_backgroundPattern
2127         && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
2129         painter->setClipRegion(translated);
2131         CGContextRef cg = qt_mac_cg_context(target);
2132         CGContextSaveGState(cg);
2133         HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
2135         const QVector<QRect> &rects = translated.rects();
2136         for (int i = 0; i < rects.size(); ++i) {
2137             const QRect rect(rects.at(i));
2138             // Anchor the pattern to the top so it stays put when the window is resized.
2139             CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
2140             CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
2141             CGContextFillRect(cg, mac_rect);
2142         }
2144         CGContextRestoreGState(cg);
2145     } else
2146 #endif
2147     {
2148         const QRect rect(translated.boundingRect());
2149         painter->setClipRegion(translated);
2150         painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
2151     }
2154 /*! \reimp */
2155 void QMacStyle::polish(QPalette &pal)
2157     if (qt_mac_backgroundPattern == 0)
2158         qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
2160     QColor pc(Qt::black);
2161     pc = qcolorForTheme(kThemeBrushDialogBackgroundActive);
2162     QBrush background(pc, *qt_mac_backgroundPattern);
2163     pal.setBrush(QPalette::All, QPalette::Window, background);
2164     pal.setBrush(QPalette::All, QPalette::Button, background);
2166     QCFString theme;
2167     const OSErr err = CopyThemeIdentifier(&theme);
2168     if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
2169         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
2170     } else {
2171         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
2172     }
2175 /*! \reimp */
2176 void QMacStyle::polish(QApplication *)
2180 /*! \reimp */
2181 void QMacStyle::unpolish(QApplication *)
2185 /*! \reimp */
2186 void QMacStyle::polish(QWidget* w)
2188     d->addWidget(w);
2189     if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
2190         // Set a clear brush so that the metal shines through.
2191         QPalette pal = w->palette();
2192         QBrush background(Qt::transparent);
2193         pal.setBrush(QPalette::All, QPalette::Window, background);
2194         pal.setBrush(QPalette::All, QPalette::Button, background);
2195         w->setPalette(pal);
2196         w->setAttribute(Qt::WA_SetPalette, false);
2197     }
2199     if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
2200         w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
2201         if (!w->testAttribute(Qt::WA_SetPalette)) {
2202             QPixmap px(64, 64);
2203             HIThemeMenuDrawInfo mtinfo;
2204             mtinfo.version = qt_mac_hitheme_version;
2205             mtinfo.menuType = kThemeMenuTypePopUp;
2206             HIRect rect = CGRectMake(0, 0, px.width(), px.height());
2207             HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
2208                                       kHIThemeOrientationNormal);
2209             QPalette pal = w->palette();
2210             QBrush background(px);
2211             pal.setBrush(QPalette::All, QPalette::Window, background);
2212             pal.setBrush(QPalette::All, QPalette::Button, background);
2213             w->setPalette(pal);
2214             w->setAttribute(Qt::WA_SetPalette, false);
2215         }
2216     }
2218     // Adjust the lineedit of the editable combo box
2219     if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_3) {
2220         if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(w)) {
2221             if (qobject_cast<QComboBox *>(lineEdit->parentWidget())
2222                     && !lineEdit->testAttribute(Qt::WA_SetFont)) {
2223                 QFont font = lineEdit->font();
2224                 font.setPointSize(font.pointSize() - 1);
2225                 lineEdit->setFont(font);
2226             }
2227         }
2228     }
2230     if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
2231         if (tb->documentMode()) {
2232             w->setAttribute(Qt::WA_Hover);
2233             w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2234             QPalette p = w->palette();
2235             p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2236             w->setPalette(p);
2237         }
2238     }
2240     QWindowsStyle::polish(w);
2242     if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2243         rubber->setWindowOpacity(0.25);
2244         rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2245         rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2246     }
2249 /*! \reimp */
2250 void QMacStyle::unpolish(QWidget* w)
2252     d->removeWidget(w);
2253     if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
2254         QPalette pal = qApp->palette(w);
2255         w->setPalette(pal);
2256         w->setAttribute(Qt::WA_SetPalette, false);
2257         w->setWindowOpacity(1.0);
2258     }
2260     if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2261         if (!combo->isEditable()) {
2262             if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
2263                 widget->setWindowOpacity(1.0);
2264         }
2265     }
2267     if (QRubberBand *rubber = ::qobject_cast<QRubberBand*>(w)) {
2268         rubber->setWindowOpacity(1.0);
2269         rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2270         rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2271     }
2273     if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w)) {
2274         frame->setAttribute(Qt::WA_NoSystemBackground, true);
2275         frame->setAutoFillBackground(true);
2276     }
2277     QWindowsStyle::unpolish(w);
2280 /*! \reimp */
2281 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
2283     int controlSize = getControlSize(opt, widget);
2284     SInt32 ret = 0;
2286     switch (metric) {
2287     case PM_TabCloseIndicatorWidth:
2288     case PM_TabCloseIndicatorHeight:
2289         ret = closeButtonSize;
2290         break;
2291     case PM_ToolBarIconSize:
2292         ret = pixelMetric(PM_LargeIconSize);
2293         break;
2294     case PM_FocusFrameVMargin:
2295     case PM_FocusFrameHMargin:
2296         GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
2297         break;
2298     case PM_DialogButtonsSeparator:
2299         ret = -5;
2300         break;
2301     case PM_DialogButtonsButtonHeight: {
2302         QSize sz;
2303         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2304         if (sz == QSize(-1, -1))
2305             ret = 32;
2306         else
2307             ret = sz.height();
2308         break; }
2309     case PM_CheckListButtonSize: {
2310         switch (d->aquaSizeConstrain(opt, widget)) {
2311         case QAquaSizeUnknown:
2312         case QAquaSizeLarge:
2313             GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2314             break;
2315         case QAquaSizeMini:
2316             GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2317             break;
2318         case QAquaSizeSmall:
2319             GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2320             break;
2321         }
2322         break; }
2323     case PM_DialogButtonsButtonWidth: {
2324         QSize sz;
2325         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2326         if (sz == QSize(-1, -1))
2327             ret = 70;
2328         else
2329             ret = sz.width();
2330         break; }
2332     case PM_MenuBarHMargin:
2333         ret = 8;
2334         break;
2336     case PM_MenuBarVMargin:
2337         ret = 0;
2338         break;
2340     case QStyle::PM_MenuDesktopFrameWidth:
2341         ret = 5;
2342         break;
2344     case PM_CheckBoxLabelSpacing:
2345     case PM_RadioButtonLabelSpacing:
2346         ret = 2;
2347         break;
2348     case PM_MenuScrollerHeight:
2349 #if 0
2350         SInt16 ash, asw;
2351         GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2352         ret = ash;
2353 #else
2354         ret = 15; // I hate having magic numbers in here...
2355 #endif
2356         break;
2357     case PM_DefaultFrameWidth:
2358 #ifndef QT_NO_MAINWINDOW
2359         if (widget && (widget->isWindow() || !widget->parentWidget()
2360                 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2361                    && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2362                 && (qobject_cast<const QAbstractScrollArea *>(widget)
2363 #ifdef QT3_SUPPORT
2364                     || widget->inherits("QScrollView")
2365 #endif
2366                     || widget->inherits("QWorkspaceChild")))
2367             ret = 0;
2368         else
2369 #endif
2370         // The combo box popup has no frame.
2371         if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2372             ret = 0;
2373         else
2374             ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2375         break;
2376     case PM_MaximumDragDistance:
2377         ret = -1;
2378         break;
2379     case PM_ScrollBarSliderMin:
2380         ret = 24;
2381         break;
2382     case PM_SpinBoxFrameWidth:
2383         GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2384         ret += 2;
2385         break;
2386     case PM_ButtonShiftHorizontal:
2387     case PM_ButtonShiftVertical:
2388         ret = 0;
2389         break;
2390     case PM_SliderLength:
2391         ret = 17;
2392         break;
2393     case PM_ButtonDefaultIndicator:
2394         ret = 0;
2395         break;
2396     case PM_TitleBarHeight:
2397         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2398             HIThemeWindowDrawInfo wdi;
2399             wdi.version = qt_mac_hitheme_version;
2400             wdi.state = kThemeStateActive;
2401             wdi.windowType = QtWinType;
2402             if (tb->titleBarState)
2403                 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2404                                   | kThemeWindowHasCollapseBox;
2405             else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2406                 wdi.attributes = kThemeWindowHasCloseBox;
2407             else
2408                 wdi.attributes = 0;
2409             wdi.titleHeight = tb->rect.height();
2410             wdi.titleWidth = tb->rect.width();
2411             QCFType<HIShapeRef> region;
2412             HIRect hirect = qt_hirectForQRect(tb->rect);
2413             if (hirect.size.width == -1)
2414                 hirect.size.width = 100;
2415             if (hirect.size.height == -1)
2416                 hirect.size.height = 30;
2418             HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, &region);
2419             HIRect rect;
2420             ptrHIShapeGetBounds(region, &rect);
2421             ret = int(rect.size.height);
2422             ret += 4;
2423         }
2424         break;
2425     case PM_TabBarTabVSpace:
2426         ret = 4;
2427         break;
2428     case PM_TabBarTabShiftHorizontal:
2429     case PM_TabBarTabShiftVertical:
2430         ret = 0;
2431         break;
2432     case PM_TabBarBaseHeight:
2433         ret = 0;
2434         break;
2435     case PM_TabBarTabOverlap:
2436         ret = 0;
2437         break;
2438     case PM_TabBarBaseOverlap:
2439         switch (d->aquaSizeConstrain(opt, widget)) {
2440         case QAquaSizeUnknown:
2441         case QAquaSizeLarge:
2442             ret = 11;
2443             break;
2444         case QAquaSizeSmall:
2445             ret = 8;
2446             break;
2447         case QAquaSizeMini:
2448             ret = 7;
2449             break;
2450         }
2451         break;
2452     case PM_ScrollBarExtent: {
2453         switch (d->aquaSizeConstrain(opt, widget)) {
2454         case QAquaSizeUnknown:
2455         case QAquaSizeLarge:
2456             GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2457             break;
2458         case QAquaSizeMini:
2459 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) && 0
2460             if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) {
2461                 GetThemeMetric(kThemeMetricMiniScrollBarWidth, &ret);
2462                 break;
2463             }
2464 #endif
2465         case QAquaSizeSmall:
2466             GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2467             break;
2468         }
2469         break; }
2470     case PM_IndicatorHeight: {
2471         switch (d->aquaSizeConstrain(opt, widget)) {
2472         case QAquaSizeUnknown:
2473         case QAquaSizeLarge:
2474             GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2475             break;
2476         case QAquaSizeMini:
2477             GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2478             break;
2479         case QAquaSizeSmall:
2480             GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2481             break;
2482         }
2483         break; }
2484     case PM_IndicatorWidth: {
2485         switch (d->aquaSizeConstrain(opt, widget)) {
2486         case QAquaSizeUnknown:
2487         case QAquaSizeLarge:
2488             GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2489             break;
2490         case QAquaSizeMini:
2491             GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2492             break;
2493         case QAquaSizeSmall:
2494             GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2495             break;
2496         }
2497         ++ret;
2498         break; }
2499     case PM_ExclusiveIndicatorHeight: {
2500         switch (d->aquaSizeConstrain(opt, widget)) {
2501         case QAquaSizeUnknown:
2502         case QAquaSizeLarge:
2503             GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2504             break;
2505         case QAquaSizeMini:
2506             GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2507             break;
2508         case QAquaSizeSmall:
2509             GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2510             break;
2511         }
2512         break; }
2513     case PM_ExclusiveIndicatorWidth: {
2514         switch (d->aquaSizeConstrain(opt, widget)) {
2515         case QAquaSizeUnknown:
2516         case QAquaSizeLarge:
2517             GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2518             break;
2519         case QAquaSizeMini:
2520             GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2521             break;
2522         case QAquaSizeSmall:
2523             GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2524             break;
2525         }
2526         ++ret;
2527         break; }
2528     case PM_MenuVMargin:
2529         ret = 4;
2530         break;
2531     case PM_MenuPanelWidth:
2532         ret = 0;
2533         break;
2534     case PM_ToolTipLabelFrameWidth:
2535         ret = 0;
2536         break;
2537     case PM_SizeGripSize: {
2538         QAquaWidgetSize aSize;
2539         if (widget && widget->window()->windowType() == Qt::Tool)
2540             aSize = QAquaSizeSmall;
2541         else
2542             aSize = QAquaSizeLarge;
2543         const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2544         ret = size.width();
2545         break; }
2546     case PM_MdiSubWindowFrameWidth:
2547         ret = 1;
2548         break;
2549     case PM_DockWidgetFrameWidth:
2550         ret = 2;
2551         break;
2552     case PM_DockWidgetTitleMargin:
2553         ret = 0;
2554         break;
2555     case PM_DockWidgetSeparatorExtent:
2556         ret = 1;
2557         break;
2558     case PM_ToolBarHandleExtent:
2559         ret = 11;
2560         break;
2561     case PM_ToolBarItemMargin:
2562         ret = 0;
2563         break;
2564     case PM_ToolBarItemSpacing:
2565         ret = 4;
2566         break;
2567     case PM_MessageBoxIconSize:
2568         ret = 64;
2569         break;
2570     case PM_SplitterWidth:
2571         ret = qMax(7, QApplication::globalStrut().width());
2572         break;
2573     case PM_LayoutLeftMargin:
2574     case PM_LayoutTopMargin:
2575     case PM_LayoutRightMargin:
2576     case PM_LayoutBottomMargin:
2577         {
2578             bool isWindow = false;
2579             if (opt) {
2580                 isWindow = (opt->state & State_Window);
2581             } else if (widget) {
2582                 isWindow = widget->isWindow();
2583             }
2585             if (isWindow) {
2586                 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2587                 if (isMetal) {
2588                     if (metric == PM_LayoutTopMargin) {
2589                         return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2590                     } else if (metric == PM_LayoutBottomMargin) {
2591                         return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2592                     } else {
2593                         return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2594                     }
2595                 } else {
2596                     /*
2597                         AHIG would have (20, 8, 10) here but that makes
2598                         no sense. It would also have 14 for the top margin
2599                         but this contradicts both Builder and most
2600                         applications.
2601                     */
2602                     return_SIZE(20, 10, 10);    // AHIG
2603                 }
2604             } else {
2605                 // hack to detect QTabWidget
2606                 if (widget && widget->parentWidget()
2607                         && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2608                     if (metric == PM_LayoutTopMargin) {
2609                         /*
2610                             Builder would have 14 (= 20 - 6) instead of 12,
2611                             but that makes the tab look disproportionate.
2612                         */
2613                         return_SIZE(12, 6, 6);  // guess
2614                     } else {
2615                         return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2616                     }
2617                 } else {
2618                     /*
2619                         Child margins are highly inconsistent in AHIG and Builder.
2620                     */
2621                     return_SIZE(12, 8, 6);    // guess
2622                 }
2623             }
2624         }
2625     case PM_LayoutHorizontalSpacing:
2626     case PM_LayoutVerticalSpacing:
2627         return -1;
2628     case QStyle::PM_TabBarTabHSpace:
2629         switch (d->aquaSizeConstrain(opt, widget)) {
2630         case QAquaSizeLarge:
2631         case QAquaSizeUnknown:
2632             ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2633             break;
2634         case QAquaSizeSmall:
2635             ret = 20;
2636             break;
2637         case QAquaSizeMini:
2638             ret = 16;
2639             break;
2640         }
2641         break;
2642     case PM_MenuHMargin:
2643         ret = 0;
2644         break;
2645     default:
2646         ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2647         break;
2648     }
2649     return ret;
2652 /*! \reimp */
2653 QPalette QMacStyle::standardPalette() const
2655     QPalette pal = QWindowsStyle::standardPalette();
2656     pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2657     pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2658     pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2659     return pal;
2662 /*! \reimp */
2663 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2664                          QStyleHintReturn *hret) const
2666     SInt32 ret = 0;
2667     switch (sh) {
2668     case SH_Menu_SelectionWrap:
2669         ret = false;
2670         break;
2671     case SH_Menu_KeyboardSearch:
2672         ret = true;
2673         break;
2674     case SH_Menu_SpaceActivatesItem:
2675         ret = true;
2676         break;
2677     case SH_Slider_AbsoluteSetButtons:
2678         ret = Qt::LeftButton|Qt::MidButton;
2679         break;
2680     case SH_Slider_PageSetButtons:
2681         ret = 0;
2682         break;
2683     case SH_ScrollBar_ContextMenu:
2684         ret = false;
2685         break;
2686     case SH_TitleBar_AutoRaise:
2687         ret = true;
2688         break;
2689     case SH_Menu_AllowActiveAndDisabled:
2690         ret = false;
2691         break;
2692     case SH_Menu_SubMenuPopupDelay:
2693         ret = 100;
2694         break;
2695     case SH_ScrollBar_LeftClickAbsolutePosition: {
2696         extern bool qt_scrollbar_jump_to_pos; //qapplication_mac.cpp
2697         if(QApplication::keyboardModifiers() & Qt::AltModifier)
2698             ret = !qt_scrollbar_jump_to_pos;
2699         else
2700             ret = qt_scrollbar_jump_to_pos;
2701         break; }
2702     case SH_TabBar_PreferNoArrows:
2703         ret = true;
2704         break;
2705     case SH_LineEdit_PasswordCharacter:
2706         ret = kBulletUnicode;
2707         break;
2708         /*
2709     case SH_DialogButtons_DefaultButton:
2710         ret = QDialogButtons::Reject;
2711         break;
2712         */
2713     case SH_Menu_SloppySubMenus:
2714         ret = true;
2715         break;
2716     case SH_GroupBox_TextLabelVerticalAlignment:
2717         ret = Qt::AlignTop;
2718         break;
2719     case SH_ScrollView_FrameOnlyAroundContents:
2720         if (w && (w->isWindow() || !w->parentWidget() || w->parentWidget()->isWindow())
2721                 && (w->inherits("QWorkspaceChild")
2722 #ifdef QT3_SUPPORT
2723                 || w->inherits("QScrollView")
2724 #endif
2725                 ))
2726             ret = true;
2727         else
2728             ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2729         break;
2730     case SH_Menu_FillScreenWithScroll:
2731         ret = false;
2732         break;
2733     case SH_Menu_Scrollable:
2734         ret = true;
2735         break;
2736     case SH_RichText_FullWidthSelection:
2737         ret = true;
2738         break;
2739     case SH_BlinkCursorWhenTextSelected:
2740         ret = false;
2741         break;
2742     case SH_ScrollBar_StopMouseOverSlider:
2743         ret = true;
2744         break;
2745     case SH_Q3ListViewExpand_SelectMouseType:
2746         ret = QEvent::MouseButtonRelease;
2747         break;
2748     case SH_TabBar_SelectMouseType:
2749         if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2750             ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2751         } else {
2752             ret = QEvent::MouseButtonRelease;
2753         }
2754         break;
2755     case SH_ComboBox_Popup:
2756         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2757             ret = !cmb->editable;
2758         else
2759             ret = 0;
2760         break;
2761     case SH_Workspace_FillSpaceOnMaximize:
2762         ret = true;
2763         break;
2764     case SH_Widget_ShareActivation:
2765         ret = true;
2766         break;
2767     case SH_Header_ArrowAlignment:
2768         ret = Qt::AlignRight;
2769         break;
2770     case SH_TabBar_Alignment: {
2771         if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2772             if (tab->documentMode()) {
2773                 ret = Qt::AlignLeft;
2774                 break;
2775             }
2776         }
2777         if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2778             if (tab->documentMode()) {
2779                 ret = Qt::AlignLeft;
2780                 break;
2781             }
2782         }
2783         ret = Qt::AlignCenter;
2784         } break;
2785     case SH_UnderlineShortcut:
2786         ret = false;
2787         break;
2788     case SH_ToolTipLabel_Opacity:
2789         ret = 242; // About 95%
2790         break;
2791     case SH_Button_FocusPolicy:
2792         ret = Qt::TabFocus;
2793         break;
2794     case SH_EtchDisabledText:
2795         ret = false;
2796         break;
2797     case SH_FocusFrame_Mask: {
2798         ret = true;
2799         if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2800             const uchar fillR = 192, fillG = 191, fillB = 190;
2801             QImage img;
2803             QSize pixmapSize = opt->rect.size();
2804             if (pixmapSize.isValid()) {
2805                 QPixmap pix(pixmapSize);
2806                 pix.fill(QColor(fillR, fillG, fillB));
2807                 QPainter pix_paint(&pix);
2808                 drawControl(CE_FocusFrame, opt, &pix_paint, w);
2809                 pix_paint.end();
2810                 img = pix.toImage();
2811             }
2813             const QRgb *sptr = (QRgb*)img.bits(), *srow;
2814             const int sbpl = img.bytesPerLine();
2815             const int w = sbpl/4, h = img.height();
2817             QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2818             QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2819             const int dbpl = img_mask.bytesPerLine();
2821             for (int y = 0; y < h; ++y) {
2822                 srow = sptr+((y*sbpl)/4);
2823                 drow = dptr+((y*dbpl)/4);
2824                 for (int x = 0; x < w; ++x) {
2825                     const int diff = (((qRed(*srow)-fillR)*(qRed(*srow)-fillR)) +
2826                                       ((qGreen(*srow)-fillG)*((qGreen(*srow)-fillG))) +
2827                                       ((qBlue(*srow)-fillB)*((qBlue(*srow)-fillB))));
2828                     (*drow++) = (diff < 100) ? 0xffffffff : 0xff000000;
2829                     ++srow;
2830                 }
2831             }
2832             QBitmap qmask = QBitmap::fromImage(img_mask);
2833             mask->region = QRegion(qmask);
2834         }
2835         break; }
2836     case SH_TitleBar_NoBorder:
2837         ret = 1;
2838         break;
2839     case SH_RubberBand_Mask:
2840         ret = 0;
2841         break;
2842     case SH_ComboBox_LayoutDirection:
2843         ret = Qt::LeftToRight;
2844         break;
2845     case SH_ItemView_EllipsisLocation:
2846         ret = Qt::AlignHCenter;
2847         break;
2848     case SH_ItemView_ShowDecorationSelected:
2849         ret = true;
2850         break;
2851     case SH_TitleBar_ModifyNotification:
2852         ret = false;
2853         break;
2854     case SH_ScrollBar_RollBetweenButtons:
2855         ret = true;
2856         break;
2857     case SH_WindowFrame_Mask:
2858         ret = 1;
2859         if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2860             mask->region = opt->rect;
2861             mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2862             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2863             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2864             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2866             mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2867             mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2868             mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2869             mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2870         }
2871         break;
2872     case SH_TabBar_ElideMode:
2873         ret = Qt::ElideRight;
2874         break;
2875     case SH_DialogButtonLayout:
2876         ret = QDialogButtonBox::MacLayout;
2877         break;
2878     case SH_FormLayoutWrapPolicy:
2879         ret = QFormLayout::DontWrapRows;
2880         break;
2881     case SH_FormLayoutFieldGrowthPolicy:
2882         ret = QFormLayout::FieldsStayAtSizeHint;
2883         break;
2884     case SH_FormLayoutFormAlignment:
2885         ret = Qt::AlignHCenter | Qt::AlignTop;
2886         break;
2887     case SH_FormLayoutLabelAlignment:
2888         ret = Qt::AlignRight;
2889         break;
2890     case SH_ComboBox_PopupFrameStyle:
2891         ret = QFrame::NoFrame | QFrame::Plain;
2892         break;
2893     case SH_MessageBox_TextInteractionFlags:
2894         ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2895         break;
2896     case SH_SpellCheckUnderlineStyle:
2897         ret = QTextCharFormat::DashUnderline;
2898         break;
2899     case SH_MessageBox_CenterButtons:
2900         ret = false;
2901         break;
2902     case SH_MenuBar_AltKeyNavigation:
2903         ret = false;
2904         break;
2905     case SH_ItemView_MovementWithoutUpdatingSelection:
2906         ret = false;
2907         break;
2908     case SH_FocusFrame_AboveWidget:
2909         ret = true;
2910         break;
2911     case SH_WizardStyle:
2912         ret = QWizard::MacStyle;
2913         break;
2914     case SH_ItemView_ArrowKeysNavigateIntoChildren:
2915         ret = false;
2916         break;
2917     case SH_Menu_FlashTriggeredItem:
2918         ret = true;
2919         break;
2920     case SH_Menu_FadeOutOnHide:
2921         ret = true;
2922         break;
2923     case SH_Menu_Mask:
2924         if (opt) {
2925             if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2926                 ret = true;
2927                 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2928                                              opt->rect.width(), opt->rect.height() - 8);
2929                 HIThemeMenuDrawInfo mdi;
2930                 mdi.version = 0;
2931                 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2932                     mdi.menuType = kThemeMenuTypeHierarchical;
2933                 else
2934                     mdi.menuType = kThemeMenuTypePopUp;
2935                 QCFType<HIShapeRef> shape;
2936                 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2937                 mask->region = QRegion::fromHIShapeRef(shape);
2938             }
2939         }
2940         break;
2941     case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2942         ret = true;
2943         break;
2944     case SH_TabBar_CloseButtonPosition:
2945         ret = QTabBar::LeftSide;
2946         break;
2947     case SH_DockWidget_ButtonsHaveFrame:
2948         ret = false;
2949         break;
2950     default:
2951         ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2952         break;
2953     }
2954     return ret;
2957 /*! \reimp */
2958 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2959                                        const QStyleOption *opt) const
2961     switch (iconMode) {
2962     case QIcon::Disabled: {
2963         QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2964         int imgh = img.height();
2965         int imgw = img.width();
2966         QRgb pixel;
2967         for (int y = 0; y < imgh; ++y) {
2968             for (int x = 0; x < imgw; ++x) {
2969                 pixel = img.pixel(x, y);
2970                 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2971                                          qAlpha(pixel) / 2));
2972             }
2973         }
2974         return QPixmap::fromImage(img);
2975     }
2976     default:
2977         ;
2978     }
2979     return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt);
2983 /*! \reimp */
2984 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2985                                   const QWidget *widget) const
2987     // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2988     // I don't want infinite recursion so if we do get in that situation, just return the Window's
2989     // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2990     // someone changes how Windows standard
2991     // pixmap works.
2992     static bool recursionGuard = false;
2994     if (recursionGuard)
2995         return QWindowsStyle::standardPixmap(standardPixmap, opt, widget);
2997     recursionGuard = true;
2998     QIcon icon = standardIconImplementation(standardPixmap, opt, widget);
2999     recursionGuard = false;
3000     int size;
3001     switch (standardPixmap) {
3002         default:
3003             size = 32;
3004             break;
3005         case SP_MessageBoxCritical:
3006         case SP_MessageBoxQuestion:
3007         case SP_MessageBoxInformation:
3008         case SP_MessageBoxWarning:
3009             size = 64;
3010             break;
3011     }
3012     return icon.pixmap(size, size);
3015     \enum QMacStyle::FocusRectPolicy
3017     This type is used to signify a widget's focus rectangle policy.
3019     \value FocusEnabled  show a focus rectangle when the widget has focus.
3020     \value FocusDisabled  never show a focus rectangle for the widget.
3021     \value FocusDefault  show a focus rectangle when the widget has
3022     focus and the widget is a QSpinWidget, QDateTimeEdit, QLineEdit,
3023     QListBox, QListView, editable QTextEdit, or one of their
3024     subclasses.
3028     \obsolete
3029     Sets the focus rectangle policy of \a w. The \a policy can be one of
3030     \l{QMacStyle::FocusRectPolicy}.
3032     This is now simply an interface to the Qt::WA_MacShowFocusRect attribute and the
3033     FocusDefault value does nothing anymore. If you want to set a widget back
3034     to its default value, you must save the old value of the attribute before
3035     you change it.
3037     \sa focusRectPolicy() QWidget::setAttribute()
3039 void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
3041     switch (policy) {
3042     case FocusDefault:
3043         break;
3044     case FocusEnabled:
3045     case FocusDisabled:
3046         w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
3047         break;
3048     }
3052     \obsolete
3053     Returns the focus rectangle policy for the widget \a w.
3055     The focus rectangle policy can be one of \l{QMacStyle::FocusRectPolicy}.
3057     In 4.3 and up this function will simply test for the
3058     Qt::WA_MacShowFocusRect attribute and will never return
3059     QMacStyle::FocusDefault.
3061     \sa setFocusRectPolicy(), QWidget::testAttribute()
3063 QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
3065     return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
3069     \obsolete
3071     Call QWidget::setAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize,
3072     or Qt::WA_MacNormalSize instead.
3074 void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
3076     QWidget *wadget = const_cast<QWidget *>(widget);
3077     wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge);
3078     wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall);
3079     wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini);
3083     \obsolete
3085     Call QWidget::testAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize,
3086     or Qt::WA_MacNormalSize instead.
3088 QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget)
3090     while (widget) {
3091         if (widget->testAttribute(Qt::WA_MacMiniSize)) {
3092             return SizeMini;
3093         } else if (widget->testAttribute(Qt::WA_MacSmallSize)) {
3094             return SizeSmall;
3095         } else if (widget->testAttribute(Qt::WA_MacNormalSize)) {
3096             return SizeLarge;
3097         }
3098         widget = widget->parentWidget();
3099     }
3100     return SizeDefault;
3103 /*! \reimp */
3104 void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
3105                               const QWidget *w) const
3107     ThemeDrawState tds = d->getDrawState(opt->state);
3108     QMacCGContext cg(p);
3109     switch (pe) {
3110     case PE_IndicatorArrowUp:
3111     case PE_IndicatorArrowDown:
3112     case PE_IndicatorArrowRight:
3113     case PE_IndicatorArrowLeft: {
3114         p->save();
3115         p->setRenderHint(QPainter::Antialiasing);
3116         int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
3117         QMatrix matrix;
3118         matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
3119         QPainterPath path;
3120         switch(pe) {
3121         default:
3122         case PE_IndicatorArrowDown:
3123             break;
3124         case PE_IndicatorArrowUp:
3125             matrix.rotate(180);
3126             break;
3127         case PE_IndicatorArrowLeft:
3128             matrix.rotate(90);
3129             break;
3130         case PE_IndicatorArrowRight:
3131             matrix.rotate(-90);
3132             break;
3133         }
3134         path.moveTo(0, 5);
3135         path.lineTo(-4, -3);
3136         path.lineTo(4, -3);
3137         p->setMatrix(matrix);
3138         p->setPen(Qt::NoPen);
3139         p->setBrush(QColor(0, 0, 0, 135));
3140         p->drawPath(path);
3141         p->restore();
3142         break; }
3143     case PE_FrameTabBarBase:
3144         if (const QStyleOptionTabBarBaseV2 *tbb
3145                 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
3146             if (tbb->documentMode) {
3147                 p->save();
3148                 drawTabBase(p, tbb, w);
3149                 p->restore();
3150                 return;
3151             }
3153             QRegion region(tbb->rect);
3154             region -= tbb->tabBarRect;
3155             p->save();
3156             p->setClipRegion(region);
3157             QStyleOptionTabWidgetFrame twf;
3158             twf.QStyleOption::operator=(*tbb);
3159             twf.shape  = tbb->shape;
3160             switch (getTabDirection(twf.shape)) {
3161             case kThemeTabNorth:
3162                 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
3163                 break;
3164             case kThemeTabSouth:
3165                 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3166                 break;
3167             case kThemeTabWest:
3168                 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
3169                 break;
3170             case kThemeTabEast:
3171                 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3172                 break;
3173             }
3174             drawPrimitive(PE_FrameTabWidget, &twf, p, w);
3175             p->restore();
3176         }
3177         break;
3178     case PE_PanelTipLabel:
3179         p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
3180         break;
3181     case PE_FrameGroupBox:
3182         if (const QStyleOptionFrame *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3183             const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt);
3184             if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) {
3185                 QWindowsStyle::drawPrimitive(pe, groupBox, p, w);
3186             } else {
3187                 HIThemeGroupBoxDrawInfo gdi;
3188                 gdi.version = qt_mac_hitheme_version;
3189                 gdi.state = tds;
3190                 if (w && qobject_cast<QGroupBox *>(w->parentWidget()))
3191                     gdi.kind = kHIThemeGroupBoxKindSecondary;
3192                 else
3193                     gdi.kind = kHIThemeGroupBoxKindPrimary;
3194                 HIRect hirect = qt_hirectForQRect(opt->rect);
3195                 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
3196             }
3197         }
3198         break;
3199     case PE_IndicatorToolBarSeparator: {
3200             QPainterPath path;
3201             if (opt->state & State_Horizontal) {
3202                 int xpoint = opt->rect.center().x();
3203                 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3204                 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3205             } else {
3206                 int ypoint = opt->rect.center().y();
3207                 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3208                 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3209             }
3210             QPainterPathStroker theStroker;
3211             theStroker.setCapStyle(Qt::FlatCap);
3212             theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3213             path = theStroker.createStroke(path);
3214             p->fillPath(path, QColor(0, 0, 0, 119));
3215         }
3216         break;
3217     case PE_FrameWindow:
3218         break;
3219     case PE_IndicatorDockWidgetResizeHandle: {
3220             // The docwidget resize handle is drawn as a one-pixel wide line.
3221             p->save();
3222             if (opt->state & State_Horizontal) {
3223                 p->setPen(QColor(160, 160, 160));
3224                 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3225             } else {
3226                 p->setPen(QColor(145, 145, 145));
3227                 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3228             }
3229             p->restore();
3230         } break;
3231     case PE_IndicatorToolBarHandle: {
3232             p->save();
3233             QPainterPath path;
3234             int x = opt->rect.x() + 6;
3235             int y = opt->rect.y() + 5;
3236             static const int RectHeight = 2;
3237             if (opt->state & State_Horizontal) {
3238                 while (y < opt->rect.height() - RectHeight - 6) {
3239                     path.moveTo(x, y);
3240                     path.addRect(x, y, RectHeight, RectHeight);
3241                     y += 6;
3242                 }
3243             } else {
3244                 while (x < opt->rect.width() - RectHeight - 6) {
3245                     path.moveTo(x, y);
3246                     path.addRect(x, y, RectHeight, RectHeight);
3247                     x += 6;
3248                 }
3249             }
3250             p->setPen(Qt::NoPen);
3251             QColor dark = opt->palette.dark().color();
3252             dark.setAlphaF(0.75);
3253             QColor light = opt->palette.light().color();
3254             light.setAlphaF(0.6);
3255             p->fillPath(path, light);
3256             p->save();
3257             p->translate(1, 1);
3258             p->fillPath(path, dark);
3259             p->restore();
3260             p->translate(3, 3);
3261             p->fillPath(path, light);
3262             p->translate(1, 1);
3263             p->fillPath(path, dark);
3264             p->restore();
3266             break;
3267         }
3268     case PE_IndicatorHeaderArrow:
3269         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3270             // In HITheme, up is down, down is up and hamburgers eat people.
3271             if (header->sortIndicator != QStyleOptionHeader::None)
3272                 drawPrimitive(
3273                     (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3274                     PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3275         }
3276         break;
3277     case PE_IndicatorMenuCheckMark: {
3278         const int checkw = 8;
3279         const int checkh = 8;
3280         const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
3281         const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
3282         const int x1 = xoff + opt->rect.x();
3283         const int y1 = yoff + opt->rect.y() + checkw/2;
3284         const int x2 = xoff + opt->rect.x() + checkw/4;
3285         const int y2 = yoff + opt->rect.y() + checkh;
3286         const int x3 = xoff + opt->rect.x() + checkw;
3287         const int y3 = yoff + opt->rect.y();
3289         QVector<QLineF> a(2);
3290         a << QLineF(x1, y1, x2, y2);
3291         a << QLineF(x2, y2, x3, y3);
3292         if (opt->palette.currentColorGroup() == QPalette::Active)
3293             p->setPen(QPen(Qt::white, 3));
3294         else
3295             p->setPen(QPen(QColor(100, 100, 100), 3));
3296         p->save();
3297         p->setRenderHint(QPainter::Antialiasing);
3298         p->drawLines(a);
3299         p->restore();
3300         break; }
3301     case PE_IndicatorViewItemCheck:
3302     case PE_Q3CheckListExclusiveIndicator:
3303     case PE_Q3CheckListIndicator:
3304     case PE_IndicatorRadioButton:
3305     case PE_IndicatorCheckBox: {
3306         bool drawColorless = (!(opt->state & State_Active))
3307                               && opt->palette.currentColorGroup() == QPalette::Active;
3308         HIThemeButtonDrawInfo bdi;
3309         bdi.version = qt_mac_hitheme_version;
3310         bdi.state = tds;
3311         if (drawColorless && tds == kThemeStateInactive)
3312             bdi.state = kThemeStateActive;
3313         bdi.adornment = kThemeDrawIndicatorOnly;
3314         if (opt->state & State_HasFocus)
3315             bdi.adornment |= kThemeAdornmentFocus;
3316         bool isRadioButton = (pe == PE_Q3CheckListExclusiveIndicator
3317                               || pe == PE_IndicatorRadioButton);
3318         switch (d->aquaSizeConstrain(opt, w)) {
3319         case QAquaSizeUnknown:
3320         case QAquaSizeLarge:
3321             if (isRadioButton)
3322                 bdi.kind = kThemeRadioButton;
3323             else
3324                 bdi.kind = kThemeCheckBox;
3325             break;
3326         case QAquaSizeMini:
3327             if (isRadioButton)
3328                 bdi.kind = kThemeMiniRadioButton;
3329             else
3330                 bdi.kind = kThemeMiniCheckBox;
3331             break;
3332         case QAquaSizeSmall:
3333             if (isRadioButton)
3334                 bdi.kind = kThemeSmallRadioButton;
3335             else
3336                 bdi.kind = kThemeSmallCheckBox;
3337             break;
3338         }
3339         if (opt->state & State_NoChange)
3340             bdi.value = kThemeButtonMixed;
3341         else if (opt->state & State_On)
3342             bdi.value = kThemeButtonOn;
3343         else
3344             bdi.value = kThemeButtonOff;
3345         HIRect macRect;
3346         if (pe == PE_Q3CheckListExclusiveIndicator || pe == PE_Q3CheckListIndicator)
3347             macRect = qt_hirectForQRect(opt->rect);
3348         else
3349             macRect = qt_hirectForQRect(opt->rect);
3350         if (!drawColorless)
3351             HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3352         else
3353             d->drawColorlessButton(macRect, &bdi, p, opt);
3354         break; }
3355     case PE_FrameFocusRect:
3356         // Use the our own focus widget stuff.
3357         break;
3358     case PE_IndicatorBranch: {
3359         if (!(opt->state & State_Children))
3360             break;
3361         HIThemeButtonDrawInfo bi;
3362         bi.version = qt_mac_hitheme_version;
3363         bi.state = tds;
3364         if (tds == kThemeStateInactive && opt->palette.currentColorGroup() == QPalette::Active)
3365             bi.state = kThemeStateActive;
3366         if (opt->state & State_Sunken)
3367             bi.state |= kThemeStatePressed;
3368         bi.kind = kThemeDisclosureButton;
3369         if (opt->state & State_Open)
3370             bi.value = kThemeDisclosureDown;
3371         else
3372             bi.value = opt->direction == Qt::LeftToRight ? kThemeDisclosureRight : kThemeDisclosureLeft;
3373         bi.adornment = kThemeAdornmentNone;
3374         HIRect hirect = qt_hirectForQRect(opt->rect);
3375         HIThemeDrawButton(&hirect, &bi, cg, kHIThemeOrientationNormal, 0);
3376         break; }
3377     case PE_Frame: {
3378         QPen oldPen = p->pen();
3379         QPen newPen;
3380         newPen.setBrush(opt->palette.dark());
3381         p->setPen(newPen);
3382         p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3383         p->setPen(oldPen);
3384         break; }
3385     case PE_FrameLineEdit:
3386         if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3387             if (frame->state & State_Sunken) {
3388                 QColor baseColor(frame->palette.background().color());
3389                 HIThemeFrameDrawInfo fdi;
3390                 fdi.version = qt_mac_hitheme_version;
3391                 fdi.state = tds;
3392                 SInt32 frame_size;
3393                 if (pe == PE_FrameLineEdit) {
3394                     fdi.kind = kHIThemeFrameTextFieldSquare;
3395                     GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
3396                     if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled))
3397                         fdi.state = kThemeStateInactive;
3398                 } else {
3399                     baseColor = QColor(150, 150, 150); //hardcoded since no query function --Sam
3400                     fdi.kind = kHIThemeFrameListBox;
3401                     GetThemeMetric(kThemeMetricListBoxFrameOutset, &frame_size);
3402                 }
3403                 fdi.isFocused = (frame->state & State_HasFocus);
3404                 int lw = frame->lineWidth;
3405                 if (lw <= 0)
3406                     lw = pixelMetric(PM_DefaultFrameWidth, frame, w);
3407                 { //clear to base color
3408                     p->save();
3409                     p->setPen(QPen(baseColor, lw));
3410                     p->setBrush(Qt::NoBrush);
3411                     p->drawRect(frame->rect);
3412                     p->restore();
3413                 }
3414                 HIRect hirect = qt_hirectForQRect(frame->rect,
3415                                                   QRect(frame_size, frame_size,
3416                                                         frame_size * 2, frame_size * 2));
3418                 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
3419             } else {
3420                 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3421             }
3422         }
3423         break;
3424     case PE_PanelLineEdit:
3425         QWindowsStyle::drawPrimitive(pe, opt, p, w);
3426         break;
3427     case PE_FrameTabWidget:
3428         if (const QStyleOptionTabWidgetFrame *twf
3429                 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
3430             HIRect hirect = qt_hirectForQRect(twf->rect);
3431 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
3432             if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
3433                 HIThemeTabPaneDrawInfo tpdi;
3434                 tpdi.version = qt_mac_hitheme_tab_version();
3435                 tpdi.state = tds;
3436                 tpdi.direction = getTabDirection(twf->shape);
3437                 tpdi.size = kHIThemeTabSizeNormal;
3438                 if (tpdi.version == 1) {
3439                     tpdi.kind = kHIThemeTabKindNormal;
3440                     tpdi.adornment = kHIThemeTabPaneAdornmentNormal;
3441                 }
3442                 HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal);
3443             } else
3444 #endif
3445             {
3446                 HIThemeGroupBoxDrawInfo gdi;
3447                 gdi.version = qt_mac_hitheme_version;
3448                 gdi.state = tds;
3449                 gdi.kind = kHIThemeGroupBoxKindSecondary;
3450                 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
3451             }
3452         }
3453         break;
3454     case PE_PanelScrollAreaCorner: {
3455         const QBrush brush(qApp->palette().brush(QPalette::Base));
3456         p->fillRect(opt->rect, brush);
3457         p->setPen(QPen(QColor(217, 217, 217)));
3458         p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3459         p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3460         } break;
3461     case PE_FrameStatusBarItem:
3462         QCommonStyle::drawPrimitive(pe, opt, p, w);
3463         break;
3464     case PE_IndicatorTabClose: {
3465         bool hover = (opt->state & State_MouseOver);
3466         bool selected = (opt->state & State_Selected);
3467         bool active = (opt->state & State_Active);
3468         drawTabCloseButton(p, hover, active, selected);
3469         } break;
3470     case PE_PanelStatusBar: {
3471         if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) {
3472             QWindowsStyle::drawPrimitive(pe, opt, p, w);
3473             break;
3474         }
3476         // Use the Leopard style only if the status bar is the status bar for a
3477         // QMainWindow with a unifed toolbar.
3478         if (w == 0 || w->parent() == 0 || qobject_cast<QMainWindow *>(w->parent()) == 0 ||
3479             qobject_cast<QMainWindow *>(w->parent())->unifiedTitleAndToolBarOnMac() == false ) {
3480             QWindowsStyle::drawPrimitive(pe, opt, p, w);
3481             break;
3482         }
3484         // Fill the status bar with the titlebar gradient.
3485         QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3486         if (opt->state & QStyle::State_Active) {
3487             linearGrad.setColorAt(0, titlebarGradientActiveBegin);
3488             linearGrad.setColorAt(1, titlebarGradientActiveEnd);
3489         } else {
3490             linearGrad.setColorAt(0, titlebarGradientInactiveBegin);
3491             linearGrad.setColorAt(1, titlebarGradientInactiveEnd);
3492         }
3493         p->fillRect(opt->rect, linearGrad);
3495         // Draw the black separator line at the top of the status bar.
3496         if (opt->state & QStyle::State_Active)
3497             p->setPen(titlebarSeparatorLineActive);
3498         else
3499             p->setPen(titlebarSeparatorLineInactive);
3500         p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3502         break;
3503     }
3505     default:
3506         QWindowsStyle::drawPrimitive(pe, opt, p, w);
3507         break;
3508     }
3511 static inline QPixmap darkenPixmap(const QPixmap &pixmap)
3513     QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
3514     int imgh = img.height();
3515     int imgw = img.width();
3516     int h, s, v, a;
3517     QRgb pixel;
3518     for (int y = 0; y < imgh; ++y) {
3519         for (int x = 0; x < imgw; ++x) {
3520             pixel = img.pixel(x, y);
3521             a = qAlpha(pixel);
3522             QColor hsvColor(pixel);
3523             hsvColor.getHsv(&h, &s, &v);
3524             s = qMin(100, s * 2);
3525             v = v / 2;
3526             hsvColor.setHsv(h, s, v);
3527             pixel = hsvColor.rgb();
3528             img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3529         }
3530     }
3531     return QPixmap::fromImage(img);
3536 /*! \reimp */
3537 void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3538                             const QWidget *w) const
3540     ThemeDrawState tds = d->getDrawState(opt->state);
3541     QMacCGContext cg(p);
3542     switch (ce) {
3543     case CE_HeaderSection:
3544         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3545             HIThemeButtonDrawInfo bdi;
3546             bdi.version = qt_mac_hitheme_version;
3547             State flags = header->state;
3548             QRect ir = header->rect;
3549             bdi.kind = kThemeListHeaderButton;
3550             bdi.adornment = kThemeAdornmentNone;
3551             bdi.state = kThemeStateActive;
3553             if (flags & State_On)
3554                 bdi.value = kThemeButtonOn;
3555             else
3556                 bdi.value = kThemeButtonOff;
3558             if (header->orientation == Qt::Horizontal){
3559                 switch (header->position) {
3560                 case QStyleOptionHeader::Beginning:
3561                     break;
3562                 case QStyleOptionHeader::Middle:
3563                 case QStyleOptionHeader::End:
3564                     ir.adjust(-1, 0, 0, 0);
3565                     break;
3566                 default:
3567                     break;
3568                 }
3570                 if (header->position != QStyleOptionHeader::Beginning
3571                     && header->position != QStyleOptionHeader::OnlyOneSection) {
3572                     bdi.adornment = header->direction == Qt::LeftToRight
3573                         ? kThemeAdornmentHeaderButtonLeftNeighborSelected
3574                         : kThemeAdornmentHeaderButtonRightNeighborSelected;
3575                 }
3576             }
3578             if (flags & State_Active) {
3579                 if (!(flags & State_Enabled))
3580                     bdi.state = kThemeStateUnavailable;
3581                 else if (flags & State_Sunken)
3582                     bdi.state = kThemeStatePressed;
3583             } else {
3584                 if (flags & State_Enabled)
3585                     bdi.state = kThemeStateInactive;
3586                 else
3587                     bdi.state = kThemeStateUnavailableInactive;
3588             }
3590             if (header->sortIndicator != QStyleOptionHeader::None) {
3591                 bdi.value = kThemeButtonOn;
3592                 if (header->sortIndicator == QStyleOptionHeader::SortDown)
3593                     bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
3594             }
3595             if (flags & State_HasFocus)
3596                 bdi.adornment = kThemeAdornmentFocus;
3598             ir = visualRect(header->direction, header->rect, ir);
3599             HIRect bounds = qt_hirectForQRect(ir);
3601             bool noVerticalHeader = true;
3602             if (w)
3603                 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3604                     noVerticalHeader = !table->verticalHeader()->isVisible();
3606             bool drawTopBorder = header->orientation == Qt::Horizontal;
3607             bool drawLeftBorder = header->orientation == Qt::Vertical
3608                 || header->position == QStyleOptionHeader::OnlyOneSection
3609                 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3610             d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
3611         }
3612         break;
3613     case CE_HeaderLabel:
3614         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3615             QRect textr = header->rect;
3616             if (!header->icon.isNull()) {
3617                 QIcon::Mode mode = QIcon::Disabled;
3618                 if (opt->state & State_Enabled)
3619                     mode = QIcon::Normal;
3620                 QPixmap pixmap = header->icon.pixmap(pixelMetric(PM_SmallIconSize), mode);
3622                 QRect pixr = header->rect;
3623                 pixr.setY(header->rect.center().y() - (pixmap.height() - 1) / 2);
3624                 drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
3625                 textr.translate(pixmap.width() + 2, 0);
3626             }
3628             drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
3629                          header->state & State_Enabled, header->text, QPalette::ButtonText);
3630         }
3631         break;
3632     case CE_ToolButtonLabel:
3633         if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3634             QStyleOptionToolButton myTb = *tb;
3635             myTb.state &= ~State_AutoRaise;
3636             if (w && qobject_cast<QToolBar *>(w->parentWidget())) {
3637                 QRect cr = tb->rect;
3638                 int shiftX = 0;
3639                 int shiftY = 0;
3640                 bool needText = false;
3641                 int alignment = 0;
3642                 bool down = tb->state & (State_Sunken | State_On);
3643                 if (down) {
3644                     shiftX = pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3645                     shiftY = pixelMetric(PM_ButtonShiftVertical, tb, w);
3646                 }
3647                 // The down state is special for QToolButtons in a toolbar on the Mac
3648                 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3649                 // This doesn't really fit into any particular case in QIcon, so we
3650                 // do the majority of the work ourselves.
3651                 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3652                     Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3653                     if (tb->icon.isNull() && !tb->text.isEmpty())
3654                         tbstyle = Qt::ToolButtonTextOnly;
3656                     switch (tbstyle) {
3657                     case Qt::ToolButtonTextOnly: {
3658                         needText = true;
3659                         alignment = Qt::AlignCenter;
3660                         break; }
3661                     case Qt::ToolButtonIconOnly:
3662                     case Qt::ToolButtonTextBesideIcon:
3663                     case Qt::ToolButtonTextUnderIcon: {
3664                         QRect pr = cr;
3665                         QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3666                                                                             : QIcon::Disabled;
3667                         QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3668                                                                          : QIcon::Off;
3669                         QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), iconMode, iconState);
3671                         // Draw the text if it's needed.
3672                         if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3673                             needText = true;
3674                             if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3675                                 pr.setHeight(pixmap.size().height() + 6);
3676                                 cr.adjust(0, pr.bottom(), 0, -3);
3677                                 alignment |= Qt::AlignCenter;
3678                             } else {
3679                                 pr.setWidth(pixmap.width() + 8);
3680                                 cr.adjust(pr.right(), 0, 0, 0);
3681                                 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3682                             }
3683                         }
3684                         if (down) {
3685                             pr.translate(shiftX, shiftY);
3686                             pixmap = darkenPixmap(pixmap);
3687                         }
3688                         drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3689                         break; }
3690                     }
3692                     if (needText) {
3693                         QPalette pal = tb->palette;
3694                         QPalette::ColorRole role = QPalette::NoRole;
3695                         if (down)
3696                             cr.translate(shiftX, shiftY);
3697                         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5
3698                             && (tbstyle == Qt::ToolButtonTextOnly
3699                                 || (tbstyle != Qt::ToolButtonTextOnly && !down))) {
3700                             QPen pen = p->pen();
3701                             QColor light = down ? Qt::black : Qt::white;
3702                             light.setAlphaF(0.375f);
3703                             p->setPen(light);
3704                             p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3705                             p->setPen(pen);
3706                             if (down && tbstyle == Qt::ToolButtonTextOnly) {
3707                                 pal = QApplication::palette("QMenu");
3708                                 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3709                                 role = QPalette::HighlightedText;
3710                             }
3711                         }
3712                         drawItemText(p, cr, alignment, pal,
3713                                      tb->state & State_Enabled, tb->text, role);
3714                         if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && down) {
3715                             // Draw a "drop shadow" in earlier versions.
3716                             drawItemText(p, cr.adjusted(0, 1, 0, 1), alignment,
3717                                          tb->palette, tb->state & State_Enabled, tb->text);
3718                         }
3719                     }
3720                 } else {
3721                     QWindowsStyle::drawControl(ce, &myTb, p, w);
3722                 }
3723             } else {
3724                 QWindowsStyle::drawControl(ce, &myTb, p, w);
3725             }
3726         }
3727         break;
3728     case CE_ToolBoxTabShape:
3729         QCommonStyle::drawControl(ce, opt, p, w);
3730         break;
3731     case CE_PushButtonBevel:
3732         if (const QStyleOptionButton *btn = ::qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3733             if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3734                 break;
3736             if (btn->features & QStyleOptionButton::CommandLinkButton) {
3737                 QWindowsStyle::drawControl(ce, opt, p, w);
3738                 break;
3739             }
3741             HIThemeButtonDrawInfo bdi;
3742             d->initHIThemePushButton(btn, w, tds, &bdi);
3743             if (btn->features & QStyleOptionButton::DefaultButton
3744                     && d->animatable(QMacStylePrivate::AquaPushButton, w)) {
3745                 bdi.adornment |= kThemeAdornmentDefault;
3746                 bdi.animation.time.start = d->defaultButtonStart;
3747                 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
3748                 if (d->timerID <= -1)
3749                     QMetaObject::invokeMethod(d, "startAnimationTimer", Qt::QueuedConnection);
3750             }
3751             // Unlike Carbon, we want the button to always be drawn inside its bounds.
3752             // Therefore, make the button a bit smaller, so that even if it got focus,
3753             // the focus 'shadow' will be inside.
3754             HIRect newRect = qt_hirectForQRect(btn->rect);
3755             if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) {
3756                 newRect.origin.x += PushButtonLeftOffset;
3757                 newRect.origin.y += PushButtonTopOffset;
3758                 newRect.size.width -= PushButtonRightOffset;
3759                 newRect.size.height -= PushButtonBottomOffset;
3760             } else if (bdi.kind == kThemePushButtonMini) {
3761                 newRect.origin.x += PushButtonLeftOffset - 2;
3762                 newRect.origin.y += PushButtonTopOffset;
3763                 newRect.size.width -= PushButtonRightOffset - 4;
3764             }
3765             HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3767             if (btn->features & QStyleOptionButton::HasMenu) {
3768                 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3769                 QRect ir = btn->rect;
3770                 HIRect arrowRect = CGRectMake(ir.right() - mbi - PushButtonRightOffset,
3771                                               ir.height() / 2 - 4, mbi, ir.height() / 2);
3772                 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
3773                 if (drawColorless && tds == kThemeStateInactive)
3774                     tds = kThemeStateActive;
3776                 HIThemePopupArrowDrawInfo pdi;
3777                 pdi.version = qt_mac_hitheme_version;
3778                 pdi.state = tds;
3779                 pdi.orientation = kThemeArrowDown;
3780                 if (arrowRect.size.width < 8.)
3781                     pdi.size = kThemeArrow5pt;
3782                 else
3783                     pdi.size = kThemeArrow9pt;
3784                 HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal);
3785             }
3786         }
3787         break;
3788     case CE_PushButtonLabel:
3789         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3790             // We really don't want the label to be drawn the same as on
3791             // windows style if it has an icon and text, then it should be more like a
3792             // tab. So, cheat a little here. However, if it *is* only an icon
3793             // the windows style works great, so just use that implementation.
3794             bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3795             bool hasIcon = !btn->icon.isNull();
3796             bool hasText = !btn->text.isEmpty();
3797             if (!hasIcon && !hasMenu) {
3798                 // ### this is really overly difficult, simplify.
3799                 // It basically tries to get the right font for "small" and "mini" icons.
3800                 QFont oldFont = p->font();
3801                 QFont newFont = qt_app_fonts_hash()->value("QPushButton", QFont());
3802                 ThemeFontID themeId = kThemePushButtonFont;
3803                 if (oldFont == newFont) {  // Yes, use HITheme to draw the text for small sizes.
3804                     switch (d->aquaSizeConstrain(opt, w)) {
3805                     default:
3806                         break;
3807                     case QAquaSizeSmall:
3808                         themeId = kThemeSmallSystemFont;
3809                         break;
3810                     case QAquaSizeMini:
3811                         themeId = kThemeMiniSystemFont;
3812                         break;
3813                     }
3814                 }
3815                 if (themeId == kThemePushButtonFont) {
3816                     QWindowsStyle::drawControl(ce, btn, p, w);
3817                 } else {
3818                     p->save();
3819                     CGContextSetShouldAntialias(cg, true);
3820                     CGContextSetShouldSmoothFonts(cg, true);
3821                     HIThemeTextInfo tti;
3822                     tti.version = qt_mac_hitheme_version;
3823                     tti.state = tds;
3824                     QColor textColor = btn->palette.buttonText().color();
3825                     CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3826                                           textColor.blueF(), textColor.alphaF() };
3827                     CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
3828                     CGContextSetFillColor(cg, colorComp);
3829                     tti.fontID = themeId;
3830                     tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3831                     tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3832                     tti.options = kHIThemeTextBoxOptionNone;
3833                     tti.truncationPosition = kHIThemeTextTruncationNone;
3834                     tti.truncationMaxLines = 1 + btn->text.count(QLatin1Char('\n'));
3835                     QCFString buttonText = qt_mac_removeMnemonics(btn->text);
3836                     QRect r = btn->rect;
3837                     HIRect bounds = qt_hirectForQRect(r);
3838                     HIThemeDrawTextBox(buttonText, &bounds, &tti,
3839                                        cg, kHIThemeOrientationNormal);
3840                     p->restore();
3841                 }
3842             } else {
3843                 if (hasIcon && !hasText) {
3844                     QWindowsStyle::drawControl(ce, btn, p, w);
3845                 } else {
3846                     QRect freeContentRect = btn->rect;
3847                     QRect textRect = itemTextRect(
3848                         btn->fontMetrics, freeContentRect, Qt::AlignCenter, btn->state & State_Enabled, btn->text);
3849                     if (hasMenu)
3850                         textRect.adjust(-1, 0, -1, 0);
3851                     // Draw the icon:
3852                     if (hasIcon) {
3853                         int contentW = textRect.width();
3854                         if (hasMenu)
3855                             contentW += pixelMetric(PM_MenuButtonIndicator) + 4;
3856                         QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3857                         if (mode == QIcon::Normal && btn->state & State_HasFocus)
3858                             mode = QIcon::Active;
3859                         // Decide if the icon is should be on or off:
3860                         QIcon::State state = QIcon::Off;
3861                         if (btn->state & State_On)
3862                             state = QIcon::On;
3863                         QPixmap pixmap = btn->icon.pixmap(btn->iconSize, mode, state);
3864                         contentW += pixmap.width() + PushButtonContentPadding;
3865                         int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3866                         int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmap.height()) / 2;
3867                         QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmap.width(), pixmap.height());
3868                         QRect visualIconDestRect = visualRect(btn->direction, freeContentRect, iconDestRect);
3869                         drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3870                         int newOffset = iconDestRect.x() + iconDestRect.width()
3871                                         + PushButtonContentPadding - textRect.x();
3872                         textRect.adjust(newOffset, 0, newOffset, 0);
3873                     }
3874                     // Draw the text:
3875                     if (hasText) {
3876                         textRect = visualRect(btn->direction, freeContentRect, textRect);
3877                         drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn->palette,
3878                                      (btn->state & State_Enabled), btn->text, QPalette::ButtonText);
3879                     }
3880                 }
3881             }
3882         }
3883         break;
3884     case CE_ComboBoxLabel:
3885         if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3886             QStyleOptionComboBox comboCopy = *cb;
3887             comboCopy.direction = Qt::LeftToRight;
3888             QWindowsStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
3889         }
3890         break;
3891     case CE_TabBarTabShape:
3892         if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3894             if (const QStyleOptionTabV3 *tabOptV3 = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
3895                 if (tabOptV3->documentMode) {
3896                     p->save();
3897                     QRect tabRect = tabOptV3->rect;
3898                     drawTabShape(p, tabOptV3);
3899                     p->restore();
3900                     return;
3901                 }
3902             }
3904 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
3905             if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_3) {
3906                 HIThemeTabDrawInfo tdi;
3907                 tdi.version = 1;
3908                 tdi.style = kThemeTabNonFront;
3909                 tdi.direction = getTabDirection(tabOpt->shape);
3910                 switch (d->aquaSizeConstrain(opt, w)) {
3911                 default:
3912                 case QAquaSizeUnknown:
3913                 case QAquaSizeLarge:
3914                     tdi.size = kHIThemeTabSizeNormal;
3915                     break;
3916                 case QAquaSizeSmall:
3917                     tdi.size = kHIThemeTabSizeSmall;
3918                     break;
3919                 case QAquaSizeMini:
3920                     tdi.size = kHIThemeTabSizeMini;
3921                     break;
3922                 }
3923                 bool verticalTabs = tdi.direction == kThemeTabWest || tdi.direction == kThemeTabEast;
3924                 QRect tabRect = tabOpt->rect;
3926                 if ((!verticalTabs && tabRect.height() > 21 || verticalTabs && tabRect.width() > 21)) {
3927                     d->drawPantherTab(tabOpt, p, w);
3928                     break;
3929                 }
3931                 bool selected = tabOpt->state & State_Selected;
3932                 if (selected) {
3933                     if (!(tabOpt->state & State_Active))
3934                         tdi.style = kThemeTabFrontUnavailable;
3935                     else if (!(tabOpt->state & State_Enabled))
3936                         tdi.style = kThemeTabFrontInactive;
3937                     else
3938                         tdi.style = kThemeTabFront;
3939                 } else if (!(tabOpt->state & State_Active)) {
3940                     tdi.style = kThemeTabNonFrontUnavailable;
3941                 } else if (!(tabOpt->state & State_Enabled)) {
3942                     tdi.style = kThemeTabNonFrontInactive;
3943                 } else if (tabOpt->state & State_Sunken) {
3944                     tdi.style = kThemeTabFrontInactive; // (should be kThemeTabNonFrontPressed)
3945                 }
3946                 if (tabOpt->state & State_HasFocus)
3947                     tdi.adornment = kHIThemeTabAdornmentFocus;
3948                 else
3949                     tdi.adornment = kHIThemeTabAdornmentNone;
3950                 tdi.kind = kHIThemeTabKindNormal;
3951                 if (!verticalTabs)
3952                     tabRect.setY(tabRect.y() - 1);
3953                 else
3954                     tabRect.setX(tabRect.x() - 1);
3955                 QStyleOptionTab::TabPosition tp = tabOpt->position;
3956                 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3957                 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3958                     if (sp == QStyleOptionTab::NextIsSelected)
3959                         sp = QStyleOptionTab::PreviousIsSelected;
3960                     else if (sp == QStyleOptionTab::PreviousIsSelected)
3961                         sp = QStyleOptionTab::NextIsSelected;
3962                     switch (tp) {
3963                         case QStyleOptionTab::Beginning:
3964                             tp = QStyleOptionTab::End;
3965                             break;
3966                         case QStyleOptionTab::End:
3967                             tp = QStyleOptionTab::Beginning;
3968                             break;
3969                         default:
3970                             break;
3971                     }
3972                 }
3973                 switch (tp) {
3974                     case QStyleOptionTab::Beginning:
3975                         tdi.position = kHIThemeTabPositionFirst;
3976                         if (sp != QStyleOptionTab::NextIsSelected)
3977                             tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3978                         break;
3979                     case QStyleOptionTab::Middle:
3980                         tdi.position = kHIThemeTabPositionMiddle;
3981                         if (selected)
3982                             tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3983                         if (sp != QStyleOptionTab::NextIsSelected)  // Also when we're selected.
3984                             tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3985                         break;
3986                     case QStyleOptionTab::End:
3987                         tdi.position = kHIThemeTabPositionLast;
3988                         if (selected)
3989                             tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3990                         break;
3991                     case QStyleOptionTab::OnlyOneTab:
3992                         tdi.position = kHIThemeTabPositionOnly;
3993                         break;
3994                 }
3995                 HIRect hirect = qt_hirectForQRect(tabRect);
3996                 HIThemeDrawTab(&hirect, &tdi, cg, kHIThemeOrientationNormal, 0);
3997             } else
3998 #endif
3999             {
4000                 d->drawPantherTab(tabOpt, p, w);
4001             }
4002         }
4003         break;
4004     case CE_TabBarTabLabel:
4005         if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4006             QStyleOptionTabV3 myTab = *tab;
4007             ThemeTabDirection ttd = getTabDirection(myTab.shape);
4008             bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
4010             // Check to see if we use have the same as the system font
4011             // (QComboMenuItem is internal and should never be seen by the
4012             // outside world, unless they read the source, in which case, it's
4013             // their own fault).
4014             bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
4015             if (verticalTabs || nonDefaultFont || !tab->icon.isNull()
4016                 || !myTab.leftButtonSize.isNull() || !myTab.rightButtonSize.isNull()) {
4017                 int heightOffset = 0;
4018                 if (verticalTabs) {
4019                     heightOffset = -1;
4020                 } else if (nonDefaultFont) {
4021                     if (p->fontMetrics().height() == myTab.rect.height())
4022                         heightOffset = 2;
4023                 }
4024                 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4026                 if (myTab.documentMode) {
4027                     p->save();
4028                     rotateTabPainter(p, myTab.shape, myTab.rect);
4030                     QPalette np = tab->palette;
4031                     np.setColor(QPalette::WindowText, QColor(255, 255, 255, 75));
4032                     QRect nr = subElementRect(SE_TabBarTabText, opt, w);
4033                     nr.moveTop(+1);
4034                     int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic;
4035                     drawItemText(p, nr, alignment, np, tab->state & State_Enabled, tab->text, QPalette::WindowText);
4036                     p->restore();
4037                 }
4039                 QCommonStyle::drawControl(ce, &myTab, p, w);
4040             } else {
4041                 p->save();
4042                 CGContextSetShouldAntialias(cg, true);
4043                 CGContextSetShouldSmoothFonts(cg, true);
4044                 HIThemeTextInfo tti;
4045                 tti.version = qt_mac_hitheme_version;
4046                 tti.state = tds;
4047                 QColor textColor = myTab.palette.windowText().color();
4048                 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4049                                         textColor.blueF(), textColor.alphaF() };
4050                 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
4051                 CGContextSetFillColor(cg, colorComp);
4052                 switch (d->aquaSizeConstrain(opt, w)) {
4053                 default:
4054                 case QAquaSizeUnknown:
4055                 case QAquaSizeLarge:
4056                     tti.fontID = kThemeSystemFont;
4057                     break;
4058                 case QAquaSizeSmall:
4059                     tti.fontID = kThemeSmallSystemFont;
4060                     break;
4061                 case QAquaSizeMini:
4062                     tti.fontID = kThemeMiniSystemFont;
4063                     break;
4064                 }
4065                 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
4066                 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4067                 tti.options = verticalTabs ? kHIThemeTextBoxOptionStronglyVertical : kHIThemeTextBoxOptionNone;
4068                 tti.truncationPosition = kHIThemeTextTruncationNone;
4069                 tti.truncationMaxLines = 1 + myTab.text.count(QLatin1Char('\n'));
4070                 QCFString tabText = qt_mac_removeMnemonics(myTab.text);
4071                 QRect r = myTab.rect.adjusted(0, 0, 0, -1);
4072                 HIRect bounds = qt_hirectForQRect(r);
4073                 HIThemeDrawTextBox(tabText, &bounds, &tti, cg, kHIThemeOrientationNormal);
4074                 p->restore();
4075             }
4076         }
4077         break;
4078     case CE_DockWidgetTitle:
4079         if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(w)) {
4080             bool floating = dockWidget->isFloating();
4081             if (floating) {
4082                 ThemeDrawState tds = d->getDrawState(opt->state);
4083                 HIThemeWindowDrawInfo wdi;
4084                 wdi.version = qt_mac_hitheme_version;
4085                 wdi.state = tds;
4086                 wdi.windowType = kThemeMovableDialogWindow;
4087                 wdi.titleHeight = opt->rect.height();
4088                 wdi.titleWidth = opt->rect.width();
4089                 wdi.attributes = 0;
4091                 HIRect titleBarRect;
4092                 HIRect tmpRect = qt_hirectForQRect(opt->rect);
4093                 {
4094                     QCFType<HIShapeRef> titleRegion;
4095                     QRect newr = opt->rect.adjusted(0, 0, 2, 0);
4096                     HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
4097                     ptrHIShapeGetBounds(titleRegion, &tmpRect);
4098                     newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
4099                     titleBarRect = qt_hirectForQRect(newr);
4100                 }
4101                 QMacCGContext cg(p);
4102                 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
4103             } else {
4104                 // fill title bar background
4105                 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
4106                 linearGrad.setColorAt(0, mainWindowGradientBegin);
4107                 linearGrad.setColorAt(1, mainWindowGradientEnd);
4108                 p->fillRect(opt->rect, linearGrad);
4110                 // draw horizontal lines at top and bottom
4111                 p->save();
4112                 p->setPen(mainWindowGradientBegin.lighter(114));
4113                 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4114                 p->setPen(mainWindowGradientEnd.darker(114));
4115                 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4116                 p->restore();
4117             }
4118         }
4120         // Draw the text...
4121         if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4122             if (!dwOpt->title.isEmpty()) {
4123                 const QStyleOptionDockWidgetV2 *v2
4124                     = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt);
4125                 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
4127                 QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w);
4128                 if (verticalTitleBar) {
4129                     QRect rect = dwOpt->rect;
4130                     QRect r = rect;
4131                     QSize s = r.size();
4132                     s.transpose();
4133                     r.setSize(s);
4135                     titleRect = QRect(r.left() + rect.bottom()
4136                                         - titleRect.bottom(),
4137                                     r.top() + titleRect.left() - rect.left(),
4138                                     titleRect.height(), titleRect.width());
4140                     p->translate(r.left(), r.top() + r.width());
4141                     p->rotate(-90);
4142                     p->translate(-r.left(), -r.top());
4143                 }
4145                 QFont oldFont = p->font();
4146                 p->setFont(qt_app_fonts_hash()->value("QToolButton", p->font()));
4147                 QString text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
4148                     titleRect.width());
4149                 drawItemText(p, titleRect,
4150                               Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette,
4151                               dwOpt->state & State_Enabled, text,
4152                               QPalette::WindowText);
4153                 p->setFont(oldFont);
4154             }
4155         }
4156         break;
4157     case CE_FocusFrame: {
4158         int xOff = pixelMetric(PM_FocusFrameHMargin, opt, w) + 1;
4159         int yOff = pixelMetric(PM_FocusFrameVMargin, opt, w) + 1;
4160         HIRect hirect = CGRectMake(xOff+opt->rect.x(), yOff+opt->rect.y(), opt->rect.width() - 2 * xOff,
4161                                    opt->rect.height() - 2 * yOff);
4162         HIThemeDrawFocusRect(&hirect, true, QMacCGContext(p), kHIThemeOrientationNormal);
4163         break; }
4164     case CE_MenuItem:
4165     case CE_MenuEmptyArea:
4166         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4167             p->fillRect(mi->rect, opt->palette.background());
4168             QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, w);
4169             int tabwidth = mi->tabWidth;
4170             int maxpmw = mi->maxIconWidth;
4171             bool active = mi->state & State_Selected;
4172             bool enabled = mi->state & State_Enabled;
4173             HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4174             HIRect itemRect = qt_hirectForQRect(mi->rect);
4175             HIThemeMenuItemDrawInfo mdi;
4176             mdi.version = qt_mac_hitheme_version;
4177             mdi.itemType = kThemeMenuItemPlain;
4178             if (!mi->icon.isNull())
4179                 mdi.itemType |= kThemeMenuItemHasIcon;
4180             if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
4181                 mdi.itemType |= kThemeMenuItemHierarchical | kThemeMenuItemHierBackground;
4182             else
4183                 mdi.itemType |= kThemeMenuItemPopUpBackground;
4184             if (enabled)
4185                 mdi.state = kThemeMenuActive;
4186             else
4187                 mdi.state = kThemeMenuDisabled;
4188             if (active)
4189                 mdi.state |= kThemeMenuSelected;
4190             QRect contentRect;
4191             if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4192                 // First arg should be &menurect, but wacky stuff happens then.
4193                 HIThemeDrawMenuSeparator(&itemRect, &itemRect, &mdi,
4194                                          cg, kHIThemeOrientationNormal);
4195                 break;
4196             } else {
4197                 HIRect cr;
4198                 bool needAlpha = mi->palette.color(QPalette::Button) == Qt::transparent;
4199                 if (needAlpha) {
4200                     needAlpha = true;
4201                     CGContextSaveGState(cg);
4202                     CGContextSetAlpha(cg, 0.0);
4203                 }
4204                 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4205                                     cg, kHIThemeOrientationNormal, &cr);
4206                 if (needAlpha)
4207                     CGContextRestoreGState(cg);
4208                 if (ce == CE_MenuEmptyArea)
4209                     break;
4210                 contentRect = qt_qrectForHIRect(cr);
4211             }
4212             int xpos = contentRect.x() + 18;
4213             int checkcol = maxpmw;
4214             if (!enabled)
4215                 p->setPen(mi->palette.text().color());
4216             else if (active)
4217                 p->setPen(mi->palette.highlightedText().color());
4218             else
4219                 p->setPen(mi->palette.buttonText().color());
4221             if (mi->checked) {
4222                 // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it,
4223                 // we somehow need to use a special encoding as it doesn't look right with our
4224                 // drawText().
4225                 p->save();
4226                 CGContextSetShouldAntialias(cg, true);
4227                 CGContextSetShouldSmoothFonts(cg, true);
4228                 QColor textColor = p->pen().color();
4229                 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4230                                       textColor.blueF(), textColor.alphaF() };
4231                 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
4232                 CGContextSetFillColor(cg, colorComp);
4233                 HIThemeTextInfo tti;
4234                 tti.version = qt_mac_hitheme_version;
4235                 tti.state = tds;
4236                 if (active && enabled)
4237                     tti.state = kThemeStatePressed;
4238                 switch (widgetSize) {
4239                 case QAquaSizeUnknown:
4240                 case QAquaSizeLarge:
4241                     tti.fontID = kThemeMenuItemMarkFont;
4242                     break;
4243                 case QAquaSizeSmall:
4244                     tti.fontID = kThemeSmallSystemFont;
4245                     break;
4246                 case QAquaSizeMini:
4247                     tti.fontID = kThemeMiniSystemFont;
4248                     break;
4249                 }
4250                 tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft;
4251                 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4252                 tti.options = kHIThemeTextBoxOptionNone;
4253                 tti.truncationPosition = kHIThemeTextTruncationNone;
4254                 tti.truncationMaxLines = 1;
4255                 QCFString checkmark;
4256 #if 0
4257                 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
4258                     checkmark = QString(QChar(kDiamondUnicode));
4259                 else
4260 #endif
4261                     checkmark = QString(QChar(kCheckUnicode));
4262                 int mw = checkcol + macItemFrame;
4263                 int mh = contentRect.height() - 2 * macItemFrame;
4264                 int xp = contentRect.x();
4265                 xp += macItemFrame;
4266                 CGFloat outWidth, outHeight, outBaseline;
4267                 HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight,
4268                                          &outBaseline);
4269                 if (widgetSize == QAquaSizeMini)
4270                     outBaseline += 1;
4271                 QRect r(xp, contentRect.y(), mw, mh);
4272                 r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1);
4273                 HIRect bounds = qt_hirectForQRect(r);
4274                 HIThemeDrawTextBox(checkmark, &bounds, &tti,
4275                                    cg, kHIThemeOrientationNormal);
4276                 p->restore();
4277             }
4278             if (!mi->icon.isNull()) {
4279                 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4280                                                                : QIcon::Disabled;
4281                 // Always be normal or disabled to follow the Mac style.
4282                 int smallIconSize = pixelMetric(PM_SmallIconSize);
4283                 QSize iconSize(smallIconSize, smallIconSize);
4284                 if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
4285                     iconSize = comboBox->iconSize();
4286                 }
4287                 QPixmap pixmap = mi->icon.pixmap(iconSize, mode);
4288                 int pixw = pixmap.width();
4289                 int pixh = pixmap.height();
4290                 QRect cr(xpos, contentRect.y(), checkcol, contentRect.height());
4291                 QRect pmr(0, 0, pixw, pixh);
4292                 pmr.moveCenter(cr.center());
4293                 p->drawPixmap(pmr.topLeft(), pixmap);
4294                 xpos += pixw + 6;
4295             }
4297             QString s = mi->text;
4298             if (!s.isEmpty()) {
4299                 int t = s.indexOf(QLatin1Char('\t'));
4300                 int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic
4301                                  | Qt::TextSingleLine | Qt::AlignAbsolute;
4302                 int yPos = contentRect.y();
4303                 if (widgetSize == QAquaSizeMini)
4304                     yPos += 1;
4305                 p->save();
4306                 if (t >= 0) {
4307                     p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
4308                     int xp = contentRect.right() - tabwidth - macRightBorder
4309                              - macItemHMargin - macItemFrame + 1;
4310                     p->drawText(xp, yPos, tabwidth, contentRect.height(), text_flags,
4311                                 s.mid(t + 1));
4312                     s = s.left(t);
4313                 }
4315                 const int xm = macItemFrame + maxpmw + macItemHMargin;
4316                 QFont myFont = mi->font;
4317                 if (mi->state & QStyle::State_Mini)
4318                     myFont.setPointSize(mi->font.pointSize());
4319                 p->setFont(myFont);
4320                 p->drawText(xpos, yPos, contentRect.width() - xm - tabwidth + 1,
4321                             contentRect.height(), text_flags ^ Qt::AlignRight, s);
4322                 p->restore();
4323             }
4324         }
4325         break;
4326     case CE_MenuHMargin:
4327     case CE_MenuVMargin:
4328     case CE_MenuTearoff:
4329     case CE_MenuScroller:
4330         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4331             p->fillRect(mi->rect, opt->palette.background());
4333             HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4334             HIRect itemRect = qt_hirectForQRect(mi->rect);
4335             HIThemeMenuItemDrawInfo mdi;
4336             mdi.version = qt_mac_hitheme_version;
4337             if (!(opt->state & State_Enabled))
4338                 mdi.state = kThemeMenuDisabled;
4339             else if (opt->state & State_Selected)
4340                 mdi.state = kThemeMenuSelected;
4341             else
4342                 mdi.state = kThemeMenuActive;
4343             if (ce == CE_MenuScroller) {
4344                 if (opt->state & State_DownArrow)
4345                     mdi.itemType = kThemeMenuItemScrollDownArrow;
4346                 else
4347                     mdi.itemType = kThemeMenuItemScrollUpArrow;
4348             } else {
4349                 mdi.itemType = kThemeMenuItemPlain;
4350             }
4351             HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4352                                 cg,
4353                                 kHIThemeOrientationNormal, 0);
4354             if (ce == CE_MenuTearoff) {
4355                 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4356                 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4357                             mi->rect.x() + mi->rect.width() - 4,
4358                             mi->rect.y() + mi->rect.height() / 2 - 1);
4359                 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4360                 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4361                             mi->rect.x() + mi->rect.width() - 4,
4362                             mi->rect.y() + mi->rect.height() / 2);
4363             }
4364         }
4365         break;
4366     case CE_MenuBarItem:
4367         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4368             HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4369             HIRect itemRect = qt_hirectForQRect(mi->rect);
4371             if ((opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken)){
4372                 // Draw a selected menu item background:
4373                 HIThemeMenuItemDrawInfo mdi;
4374                 mdi.version = qt_mac_hitheme_version;
4375                 mdi.state = kThemeMenuSelected;
4376                 mdi.itemType = kThemeMenuItemPlain;
4377                 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, cg, kHIThemeOrientationNormal, 0);
4378             } else {
4379                 // Draw the toolbar background:
4380                 HIThemeMenuBarDrawInfo bdi;
4381                 bdi.version = qt_mac_hitheme_version;
4382                 bdi.state = kThemeMenuBarNormal;
4383                 bdi.attributes = 0;
4384                 HIRect hirect = qt_hirectForQRect(mi->rect);
4385                 HIThemeDrawMenuBarBackground(&menuRect, &bdi, cg, kHIThemeOrientationNormal);
4386             }
4388             if (!mi->icon.isNull()) {
4389                 drawItemPixmap(p, mi->rect,
4390                                   Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4391                                   | Qt::TextSingleLine,
4392                                   mi->icon.pixmap(pixelMetric(PM_SmallIconSize),
4393                           (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4394             } else {
4395                 drawItemText(p, mi->rect,
4396                                 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4397                                 | Qt::TextSingleLine,
4398                                 mi->palette, mi->state & State_Enabled,
4399                                 mi->text, QPalette::ButtonText);
4400             }
4401         }
4402         break;
4403     case CE_MenuBarEmptyArea:
4404         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4405             HIThemeMenuBarDrawInfo bdi;
4406             bdi.version = qt_mac_hitheme_version;
4407             bdi.state = kThemeMenuBarNormal;
4408             bdi.attributes = 0;
4409             HIRect hirect = qt_hirectForQRect(mi->rect);
4410             HIThemeDrawMenuBarBackground(&hirect, &bdi, cg,
4411                                          kHIThemeOrientationNormal);
4412             break;
4413         }
4414     case CE_ProgressBarContents:
4415         if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4416             HIThemeTrackDrawInfo tdi;
4417             tdi.version = qt_mac_hitheme_version;
4418             tdi.reserved = 0;
4419             bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4420             bool vertical = false;
4421             bool inverted = false;
4422             if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
4423                 vertical = (pb2->orientation == Qt::Vertical);
4424                 inverted = pb2->invertedAppearance;
4425             }
4426             bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4427             if (inverted)
4428                 reverse = !reverse;
4429             switch (d->aquaSizeConstrain(opt, w)) {
4430             case QAquaSizeUnknown:
4431             case QAquaSizeLarge:
4432                 tdi.kind = !isIndeterminate ? kThemeLargeProgressBar
4433                                             : kThemeLargeIndeterminateBar;
4434                 break;
4435             case QAquaSizeMini:
4436             case QAquaSizeSmall:
4437                 tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar;
4438                 break;
4439             }
4440             tdi.bounds = qt_hirectForQRect(pb->rect);
4441             tdi.max = pb->maximum;
4442             tdi.min = pb->minimum;
4443             tdi.value = pb->progress;
4444             tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
4445             tdi.trackInfo.progress.phase = d->progressFrame;
4446             if (!(pb->state & State_Active))
4447                 tdi.enableState = kThemeTrackInactive;
4448             else if (!(pb->state & State_Enabled))
4449                 tdi.enableState = kThemeTrackDisabled;
4450             else
4451                 tdi.enableState = kThemeTrackActive;
4452             HIThemeDrawTrack(&tdi, 0, cg, kHIThemeOrientationNormal);
4453         }
4454         break;
4455     case CE_ProgressBarLabel:
4456     case CE_ProgressBarGroove:
4457         break;
4458     case CE_SizeGrip: {
4459         if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) {
4460             HIThemeGrowBoxDrawInfo gdi;
4461             gdi.version = qt_mac_hitheme_version;
4462             gdi.state = tds;
4463             gdi.kind = kHIThemeGrowBoxKindNormal;
4464             gdi.direction = kThemeGrowRight | kThemeGrowDown;
4465             gdi.size = kHIThemeGrowBoxSizeNormal;
4466             HIPoint pt = CGPointMake(opt->rect.x(), opt->rect.y());
4467             HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal);
4468         } else {
4469             // It isn't possible to draw a transparent size grip with the
4470             // native API, so we do it ourselves here.
4471             const bool metal = qt_mac_is_metal(w);
4472             QPen lineColor = metal ? QColor(236, 236, 236) : QColor(82, 82, 82, 192);
4473             QPen metalHighlight = QColor(5, 5, 5, 192);
4474             lineColor.setWidth(1);
4475             p->save();
4476             p->setRenderHint(QPainter::Antialiasing);
4477             p->setPen(lineColor);
4478             const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4479             const int NumLines = metal ? 4 : 3;
4480             for (int l = 0; l < NumLines; ++l) {
4481                 const int offset = (l * 4 + (metal ? 2 : 3));
4482                 QPoint start, end;
4483                 if (layoutDirection == Qt::LeftToRight) {
4484                     start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4485                     end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4486                 } else {
4487                     start = QPoint(offset, opt->rect.height() - 1);
4488                     end = QPoint(1, opt->rect.height() - offset);
4489                 }
4490                 p->drawLine(start, end);
4491                 if (metal) {
4492                     p->setPen(metalHighlight);
4493                     p->setRenderHint(QPainter::Antialiasing, false);
4494                     p->drawLine(start + QPoint(0, -1), end + QPoint(0, -1));
4495                     p->setRenderHint(QPainter::Antialiasing, true);
4496                     p->setPen(lineColor);
4497                 }
4498             }
4499             p->restore();
4500         }
4501         break;
4502         }
4503     case CE_Splitter: {
4504         HIThemeSplitterDrawInfo sdi;
4505         sdi.version = qt_mac_hitheme_version;
4506         sdi.state = tds;
4507         sdi.adornment = qt_mac_is_metal(w) ? kHIThemeSplitterAdornmentMetal
4508                                            : kHIThemeSplitterAdornmentNone;
4509         HIRect hirect = qt_hirectForQRect(opt->rect);
4510         HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal);
4511         break; }
4512     case CE_RubberBand:
4513         if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
4514             QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4515             if (!rubber->opaque) {
4516                 QColor strokeColor;
4517                 // I retrieved these colors from the Carbon-Dev mailing list
4518                 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4519                 fillColor.setHsvF(0, 0, 0.53, 0.25);
4520                 if (opt->rect.width() * opt->rect.height() <= 3) {
4521                     p->fillRect(opt->rect, strokeColor);
4522                 } else {
4523                     QPen oldPen = p->pen();
4524                     QBrush oldBrush = p->brush();
4525                     QPen pen(strokeColor);
4526                     p->setPen(pen);
4527                     p->setBrush(fillColor);
4528                     p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
4529                     p->setPen(oldPen);
4530                     p->setBrush(oldBrush);
4531                 }
4532             } else {
4533                 p->fillRect(opt->rect, fillColor);
4534             }
4535         }
4536         break;
4537     case CE_ToolBar: {
4538         // For unified tool bars, draw nothing.
4539         if (w) {
4540             if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window()))
4541                 if (mainWindow->unifiedTitleAndToolBarOnMac())
4542                     break;
4543         }
4545         // draw background gradient
4546         QLinearGradient linearGrad;
4547         if (opt->state & State_Horizontal)
4548             linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4549         else
4550             linearGrad = QLinearGradient(opt->rect.left(), 0,  opt->rect.right(), 0);
4552         linearGrad.setColorAt(0, mainWindowGradientBegin);
4553         linearGrad.setColorAt(1, mainWindowGradientEnd);
4554         p->fillRect(opt->rect, linearGrad);
4556         p->save();
4557         if (opt->state & State_Horizontal) {
4558             p->setPen(mainWindowGradientBegin.lighter(114));
4559             p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4560             p->setPen(mainWindowGradientEnd.darker(114));
4561             p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4563         } else {
4564             p->setPen(mainWindowGradientBegin.lighter(114));
4565             p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4566             p->setPen(mainWindowGradientEnd.darker(114));
4567             p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
4568         }
4569         p->restore();
4572         } break;
4573     default:
4574         QWindowsStyle::drawControl(ce, opt, p, w);
4575         break;
4576     }
4579 static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
4581     if (dir == Qt::RightToLeft) {
4582         rect->adjust(-right, top, -left, bottom);
4583     } else {
4584         rect->adjust(left, top, right, bottom);
4585     }
4587 /*! \reimp */
4588 QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
4589                                 const QWidget *widget) const
4591     QRect rect;
4592     int controlSize = getControlSize(opt, widget);
4594     switch (sr) {
4595     case SE_ToolBoxTabContents:
4596         rect = QCommonStyle::subElementRect(sr, opt, widget);
4597         break;
4598     case SE_PushButtonContents:
4599         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4600             // Unlike Carbon, we want the button to always be drawn inside its bounds.
4601             // Therefore, the button is a bit smaller, so that even if it got focus,
4602             // the focus 'shadow' will be inside. Adjust the content rect likewise.
4603             HIThemeButtonDrawInfo bdi;
4604             d->initHIThemePushButton(btn, widget, d->getDrawState(opt->state), &bdi);
4605             HIRect contentRect = d->pushButtonContentBounds(btn, &bdi);
4606             rect = qt_qrectForHIRect(contentRect);
4607         }
4608         break;
4609     case SE_HeaderLabel:
4610         if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4611             rect = QWindowsStyle::subElementRect(sr, opt, widget);
4612             if (widget && widget->height() <= qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight)){
4613                 // We need to allow the text a bit more space when the header is as
4614                 // small as kThemeMetricListHeaderHeight, otherwise it gets clipped:
4615                 rect.setY(0);
4616                 rect.setHeight(widget->height());
4617             }
4618             if (opt->direction == Qt::RightToLeft)
4619                 rect.adjust(15, 0, -20, 0);
4620         }
4621         break;
4622     case SE_ProgressBarGroove:
4623     case SE_ProgressBarLabel:
4624         break;
4625     case SE_ProgressBarContents:
4626         rect = opt->rect;
4627         break;
4628     case SE_TreeViewDisclosureItem: {
4629         HIRect inRect = CGRectMake(opt->rect.x(), opt->rect.y(),
4630                                    opt->rect.width(), opt->rect.height());
4631         HIThemeButtonDrawInfo bdi;
4632         bdi.version = qt_mac_hitheme_version;
4633         bdi.state = kThemeStateActive;
4634         bdi.kind = kThemeDisclosureButton;
4635         bdi.value = kThemeDisclosureRight;
4636         bdi.adornment = kThemeAdornmentNone;
4637         HIRect contentRect;
4638         HIThemeGetButtonContentBounds(&inRect, &bdi, &contentRect);
4639         QCFType<HIShapeRef> shape;
4640         HIRect outRect;
4641         HIThemeGetButtonShape(&inRect, &bdi, &shape);
4642         ptrHIShapeGetBounds(shape, &outRect);
4643         rect = QRect(int(outRect.origin.x), int(outRect.origin.y),
4644                   int(contentRect.origin.x - outRect.origin.x), int(outRect.size.height));
4645         break;
4646     }
4647     case SE_TabWidgetLeftCorner:
4648         if (const QStyleOptionTabWidgetFrame *twf
4649                 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4650             switch (twf->shape) {
4651             case QTabBar::RoundedNorth:
4652             case QTabBar::TriangularNorth:
4653                 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4654                 break;
4655             case QTabBar::RoundedSouth:
4656             case QTabBar::TriangularSouth:
4657                 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4658                           twf->leftCornerWidgetSize);
4659                 break;
4660             default:
4661                 break;
4662             }
4663             rect = visualRect(twf->direction, twf->rect, rect);
4664         }
4665         break;
4666     case SE_TabWidgetRightCorner:
4667         if (const QStyleOptionTabWidgetFrame *twf
4668                 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4669             switch (twf->shape) {
4670             case QTabBar::RoundedNorth:
4671             case QTabBar::TriangularNorth:
4672                 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4673                           twf->rightCornerWidgetSize);
4674                 break;
4675             case QTabBar::RoundedSouth:
4676             case QTabBar::TriangularSouth:
4677                 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4678                                  twf->rect.height() - twf->rightCornerWidgetSize.height()),
4679                           twf->rightCornerWidgetSize);
4680                 break;
4681             default:
4682                 break;
4683             }
4684             rect = visualRect(twf->direction, twf->rect, rect);
4685         }
4686         break;
4687     case SE_TabWidgetTabContents:
4688         rect = QWindowsStyle::subElementRect(sr, opt, widget);
4689         if (const QStyleOptionTabWidgetFrame *twf
4690                 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4691             if (twf->lineWidth != 0) {
4692                 switch (getTabDirection(twf->shape)) {
4693                 case kThemeTabNorth:
4694                     rect.adjust(+1, +14, -1, -1);
4695                     break;
4696                 case kThemeTabSouth:
4697                     rect.adjust(+1, +1, -1, -14);
4698                     break;
4699                 case kThemeTabWest:
4700                     rect.adjust(+14, +1, -1, -1);
4701                     break;
4702                 case kThemeTabEast:
4703                     rect.adjust(+1, +1, -14, -1);
4704                 }
4705             }
4706         }
4707         break;
4708     case SE_LineEditContents:
4709         rect = QWindowsStyle::subElementRect(sr, opt, widget);
4710         if(widget->parentWidget() && qobject_cast<const QComboBox*>(widget->parentWidget()))
4711             rect.adjust(-1, -2, 0, 0);
4712         else
4713             rect.adjust(-1, 0, 0, +1);
4714         break;
4715     case SE_CheckBoxLayoutItem:
4716         rect = opt->rect;
4717         if (controlSize == QAquaSizeLarge) {
4718             setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4719         } else if (controlSize == QAquaSizeSmall) {
4720             setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction);
4721         } else {
4722             setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction);
4723         }
4724         break;
4725     case SE_ComboBoxLayoutItem:
4726         if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4727             // Do nothing, because QToolbar needs the entire widget rect.
4728             // Otherwise it will be clipped. Equivalent to
4729             // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4730             // all the hassle.
4731         } else {
4732             rect = opt->rect;
4733             if (controlSize == QAquaSizeLarge) {
4734                 rect.adjust(+3, +2, -3, -4);
4735             } else if (controlSize == QAquaSizeSmall) {
4736                 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4737             } else {
4738                 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4739             }
4740         }
4741         break;
4742     case SE_LabelLayoutItem:
4743         rect = opt->rect;
4744         setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4745         break;
4746     case SE_ProgressBarLayoutItem: {
4747         rect = opt->rect;
4748         int bottom = SIZE(3, 8, 8);
4749         if (opt->state & State_Horizontal) {
4750             rect.adjust(0, +1, 0, -bottom);
4751         } else {
4752             setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
4753         }
4754         break;
4755     }
4756     case SE_PushButtonLayoutItem:
4757         if (const QStyleOptionButton *buttonOpt
4758                 = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4759             if ((buttonOpt->features & QStyleOptionButton::Flat))
4760                 break;  // leave rect alone
4761         }
4762         rect = opt->rect;
4763         if (controlSize == QAquaSizeLarge) {
4764             rect.adjust(+6, +4, -6, -8);
4765         } else if (controlSize == QAquaSizeSmall) {
4766             rect.adjust(+5, +4, -5, -6);
4767         } else {
4768             rect.adjust(+1, 0, -1, -2);
4769         }
4770         break;
4771     case SE_RadioButtonLayoutItem:
4772         rect = opt->rect;
4773         if (controlSize == QAquaSizeLarge) {
4774             setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */,
4775                                  0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction);
4776         } else if (controlSize == QAquaSizeSmall) {
4777             rect.adjust(0, +6, 0 /* fix */, -5);
4778         } else {
4779             rect.adjust(0, +6, 0 /* fix */, -7);
4780         }
4781         break;
4782     case SE_SliderLayoutItem:
4783         if (const QStyleOptionSlider *sliderOpt
4784                 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4785             rect = opt->rect;
4786             if (sliderOpt->tickPosition == QSlider::NoTicks) {
4787                 int above = SIZE(3, 0, 2);
4788                 int below = SIZE(4, 3, 0);
4789                 if (sliderOpt->orientation == Qt::Horizontal) {
4790                     rect.adjust(0, +above, 0, -below);
4791                 } else {
4792                     rect.adjust(+above, 0, -below, 0);  //### Seems that QSlider flip the position of the ticks in reverse mode.
4793                 }
4794             } else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4795                 int below = SIZE(3, 2, 0);
4796                 if (sliderOpt->orientation == Qt::Horizontal) {
4797                     rect.setHeight(rect.height() - below);
4798                 } else {
4799                     rect.setWidth(rect.width() - below);
4800                 }
4801             } else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4802                 int above = SIZE(3, 2, 0);
4803                 if (sliderOpt->orientation == Qt::Horizontal) {
4804                     rect.setTop(rect.top() + above);
4805                 } else {
4806                     rect.setLeft(rect.left() + above);
4807                 }
4808             }
4809         }
4810         break;
4811     case SE_FrameLayoutItem:
4812         // hack because QStyleOptionFrameV2 doesn't have a frameStyle member
4813         if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4814             rect = opt->rect;
4815             switch (frame->frameStyle() & QFrame::Shape_Mask) {
4816             case QFrame::HLine:
4817                 rect.adjust(0, +1, 0, -1);
4818                 break;
4819             case QFrame::VLine:
4820                 rect.adjust(+1, 0, -1, 0);
4821                 break;
4822             default:
4823                 ;
4824             }
4825         }
4826         break;
4827     case SE_GroupBoxLayoutItem:
4828         rect = opt->rect;
4829         if (const QStyleOptionGroupBox *groupBoxOpt =
4830                 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4831             /*
4832                 AHIG is very inconsistent when it comes to group boxes.
4833                 Basically, we make sure that (non-checkable) group boxes
4834                 and tab widgets look good when laid out side by side.
4835             */
4836             if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4837                                             | QStyle::SC_GroupBoxLabel)) {
4838                 int delta;
4839                 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4840                     delta = SIZE(8, 4, 4);       // guess
4841                 } else {
4842                     delta = SIZE(15, 12, 12);    // guess
4843                 }
4844                 rect.setTop(rect.top() + delta);
4845             }
4846         }
4847         rect.setBottom(rect.bottom() - 1);
4848         break;
4849     case SE_TabWidgetLayoutItem:
4850         if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4851                 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4852             /*
4853                 AHIG specifies "12 or 14" as the distance from the window
4854                 edge. We choose 14 and since the default top margin is 20,
4855                 the overlap is 6.
4856             */
4857             rect = tabWidgetOpt->rect;
4858             if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4859                 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4860         }
4861         break;
4862     default:
4863         rect = QWindowsStyle::subElementRect(sr, opt, widget);
4864         break;
4865     }
4866     return rect;
4869 static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDrawState tds, CGContextRef cg)
4871     QRect arrowRect = QRect(toolButtonRect.right() - 9, toolButtonRect.bottom() - 9, 7, 5);
4872     HIThemePopupArrowDrawInfo padi;
4873     padi.version = qt_mac_hitheme_version;
4874     padi.state = tds;
4875     padi.orientation = kThemeArrowDown;
4876     padi.size = kThemeArrow7pt;
4877     HIRect hirect = qt_hirectForQRect(arrowRect);
4878     HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
4881 /*! \reimp */
4882 void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
4883                                    const QWidget *widget) const
4885     ThemeDrawState tds = d->getDrawState(opt->state);
4886     QMacCGContext cg(p);
4887     switch (cc) {
4888     case CC_Slider:
4889     case CC_ScrollBar:
4890         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4891             HIThemeTrackDrawInfo tdi;
4892             d->getSliderInfo(cc, slider, &tdi, widget);
4893             if (slider->state & State_Sunken) {
4894                 if (cc == CC_Slider) {
4895                     if (slider->activeSubControls == SC_SliderHandle)
4896                         tdi.trackInfo.slider.pressState = kThemeThumbPressed;
4897                     else if (slider->activeSubControls == SC_SliderGroove)
4898                         tdi.trackInfo.slider.pressState = kThemeLeftTrackPressed;
4899                 } else {
4900                     if (slider->activeSubControls == SC_ScrollBarSubLine
4901                         || slider->activeSubControls == SC_ScrollBarAddLine) {
4902                         // This test looks complex but it basically boils down
4903                         // to the following: The "RTL look" on the mac also
4904                         // changed the directions of the controls, that's not
4905                         // what people expect (an arrow is an arrow), so we
4906                         // kind of fake and say the opposite button is hit.
4907                         // This works great, up until 10.4 which broke the
4908                         // scroll bars, so I also have actually do something
4909                         // similar when I have an upside down scroll bar
4910                         // because on Tiger I only "fake" the reverse stuff.
4911                         bool reverseHorizontal = (slider->direction == Qt::RightToLeft
4912                                                   && slider->orientation == Qt::Horizontal
4913                                                   && (!slider->upsideDown
4914                                                       || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
4915                                                           && slider->upsideDown)));
4916                         if ((reverseHorizontal
4917                              && slider->activeSubControls == SC_ScrollBarAddLine)
4918                             || (!reverseHorizontal
4919                                 && slider->activeSubControls == SC_ScrollBarSubLine)) {
4920                             tdi.trackInfo.scrollbar.pressState = kThemeRightInsideArrowPressed
4921                                                                  | kThemeLeftOutsideArrowPressed;
4922                         } else {
4923                             tdi.trackInfo.scrollbar.pressState = kThemeLeftInsideArrowPressed
4924                                                                  | kThemeRightOutsideArrowPressed;
4925                         }
4926                     } else if (slider->activeSubControls == SC_ScrollBarAddPage) {
4927                         tdi.trackInfo.scrollbar.pressState = kThemeRightTrackPressed;
4928                     } else if (slider->activeSubControls == SC_ScrollBarSubPage) {
4929                         tdi.trackInfo.scrollbar.pressState = kThemeLeftTrackPressed;
4930                     } else if (slider->activeSubControls == SC_ScrollBarSlider) {
4931                         tdi.trackInfo.scrollbar.pressState = kThemeThumbPressed;
4932                     }
4933                 }
4934             }
4935             HIRect macRect;
4936             bool tracking = slider->sliderPosition == slider->sliderValue;
4937             if (!tracking) {
4938                 // Small optimization, the same as q->subControlRect
4939                 QCFType<HIShapeRef> shape;
4940                 HIThemeGetTrackThumbShape(&tdi, &shape);
4941                 ptrHIShapeGetBounds(shape, &macRect);
4942                 tdi.value = slider->sliderValue;
4943             }
4945             // Remove controls from the scroll bar if it is to short to draw them correctly.
4946             // This is done in two stages: first the thumb indicator is removed when it is
4947             // no longer possible to move it, second the up/down buttons are removed when
4948             // there is not enough space for them.
4949             if (cc == CC_ScrollBar) {
4950                 const int scrollBarLenght = (slider->orientation == Qt::Horizontal)
4951                     ? slider->rect.width() : slider->rect.height();
4952                 const QMacStyle::WidgetSizePolicy sizePolicy = widgetSizePolicy(widget);
4953                 if (scrollBarLenght < scrollButtonsCutoffSize(thumbIndicatorCutoff, sizePolicy))
4954                     tdi.attributes &= ~kThemeTrackShowThumb;
4955                 if (scrollBarLenght < scrollButtonsCutoffSize(scrollButtonsCutoff, sizePolicy))
4956                     tdi.enableState = kThemeTrackNothingToScroll;
4957             }
4959             HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg,
4960                              kHIThemeOrientationNormal);
4961             if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
4962                 if (qt_mac_is_metal(widget)) {
4963                     if (tdi.enableState == kThemeTrackInactive)
4964                         tdi.enableState = kThemeTrackActive;  // Looks more Cocoa-like
4965                 }
4966                 int interval = slider->tickInterval;
4967                 if (interval == 0) {
4968                     interval = slider->pageStep;
4969                     if (interval == 0)
4970                         interval = slider->singleStep;
4971                     if (interval == 0)
4972                         interval = 1;
4973                 }
4974                 int numMarks = 1 + ((slider->maximum - slider->minimum) / interval);
4976                 if (tdi.trackInfo.slider.thumbDir == kThemeThumbPlain) {
4977                     // They asked for both, so we'll give it to them.
4978                     tdi.trackInfo.slider.thumbDir = kThemeThumbDownward;
4979                     HIThemeDrawTrackTickMarks(&tdi, numMarks,
4980                                               cg,
4981                                               kHIThemeOrientationNormal);
4982                     tdi.trackInfo.slider.thumbDir = kThemeThumbUpward;
4983                     HIThemeDrawTrackTickMarks(&tdi, numMarks,
4984                                               cg,
4985                                                kHIThemeOrientationNormal);
4986                 } else {
4987                     HIThemeDrawTrackTickMarks(&tdi, numMarks,
4988                                               cg,
4989                                               kHIThemeOrientationNormal);
4991                 }
4992             }
4993         }
4994         break;
4995     case CC_Q3ListView:
4996         if (const QStyleOptionQ3ListView *lv = qstyleoption_cast<const QStyleOptionQ3ListView *>(opt)) {
4997             if (lv->subControls & SC_Q3ListView)
4998                 QWindowsStyle::drawComplexControl(cc, lv, p, widget);
4999             if (lv->subControls & (SC_Q3ListViewBranch | SC_Q3ListViewExpand)) {
5000                 int y = lv->rect.y();
5001                 int h = lv->rect.height();
5002                 int x = lv->rect.right() - 10;
5003                 for (int i = 1; i < lv->items.size() && y < h; ++i) {
5004                     QStyleOptionQ3ListViewItem item = lv->items.at(i);
5005                     if (y + item.height > 0 && (item.childCount > 0
5006                         || (item.features & (QStyleOptionQ3ListViewItem::Expandable
5007                                             | QStyleOptionQ3ListViewItem::Visible))
5008                             == (QStyleOptionQ3ListViewItem::Expandable
5009                                 | QStyleOptionQ3ListViewItem::Visible))) {
5010                         QStyleOption treeOpt(0);
5011                         treeOpt.rect.setRect(x, y + item.height / 2 - 4, 9, 9);
5012                         treeOpt.palette = lv->palette;
5013                         treeOpt.state = lv->state;
5014                         treeOpt.state |= State_Children;
5015                         if (item.state & State_Open)
5016                             treeOpt.state |= State_Open;
5017                         drawPrimitive(PE_IndicatorBranch, &treeOpt, p, widget);
5018                     }
5019                     y += item.totalHeight;
5020                 }
5021             }
5022         }
5023         break;
5024     case CC_SpinBox:
5025         if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5026             QStyleOptionSpinBox newSB = *sb;
5027             if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5028                 SInt32 frame_size;
5029                 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
5031                 QRect lineeditRect = subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5032                 lineeditRect.adjust(-frame_size, -frame_size, +frame_size, +frame_size);
5034                 HIThemeFrameDrawInfo fdi;
5035                 fdi.version = qt_mac_hitheme_version;
5036                 fdi.state = kThemeStateInactive;
5037                 fdi.kind = kHIThemeFrameTextFieldSquare;
5038                 fdi.isFocused = false;
5039                 HIRect hirect = qt_hirectForQRect(lineeditRect);
5040                 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
5041             }
5042             if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5043                 HIThemeButtonDrawInfo bdi;
5044                 bdi.version = qt_mac_hitheme_version;
5045                 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
5046                 switch (aquaSize) {
5047                     case QAquaSizeUnknown:
5048                     case QAquaSizeLarge:
5049                         bdi.kind = kThemeIncDecButton;
5050                         break;
5051                     case QAquaSizeMini:
5052                     case QAquaSizeSmall:
5053                         if (aquaSize == QAquaSizeMini)
5054                             bdi.kind = kThemeIncDecButtonMini;
5055                         else
5056                             bdi.kind = kThemeIncDecButtonSmall;
5057                         break;
5058                 }
5059                 if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled
5060                                         | QAbstractSpinBox::StepDownEnabled)))
5061                     tds = kThemeStateUnavailable;
5062                 if (sb->activeSubControls == SC_SpinBoxDown
5063                     && (sb->state & State_Sunken))
5064                     tds = kThemeStatePressedDown;
5065                 else if (sb->activeSubControls == SC_SpinBoxUp
5066                          && (sb->state & State_Sunken))
5067                     tds = kThemeStatePressedUp;
5068                 bdi.state = tds;
5069                 if (!(sb->state & State_Active)
5070                         && sb->palette.currentColorGroup() == QPalette::Active
5071                         && tds == kThemeStateInactive)
5072                     bdi.state = kThemeStateActive;
5073                 bdi.value = kThemeButtonOff;
5074                 bdi.adornment = kThemeAdornmentNone;
5076                 QRect updown = subControlRect(CC_SpinBox, sb, SC_SpinBoxUp,
5077                                                  widget);
5078                 updown |= subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5079                 HIRect newRect = qt_hirectForQRect(updown);
5080                 QRect off_rct;
5081                 HIRect outRect;
5082                 HIThemeGetButtonBackgroundBounds(&newRect, &bdi, &outRect);
5083                 off_rct.setRect(int(newRect.origin.x - outRect.origin.x),
5084                                 int(newRect.origin.y - outRect.origin.y),
5085                                 int(outRect.size.width - newRect.size.width),
5086                                 int(outRect.size.height - newRect.size.height));
5088                 // HIThemeGetButtonBackgroundBounds offsets non-focused normal sized
5089                 // buttons by one in de y direction, account for that here.
5090                 if (bdi.adornment == kThemeAdornmentNone && bdi.kind == kThemeIncDecButton)
5091                     off_rct.adjust(0, 1, 0, 0);
5093                 // Adjust the rect for small buttos also.
5094                 if (bdi.adornment == kThemeAdornmentFocus && bdi.kind == kThemeIncDecButtonSmall)
5095                     off_rct.adjust(0, 0, 0, -1);
5097                 newRect = qt_hirectForQRect(updown, off_rct);
5098                 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5099             }
5100         }
5101         break;
5102     case CC_ComboBox:
5103         if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
5104             HIThemeButtonDrawInfo bdi;
5105             d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5106             bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
5107             if (!drawColorless)
5108                 QMacStylePrivate::drawCombobox(qt_hirectForQRect(combo->rect), bdi, p);
5109             else
5110                 d->drawColorlessButton(qt_hirectForQRect(combo->rect), &bdi, p, opt);
5111         }
5112         break;
5113     case CC_TitleBar:
5114         if (const QStyleOptionTitleBar *titlebar
5115                 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5116             if (titlebar->state & State_Active) {
5117                 if (titlebar->titleBarState & State_Active)
5118                     tds = kThemeStateActive;
5119                 else
5120                     tds = kThemeStateInactive;
5121             } else {
5122                 tds = kThemeStateInactive;
5123             }
5125             HIThemeWindowDrawInfo wdi;
5126             wdi.version = qt_mac_hitheme_version;
5127             wdi.state = tds;
5128             wdi.windowType = QtWinType;
5129             wdi.titleHeight = titlebar->rect.height();
5130             wdi.titleWidth = titlebar->rect.width();
5131             wdi.attributes = kThemeWindowHasTitleText;
5132             // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty
5133             // close button, so use HIThemeDrawWindowFrame instead.
5134             if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton)
5135                 wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty;
5137             HIRect titleBarRect;
5138             HIRect tmpRect = qt_hirectForQRect(titlebar->rect);
5139             {
5140                 QCFType<HIShapeRef> titleRegion;
5141                 QRect newr = titlebar->rect.adjusted(0, 0, 2, 0);
5142                 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
5143                 ptrHIShapeGetBounds(titleRegion, &tmpRect);
5144                 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
5145                 titleBarRect = qt_hirectForQRect(newr);
5146             }
5147             HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
5148             if (titlebar->subControls & (SC_TitleBarCloseButton
5149                                          | SC_TitleBarMaxButton
5150                                          | SC_TitleBarMinButton
5151                                          | SC_TitleBarNormalButton)) {
5152                 HIThemeWindowWidgetDrawInfo wwdi;
5153                 wwdi.version = qt_mac_hitheme_version;
5154                 wwdi.widgetState = tds;
5155                 if (titlebar->state & State_MouseOver)
5156                     wwdi.widgetState = kThemeStateRollover;
5157                 wwdi.windowType = QtWinType;
5158                 wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox;
5159                 wwdi.windowState = wdi.state;
5160                 wwdi.titleHeight = wdi.titleHeight;
5161                 wwdi.titleWidth = wdi.titleWidth;
5162                 ThemeDrawState savedControlState = wwdi.widgetState;
5163                 uint sc = SC_TitleBarMinButton;
5164                 ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox;
5165                 bool active = titlebar->state & State_Active;
5166                 int border = 2;
5167                 titleBarRect.origin.x += border;
5168                 titleBarRect.origin.y -= border;
5170                 while (sc <= SC_TitleBarCloseButton) {
5171                     if (sc & titlebar->subControls) {
5172                         uint tmp = sc;
5173                         wwdi.widgetState = savedControlState;
5174                         wwdi.widgetType = tbw;
5175                         if (sc == SC_TitleBarMinButton)
5176                             tmp |= SC_TitleBarNormalButton;
5177                         if (active && (titlebar->activeSubControls & tmp)
5178                                 && (titlebar->state & State_Sunken))
5179                             wwdi.widgetState = kThemeStatePressed;
5180                         // Draw all sub controllers except the dirty close button
5181                         // (it is already handled by HIThemeDrawWindowFrame).
5182                         if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) {
5183                             HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal);
5184                             p->paintEngine()->syncState();
5185                         }
5186                     }
5187                     sc = sc << 1;
5188                     tbw = tbw >> 1;
5189                 }
5190             }
5191             p->paintEngine()->syncState();
5192             if (titlebar->subControls & SC_TitleBarLabel) {
5193                 int iw = 0;
5194                 if (!titlebar->icon.isNull()) {
5195                     QCFType<HIShapeRef> titleRegion2;
5196                     HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn,
5197                                           &titleRegion2);
5198                     ptrHIShapeGetBounds(titleRegion2, &tmpRect);
5199                     if (tmpRect.size.width != 1) {
5200                         int iconExtent = pixelMetric(PM_SmallIconSize);
5201                         iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width();
5202                     }
5203                 }
5204                 if (!titlebar->text.isEmpty()) {
5205                     p->save();
5206                     QCFType<HIShapeRef> titleRegion3;
5207                     HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3);
5208                     ptrHIShapeGetBounds(titleRegion3, &tmpRect);
5209                     p->setClipRect(qt_qrectForHIRect(tmpRect));
5210                     QRect br = p->clipRegion().boundingRect();
5211                     int x = br.x(),
5212                     y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2);
5213                     if (br.width() <= (p->fontMetrics().width(titlebar->text) + iw * 2))
5214                         x += iw;
5215                     else
5216                         x += br.width() / 2 - p->fontMetrics().width(titlebar->text) / 2;
5217                     if (iw)
5218                         p->drawPixmap(x - iw, y, titlebar->icon.pixmap(pixelMetric(PM_SmallIconSize), QIcon::Normal));
5219                     drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive,
5220                                     titlebar->text, QPalette::Text);
5221                     p->restore();
5222                 }
5223             }
5224         }
5225         break;
5226     case CC_GroupBox:
5227         if (const QStyleOptionGroupBox *groupBox
5228                 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5230             QStyleOptionGroupBox groupBoxCopy(*groupBox);
5231             if ((widget && !widget->testAttribute(Qt::WA_SetFont))
5232                     && QApplication::desktopSettingsAware())
5233                 groupBoxCopy.subControls = groupBoxCopy.subControls & ~SC_GroupBoxLabel;
5234             QWindowsStyle::drawComplexControl(cc, &groupBoxCopy, p, widget);
5235             if (groupBoxCopy.subControls != groupBox->subControls) {
5236                 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5237                 p->save();
5238                 CGContextSetShouldAntialias(cg, true);
5239                 CGContextSetShouldSmoothFonts(cg, true);
5240                 HIThemeTextInfo tti;
5241                 tti.version = qt_mac_hitheme_version;
5242                 tti.state = tds;
5243                 QColor textColor = groupBox->palette.windowText().color();
5244                 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
5245                                       textColor.blueF(), textColor.alphaF() };
5246                 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
5247                 CGContextSetFillColor(cg, colorComp);
5248                 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5249                 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5250                 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5251                 tti.options = kHIThemeTextBoxOptionNone;
5252                 tti.truncationPosition = kHIThemeTextTruncationNone;
5253                 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5254                 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5255                 QRect r = subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget);
5256                 HIRect bounds = qt_hirectForQRect(r);
5257                 HIThemeDrawTextBox(groupText, &bounds, &tti, cg, kHIThemeOrientationNormal);
5258                 p->restore();
5259             }
5260         }
5261         break;
5262     case CC_ToolButton:
5263         if (const QStyleOptionToolButton *tb
5264                 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5265             if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5266                 if (tb->subControls & SC_ToolButtonMenu) {
5267                     QStyleOption arrowOpt(0);
5268                     arrowOpt.rect = subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5269                     arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5270                     arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5271                     arrowOpt.state = tb->state;
5272                     arrowOpt.palette = tb->palette;
5273                     drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5274                 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5275                     drawToolbarButtonArrow(tb->rect, tds, cg);
5276                 }
5277                 if (tb->state & State_On) {
5278                     QPen oldPen = p->pen();
5279                     p->setPen(QColor(0, 0, 0, 0x3a));
5280                     p->fillRect(tb->rect.adjusted(1, 1, -1, -1), QColor(0, 0, 0, 0x12));
5281                     p->drawLine(tb->rect.left() + 1, tb->rect.top(),
5282                                 tb->rect.right() - 1, tb->rect.top());
5283                     p->drawLine(tb->rect.left() + 1, tb->rect.bottom(),
5284                                 tb->rect.right() - 1, tb->rect.bottom());
5285                     p->drawLine(tb->rect.topLeft(), tb->rect.bottomLeft());
5286                     p->drawLine(tb->rect.topRight(), tb->rect.bottomRight());
5287                     p->setPen(oldPen);
5288                 }
5289                 drawControl(CE_ToolButtonLabel, opt, p, widget);
5290             } else {
5291                 ThemeButtonKind bkind = kThemeBevelButton;
5292                 switch (d->aquaSizeConstrain(opt, widget)) {
5293                 case QAquaSizeUnknown:
5294                 case QAquaSizeLarge:
5295                     bkind = kThemeBevelButton;
5296                     break;
5297                 case QAquaSizeMini:
5298 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) && 0
5299                     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) {
5300                         bkind = kThemeMiniBevelButton;
5301                         break;
5302                     }
5303 #endif
5304                 case QAquaSizeSmall:
5305                     bkind = kThemeSmallBevelButton;
5306                     break;
5307                 }
5309                 QRect button, menuarea;
5310                 button   = subControlRect(cc, tb, SC_ToolButton, widget);
5311                 menuarea = subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5312                 State bflags = tb->state,
5313                 mflags = tb->state;
5314                 if (tb->subControls & SC_ToolButton)
5315                     bflags |= State_Sunken;
5316                 if (tb->subControls & SC_ToolButtonMenu)
5317                     mflags |= State_Sunken;
5319                 if (tb->subControls & SC_ToolButton) {
5320                     if (bflags & (State_Sunken | State_On | State_Raised)) {
5321                         HIThemeButtonDrawInfo bdi;
5322                         bdi.version = qt_mac_hitheme_version;
5323                         bdi.state = tds;
5324                         bdi.adornment = kThemeAdornmentNone;
5325                         bdi.kind = bkind;
5326                         bdi.value = kThemeButtonOff;
5327                         if (tb->state & State_HasFocus)
5328                             bdi.adornment = kThemeAdornmentFocus;
5329                         if (tb->state & State_Sunken)
5330                             bdi.state = kThemeStatePressed;
5331                         if (tb->state & State_On)
5332                             bdi.value = kThemeButtonOn;
5334                         QRect off_rct(0, 0, 0, 0);
5335                         HIRect myRect, macRect;
5336                         myRect = CGRectMake(tb->rect.x(), tb->rect.y(),
5337                                             tb->rect.width(), tb->rect.height());
5338                         HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
5339                         off_rct.setRect(int(myRect.origin.x - macRect.origin.x),
5340                                         int(myRect.origin.y - macRect.origin.y),
5341                                         int(macRect.size.width - myRect.size.width),
5342                                         int(macRect.size.height - myRect.size.height));
5344                         myRect = qt_hirectForQRect(button, off_rct);
5345                         HIThemeDrawButton(&myRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5346                     }
5347                 }
5349                 if (tb->subControls & SC_ToolButtonMenu) {
5350                     HIThemeButtonDrawInfo bdi;
5351                     bdi.version = qt_mac_hitheme_version;
5352                     bdi.state = tds;
5353                     bdi.value = kThemeButtonOff;
5354                     bdi.adornment = kThemeAdornmentNone;
5355                     bdi.kind = bkind;
5356                     if (tb->state & State_HasFocus)
5357                         bdi.adornment = kThemeAdornmentFocus;
5358                     if (tb->state & (State_On | State_Sunken)
5359                                      || (tb->activeSubControls & SC_ToolButtonMenu))
5360                         bdi.state = kThemeStatePressed;
5361                     HIRect hirect = qt_hirectForQRect(menuarea);
5362                     HIThemeDrawButton(&hirect, &bdi, cg, kHIThemeOrientationNormal, 0);
5363                     QRect r(menuarea.x() + ((menuarea.width() / 2) - 3), menuarea.height() - 8, 8, 8);
5364                     HIThemePopupArrowDrawInfo padi;
5365                     padi.version = qt_mac_hitheme_version;
5366                     padi.state = tds;
5367                     padi.orientation = kThemeArrowDown;
5368                     padi.size = kThemeArrow7pt;
5369                     hirect = qt_hirectForQRect(r);
5370                     HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
5371                 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5372                     drawToolbarButtonArrow(tb->rect, tds, cg);
5373                 }
5374                 QRect buttonRect = subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
5375                 int fw = pixelMetric(PM_DefaultFrameWidth, opt, widget);
5376                 QStyleOptionToolButton label = *tb;
5377                 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5378                 drawControl(CE_ToolButtonLabel, &label, p, widget);
5379             }
5380         }
5381         break;
5382     case CC_Dial:
5383         if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5384             QStyleHelper::drawDial(dial, p);
5385         break;
5386     default:
5387         QWindowsStyle::drawComplexControl(cc, opt, p, widget);
5388         break;
5389     }
5392 /*! \reimp */
5393 QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
5394                                                     const QStyleOptionComplex *opt,
5395                                                     const QPoint &pt, const QWidget *widget) const
5397     SubControl sc = QStyle::SC_None;
5398     switch (cc) {
5399     case CC_ComboBox:
5400         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5401             sc = QWindowsStyle::hitTestComplexControl(cc, cmb, pt, widget);
5402             if (!cmb->editable && sc != QStyle::SC_None)
5403                 sc = SC_ComboBoxArrow;  // A bit of a lie, but what we want
5404         }
5405         break;
5406     case CC_Slider:
5407         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5408             HIThemeTrackDrawInfo tdi;
5409             d->getSliderInfo(cc, slider, &tdi, widget);
5410             ControlPartCode part;
5411             HIPoint pos = CGPointMake(pt.x(), pt.y());
5412             if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5413                 if (part == kControlPageUpPart || part == kControlPageDownPart)
5414                     sc = SC_SliderGroove;
5415                 else
5416                     sc = SC_SliderHandle;
5417             }
5418         }
5419         break;
5420     case CC_ScrollBar:
5421         if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5422             HIScrollBarTrackInfo sbi;
5423             sbi.version = qt_mac_hitheme_version;
5424             if (!(sb->state & State_Active))
5425                 sbi.enableState = kThemeTrackInactive;
5426             else if (sb->state & State_Enabled)
5427                 sbi.enableState = kThemeTrackActive;
5428             else
5429                 sbi.enableState = kThemeTrackDisabled;
5431             // The arrow buttons are not drawn if the scroll bar is to short,
5432             // exclude them from the hit test.
5433             const int scrollBarLenght = (sb->orientation == Qt::Horizontal)
5434                 ? sb->rect.width() : sb->rect.height();
5435             if (scrollBarLenght < scrollButtonsCutoffSize(scrollButtonsCutoff, widgetSizePolicy(widget)))
5436                 sbi.enableState = kThemeTrackNothingToScroll;
5438             sbi.viewsize = sb->pageStep;
5439             HIPoint pos = CGPointMake(pt.x(), pt.y());
5441             HIRect macSBRect = qt_hirectForQRect(sb->rect);
5442             ControlPartCode part;
5443             bool reverseHorizontal = (sb->direction == Qt::RightToLeft
5444                                       && sb->orientation == Qt::Horizontal
5445                                       && (!sb->upsideDown ||
5446                                           (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5447                                                       && sb->upsideDown)));
5448             if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal,
5449                         &pos, 0, &part)) {
5450                 if (part == kControlUpButtonPart)
5451                     sc = reverseHorizontal ? SC_ScrollBarAddLine : SC_ScrollBarSubLine;
5452                 else if (part == kControlDownButtonPart)
5453                     sc = reverseHorizontal ? SC_ScrollBarSubLine : SC_ScrollBarAddLine;
5454             } else {
5455                 HIThemeTrackDrawInfo tdi;
5456                 d->getSliderInfo(cc, sb, &tdi, widget);
5457                 if(tdi.enableState == kThemeTrackInactive)
5458                     tdi.enableState = kThemeTrackActive;
5459                 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5460                     if (part == kControlPageUpPart)
5461                         sc = reverseHorizontal ? SC_ScrollBarAddPage
5462                                                : SC_ScrollBarSubPage;
5463                     else if (part == kControlPageDownPart)
5464                         sc = reverseHorizontal ? SC_ScrollBarSubPage
5465                                                : SC_ScrollBarAddPage;
5466                     else
5467                         sc = SC_ScrollBarSlider;
5468                 }
5469             }
5470         }
5471         break;
5473     I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all.
5474     It would be very nice if this would work.
5475     case QStyle::CC_TitleBar:
5476         if (const QStyleOptionTitleBar *tbar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5477             HIThemeWindowDrawInfo wdi;
5478             memset(&wdi, 0, sizeof(wdi));
5479             wdi.version = qt_mac_hitheme_version;
5480             wdi.state = kThemeStateActive;
5481             wdi.windowType = QtWinType;
5482             wdi.titleWidth = tbar->rect.width();
5483             wdi.titleHeight = tbar->rect.height();
5484             if (tbar->titleBarState)
5485                 wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
5486                                   | kThemeWindowHasCollapseBox;
5487             else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint)
5488                 wdi.attributes |= kThemeWindowHasCloseBox;
5489             QRect tmpRect = tbar->rect;
5490             tmpRect.setHeight(tmpRect.height() + 100);
5491             HIRect hirect = qt_hirectForQRect(tmpRect);
5492             WindowRegionCode hit;
5493             HIPoint hipt = CGPointMake(pt.x(), pt.y());
5494             if (HIThemeGetWindowRegionHit(&hirect, &wdi, &hipt, &hit)) {
5495                 switch (hit) {
5496                 case kWindowCloseBoxRgn:
5497                     sc = QStyle::SC_TitleBarCloseButton;
5498                     break;
5499                 case kWindowCollapseBoxRgn:
5500                     sc = QStyle::SC_TitleBarMinButton;
5501                     break;
5502                 case kWindowZoomBoxRgn:
5503                     sc = QStyle::SC_TitleBarMaxButton;
5504                     break;
5505                 case kWindowTitleTextRgn:
5506                     sc = QStyle::SC_TitleBarLabel;
5507                     break;
5508                 default:
5509                     qDebug("got something else %d", hit);
5510                     break;
5511                 }
5512             }
5513         }
5514         break;
5516     default:
5517         sc = QWindowsStyle::hitTestComplexControl(cc, opt, pt, widget);
5518         break;
5519     }
5520     return sc;
5523 /*! \reimp */
5524 QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5525                                 const QWidget *widget) const
5527     QRect ret;
5528     switch (cc) {
5529     case CC_Slider:
5530     case CC_ScrollBar:
5531         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5532             HIThemeTrackDrawInfo tdi;
5533             d->getSliderInfo(cc, slider, &tdi, widget);
5534             HIRect macRect;
5535             QCFType<HIShapeRef> shape;
5536             bool scrollBar = cc == CC_ScrollBar;
5537             if ((scrollBar && sc == SC_ScrollBarSlider)
5538                 || (!scrollBar && sc == SC_SliderHandle)) {
5539                 HIThemeGetTrackThumbShape(&tdi, &shape);
5540                 ptrHIShapeGetBounds(shape, &macRect);
5541             } else if (!scrollBar && sc == SC_SliderGroove) {
5542                 HIThemeGetTrackBounds(&tdi, &macRect);
5543             } else if (sc == SC_ScrollBarGroove) { // Only scroll bar parts available...
5544                 HIThemeGetTrackDragRect(&tdi, &macRect);
5545             } else {
5546                 ControlPartCode cpc;
5547                 if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5548                     cpc = sc == SC_ScrollBarSubPage ? kControlPageDownPart
5549                                                             : kControlPageUpPart;
5550                 } else {
5551                     cpc = sc == SC_ScrollBarSubLine ? kControlUpButtonPart
5552                                                             : kControlDownButtonPart;
5553                     if (slider->direction == Qt::RightToLeft
5554                         && slider->orientation == Qt::Horizontal
5555                         && (!slider->upsideDown
5556                             || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5557                                 && slider->upsideDown))
5558                         ) {
5559                         if (cpc == kControlDownButtonPart)
5560                             cpc = kControlUpButtonPart;
5561                         else if (cpc == kControlUpButtonPart)
5562                             cpc = kControlDownButtonPart;
5563                     }
5564                 }
5565                 HIThemeGetTrackPartBounds(&tdi, cpc, &macRect);
5566             }
5567             ret = qt_qrectForHIRect(macRect);
5569             // Tweak: the dark line between the sub/add line buttons belong to only one of the buttons
5570             // when doing hit-testing, but both of them have to repaint it. Extend the rect to cover
5571             // the line in the cases where HIThemeGetTrackPartBounds returns a rect that doesn't.
5572             if (slider->orientation == Qt::Horizontal) {
5573                 if (slider->direction == Qt::LeftToRight && sc == SC_ScrollBarSubLine)
5574                     ret.adjust(0, 0, 1, 0);
5575                 else if (slider->direction == Qt::RightToLeft && sc == SC_ScrollBarAddLine)
5576                     ret.adjust(-1, 0, 1, 0);
5577             } else if (sc == SC_ScrollBarAddLine) {
5578                 ret.adjust(0, -1, 0, 1);
5579             }
5580         }
5581         break;
5582     case CC_TitleBar:
5583         if (const QStyleOptionTitleBar *titlebar
5584                 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5585             HIThemeWindowDrawInfo wdi;
5586             memset(&wdi, 0, sizeof(wdi));
5587             wdi.version = qt_mac_hitheme_version;
5588             wdi.state = kThemeStateActive;
5589             wdi.windowType = QtWinType;
5590             wdi.titleHeight = titlebar->rect.height();
5591             wdi.titleWidth = titlebar->rect.width();
5592             wdi.attributes = kThemeWindowHasTitleText;
5593             if (titlebar->subControls & SC_TitleBarCloseButton)
5594                 wdi.attributes |= kThemeWindowHasCloseBox;
5595             if (titlebar->subControls & SC_TitleBarMaxButton
5596                                         | SC_TitleBarNormalButton)
5597                 wdi.attributes |= kThemeWindowHasFullZoom;
5598             if (titlebar->subControls & SC_TitleBarMinButton)
5599                 wdi.attributes |= kThemeWindowHasCollapseBox;
5600             WindowRegionCode wrc = kWindowGlobalPortRgn;
5602             if (sc == SC_TitleBarCloseButton)
5603                 wrc = kWindowCloseBoxRgn;
5604             else if (sc == SC_TitleBarMinButton)
5605                 wrc = kWindowCollapseBoxRgn;
5606             else if (sc == SC_TitleBarMaxButton)
5607                 wrc = kWindowZoomBoxRgn;
5608             else if (sc == SC_TitleBarLabel)
5609                 wrc = kWindowTitleTextRgn;
5610             else if (sc == SC_TitleBarSysMenu)
5611                 ret.setRect(-1024, -1024, 10, pixelMetric(PM_TitleBarHeight,
5612                                                              titlebar, widget));
5613             if (wrc != kWindowGlobalPortRgn) {
5614                 QCFType<HIShapeRef> region;
5615                 QRect tmpRect = titlebar->rect;
5616                 HIRect titleRect = qt_hirectForQRect(tmpRect);
5617                 HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, &region);
5618                 ptrHIShapeGetBounds(region, &titleRect);
5619                 CFRelease(region);
5620                 tmpRect.translate(tmpRect.x() - int(titleRect.origin.x),
5621                                tmpRect.y() - int(titleRect.origin.y));
5622                 titleRect = qt_hirectForQRect(tmpRect);
5623                 HIThemeGetWindowShape(&titleRect, &wdi, wrc, &region);
5624                 ptrHIShapeGetBounds(region, &titleRect);
5625                 ret = qt_qrectForHIRect(titleRect);
5626             }
5627         }
5628         break;
5629     case CC_ComboBox:
5630         if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5631             HIThemeButtonDrawInfo bdi;
5632             d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5634             switch (sc) {
5635             case SC_ComboBoxEditField:{
5636                 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5637                     // hack to posistion the edit feld correctly for QDateTimeEdits
5638                     // in calendarPopup mode.
5639                     if (qobject_cast<const QDateTimeEdit *>(widget)) {
5640                        ret.moveTop(ret.top() - 2);
5641                        ret.setHeight(ret.height() +1);
5642                     }
5643                 break; }
5644             case SC_ComboBoxArrow:{
5645                 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5646                 ret.setX(ret.x() + ret.width());
5647                 ret.setWidth(combo->rect.width() - ret.width() - ret.x());
5648                 break; }
5649             case SC_ComboBoxListBoxPopup:{
5650                 if (combo->editable) {
5651                     HIRect inner = QMacStylePrivate::comboboxInnerBounds(qt_hirectForQRect(combo->rect), bdi.kind);
5652                     QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5653                     ret.adjust(qRound(inner.origin.x), 0, qRound(inner.origin.x + inner.size.width), editRect.y() + editRect.height() + 2);
5654                 } else {
5655                     QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5656                     ret.adjust(4 - 11, 1, editRect.width() + 10 + 11, 1);
5657                  }
5658                 break; }
5659             default:
5660                 break;
5661             }
5662         }
5663         break;
5664     case CC_GroupBox:
5665         if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5666             bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5667             bool flat = (groupBox->features & QStyleOptionFrameV2::Flat);
5668             bool hasNoText = !checkable && groupBox->text.isEmpty();
5669             switch (sc) {
5670             case SC_GroupBoxLabel:
5671             case SC_GroupBoxCheckBox: {
5672                 // Cheat and use the smaller font if we need to
5673                 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5674                 bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont)
5675                                   || !QApplication::desktopSettingsAware());
5676                 int tw;
5677                 int h;
5678                 int margin =  flat || hasNoText ? 0 : 12;
5679                 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5681                 if (!fontIsSet) {
5682                     HIThemeTextInfo tti;
5683                     tti.version = qt_mac_hitheme_version;
5684                     tti.state = kThemeStateActive;
5685                     tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5686                     tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5687                     tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5688                     tti.options = kHIThemeTextBoxOptionNone;
5689                     tti.truncationPosition = kHIThemeTextTruncationNone;
5690                     tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5691                     CGFloat width;
5692                     CGFloat height;
5693                     QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5694                     HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0);
5695                     tw = int(width);
5696                     h = int(height);
5697                 } else {
5698                     QFontMetrics fm = groupBox->fontMetrics;
5699                     if (!checkable && !fontIsSet)
5700                         fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5701                     h = fm.height();
5702                     tw = fm.size(Qt::TextShowMnemonic, groupBox->text).width();
5703                 }
5704                 ret.setHeight(h);
5706                 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5707                                               QSize(tw, h), ret);
5708                 int indicatorWidth = pixelMetric(PM_IndicatorWidth, opt, widget);
5709                 bool rtl = groupBox->direction == Qt::RightToLeft;
5710                 if (sc == SC_GroupBoxLabel) {
5711                     if (checkable) {
5712                         int newSum = indicatorWidth + 1;
5713                         int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5714                         labelRect.moveLeft(newLeft);
5715                     } else if (flat) {
5716                         int newLeft = labelRect.left() - (rtl ? 3 : -3);
5717                         labelRect.moveLeft(newLeft);
5718                         labelRect.moveTop(labelRect.top() + 3);
5719                     } else {
5720                         int newLeft = labelRect.left() - (rtl ? 3 : 2);
5721                         labelRect.moveLeft(newLeft);
5722                         labelRect.moveTop(labelRect.top() + 5);
5723                     }
5724                     ret = labelRect;
5725                 }
5727                 if (sc == SC_GroupBoxCheckBox) {
5728                     int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left();
5729                     ret.setRect(left, ret.top(),
5730                                 indicatorWidth, pixelMetric(PM_IndicatorHeight, opt, widget));
5731                 }
5732                 break;
5733             }
5734             case SC_GroupBoxContents:
5735             case SC_GroupBoxFrame: {
5736                 if (flat) {
5737                     ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5738                     break;
5739                 }
5740                 QFontMetrics fm = groupBox->fontMetrics;
5741                 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5742                 int yOffset = 3;
5743                 if (!checkable) {
5744                     if (widget && !widget->testAttribute(Qt::WA_SetFont)
5745                             && QApplication::desktopSettingsAware())
5746                         fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5747                     yOffset = 5;
5748                     if (hasNoText)
5749                         yOffset = -fm.height();
5750                 }
5752                 ret = opt->rect.adjusted(0, fm.height() + yOffset, 0, 0);
5753                 if (sc == SC_GroupBoxContents)
5754                     ret.adjust(3, 3, -3, -4);    // guess
5755             }
5756                 break;
5757             default:
5758                 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5759                 break;
5760             }
5761         }
5762         break;
5763     case CC_SpinBox:
5764         if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5765             const int spinner_w = 14,
5766                       fw = pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5767             switch (sc) {
5768             case SC_SpinBoxUp:
5769             case SC_SpinBoxDown: {
5770                 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
5771                     break;
5772                 const int frameWidth = pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5773                 const int spinner_w = 18;
5774                 const int y = frameWidth;
5775                 const int x = spin->rect.width() - spinner_w + frameWidth;
5776                 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
5777                 HIThemeButtonDrawInfo bdi;
5778                 bdi.version = qt_mac_hitheme_version;
5779                 bdi.kind = kThemeIncDecButton;
5780                 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
5781                 switch (aquaSize) {
5782                     case QAquaSizeUnknown:
5783                     case QAquaSizeLarge:
5784                         bdi.kind = kThemeIncDecButton;
5785                         break;
5786                     case QAquaSizeMini:
5787                     case QAquaSizeSmall:
5788                         if (aquaSize == QAquaSizeMini)
5789                             bdi.kind = kThemeIncDecButtonMini;
5790                         else
5791                             bdi.kind = kThemeIncDecButtonSmall;
5792                         break;
5793                 }
5794                 bdi.state = kThemeStateActive;
5795                 bdi.value = kThemeButtonOff;
5796                 bdi.adornment = kThemeAdornmentNone;
5797                 HIRect hirect = qt_hirectForQRect(ret);
5798                 HIRect outRect;
5799                 HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect);
5800                 ret = qt_qrectForHIRect(outRect);
5801                 switch (sc) {
5802                 case SC_SpinBoxUp:
5803                     ret.setHeight(ret.height() / 2);
5804                     break;
5805                 case SC_SpinBoxDown:
5806                     ret.setY(ret.y() + ret.height() / 2);
5807                     break;
5808                 default:
5809                     Q_ASSERT(0);
5810                     break;
5811                 }
5812                 ret.translate(-1, -2); // hack: position the buttons correctly (weird that we need this)
5813                 ret = visualRect(spin->direction, spin->rect, ret);
5814                 break;
5815             }
5816             case SC_SpinBoxEditField:
5817                 ret.setRect(fw, fw,
5818                             spin->rect.width() - spinner_w - fw * 2 - macSpinBoxSep + 1,
5819                             spin->rect.height() - fw * 2);
5820                 ret = visualRect(spin->direction, spin->rect, ret);
5821                 break;
5822             default:
5823                 ret = QWindowsStyle::subControlRect(cc, spin, sc, widget);
5824                 break;
5825             }
5826         }
5827         break;
5828     case CC_ToolButton:
5829         ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5830         if (sc == SC_ToolButtonMenu && widget && !qobject_cast<QToolBar*>(widget->parentWidget())) {
5831             ret.adjust(-1, 0, 0, 0);
5832         }
5833         break;
5834     default:
5835         ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5836         break;
5837     }
5838     return ret;
5841 /*! \reimp */
5842 QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5843                                   const QSize &csz, const QWidget *widget) const
5845     QSize sz(csz);
5846     bool useAquaGuideline = true;
5848     switch (ct) {
5849     case QStyle::CT_SpinBox:
5850         sz.setWidth(sz.width() + macSpinBoxSep);
5851         sz.setHeight(sz.height() - 3); // hack to work around horrible sizeHint() code in QAbstractSpinBox
5852         break;
5853     case QStyle::CT_TabBarTab:
5854         if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
5855             bool newStyleTabs =
5856 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
5857                 QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? true :
5858 #endif
5859                 false;
5860             const QAquaWidgetSize AquaSize = d->aquaSizeConstrain(opt, widget);
5861             const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
5862                                        || !QApplication::desktopSettingsAware();
5863             ThemeTabDirection ttd = getTabDirection(tab->shape);
5864             bool vertTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
5865             if (vertTabs)
5866                 sz.transpose();
5867             if (newStyleTabs) {
5868                 int defaultTabHeight;
5869                 int defaultExtraSpace = pixelMetric(PM_TabBarTabHSpace, tab, widget); // Remove spurious gcc warning (AFAIK)
5870                 QFontMetrics fm = opt->fontMetrics;
5871                 switch (AquaSize) {
5872                 case QAquaSizeUnknown:
5873                 case QAquaSizeLarge:
5874                     if (tab->documentMode)
5875                         defaultTabHeight = 23;
5876                     else
5877                         defaultTabHeight = 21;
5878                     break;
5879                 case QAquaSizeSmall:
5880                     defaultTabHeight = 18;
5881                     break;
5882                 case QAquaSizeMini:
5883                     defaultTabHeight = 16;
5884                     break;
5885                 }
5887                 bool setWidth = false;
5888                 if (differentFont || !tab->icon.isNull()) {
5889                     sz.rheight() = qMax(defaultTabHeight, sz.height());
5890                 } else {
5891                     QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text);
5892                     sz.rheight() = qMax(defaultTabHeight, textSize.height());
5893                     sz.rwidth() = textSize.width() + defaultExtraSpace;
5894                     setWidth = true;
5895                 }
5897                 if (vertTabs)
5898                     sz.transpose();
5900                 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5901                 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5903                 int widgetWidth = 0;
5904                 int widgetHeight = 0;
5905                 int padding = 0;
5906                 if (tab->leftButtonSize.isValid()) {
5907                     padding += 8;
5908                     widgetWidth += tab->leftButtonSize.width();
5909                     widgetHeight += tab->leftButtonSize.height();
5910                 }
5911                 if (tab->rightButtonSize.isValid()) {
5912                     padding += 8;
5913                     widgetWidth += tab->rightButtonSize.width();
5914                     widgetHeight += tab->rightButtonSize.height();
5915                 }
5917                 if (vertTabs) {
5918                     sz.setHeight(sz.height() + widgetHeight + padding);
5919                     sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5920                 } else {
5921                     if (setWidth)
5922                         sz.setWidth(sz.width() + widgetWidth + padding);
5923                     sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5924                 }
5925             } else {
5926                 SInt32 tabh = sz.height();
5927                 SInt32 overlap = 0;
5928                 switch (AquaSize) {
5929                 default:
5930                 case QAquaSizeUnknown:
5931                 case QAquaSizeLarge:
5932                     GetThemeMetric(kThemeLargeTabHeight, &tabh);
5933                     GetThemeMetric(kThemeMetricTabFrameOverlap, &overlap);
5934                     break;
5935                 case QAquaSizeMini:
5936                     GetThemeMetric(kThemeMetricMiniTabHeight, &tabh);
5937                     GetThemeMetric(kThemeMetricMiniTabFrameOverlap, &overlap);
5938                     break;
5939                 case QAquaSizeSmall:
5940                     GetThemeMetric(kThemeSmallTabHeight, &tabh);
5941                     GetThemeMetric(kThemeMetricSmallTabFrameOverlap, &overlap);
5942                     break;
5943                 }
5944                 tabh += overlap;
5945                 if (sz.height() < tabh)
5946                     sz.rheight() = tabh;
5947             }
5948         }
5949         break;
5950     case QStyle::CT_PushButton:
5951         // By default, we fit the contents inside a normal rounded push button.
5952         // Do this by add enough space around the contents so that rounded
5953         // borders (including highlighting when active) will show.
5954         sz.rwidth() += PushButtonLeftOffset + PushButtonRightOffset + 12;
5955         sz.rheight() += PushButtonTopOffset + PushButtonBottomOffset;
5956         break;
5957     case QStyle::CT_MenuItem:
5958         if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5959             int maxpmw = mi->maxIconWidth;
5960             const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
5961             int w = sz.width(),
5962                 h = sz.height();
5963             if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5964                 w = 10;
5965                 SInt16 ash;
5966                 GetThemeMenuSeparatorHeight(&ash);
5967                 h = ash;
5968             } else {
5969                 h = mi->fontMetrics.height() + 2;
5970                 if (!mi->icon.isNull()) {
5971                     if (comboBox) {
5972                         const QSize &iconSize = comboBox->iconSize();
5973                         h = qMax(h, iconSize.height() + 4);
5974                         maxpmw = qMax(maxpmw, iconSize.width());
5975                     } else {
5976                         int iconExtent = pixelMetric(PM_SmallIconSize);
5977                         h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5978                     }
5979                 }
5980             }
5981             if (mi->text.contains(QLatin1Char('\t')))
5982                 w += 12;
5983             if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5984                 w += 20;
5985             if (maxpmw)
5986                 w += maxpmw + 6;
5987             // add space for a check. All items have place for a check too.
5988             w += 20;
5989             if (comboBox && comboBox->isVisible()) {
5990                 QStyleOptionComboBox cmb;
5991                 cmb.initFrom(comboBox);
5992                 cmb.editable = false;
5993                 cmb.subControls = QStyle::SC_ComboBoxEditField;
5994                 cmb.activeSubControls = QStyle::SC_None;
5995                 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
5996                                                    QStyle::SC_ComboBoxEditField,
5997                                                    comboBox).width());
5998             } else {
5999                 w += 12;
6000             }
6001             sz = QSize(w, h);
6002         }
6003         break;
6004     case CT_ToolButton:
6005         sz.rwidth() += 10;
6006         sz.rheight() += 10;
6007         return sz;
6008     case CT_ComboBox:
6009         sz.rwidth() += 50;
6010         break;
6011     case CT_Menu: {
6012         QStyleHintReturnMask menuMask;
6013         QStyleOption myOption = *opt;
6014         myOption.rect.setSize(sz);
6015         if (styleHint(SH_Menu_Mask, &myOption, widget, &menuMask)) {
6016             sz = menuMask.region.boundingRect().size();
6017         }
6018         break; }
6019     case CT_HeaderSection:{
6020         const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
6021         sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6022         if (header->text.contains(QLatin1Char('\n')))
6023             useAquaGuideline = false;
6024         break; }
6025     case CT_ScrollBar :
6026         // Make sure that the scroll bar is large enough to display the thumb indicator.
6027         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6028             const int minimumSize = scrollButtonsCutoffSize(thumbIndicatorCutoff, widgetSizePolicy(widget));
6029             if (slider->orientation == Qt::Horizontal)
6030                 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6031             else
6032                 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6033         }
6034         break;
6035     default:
6036         sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6037     }
6039     if (useAquaGuideline){
6040         QSize macsz;
6041         if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QAquaSizeUnknown) {
6042             if (macsz.width() != -1)
6043                 sz.setWidth(macsz.width());
6044             if (macsz.height() != -1)
6045                 sz.setHeight(macsz.height());
6046         }
6047     }
6049     // The sizes that Carbon and the guidelines gives us excludes the focus frame.
6050     // We compensate for this by adding some extra space here to make room for the frame when drawing:
6051     if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
6052         QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6053         int bkind = 0;
6054         switch (widgetSize) {
6055         default:
6056         case QAquaSizeLarge:
6057             bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
6058             break;
6059         case QAquaSizeSmall:
6060             bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
6061             break;
6062         case QAquaSizeMini:
6063             bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
6064             break;
6065         }
6066         HIRect tmpRect = {{0, 0}, {0, 0}};
6067         HIRect diffRect = QMacStylePrivate::comboboxInnerBounds(tmpRect, bkind);
6068         sz.rwidth() -= qRound(diffRect.size.width);
6069         sz.rheight() -= qRound(diffRect.size.height);
6070     } else if (ct == CT_PushButton || ct == CT_ToolButton){
6071         ThemeButtonKind bkind;
6072         QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6073         switch (ct) {
6074         default:
6075         case CT_PushButton:
6076             if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6077                 if (btn->features & QStyleOptionButton::CommandLinkButton) {
6078                     return QWindowsStyle::sizeFromContents(ct, opt, sz, widget);
6079                 }
6080             }
6082             switch (widgetSize) {
6083             default:
6084             case QAquaSizeLarge:
6085                 bkind = kThemePushButton;
6086                 break;
6087             case QAquaSizeSmall:
6088                 bkind = kThemePushButtonSmall;
6089                 break;
6090             case QAquaSizeMini:
6091                 bkind = kThemePushButtonMini;
6092                 break;
6093             }
6094             break;
6095         case CT_ToolButton:
6096             switch (widgetSize) {
6097             default:
6098             case QAquaSizeLarge:
6099                 bkind = kThemeLargeBevelButton;
6100                 break;
6101             case QAquaSizeMini:
6102             case QAquaSizeSmall:
6103                 bkind = kThemeSmallBevelButton;
6104             }
6105             break;
6106         }
6108         HIThemeButtonDrawInfo bdi;
6109         bdi.version = qt_mac_hitheme_version;
6110         bdi.state = kThemeStateActive;
6111         bdi.kind = bkind;
6112         bdi.value = kThemeButtonOff;
6113         bdi.adornment = kThemeAdornmentNone;
6114         HIRect macRect, myRect;
6115         myRect = CGRectMake(0, 0, sz.width(), sz.height());
6116         HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
6117         // Mini buttons only return their actual size in HIThemeGetButtonBackgroundBounds, so help them out a bit (guess),
6118         if (bkind == kThemePushButtonMini)
6119             macRect.size.height += 8.;
6120         else if (bkind == kThemePushButtonSmall)
6121             macRect.size.height -= 10;
6122         sz.setWidth(sz.width() + int(macRect.size.width - myRect.size.width));
6123         sz.setHeight(sz.height() + int(macRect.size.height - myRect.size.height));
6124     }
6125     return sz;
6129     \reimp
6131 void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
6132                              bool enabled, const QString &text, QPalette::ColorRole textRole) const
6134     if(flags & Qt::TextShowMnemonic)
6135         flags |= Qt::TextHideMnemonic;
6136     QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6140   \reimp
6142 bool QMacStyle::event(QEvent *e)
6144     if(e->type() == QEvent::FocusIn) {
6145         QWidget *f = 0;
6146         QWidget *focusWidget = QApplication::focusWidget();
6147 #ifndef QT_NO_GRAPHICSVIEW
6148         if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
6149             QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
6150             if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
6151                 QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(focusItem);
6152                 if (proxy->widget())
6153                     focusWidget = proxy->widget()->focusWidget();
6154             }
6155         }
6156 #endif
6157         if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) {
6158             f = focusWidget;
6159             QWidget *top = f->parentWidget();
6160             while (top && !top->isWindow() && !(top->windowType() == Qt::SubWindow))
6161                 top = top->parentWidget();
6162 #ifndef QT_NO_MAINWINDOW
6163             if (qobject_cast<QMainWindow *>(top)) {
6164                 QWidget *central = static_cast<QMainWindow *>(top)->centralWidget();
6165                 for (const QWidget *par = f; par; par = par->parentWidget()) {
6166                     if (par == central) {
6167                         top = central;
6168                         break;
6169                     }
6170                     if (par->isWindow())
6171                         break;
6172                 }
6173             }
6174 #endif
6175         }
6176         if (f) {
6177             if(!d->focusWidget)
6178                 d->focusWidget = new QFocusFrame(f);
6179             d->focusWidget->setWidget(f);
6180         } else if(d->focusWidget) {
6181             d->focusWidget->setWidget(0);
6182         }
6183     } else if(e->type() == QEvent::FocusOut) {
6184         if(d->focusWidget)
6185             d->focusWidget->setWidget(0);
6186     }
6187     return false;
6190 void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase)
6192     int size = 16;
6193     while (size <= 128) {
6195         const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size);
6196         QPixmap mainIcon;
6197         if (standardIcon >= QStyle::SP_CustomBase) {
6198             mainIcon = qt_mac_convert_iconref(icon, size, size);
6199         } else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
6200             mainIcon = qt_mac_convert_iconref(icon, size, size);
6201             QPixmapCache::insert(cacheKey, mainIcon);
6202         }
6204         if (overlayIcon) {
6205             int littleSize = size / 2;
6206             QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize);
6207             QPainter painter(&mainIcon);
6208             painter.drawPixmap(size - littleSize, size - littleSize, overlayPix);
6209         }
6211         retIcon->addPixmap(mainIcon);
6212         size += size;  // 16 -> 32 -> 64 -> 128
6213     }
6217     \internal
6219 QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt,
6220                                             const QWidget *widget) const
6222     OSType iconType = 0;
6223     switch (standardIcon) {
6224     case QStyle::SP_MessageBoxQuestion:
6225     case QStyle::SP_MessageBoxInformation:
6226     case QStyle::SP_MessageBoxWarning:
6227     case QStyle::SP_MessageBoxCritical:
6228         iconType = kGenericApplicationIcon;
6229         break;
6230     case SP_DesktopIcon:
6231         iconType = kDesktopIcon;
6232         break;
6233     case SP_TrashIcon:
6234         iconType = kTrashIcon;
6235         break;
6236 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
6237     case SP_ComputerIcon:
6238         iconType = kComputerIcon;
6239         break;
6240 #endif
6241     case SP_DriveFDIcon:
6242         iconType = kGenericFloppyIcon;
6243         break;
6244     case SP_DriveHDIcon:
6245         iconType = kGenericHardDiskIcon;
6246         break;
6247     case SP_DriveCDIcon:
6248     case SP_DriveDVDIcon:
6249         iconType = kGenericCDROMIcon;
6250         break;
6251     case SP_DriveNetIcon:
6252         iconType = kGenericNetworkIcon;
6253         break;
6254     case SP_DirOpenIcon:
6255         iconType = kOpenFolderIcon;
6256         break;
6257     case SP_DirClosedIcon:
6258     case SP_DirLinkIcon:
6259         iconType = kGenericFolderIcon;
6260         break;
6261     case SP_FileLinkIcon:
6262     case SP_FileIcon:
6263         iconType = kGenericDocumentIcon;
6264         break;
6265     case SP_ToolBarHorizontalExtensionButton:
6266     case SP_ToolBarVerticalExtensionButton: {
6267         QPixmap pixmap(qt_mac_toolbar_ext);
6268         if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6269             QPixmap pix2(pixmap.height(), pixmap.width());
6270             pix2.fill(Qt::transparent);
6271             QPainter p(&pix2);
6272             p.translate(pix2.width(), 0);
6273             p.rotate(90);
6274             p.drawPixmap(0, 0, pixmap);
6275             return pix2;
6276         }
6277         return pixmap;
6278         }
6279         break;
6280     case SP_DirIcon: {
6281         // A rather special case
6282         QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, opt, widget);
6283         QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, opt, widget);
6284         closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On);
6285         closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On);
6286         closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On);
6287         closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On);
6288         return closeIcon;
6289     }
6290     case SP_TitleBarNormalButton:
6291     case SP_TitleBarCloseButton: {
6292         QIcon titleBarIcon;
6293         if (standardIcon == SP_TitleBarCloseButton) {
6294             titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png"));
6295             titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
6296         } else {
6297             titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png"));
6298             titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
6299         }
6300         return titleBarIcon;
6301     }
6302     default:
6303         break;
6304     }
6305     if (iconType != 0) {
6306         QIcon retIcon;
6307         IconRef icon;
6308         IconRef overlayIcon = 0;
6309         if (iconType != kGenericApplicationIcon) {
6310             GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
6311         } else {
6312             FSRef fsRef;
6313             ProcessSerialNumber psn = { 0, kCurrentProcess };
6314             GetProcessBundleLocation(&psn, &fsRef);
6315             GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0);
6316             if (standardIcon == SP_MessageBoxCritical) {
6317                 overlayIcon = icon;
6318                 GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon);
6319             }
6320         }
6321         if (icon) {
6322             qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon);
6323             ReleaseIconRef(icon);
6324         }
6325         if (overlayIcon)
6326             ReleaseIconRef(overlayIcon);
6327         return retIcon;
6328     }
6329     return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget);
6333   \internal
6335 int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
6336                                            QSizePolicy::ControlType control2,
6337                                            Qt::Orientation orientation,
6338                                            const QStyleOption *option,
6339                                            const QWidget *widget) const
6341     const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton;
6342     bool isMetal = (widget && widget->testAttribute(Qt::WA_MacBrushedMetal));
6343     int controlSize = getControlSize(option, widget);
6345     if (control2 == QSizePolicy::ButtonBox) {
6346         /*
6347             AHIG seems to prefer a 12-pixel margin between group
6348             boxes and the row of buttons. The 20 pixel comes from
6349             Builder.
6350         */
6351         if (isMetal                                         // (AHIG, guess, guess)
6352                 || (control1 & (QSizePolicy::Frame          // guess
6353                                 | QSizePolicy::GroupBox     // (AHIG, guess, guess)
6354                                 | QSizePolicy::TabWidget    // guess
6355                                 | ButtonMask)))    {        // AHIG
6356             return_SIZE(14, 8, 8);
6357         } else if (control1 == QSizePolicy::LineEdit) {
6358             return_SIZE(8, 8, 8); // Interface Builder
6359         } else {
6360             return_SIZE(20, 7, 7); // Interface Builder
6361         }
6362     }
6364     if ((control1 | control2) & ButtonMask) {
6365         if (control1 == QSizePolicy::LineEdit)
6366             return_SIZE(8, 8, 8); // Interface Builder
6367         else if (control2 == QSizePolicy::LineEdit) {
6368             if (orientation == Qt::Vertical)
6369                 return_SIZE(20, 7, 7); // Interface Builder
6370             else
6371                 return_SIZE(20, 8, 8);
6372         }
6373         return_SIZE(14, 8, 8);     // Interface Builder
6374     }
6376     switch (CT2(control1, control2)) {
6377     case CT1(QSizePolicy::Label):                             // guess
6378     case CT2(QSizePolicy::Label, QSizePolicy::DefaultType):   // guess
6379     case CT2(QSizePolicy::Label, QSizePolicy::CheckBox):      // AHIG
6380     case CT2(QSizePolicy::Label, QSizePolicy::ComboBox):      // AHIG
6381     case CT2(QSizePolicy::Label, QSizePolicy::LineEdit):      // guess
6382     case CT2(QSizePolicy::Label, QSizePolicy::RadioButton):   // AHIG
6383     case CT2(QSizePolicy::Label, QSizePolicy::Slider):        // guess
6384     case CT2(QSizePolicy::Label, QSizePolicy::SpinBox):       // guess
6385     case CT2(QSizePolicy::Label, QSizePolicy::ToolButton):    // guess
6386         return_SIZE(8, 6, 5);
6387     case CT1(QSizePolicy::ToolButton):
6388         return 8;   // AHIG
6389     case CT1(QSizePolicy::CheckBox):
6390     case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton):
6391     case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox):
6392         if (orientation == Qt::Vertical)
6393             return_SIZE(8, 8, 7);        // AHIG and Builder
6394         break;
6395     case CT1(QSizePolicy::RadioButton):
6396         if (orientation == Qt::Vertical)
6397             return 5;                   // (Builder, guess, AHIG)
6398     }
6400     if (orientation == Qt::Horizontal
6401             && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton)))
6402         return_SIZE(12, 10, 8);        // guess
6404     if ((control1 | control2) & (QSizePolicy::Frame
6405                                  | QSizePolicy::GroupBox
6406                                  | QSizePolicy::TabWidget)) {
6407         /*
6408             These values were chosen so that nested container widgets
6409             look good side by side. Builder uses 8, which looks way
6410             too small, and AHIG doesn't say anything.
6411         */
6412         return_SIZE(16, 10, 10);    // guess
6413     }
6415     if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider))
6416         return_SIZE(12, 10, 8);     // AHIG
6418     if ((control1 | control2) & QSizePolicy::LineEdit)
6419         return_SIZE(10, 8, 8);      // AHIG
6421     /*
6422         AHIG and Builder differ by up to 4 pixels for stacked editable
6423         comboboxes. We use some values that work fairly well in all
6424         cases.
6425     */
6426     if ((control1 | control2) & QSizePolicy::ComboBox)
6427         return_SIZE(10, 8, 7);      // guess
6429     /*
6430         Builder defaults to 8, 6, 5 in lots of cases, but most of the time the
6431         result looks too cramped.
6432     */
6433     return_SIZE(10, 8, 6);  // guess
6436 QT_END_NAMESPACE