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