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