1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Qt Software Information (qt-info@nokia.com)
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at qt-sales@nokia.com.
40 ****************************************************************************/
42 #include "qmacstyle_mac.h"
44 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
45 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
46 //#define DEBUG_SIZE_CONSTRAINT
48 #include <private/qcombobox_p.h>
49 #include <private/qmacstylepixmaps_mac_p.h>
50 #include <private/qpaintengine_mac_p.h>
51 #include <private/qpainter_p.h>
52 #include <private/qprintengine_mac_p.h>
53 #include <private/qstylehelper_p.h>
54 #include <qapplication.h>
56 #include <qcheckbox.h>
57 #include <qcombobox.h>
58 #include <qdialogbuttonbox.h>
59 #include <qdockwidget.h>
61 #include <qfocusframe.h>
62 #include <qformlayout.h>
63 #include <qgroupbox.h>
65 #include <qheaderview.h>
67 #include <qlineedit.h>
68 #include <qlistview.h>
69 #include <qmainwindow.h>
72 #include <qpaintdevice.h>
74 #include <qpixmapcache.h>
76 #include <qprogressbar.h>
77 #include <qpushbutton.h>
78 #include <qradiobutton.h>
79 #include <qrubberband.h>
80 #include <qsizegrip.h>
82 #include <qsplitter.h>
83 #include <qstyleoption.h>
84 #include <qtextedit.h>
85 #include <qtextstream.h>
87 #include <qtoolbutton.h>
88 #include <qtreeview.h>
89 #include <qtableview.h>
93 #include <qdatetimeedit.h>
94 #include <QtGui/qgraphicsproxywidget.h>
95 #include <QtGui/qgraphicsview.h>
96 #include <private/qt_cocoa_helpers_mac_p.h>
100 extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
101 extern QHash<QByteArray, QFont> *qt_app_fonts_hash(); // qapplication.cpp
103 // The following constants are used for adjusting the size
104 // of push buttons so that they are drawn inside their bounds.
105 static const int PushButtonLeftOffset = 6;
106 static const int PushButtonTopOffset = 4;
107 static const int PushButtonRightOffset = 12;
108 static const int PushButtonBottomOffset = 12;
109 static const int MiniButtonH = 26;
110 static const int SmallButtonH = 30;
111 static const int BevelButtonW = 50;
112 static const int BevelButtonH = 22;
113 static const int PushButtonContentPadding = 6;
115 // These colors specify the titlebar gradient colors on
116 // Leopard. Ideally we should get them from the system.
117 static const QColor titlebarGradientActiveBegin(220, 220, 220);
118 static const QColor titlebarGradientActiveEnd(151, 151, 151);
119 static const QColor titlebarSeparatorLineActive(111, 111, 111);
120 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
121 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
122 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
124 // Gradient colors used for the dock widget title bar and
125 // non-unifed tool bar bacground.
126 static const QColor mainWindowGradientBegin(240, 240, 240);
127 static const QColor mainWindowGradientEnd(200, 200, 200);
129 #if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5)
131 kThemePushButtonTextured = 31,
132 kThemePushButtonTexturedSmall = 32,
133 kThemePushButtonTexturedMini = 33
137 // Resolve these at run-time, since the functions was moved in Leopard.
138 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
139 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
141 static bool isVerticalTabs(const QTabBar::Shape shape) {
142 return (shape == QTabBar::RoundedEast
143 || shape == QTabBar::TriangularEast
144 || shape == QTabBar::RoundedWest
145 || shape == QTabBar::TriangularWest);
148 static int closeButtonSize = 12;
150 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
152 // draw background circle
153 p->setRenderHints(QPainter::Antialiasing);
154 QRect rect(0, 0, closeButtonSize, closeButtonSize);
157 background = QColor(124, 124, 124);
161 background = QColor(104, 104, 104);
163 background = QColor(83, 83, 83);
166 background = QColor(144, 144, 144);
168 background = QColor(114, 114, 114);
171 p->setPen(Qt::transparent);
172 p->setBrush(background);
173 p->drawEllipse(rect);
179 crossPen.setColor(QColor(194, 194, 194));
180 crossPen.setWidthF(1.3);
181 crossPen.setCapStyle(Qt::FlatCap);
183 p->drawLine(min, min, max, max);
184 p->drawLine(min, max, max, min);
187 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
189 if (isVerticalTabs(shape)) {
190 int newX, newY, newRot;
191 if (shape == QTabBar::RoundedEast
192 || shape == QTabBar::TriangularEast) {
193 newX = tabRect.width();
198 newY = tabRect.y() + tabRect.height();
201 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
203 m.translate(newX, newY);
205 p->setMatrix(m, true);
210 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt)
212 QRect r = tabOpt->rect;
213 p->translate(tabOpt->rect.x(), tabOpt->rect.y());
216 QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
218 int width = tabRect.width();
220 bool active = (tabOpt->state & QStyle::State_Active);
221 bool selected = (tabOpt->state & QStyle::State_Selected);
224 QRect rect(1, 0, width - 2, height);
228 p->fillRect(rect, QColor(151, 151, 151));
230 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
231 gradient.setColorAt(0, QColor(207, 207, 207));
232 gradient.setColorAt(0.5, QColor(206, 206, 206));
233 gradient.setColorAt(1, QColor(201, 201, 201));
234 p->fillRect(rect, gradient);
241 borderSides = QColor(88, 88, 88);
242 borderBottom = QColor(88, 88, 88);
244 borderSides = QColor(121, 121, 121);
245 borderBottom = QColor(116, 116, 116);
248 p->setPen(borderSides);
252 p->drawLine(0, 1, 0, bottom-2);
254 p->drawLine(width-1, 1, width-1, bottom-2);
258 p->setPen(QColor(168, 168, 168));
259 p->drawLine(3, bottom-1, width-3, bottom-1);
261 p->setPen(borderBottom);
262 p->drawLine(2, bottom, width-2, bottom);
265 QRectF rectangleLeft(1, height - w, w, w);
266 QRectF rectangleRight(width - 2, height - 1, w, w);
267 int startAngle = 180 * 16;
268 int spanAngle = 90 * 16;
269 p->setRenderHint(QPainter::Antialiasing);
270 p->drawArc(rectangleLeft, startAngle, spanAngle);
271 p->drawArc(rectangleRight, startAngle, -spanAngle);
273 // when the mouse is over non selected tabs they get a new color
274 bool hover = (tabOpt->state & QStyle::State_MouseOver);
276 QRect rect(1, 2, width - 1, height - 1);
277 p->fillRect(rect, QColor(110, 110, 110));
280 // seperator lines between tabs
281 bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
282 bool drawOnRight = !west;
283 if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
284 || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
286 QColor borderHighlightColor;
288 borderColor = QColor(64, 64, 64);
289 borderHighlightColor = QColor(140, 140, 140);
291 borderColor = QColor(135, 135, 135);
292 borderHighlightColor = QColor(178, 178, 178);
295 int x = drawOnRight ? width : 0;
297 // tab seperator line
298 p->setPen(borderColor);
299 p->drawLine(x, 2, x, height + 1);
301 // tab seperator highlight
302 p->setPen(borderHighlightColor);
303 p->drawLine(x-1, 2, x-1, height + 1);
304 p->drawLine(x+1, 2, x+1, height + 1);
309 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
312 if (isVerticalTabs(tbb->shape)) {
313 r.setWidth(w->width());
315 r.setHeight(w->height());
317 QRect tabRect = rotateTabPainter(p, tbb->shape, r);
318 int width = tabRect.width();
319 int height = tabRect.height();
320 bool active = (tbb->state & QStyle::State_Active);
323 QColor borderHighlightTop;
326 borderTop = QColor(64, 64, 64);
327 borderHighlightTop = QColor(174, 174, 174);
329 borderTop = QColor(135, 135, 135);
330 borderHighlightTop = QColor(207, 207, 207);
332 p->setPen(borderHighlightTop);
333 p->drawLine(0, 0, width, 0);
334 p->setPen(borderTop);
335 p->drawLine(0, 1, width, 1);
338 QRect centralRect(0, 2, width, height - 2);
340 QColor mainColor = QColor(120, 120, 120);
341 p->fillRect(centralRect, mainColor);
343 QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
344 gradient.setColorAt(0, QColor(165, 165, 165));
345 gradient.setColorAt(0.5, QColor(164, 164, 164));
346 gradient.setColorAt(1, QColor(158, 158, 158));
347 p->fillRect(centralRect, gradient);
350 // bottom border lines
351 QColor borderHighlightBottom;
354 borderHighlightBottom = QColor(153, 153, 153);
355 borderBottom = QColor(64, 64, 64);
357 borderHighlightBottom = QColor(177, 177, 177);
358 borderBottom = QColor(127, 127, 127);
360 p->setPen(borderHighlightBottom);
361 p->drawLine(0, height - 2, width, height - 2);
362 p->setPen(borderBottom);
363 p->drawLine(0, height - 1, width, height - 1);
368 Apple Human Interface Guidelines
369 http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/
372 Apple Interface Builder v. 3.1.1
375 // this works as long as we have at most 16 different control types
376 #define CT1(c) CT2(c, c)
377 #define CT2(c1, c2) ((uint(c1) << 16) | uint(c2))
379 enum QAquaWidgetSize { QAquaSizeLarge = 0, QAquaSizeSmall = 1, QAquaSizeMini = 2,
380 QAquaSizeUnknown = -1 };
382 #define SIZE(large, small, mini) \
383 (controlSize == QAquaSizeLarge ? (large) : controlSize == QAquaSizeSmall ? (small) : (mini))
385 // same as return SIZE(...) but optimized
386 #define return_SIZE(large, small, mini) \
388 static const int sizes[] = { (large), (small), (mini) }; \
389 return sizes[controlSize]; \
392 static int getControlSize(const QStyleOption *option, const QWidget *widget)
395 if (option->state & (QStyle::State_Small | QStyle::State_Mini))
396 return (option->state & QStyle::State_Mini) ? QAquaSizeMini : QAquaSizeSmall;
398 switch (QMacStyle::widgetSizePolicy(widget)) {
399 case QMacStyle::SizeSmall:
400 return QAquaSizeSmall;
401 case QMacStyle::SizeMini:
402 return QAquaSizeMini;
407 return QAquaSizeLarge;
411 static inline bool isTreeView(const QWidget *widget)
413 return (widget && widget->parentWidget() &&
414 (qobject_cast<const QTreeView *>(widget->parentWidget())
416 || widget->parentWidget()->inherits("Q3ListView")
421 QString qt_mac_removeMnemonics(const QString &original)
423 // copied from qt_format_text (to be bug-for-bug compatible).
424 QString returnText(original.size(), 0);
427 int l = original.length();
429 if (original.at(currPos) == QLatin1Char('&')) {
435 returnText[finalDest] = original.at(currPos);
440 returnText.truncate(finalDest);
444 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
446 ThemeTabDirection ttd;
448 case QTabBar::RoundedSouth:
449 case QTabBar::TriangularSouth:
450 ttd = kThemeTabSouth;
452 default: // Added to remove the warning, since all values are taken care of, really!
453 case QTabBar::RoundedNorth:
454 case QTabBar::TriangularNorth:
455 ttd = kThemeTabNorth;
457 case QTabBar::RoundedWest:
458 case QTabBar::TriangularWest:
461 case QTabBar::RoundedEast:
462 case QTabBar::TriangularEast:
469 class QMacStylePrivate : public QObject
474 QMacStylePrivate(QMacStyle *style);
476 // Stuff from QAquaAnimate:
477 bool addWidget(QWidget *);
478 void removeWidget(QWidget *);
480 enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen };
481 bool animatable(Animates, const QWidget *) const;
482 void stopAnimate(Animates, QWidget *);
483 void startAnimate(Animates, QWidget *);
484 static ThemeDrawState getDrawState(QStyle::State flags);
485 QAquaWidgetSize aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
486 QStyle::ContentsType ct = QStyle::CT_CustomBase,
487 QSize szHint=QSize(-1, -1), QSize *insz = 0) const;
488 void getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
489 HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe);
490 bool doAnimate(Animates);
491 inline int animateSpeed(Animates) const { return 33; }
494 void drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
495 QPainter *p, const QStyleOption *opt) const;
497 void drawPantherTab(const QStyleOptionTab *tab, QPainter *p, const QWidget *w = 0) const;
499 QSize pushButtonSizeFromContents(const QStyleOptionButton *btn) const;
501 HIRect pushButtonContentBounds(const QStyleOptionButton *btn,
502 const HIThemeButtonDrawInfo *bdi) const;
504 void initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
505 const QWidget *widget, const ThemeDrawState &tds);
507 static HIRect comboboxInnerBounds(const HIRect &outerBounds, int buttonKind);
509 static QRect comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi);
511 static void drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p);
512 static void drawTableHeader(const HIRect &outerBounds, bool drawTopBorder, bool drawLeftBorder,
513 const HIThemeButtonDrawInfo &bdi, QPainter *p);
514 bool contentFitsInPushButton(const QStyleOptionButton *btn, HIThemeButtonDrawInfo *bdi,
515 ThemeButtonKind buttonKindToCheck) const;
516 void initHIThemePushButton(const QStyleOptionButton *btn, const QWidget *widget,
517 const ThemeDrawState tds,
518 HIThemeButtonDrawInfo *bdi) const;
519 QPixmap generateBackgroundPattern() const;
521 bool eventFilter(QObject *, QEvent *);
522 void timerEvent(QTimerEvent *);
525 void startAnimationTimer();
528 QPointer<QPushButton> defaultButton; //default push buttons
530 QList<QPointer<QWidget> > progressBars; //existing progress bars that need animation
534 enum { ButtonDark, ButtonLight } dir;
537 QPointer<QFocusFrame> focusWidget;
538 CFAbsoluteTime defaultButtonStart;
543 QT_BEGIN_INCLUDE_NAMESPACE
544 #include "qmacstyle_mac.moc"
545 QT_END_INCLUDE_NAMESPACE
547 /*****************************************************************************
549 *****************************************************************************/
550 extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
551 extern QPixmap qt_mac_convert_iconref(const IconRef, int, int); //qpixmap_mac.cpp
552 extern QRegion qt_mac_convert_mac_region(HIShapeRef); //qregion_mac.cpp
553 void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
554 extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp
556 /*****************************************************************************
558 *****************************************************************************/
559 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
560 const int macSpinBoxSep = 5; // distance between spinwidget and the lineedit
561 const int macItemFrame = 2; // menu item frame width
562 const int macItemHMargin = 3; // menu item hor text margin
563 const int macItemVMargin = 2; // menu item ver text margin
564 const int macRightBorder = 12; // right border on mac
565 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
566 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
568 /*****************************************************************************
569 QMacCGStyle utility functions
570 *****************************************************************************/
571 static inline int qt_mac_hitheme_tab_version()
573 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
574 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4)
580 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
582 return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
583 convertRect.width() - rect.width(), convertRect.height() - rect.height());
586 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
588 return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
589 QSize(int(hirect.size.width), int(hirect.size.height)));
592 inline bool qt_mac_is_metal(const QWidget *w)
594 for (; w; w = w->parentWidget()) {
595 if (w->testAttribute(Qt::WA_MacBrushedMetal))
597 if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) { // If not created will fall through to the opaque check and be fine anyway.
598 return macWindowIsTextured(qt_mac_window_for(w));
600 if (w->d_func()->isOpaque)
606 static int qt_mac_aqua_get_metric(ThemeMetric met)
609 GetThemeMetric(met, &ret);
613 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
617 if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
618 qDebug("Not sure how to return this...");
621 if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
622 // If you're using a custom font and it's bigger than the default font,
623 // then no constraints for you. If you are smaller, we can try to help you out
624 QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
625 if (widg->font().pointSize() > font.pointSize())
629 if (ct == QStyle::CT_CustomBase && widg) {
630 if (qobject_cast<const QPushButton *>(widg))
631 ct = QStyle::CT_PushButton;
632 else if (qobject_cast<const QRadioButton *>(widg))
633 ct = QStyle::CT_RadioButton;
634 else if (qobject_cast<const QCheckBox *>(widg))
635 ct = QStyle::CT_CheckBox;
636 else if (qobject_cast<const QComboBox *>(widg))
637 ct = QStyle::CT_ComboBox;
638 else if (qobject_cast<const QToolButton *>(widg))
639 ct = QStyle::CT_ToolButton;
640 else if (qobject_cast<const QSlider *>(widg))
641 ct = QStyle::CT_Slider;
642 else if (qobject_cast<const QProgressBar *>(widg))
643 ct = QStyle::CT_ProgressBar;
644 else if (qobject_cast<const QLineEdit *>(widg))
645 ct = QStyle::CT_LineEdit;
646 else if (qobject_cast<const QHeaderView *>(widg)
648 || widg->inherits("Q3Header")
651 ct = QStyle::CT_HeaderSection;
652 else if (qobject_cast<const QMenuBar *>(widg)
654 || widg->inherits("Q3MenuBar")
657 ct = QStyle::CT_MenuBar;
658 else if (qobject_cast<const QSizeGrip *>(widg))
659 ct = QStyle::CT_SizeGrip;
665 case QStyle::CT_PushButton: {
666 const QPushButton *psh = static_cast<const QPushButton *>(widg);
667 QString buttonText = qt_mac_removeMnemonics(psh->text());
668 if (buttonText.contains(QLatin1Char('\n')))
670 else if (sz == QAquaSizeLarge)
671 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
672 else if (sz == QAquaSizeSmall)
673 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
674 else if (sz == QAquaSizeMini)
675 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
677 if (!psh->icon().isNull()){
678 // If the button got an icon, and the icon is larger than the
679 // button, we can't decide on a default size
681 if (ret.height() < psh->iconSize().height())
684 else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
685 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
686 // However, this doesn't work for German, therefore only do it for English,
687 // I suppose it would be better to do some sort of lookups for languages
688 // that like to have really long words.
689 ret.setWidth(77 - 8);
692 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
693 } else if (ct == QStyle::CT_RadioButton) {
694 QRadioButton *rdo = static_cast<QRadioButton *>(widg);
695 // Exception for case where multiline radio button text requires no size constrainment
696 if (rdo->text().find('\n') != -1)
698 if (sz == QAquaSizeLarge)
699 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
700 else if (sz == QAquaSizeSmall)
701 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
702 else if (sz == QAquaSizeMini)
703 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
704 } else if (ct == QStyle::CT_CheckBox) {
705 if (sz == QAquaSizeLarge)
706 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
707 else if (sz == QAquaSizeSmall)
708 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
709 else if (sz == QAquaSizeMini)
710 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
714 case QStyle::CT_SizeGrip:
715 if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
717 HIPoint p = { 0, 0 };
718 HIThemeGrowBoxDrawInfo gbi;
720 gbi.state = kThemeStateActive;
721 gbi.kind = kHIThemeGrowBoxKindNormal;
722 gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
723 : kThemeGrowRight | kThemeGrowDown;
724 gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
725 if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr)
726 ret = QSize(r.size.width, r.size.height);
729 case QStyle::CT_ComboBox:
732 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
735 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
738 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
744 case QStyle::CT_ToolButton:
745 if (sz == QAquaSizeSmall) {
746 int width = 0, height = 0;
747 if (szHint == QSize(-1, -1)) { //just 'guess'..
748 const QToolButton *bt = static_cast<const QToolButton *>(widg);
749 if (!bt->icon().isNull()) {
750 QSize iconSize = bt->iconSize();
751 QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
752 width = qMax(width, qMax(iconSize.width(), pmSize.width()));
753 height = qMax(height, qMax(iconSize.height(), pmSize.height()));
755 if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
756 int text_width = bt->fontMetrics().width(bt->text()),
757 text_height = bt->fontMetrics().height();
758 if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
759 width = qMax(width, text_width);
760 height += text_height;
763 width = qMax(height, text_height);
767 width = szHint.width();
768 height = szHint.height();
770 width = qMax(20, width + 5); //border
771 height = qMax(20, height + 5); //border
772 ret = QSize(width, height);
775 case QStyle::CT_Slider: {
777 const QSlider *sld = static_cast<const QSlider *>(widg);
778 if (sz == QAquaSizeLarge) {
779 if (sld->orientation() == Qt::Horizontal) {
780 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
781 if (sld->tickPosition() != QSlider::NoTicks)
782 w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
784 w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
785 if (sld->tickPosition() != QSlider::NoTicks)
786 w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
788 } else if (sz == QAquaSizeSmall) {
789 if (sld->orientation() == Qt::Horizontal) {
790 w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
791 if (sld->tickPosition() != QSlider::NoTicks)
792 w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
794 w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
795 if (sld->tickPosition() != QSlider::NoTicks)
796 w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
798 } else if (sz == QAquaSizeMini) {
799 if (sld->orientation() == Qt::Horizontal) {
800 w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
801 if (sld->tickPosition() != QSlider::NoTicks)
802 w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
804 w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
805 if (sld->tickPosition() != QSlider::NoTicks)
806 w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
809 if (sld->orientation() == Qt::Horizontal)
815 case QStyle::CT_ProgressBar: {
817 Qt::Orientation orient = Qt::Horizontal;
818 if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
819 orient = pb->orientation();
821 if (sz == QAquaSizeLarge)
822 finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
823 + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
825 finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
826 + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
827 if (orient == Qt::Horizontal)
828 ret.setHeight(finalValue);
830 ret.setWidth(finalValue);
833 case QStyle::CT_LineEdit:
834 if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
835 //should I take into account the font dimentions of the lineedit? -Sam
836 if (sz == QAquaSizeLarge)
842 case QStyle::CT_HeaderSection:
843 if (sz == QAquaSizeLarge && isTreeView(widg))
844 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
846 case QStyle::CT_MenuBar:
847 if (sz == QAquaSizeLarge) {
848 #ifndef QT_MAC_USE_COCOA
850 if (!GetThemeMenuBarHeight(&size))
851 ret = QSize(-1, size);
853 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
854 // In the qt_mac_set_native_menubar(false) case,
855 // we come it here with a zero-height main menu,
856 // preventing the in-window menu from displaying.
857 // Use 22 pixels for the height, by observation.
858 if (ret.height() <= 0)
870 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
871 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
873 if (large == QSize(-1, -1)) {
874 if (small != QSize(-1, -1))
875 return QAquaSizeSmall;
876 if (mini != QSize(-1, -1))
877 return QAquaSizeMini;
878 return QAquaSizeUnknown;
879 } else if (small == QSize(-1, -1)) {
880 if (mini != QSize(-1, -1))
881 return QAquaSizeMini;
882 return QAquaSizeLarge;
883 } else if (mini == QSize(-1, -1)) {
884 return QAquaSizeLarge;
887 #ifndef QT_NO_MAINWINDOW
888 if (qobject_cast<QDockWidget *>(widg->window()) || !qgetenv("QWIDGET_ALL_SMALL").isNull()) {
889 //if (small.width() != -1 || small.height() != -1)
890 return QAquaSizeSmall;
891 } else if (!qgetenv("QWIDGET_ALL_MINI").isNull()) {
892 return QAquaSizeMini;
897 /* Figure out which size we're closer to, I just hacked this in, I haven't
898 tested it as it would probably look pretty strange to have some widgets
899 big and some widgets small in the same window?? -Sam */
901 if (large.width() != -1) {
902 int delta = large.width() - widg->width();
903 large_delta += delta * delta;
905 if (large.height() != -1) {
906 int delta = large.height() - widg->height();
907 large_delta += delta * delta;
910 if (small.width() != -1) {
911 int delta = small.width() - widg->width();
912 small_delta += delta * delta;
914 if (small.height() != -1) {
915 int delta = small.height() - widg->height();
916 small_delta += delta * delta;
919 if (mini.width() != -1) {
920 int delta = mini.width() - widg->width();
921 mini_delta += delta * delta;
923 if (mini.height() != -1) {
924 int delta = mini.height() - widg->height();
925 mini_delta += delta * delta;
927 if (mini_delta < small_delta && mini_delta < large_delta)
928 return QAquaSizeMini;
929 else if (small_delta < large_delta)
930 return QAquaSizeSmall;
932 return QAquaSizeLarge;
936 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
937 QStyle::ContentsType ct, QSize szHint, QSize *insz) const
939 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
941 if (option->state & QStyle::State_Small)
942 return QAquaSizeSmall;
943 if (option->state & QStyle::State_Mini)
944 return QAquaSizeMini;
950 if (!qgetenv("QWIDGET_ALL_SMALL").isNull())
951 return QAquaSizeSmall;
952 if (!qgetenv("QWIDGET_ALL_MINI").isNull())
953 return QAquaSizeMini;
954 return QAquaSizeUnknown;
956 QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
957 small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
958 mini = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
959 bool guess_size = false;
960 QAquaWidgetSize ret = QAquaSizeUnknown;
961 QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
962 if (wsp == QMacStyle::SizeDefault)
964 else if (wsp == QMacStyle::SizeMini)
966 else if (wsp == QMacStyle::SizeSmall)
967 ret = QAquaSizeSmall;
968 else if (wsp == QMacStyle::SizeLarge)
969 ret = QAquaSizeLarge;
971 ret = qt_aqua_guess_size(widg, large, small, mini);
974 if (ret == QAquaSizeSmall)
976 else if (ret == QAquaSizeLarge)
978 else if (ret == QAquaSizeMini)
981 *insz = sz ? *sz : QSize(-1, -1);
982 #ifdef DEBUG_SIZE_CONSTRAINT
984 const char *size_desc = "Unknown";
987 else if (sz == &large)
989 else if (sz == &mini)
991 qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
992 widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
993 widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
994 sz->width(), sz->height());
1004 return QAquaSizeUnknown;
1009 Returns the free space awailable for contents inside the
1010 button (and not the size of the contents itself)
1012 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
1013 const HIThemeButtonDrawInfo *bdi) const
1015 HIRect outerBounds = qt_hirectForQRect(btn->rect);
1016 // Adjust the bounds to correct for
1017 // carbon not calculating the content bounds fully correct
1018 if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
1019 outerBounds.origin.y += PushButtonTopOffset;
1020 outerBounds.size.height -= PushButtonBottomOffset;
1021 } else if (bdi->kind == kThemePushButtonMini) {
1022 outerBounds.origin.y += PushButtonTopOffset;
1025 HIRect contentBounds;
1026 HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
1027 return contentBounds;
1031 Calculates the size of the button contents.
1032 This includes both the text and the icon.
1034 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
1037 QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
1038 : (btn->iconSize + QSize(PushButtonContentPadding, 0));
1039 QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
1040 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
1041 csz.setWidth(iconSize.width() + textRect.width()
1042 + ((btn->features & QStyleOptionButton::HasMenu)
1043 ? q->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
1044 csz.setHeight(qMax(iconSize.height(), textRect.height()));
1049 Checks if the actual contents of btn fits inside the free content bounds of
1050 'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
1051 for determining which button kind to use for drawing.
1053 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
1054 HIThemeButtonDrawInfo *bdi,
1055 ThemeButtonKind buttonKindToCheck) const
1057 ThemeButtonKind tmp = bdi->kind;
1058 bdi->kind = buttonKindToCheck;
1059 QSize contentSize = pushButtonSizeFromContents(btn);
1060 QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
1062 return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
1063 contentSize.width(), contentSize.height()));
1067 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1068 kind and other details to use for drawing the given push button. Which
1069 button kind depends on the size of the button, the size of the contents,
1070 explicit user style settings, etc.
1072 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1073 const QWidget *widget,
1074 const ThemeDrawState tds,
1075 HIThemeButtonDrawInfo *bdi) const
1077 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
1078 ThemeDrawState tdsModified = tds;
1079 if (btn->state & QStyle::State_On)
1080 tdsModified = kThemeStatePressed;
1081 bdi->version = qt_mac_hitheme_version;
1082 bdi->state = tdsModified;
1083 bdi->value = kThemeButtonOff;
1085 if (drawColorless && tdsModified == kThemeStateInactive)
1086 bdi->state = kThemeStateActive;
1087 if (btn->state & QStyle::State_HasFocus)
1088 bdi->adornment = kThemeAdornmentFocus;
1090 bdi->adornment = kThemeAdornmentNone;
1093 if (btn->features & (QStyleOptionButton::Flat)) {
1094 bdi->kind = kThemeBevelButton;
1096 switch (aquaSizeConstrain(btn, widget)) {
1097 case QAquaSizeSmall:
1098 bdi->kind = kThemePushButtonSmall;
1101 bdi->kind = kThemePushButtonMini;
1103 case QAquaSizeLarge:
1104 // ... We should honor if the user is explicit about using the
1105 // large button. But right now Qt will specify the large button
1106 // as default rather than QAquaSizeUnknown.
1107 // So we treat it like QAquaSizeUnknown
1108 // to get the dynamic choosing of button kind.
1109 case QAquaSizeUnknown:
1110 // Choose the button kind that closest match the button rect, but at the
1111 // same time displays the button contents without clipping.
1112 bdi->kind = kThemeBevelButton;
1113 if (btn->rect.width() >= BevelButtonW && btn->rect.height() >= BevelButtonH){
1114 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1115 if (btn->rect.height() <= MiniButtonH){
1116 if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1117 bdi->kind = kThemePushButtonMini;
1118 } else if (btn->rect.height() <= SmallButtonH){
1119 if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1120 bdi->kind = kThemePushButtonSmall;
1121 } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1122 bdi->kind = kThemePushButton;
1125 bdi->kind = kThemePushButton;
1133 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1134 kind and other details to use for drawing the given combobox. Which button
1135 kind depends on the size of the combo, wether or not it is editable,
1136 explicit user style settings, etc.
1138 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1139 const QWidget *widget, const ThemeDrawState &tds)
1141 bdi->version = qt_mac_hitheme_version;
1142 bdi->adornment = kThemeAdornmentArrowLeftArrow;
1143 bdi->value = kThemeButtonOff;
1144 if (combo->state & QStyle::State_HasFocus)
1145 bdi->adornment = kThemeAdornmentFocus;
1146 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
1147 if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1148 bdi->state = kThemeStatePressed;
1149 else if (drawColorless)
1150 bdi->state = kThemeStateActive;
1154 QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1157 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1158 : ThemeButtonKind(kThemePopupButtonMini);
1160 case QAquaSizeSmall:
1161 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1162 : ThemeButtonKind(kThemePopupButtonSmall);
1164 case QAquaSizeUnknown:
1165 case QAquaSizeLarge:
1166 // Unless the user explicitly specified large buttons, determine the
1167 // kind by looking at the combox size.
1168 // ... specifying small and mini-buttons it not a current feature of
1169 // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1170 // an extra check here before using the mini and small buttons.
1171 int h = combo->rect.size().height();
1172 if (combo->editable){
1174 bdi->kind = kThemeComboBoxMini;
1176 bdi->kind = kThemeComboBoxSmall;
1178 bdi->kind = kThemeComboBox;
1180 // Even if we specify that we want the kThemePopupButton, Carbon
1181 // will use the kThemePopupButtonSmall if the size matches. So we
1182 // do the same size check explicit to have the size of the inner
1183 // text field be correct. Therefore, do this even if the user specifies
1184 // the use of LargeButtons explicit.
1186 bdi->kind = kThemePopupButtonMini;
1188 bdi->kind = kThemePopupButtonSmall;
1190 bdi->kind = kThemePopupButton;
1197 Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1198 the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1200 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1202 HIRect innerBounds = outerBounds;
1203 // Carbon draw parts of the view outside the rect.
1204 // So make the rect a bit smaller to compensate
1205 // (I wish HIThemeGetButtonBackgroundBounds worked)
1206 switch (buttonKind){
1207 case kThemePopupButton:
1208 innerBounds.origin.x += 2;
1209 innerBounds.origin.y += 3;
1210 innerBounds.size.width -= 5;
1211 innerBounds.size.height -= 6;
1213 case kThemePopupButtonSmall:
1214 innerBounds.origin.x += 3;
1215 innerBounds.origin.y += 3;
1216 innerBounds.size.width -= 6;
1217 innerBounds.size.height -= 7;
1219 case kThemePopupButtonMini:
1220 innerBounds.origin.x += 2;
1221 innerBounds.origin.y += 2;
1222 innerBounds.size.width -= 5;
1223 innerBounds.size.height -= 6;
1225 case kThemeComboBox:
1226 innerBounds.origin.x += 3;
1227 innerBounds.origin.y += 3;
1228 innerBounds.size.width -= 6;
1229 innerBounds.size.height -= 6;
1231 case kThemeComboBoxSmall:
1232 innerBounds.origin.x += 3;
1233 innerBounds.origin.y += 3;
1234 innerBounds.size.width -= 7;
1235 innerBounds.size.height -= 8;
1237 case kThemeComboBoxMini:
1238 innerBounds.origin.x += 3;
1239 innerBounds.origin.y += 3;
1240 innerBounds.size.width -= 4;
1241 innerBounds.size.height -= 8;
1250 Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1251 of combobox we choose to draw. This function calculates and returns this size.
1253 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1255 QRect ret = outerBounds;
1257 case kThemeComboBox:
1258 ret.adjust(5, 8, -21, -4);
1260 case kThemeComboBoxSmall:
1261 ret.adjust(4, 5, -18, 0);
1264 case kThemeComboBoxMini:
1265 ret.adjust(4, 5, -16, 0);
1268 case kThemePopupButton:
1269 ret.adjust(10, 3, -23, -3);
1271 case kThemePopupButtonSmall:
1272 ret.adjust(9, 3, -20, -3);
1274 case kThemePopupButtonMini:
1275 ret.adjust(8, 3, -19, 0);
1283 Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1284 create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1285 it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1287 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1289 if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1290 // We have an unscaled combobox, or popup-button; use Carbon directly.
1291 HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1292 HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1295 QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1296 if (!QPixmapCache::find(key, buffer)) {
1297 HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1298 buffer = QPixmap(35, 28);
1299 buffer.fill(Qt::transparent);
1300 QPainter buffPainter(&buffer);
1301 HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1303 QPixmapCache::insert(key, buffer);
1306 const int bwidth = 20;
1307 const int fwidth = 10;
1308 const int fheight = 10;
1309 int w = qRound(outerBounds.size.width);
1310 int h = qRound(outerBounds.size.height);
1311 int bstart = w - bwidth;
1312 int blower = fheight + 1;
1313 int flower = h - fheight;
1314 int sheight = flower - fheight;
1315 int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1317 // Draw upper and lower gap
1318 p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1319 p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1320 // Draw left and right gap. Right gap is drawn top and bottom separatly
1321 p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1322 p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1323 p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1325 p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1327 p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1328 p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1329 p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1330 p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1335 Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1336 onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1338 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1339 bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1341 static SInt32 headerHeight = 0;
1342 static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1346 QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1347 if (!QPixmapCache::find(key, buffer)) {
1348 HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1349 buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1350 buffer.fill(Qt::transparent);
1351 QPainter buffPainter(&buffer);
1352 HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1354 QPixmapCache::insert(key, buffer);
1356 const int buttonw = qRound(outerBounds.size.width);
1357 const int buttonh = qRound(outerBounds.size.height);
1358 const int framew = 1;
1359 const int frameh_n = 4;
1360 const int frameh_s = 3;
1361 const int transh = buffer.height() - frameh_n - frameh_s;
1362 int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1364 int skipTopBorder = 0;
1368 p->translate(outerBounds.origin.x, outerBounds.origin.y);
1370 p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1371 p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1372 // Draw upper and lower center blocks
1373 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1374 p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1375 // Draw right center block borders
1376 p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1377 p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1378 // Draw right corners
1379 p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1380 p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1381 // Draw center transition block
1382 p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh));
1383 // Draw right center transition block border
1384 p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh));
1385 if (drawLeftBorder){
1386 // Draw left center block borders
1387 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1388 p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1389 // Draw left corners
1390 p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1391 p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1392 // Draw left center transition block border
1393 p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1396 p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1400 Returns cutoff sizes for scroll bars.
1401 thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1402 scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1404 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1405 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1407 // Mini scroll bars do not exist as of version 10.4.
1408 if (widgetSize == QMacStyle::SizeMini)
1411 const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1412 static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1413 return sizeTable[sizeIndex][cutoffType];
1416 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1417 HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe)
1419 memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1420 tdi->version = qt_mac_hitheme_version;
1423 bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1424 switch (aquaSizeConstrain(0, needToRemoveMe)) {
1425 case QAquaSizeUnknown:
1426 case QAquaSizeLarge:
1428 tdi->kind = kThemeMediumScrollBar;
1430 tdi->kind = kThemeMediumSlider;
1434 tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1436 tdi->kind = kThemeMiniSlider;
1438 case QAquaSizeSmall:
1440 tdi->kind = kThemeSmallScrollBar;
1442 tdi->kind = kThemeSmallSlider;
1445 tdi->bounds = qt_hirectForQRect(slider->rect);
1446 tdi->min = slider->minimum;
1447 tdi->max = slider->maximum;
1448 tdi->value = slider->sliderPosition;
1449 tdi->attributes = kThemeTrackShowThumb;
1450 if (slider->upsideDown)
1451 tdi->attributes |= kThemeTrackRightToLeft;
1452 if (slider->orientation == Qt::Horizontal) {
1453 tdi->attributes |= kThemeTrackHorizontal;
1454 if (isScrollbar && slider->direction == Qt::RightToLeft) {
1455 if (!slider->upsideDown)
1456 tdi->attributes |= kThemeTrackRightToLeft;
1458 tdi->attributes &= ~kThemeTrackRightToLeft;
1462 // Tiger broke reverse scroll bars so put them back and "fake it"
1463 if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)
1464 && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
1465 tdi->attributes &= ~kThemeTrackRightToLeft;
1466 tdi->value = tdi->max - slider->sliderPosition;
1469 tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1470 : kThemeTrackDisabled;
1471 if (!(slider->state & QStyle::State_Active))
1472 tdi->enableState = kThemeTrackInactive;
1474 if (slider->state & QStyle::QStyle::State_HasFocus)
1475 tdi->attributes |= kThemeTrackHasFocus;
1476 if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1477 tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1478 else if (slider->tickPosition == QSlider::TicksAbove)
1479 tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1481 tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1483 tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1488 QMacStylePrivate::QMacStylePrivate(QMacStyle *style)
1489 : timerID(-1), progressFrame(0), q(style), mouseDown(false)
1491 defaultButtonStart = CFAbsoluteTimeGetCurrent();
1492 memset(&buttonState, 0, sizeof(ButtonState));
1494 if (ptrHIShapeGetBounds == 0) {
1495 QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1496 library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1497 ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1502 bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QWidget *w) const
1504 if (as == AquaPushButton) {
1505 QPushButton *pb = const_cast<QPushButton *>(static_cast<const QPushButton *>(w));
1506 if (w->window()->isActiveWindow() && pb && !mouseDown) {
1507 if (static_cast<const QPushButton *>(w) != defaultButton) {
1508 // Changed on its own, update the value.
1509 const_cast<QMacStylePrivate *>(this)->stopAnimate(as, defaultButton);
1510 const_cast<QMacStylePrivate *>(this)->startAnimate(as, pb);
1514 } else if (as == AquaProgressBar) {
1515 if (progressBars.contains((const_cast<QWidget *>(w))))
1521 void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QWidget *w)
1523 if (as == AquaPushButton && defaultButton) {
1524 QPushButton *tmp = defaultButton;
1527 } else if (as == AquaProgressBar) {
1528 progressBars.removeAll(w);
1532 void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QWidget *w)
1534 if (as == AquaPushButton)
1535 defaultButton = static_cast<QPushButton *>(w);
1536 else if (as == AquaProgressBar)
1537 progressBars.append(w);
1538 startAnimationTimer();
1541 void QMacStylePrivate::startAnimationTimer()
1543 if ((defaultButton || !progressBars.isEmpty()) && timerID <= -1)
1544 timerID = startTimer(animateSpeed(AquaListViewItemOpen));
1547 enum { TabNormalLeft, TabNormalMid, TabNormalRight, TabSelectedActiveLeft,
1548 TabSelectedActiveMid, TabSelectedActiveRight, TabSelectedInactiveLeft,
1549 TabSelectedInactiveMid, TabSelectedInactiveRight, TabSelectedActiveGraphiteLeft,
1550 TabSelectedActiveGraphiteMid, TabSelectedActiveGraphiteRight,
1551 TabPressedLeft, TabPressedMid, TabPressedRight };
1553 static const char * const * const PantherTabXpms[] = {
1556 qt_mac_tabnrm_right,
1557 qt_mac_tabselected_active_left,
1558 qt_mac_tabselected_active_mid,
1559 qt_mac_tabselected_active_right,
1560 qt_mac_tabselected_inactive_left,
1561 qt_mac_tabselected_inactive_mid,
1562 qt_mac_tabselected_inactive_right,
1563 qt_mac_tab_selected_active_graph_left,
1564 qt_mac_tab_selected_active_graph_mid,
1565 qt_mac_tab_selected_active_graph_right,
1566 qt_mac_tab_press_left,
1567 qt_mac_tab_press_mid,
1568 qt_mac_tab_press_right};
1570 void QMacStylePrivate::drawPantherTab(const QStyleOptionTab *tabOpt, QPainter *p,
1571 const QWidget *) const
1573 QString tabKey = QLatin1String("$qt_mac_style_tab_");
1574 int pantherTabStart;
1578 ThemeTabDirection ttd = getTabDirection(tabOpt->shape);
1580 if (tabOpt->state & QStyle::State_Selected) {
1581 if (!(tabOpt->state & QStyle::State_Active)) {
1582 pantherTabStart = TabSelectedInactiveLeft;
1584 // Draw into a pixmap to determine which version we use, Aqua or Graphite.
1585 QPixmap tabPix(20, 20);
1586 QPainter pixPainter(&tabPix);
1587 HIThemeTabDrawInfo tdi;
1589 tdi.style = kThemeTabFront;
1590 tdi.direction = kThemeTabNorth;
1591 tdi.size = kHIThemeTabSizeNormal;
1592 tdi.adornment = kHIThemeTabAdornmentNone;
1593 HIRect inRect = CGRectMake(0.0f, 0.0f, 20.0f, 20.0f);
1594 HIThemeDrawTab(&inRect, &tdi, QMacCGContext(&pixPainter), kHIThemeOrientationNormal, 0);
1596 const QRgb GraphiteColor = 0xffa7b0ba;
1597 QRgb pmColor = tabPix.toImage().pixel(10, 10);
1598 if (qAbs(qRed(pmColor) - qRed(GraphiteColor)) < 3 &&
1599 qAbs(qGreen(pmColor) - qGreen(GraphiteColor)) < 3
1600 && qAbs(qBlue(pmColor) - qBlue(GraphiteColor)) < 3)
1601 pantherTabStart = TabSelectedActiveGraphiteLeft;
1603 pantherTabStart = TabSelectedActiveLeft;
1605 } else if (tabOpt->state & QStyle::State_Sunken) {
1606 pantherTabStart = TabPressedLeft;
1608 pantherTabStart = TabNormalLeft;
1613 bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
1615 QStyleOptionTab::TabPosition tp = tabOpt->position;
1616 if (ttd == kThemeTabWest
1617 || ((ttd == kThemeTabNorth || ttd == kThemeTabSouth)
1618 && tabOpt->direction == Qt::RightToLeft)) {
1619 if (tp == QStyleOptionTab::Beginning)
1620 tp = QStyleOptionTab::End;
1621 else if (tp == QStyleOptionTab::End)
1622 tp = QStyleOptionTab::Beginning;
1626 default: // Stupid GCC, being overly pedantic
1627 case QStyleOptionTab::Beginning:
1629 pantherTabMid = pantherTabEnd = pantherTabStart + 1;
1631 case QStyleOptionTab::Middle:
1633 pantherTabMid = pantherTabEnd = ++pantherTabStart;
1635 case QStyleOptionTab::End:
1637 pantherTabMid = ++pantherTabStart;
1638 pantherTabEnd = pantherTabMid + 1;
1640 case QStyleOptionTab::OnlyOneTab:
1642 pantherTabMid = pantherTabStart + 1;
1643 pantherTabEnd = pantherTabMid + 1;
1648 if (!QPixmapCache::find(tabKey + QString::number(pantherTabStart), pmStart)) {
1649 pmStart = QPixmap(PantherTabXpms[pantherTabStart]);
1650 QPixmapCache::insert(tabKey + QString::number(pantherTabStart), pmStart);
1654 if (!QPixmapCache::find(tabKey + QString::number(pantherTabMid), pmMid)) {
1655 pmMid = QPixmap(PantherTabXpms[pantherTabMid]);
1656 QPixmapCache::insert(tabKey + QString::number(pantherTabMid), pmMid);
1660 if (!QPixmapCache::find(tabKey + QString::number(pantherTabEnd), pmEnd)) {
1661 pmEnd = QPixmap(PantherTabXpms[pantherTabEnd]);
1662 QPixmapCache::insert(tabKey + QString::number(pantherTabEnd), pmEnd);
1664 QRect tr = tabOpt->rect;
1667 int newX, newY, newRot;
1668 if (tabOpt->shape == QTabBar::RoundedEast || tabOpt->shape == QTabBar::TriangularEast) {
1674 newY = tr.y() + tr.height();
1677 tr.setRect(0, 0, tr.height(), tr.width());
1679 if (ttd == kThemeTabEast) {
1680 // It's lame but Apple inverts these on the East side.
1682 m.translate(-tabOpt->rect.width(), 0);
1684 m.translate(newX, newY);
1686 p->setMatrix(m, true);
1691 int endX = x + tr.width() - pmEnd.width();
1693 p->drawPixmap(x, y, pmStart.width(), tr.height(), pmStart);
1695 QPen oldPen = p->pen();
1696 p->setPen(QColor(0, 0, 0, 0x35));
1697 p->drawLine(x, y + (verticalTabs ? 0 : 1), x, tr.height() - 2);
1700 for (x = x + pmStart.width(); x < endX; x += pmMid.width())
1701 p->drawPixmap(x, y, pmMid.width(), tr.height(), pmMid);
1702 p->drawPixmap(endX, y, pmEnd.width(), tr.height(), pmEnd);
1707 bool QMacStylePrivate::addWidget(QWidget *w)
1709 //already knew of it
1710 if (static_cast<QPushButton*>(w) == defaultButton
1711 || progressBars.contains(static_cast<QProgressBar*>(w)))
1714 if (QPushButton *btn = qobject_cast<QPushButton *>(w)) {
1715 btn->installEventFilter(this);
1716 if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus()))
1717 startAnimate(AquaPushButton, btn);
1720 bool isProgressBar = (qobject_cast<QProgressBar *>(w)
1722 || w->inherits("Q3ProgressBar")
1725 if (isProgressBar) {
1726 w->installEventFilter(this);
1727 startAnimate(AquaProgressBar, w);
1731 if (w->isWindow()) {
1732 w->installEventFilter(this);
1738 void QMacStylePrivate::removeWidget(QWidget *w)
1740 QPushButton *btn = qobject_cast<QPushButton *>(w);
1741 if (btn && btn == defaultButton) {
1742 stopAnimate(AquaPushButton, btn);
1743 } else if (qobject_cast<QProgressBar *>(w)
1745 || w->inherits("Q3ProgressBar")
1748 stopAnimate(AquaProgressBar, w);
1752 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1754 ThemeDrawState tds = kThemeStateActive;
1755 if (flags & QStyle::State_Sunken) {
1756 tds = kThemeStatePressed;
1757 } else if (flags & QStyle::State_Active) {
1758 if (!(flags & QStyle::State_Enabled))
1759 tds = kThemeStateUnavailable;
1761 if (flags & QStyle::State_Enabled)
1762 tds = kThemeStateInactive;
1764 tds = kThemeStateUnavailableInactive;
1769 void QMacStylePrivate::timerEvent(QTimerEvent *)
1772 if (defaultButton && defaultButton->isEnabled() && defaultButton->window()->isActiveWindow()
1773 && defaultButton->isVisibleTo(0) && (defaultButton->isDefault()
1774 || (defaultButton->autoDefault() && defaultButton->hasFocus()))
1775 && doAnimate(AquaPushButton)) {
1777 defaultButton->update();
1779 if (!progressBars.isEmpty()) {
1781 while (i < progressBars.size()) {
1782 QWidget *maybeProgress = progressBars.at(i);
1783 if (!maybeProgress) {
1784 progressBars.removeAt(i);
1786 if (QProgressBar *pb = qobject_cast<QProgressBar *>(maybeProgress)) {
1787 if (pb->maximum() == 0 || pb->value() > 0
1788 && pb->value() < pb->maximum()) {
1789 if (doAnimate(AquaProgressBar))
1796 QVariant progress = maybeProgress->property("progress");
1797 QVariant totalSteps = maybeProgress->property("totalSteps");
1798 if (progress.isValid() && totalSteps.isValid()) {
1799 int intProgress = progress.toInt();
1800 int intTotalSteps = totalSteps.toInt();
1801 if (intTotalSteps == 0 || intProgress > 0 && intProgress < intTotalSteps) {
1802 if (doAnimate(AquaProgressBar))
1803 maybeProgress->update();
1816 if (animated <= 0) {
1822 bool QMacStylePrivate::eventFilter(QObject *o, QEvent *e)
1825 if (QProgressBar *pb = qobject_cast<QProgressBar *>(o)) {
1826 switch (e->type()) {
1830 if (!progressBars.contains(pb))
1831 startAnimate(AquaProgressBar, pb);
1833 case QEvent::Destroy:
1835 progressBars.removeAll(pb);
1837 } else if (QPushButton *btn = qobject_cast<QPushButton *>(o)) {
1838 switch (e->type()) {
1841 case QEvent::FocusIn:
1842 if (btn->autoDefault())
1843 startAnimate(AquaPushButton, btn);
1845 case QEvent::Destroy:
1847 if (btn == defaultButton)
1848 stopAnimate(AquaPushButton, btn);
1850 case QEvent::MouseButtonPress:
1851 // It is very confusing to keep the button pulsing, so just stop the animation.
1852 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1854 stopAnimate(AquaPushButton, btn);
1856 case QEvent::MouseButtonRelease:
1857 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1860 case QEvent::FocusOut:
1862 case QEvent::WindowActivate: {
1863 QList<QPushButton *> list = qFindChildren<QPushButton *>(btn->window());
1864 for (int i = 0; i < list.size(); ++i) {
1865 QPushButton *pBtn = list.at(i);
1866 if ((e->type() == QEvent::FocusOut
1867 && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus()))
1869 || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease
1870 || e->type() == QEvent::WindowActivate)
1871 && pBtn->isDefault())) {
1872 if (pBtn->window()->isActiveWindow()) {
1873 startAnimate(AquaPushButton, pBtn);
1884 bool QMacStylePrivate::doAnimate(QMacStylePrivate::Animates as)
1886 if (as == AquaPushButton) {
1887 } else if (as == AquaProgressBar) {
1888 // something for later...
1889 } else if (as == AquaListViewItemOpen) {
1890 // To be revived later...
1895 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1896 QPainter *p, const QStyleOption *opt) const
1904 const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
1905 int width = int(macRect.size.width) + extraWidth;
1906 int height = int(macRect.size.height) + extraHeight;
1908 if (width <= 0 || height <= 0)
1909 return; // nothing to draw
1911 QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1912 + QString::number(bdi->value) + QLatin1Char('_') + QString::number(width)
1913 + QLatin1Char('_') + QString::number(height);
1915 if (!QPixmapCache::find(key, pm)) {
1916 QPixmap activePixmap(width, height);
1917 activePixmap.fill(Qt::transparent);
1920 // Carbon combos don't scale. Therefore we draw it
1921 // ourselves, if a scaled version is needed.
1922 QPainter tmpPainter(&activePixmap);
1923 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1926 QMacCGContext cg(&activePixmap);
1927 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1928 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1932 if (!combo && bdi->value == kThemeButtonOff) {
1935 QImage image = activePixmap.toImage();
1937 for (int y = 0; y < height; ++y) {
1938 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1940 for (int x = 0; x < width; ++x) {
1941 QRgb &pixel = scanLine[x];
1943 int darkest = qRed(pixel);
1944 int mid = qGreen(pixel);
1945 int lightest = qBlue(pixel);
1948 qSwap(darkest, mid);
1950 qSwap(mid, lightest);
1952 qSwap(darkest, mid);
1954 int gray = (mid + 2 * lightest) / 3;
1955 pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1958 pm = QPixmap::fromImage(image);
1960 QImage activeImage = activePixmap.toImage();
1961 QImage colorlessImage;
1963 QPixmap colorlessPixmap(width, height);
1964 colorlessPixmap.fill(Qt::transparent);
1966 QMacCGContext cg(&colorlessPixmap);
1967 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1968 int oldValue = bdi->value;
1969 bdi->value = kThemeButtonOff;
1970 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1971 bdi->value = oldValue;
1972 colorlessImage = colorlessPixmap.toImage();
1975 for (int y = 0; y < height; ++y) {
1976 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1977 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1979 for (int x = 0; x < width; ++x) {
1980 QRgb &colorlessPixel = colorlessScanLine[x];
1981 QRgb activePixel = activeScanLine[x];
1983 if (activePixel != colorlessPixel) {
1984 int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1985 qBlue(activePixel));
1986 QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1987 if (qGray(newPixel) < qGray(colorlessPixel)
1988 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1989 colorlessPixel = newPixel;
1993 pm = QPixmap::fromImage(colorlessImage);
1995 QPixmapCache::insert(key, pm);
1997 p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm);
2002 \brief The QMacStyle class provides a Mac OS X style using the Apple Appearance Manager.
2006 This class is implemented as a wrapper to the HITheme
2007 APIs, allowing applications to be styled according to the current
2008 theme in use on Mac OS X. This is done by having primitives
2009 in QStyle implemented in terms of what Mac OS X would normally theme.
2011 \warning This style is only available on Mac OS X because it relies on the
2014 There are additional issues that should be taken
2015 into consideration to make an application compatible with the
2016 \link http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html
2017 Apple Human Interface Guidelines \endlink. Some of these issues are outlined
2022 \i Layout - The restrictions on window layout are such that some
2023 aspects of layout that are style-dependent cannot be achieved
2024 using QLayout. Changes are being considered (and feedback would be
2025 appreciated) to make layouts QStyle-able. Some of the restrictions
2026 involve horizontal and vertical widget alignment and widget size
2029 \i Widget size - Mac OS X allows widgets to have specific fixed sizes. Qt
2030 does not fully implement this behavior so as to maintain cross-platform
2031 compatibility. As a result some widgets sizes may be inappropriate (and
2032 subsequently not rendered correctly by the HITheme APIs).The
2033 QWidget::sizeHint() will return the appropriate size for many
2034 managed widgets (widgets enumerated in \l QStyle::ContentsType).
2036 \i Effects - QMacStyle uses HITheme for performing most of the drawing, but
2037 also uses emulation in a few cases where HITheme does not provide the
2038 required functionality (for example, tab bars on Panther, the toolbar
2039 separator, etc). We tried to make the emulation as close to the original as
2040 possible. Please report any issues you see in effects or non-standard
2045 There are other issues that need to be considered in the feel of
2046 your application (including the general color scheme to match the
2047 Aqua colors). The Guidelines mentioned above will remain current
2048 with new advances and design suggestions for Mac OS X.
2050 Note that the functions provided by QMacStyle are
2051 reimplementations of QStyle functions; see QStyle for their
2055 \sa QWindowsXPStyle, QWindowsStyle, QPlastiqueStyle, QCDEStyle, QMotifStyle
2060 \enum QMacStyle::WidgetSizePolicy
2070 Constructs a QMacStyle object.
2072 QMacStyle::QMacStyle()
2075 d = new QMacStylePrivate(this);
2079 Destructs a QMacStyle object.
2081 QMacStyle::~QMacStyle()
2083 delete qt_mac_backgroundPattern;
2084 qt_mac_backgroundPattern = 0;
2089 Generates the standard widget background pattern.
2091 QPixmap QMacStylePrivate::generateBackgroundPattern() const
2094 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
2095 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
2096 QMacCGContext cg(&px);
2097 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
2098 const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
2099 CGContextFillRect(cg, cgRect);
2103 #ifndef QT_MAC_NO_QUICKDRAW
2104 QMacSavedPortInfo port(&px);
2105 SetThemeBackground(kThemeBrushDialogBackgroundActive, px.depth(), true);
2106 const Rect qdRect = { 0, 0, px.width(), px.height() };
2114 Fills the given \a rect with the pattern stored in \a brush. As an optimization,
2115 HIThemeSetFill us used directly if we are filling with the standard background.
2117 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush)
2119 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
2121 const QPaintDevice *target = painter->device();
2122 const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
2123 const bool usePainter = redirected && redirected != target;
2124 const QRegion translated = rgn.translated(offset);
2126 if (!usePainter && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 && qt_mac_backgroundPattern
2127 && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
2129 painter->setClipRegion(translated);
2131 CGContextRef cg = qt_mac_cg_context(target);
2132 CGContextSaveGState(cg);
2133 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
2135 const QVector<QRect> &rects = translated.rects();
2136 for (int i = 0; i < rects.size(); ++i) {
2137 const QRect rect(rects.at(i));
2138 // Anchor the pattern to the top so it stays put when the window is resized.
2139 CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
2140 CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
2141 CGContextFillRect(cg, mac_rect);
2144 CGContextRestoreGState(cg);
2148 const QRect rect(translated.boundingRect());
2149 painter->setClipRegion(translated);
2150 painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
2155 void QMacStyle::polish(QPalette &pal)
2157 if (qt_mac_backgroundPattern == 0)
2158 qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
2160 QColor pc(Qt::black);
2161 pc = qcolorForTheme(kThemeBrushDialogBackgroundActive);
2162 QBrush background(pc, *qt_mac_backgroundPattern);
2163 pal.setBrush(QPalette::All, QPalette::Window, background);
2164 pal.setBrush(QPalette::All, QPalette::Button, background);
2167 const OSErr err = CopyThemeIdentifier(&theme);
2168 if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
2169 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
2171 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
2176 void QMacStyle::polish(QApplication *)
2181 void QMacStyle::unpolish(QApplication *)
2186 void QMacStyle::polish(QWidget* w)
2189 if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
2190 // Set a clear brush so that the metal shines through.
2191 QPalette pal = w->palette();
2192 QBrush background(Qt::transparent);
2193 pal.setBrush(QPalette::All, QPalette::Window, background);
2194 pal.setBrush(QPalette::All, QPalette::Button, background);
2196 w->setAttribute(Qt::WA_SetPalette, false);
2199 if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
2200 w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
2201 if (!w->testAttribute(Qt::WA_SetPalette)) {
2203 HIThemeMenuDrawInfo mtinfo;
2204 mtinfo.version = qt_mac_hitheme_version;
2205 mtinfo.menuType = kThemeMenuTypePopUp;
2206 HIRect rect = CGRectMake(0, 0, px.width(), px.height());
2207 HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
2208 kHIThemeOrientationNormal);
2209 QPalette pal = w->palette();
2210 QBrush background(px);
2211 pal.setBrush(QPalette::All, QPalette::Window, background);
2212 pal.setBrush(QPalette::All, QPalette::Button, background);
2214 w->setAttribute(Qt::WA_SetPalette, false);
2218 // Adjust the lineedit of the editable combo box
2219 if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_3) {
2220 if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(w)) {
2221 if (qobject_cast<QComboBox *>(lineEdit->parentWidget())
2222 && !lineEdit->testAttribute(Qt::WA_SetFont)) {
2223 QFont font = lineEdit->font();
2224 font.setPointSize(font.pointSize() - 1);
2225 lineEdit->setFont(font);
2230 if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
2231 if (tb->documentMode()) {
2232 w->setAttribute(Qt::WA_Hover);
2233 w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2234 QPalette p = w->palette();
2235 p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2240 QWindowsStyle::polish(w);
2242 if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2243 rubber->setWindowOpacity(0.25);
2244 rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2245 rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2250 void QMacStyle::unpolish(QWidget* w)
2253 if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
2254 QPalette pal = qApp->palette(w);
2256 w->setAttribute(Qt::WA_SetPalette, false);
2257 w->setWindowOpacity(1.0);
2260 if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2261 if (!combo->isEditable()) {
2262 if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
2263 widget->setWindowOpacity(1.0);
2267 if (QRubberBand *rubber = ::qobject_cast<QRubberBand*>(w)) {
2268 rubber->setWindowOpacity(1.0);
2269 rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2270 rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2273 if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w)) {
2274 frame->setAttribute(Qt::WA_NoSystemBackground, true);
2275 frame->setAutoFillBackground(true);
2277 QWindowsStyle::unpolish(w);
2281 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
2283 int controlSize = getControlSize(opt, widget);
2287 case PM_TabCloseIndicatorWidth:
2288 case PM_TabCloseIndicatorHeight:
2289 ret = closeButtonSize;
2291 case PM_ToolBarIconSize:
2292 ret = pixelMetric(PM_LargeIconSize);
2294 case PM_FocusFrameVMargin:
2295 case PM_FocusFrameHMargin:
2296 GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
2298 case PM_DialogButtonsSeparator:
2301 case PM_DialogButtonsButtonHeight: {
2303 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2304 if (sz == QSize(-1, -1))
2309 case PM_CheckListButtonSize: {
2310 switch (d->aquaSizeConstrain(opt, widget)) {
2311 case QAquaSizeUnknown:
2312 case QAquaSizeLarge:
2313 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2316 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2318 case QAquaSizeSmall:
2319 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2323 case PM_DialogButtonsButtonWidth: {
2325 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2326 if (sz == QSize(-1, -1))
2332 case PM_MenuBarHMargin:
2336 case PM_MenuBarVMargin:
2340 case QStyle::PM_MenuDesktopFrameWidth:
2344 case PM_CheckBoxLabelSpacing:
2345 case PM_RadioButtonLabelSpacing:
2348 case PM_MenuScrollerHeight:
2351 GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2354 ret = 15; // I hate having magic numbers in here...
2357 case PM_DefaultFrameWidth:
2358 #ifndef QT_NO_MAINWINDOW
2359 if (widget && (widget->isWindow() || !widget->parentWidget()
2360 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2361 && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2362 && (qobject_cast<const QAbstractScrollArea *>(widget)
2364 || widget->inherits("QScrollView")
2366 || widget->inherits("QWorkspaceChild")))
2370 // The combo box popup has no frame.
2371 if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2374 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2376 case PM_MaximumDragDistance:
2379 case PM_ScrollBarSliderMin:
2382 case PM_SpinBoxFrameWidth:
2383 GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2386 case PM_ButtonShiftHorizontal:
2387 case PM_ButtonShiftVertical:
2390 case PM_SliderLength:
2393 case PM_ButtonDefaultIndicator:
2396 case PM_TitleBarHeight:
2397 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2398 HIThemeWindowDrawInfo wdi;
2399 wdi.version = qt_mac_hitheme_version;
2400 wdi.state = kThemeStateActive;
2401 wdi.windowType = QtWinType;
2402 if (tb->titleBarState)
2403 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2404 | kThemeWindowHasCollapseBox;
2405 else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2406 wdi.attributes = kThemeWindowHasCloseBox;
2409 wdi.titleHeight = tb->rect.height();
2410 wdi.titleWidth = tb->rect.width();
2411 QCFType<HIShapeRef> region;
2412 HIRect hirect = qt_hirectForQRect(tb->rect);
2413 if (hirect.size.width == -1)
2414 hirect.size.width = 100;
2415 if (hirect.size.height == -1)
2416 hirect.size.height = 30;
2418 HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, ®ion);
2420 ptrHIShapeGetBounds(region, &rect);
2421 ret = int(rect.size.height);
2425 case PM_TabBarTabVSpace:
2428 case PM_TabBarTabShiftHorizontal:
2429 case PM_TabBarTabShiftVertical:
2432 case PM_TabBarBaseHeight:
2435 case PM_TabBarTabOverlap:
2438 case PM_TabBarBaseOverlap:
2439 switch (d->aquaSizeConstrain(opt, widget)) {
2440 case QAquaSizeUnknown:
2441 case QAquaSizeLarge:
2444 case QAquaSizeSmall:
2452 case PM_ScrollBarExtent: {
2453 switch (d->aquaSizeConstrain(opt, widget)) {
2454 case QAquaSizeUnknown:
2455 case QAquaSizeLarge:
2456 GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2459 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) && 0
2460 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) {
2461 GetThemeMetric(kThemeMetricMiniScrollBarWidth, &ret);
2465 case QAquaSizeSmall:
2466 GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2470 case PM_IndicatorHeight: {
2471 switch (d->aquaSizeConstrain(opt, widget)) {
2472 case QAquaSizeUnknown:
2473 case QAquaSizeLarge:
2474 GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2477 GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2479 case QAquaSizeSmall:
2480 GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2484 case PM_IndicatorWidth: {
2485 switch (d->aquaSizeConstrain(opt, widget)) {
2486 case QAquaSizeUnknown:
2487 case QAquaSizeLarge:
2488 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2491 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2493 case QAquaSizeSmall:
2494 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2499 case PM_ExclusiveIndicatorHeight: {
2500 switch (d->aquaSizeConstrain(opt, widget)) {
2501 case QAquaSizeUnknown:
2502 case QAquaSizeLarge:
2503 GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2506 GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2508 case QAquaSizeSmall:
2509 GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2513 case PM_ExclusiveIndicatorWidth: {
2514 switch (d->aquaSizeConstrain(opt, widget)) {
2515 case QAquaSizeUnknown:
2516 case QAquaSizeLarge:
2517 GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2520 GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2522 case QAquaSizeSmall:
2523 GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2528 case PM_MenuVMargin:
2531 case PM_MenuPanelWidth:
2534 case PM_ToolTipLabelFrameWidth:
2537 case PM_SizeGripSize: {
2538 QAquaWidgetSize aSize;
2539 if (widget && widget->window()->windowType() == Qt::Tool)
2540 aSize = QAquaSizeSmall;
2542 aSize = QAquaSizeLarge;
2543 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2546 case PM_MdiSubWindowFrameWidth:
2549 case PM_DockWidgetFrameWidth:
2552 case PM_DockWidgetTitleMargin:
2555 case PM_DockWidgetSeparatorExtent:
2558 case PM_ToolBarHandleExtent:
2561 case PM_ToolBarItemMargin:
2564 case PM_ToolBarItemSpacing:
2567 case PM_MessageBoxIconSize:
2570 case PM_SplitterWidth:
2571 ret = qMax(7, QApplication::globalStrut().width());
2573 case PM_LayoutLeftMargin:
2574 case PM_LayoutTopMargin:
2575 case PM_LayoutRightMargin:
2576 case PM_LayoutBottomMargin:
2578 bool isWindow = false;
2580 isWindow = (opt->state & State_Window);
2581 } else if (widget) {
2582 isWindow = widget->isWindow();
2586 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2588 if (metric == PM_LayoutTopMargin) {
2589 return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2590 } else if (metric == PM_LayoutBottomMargin) {
2591 return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2593 return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2597 AHIG would have (20, 8, 10) here but that makes
2598 no sense. It would also have 14 for the top margin
2599 but this contradicts both Builder and most
2602 return_SIZE(20, 10, 10); // AHIG
2605 // hack to detect QTabWidget
2606 if (widget && widget->parentWidget()
2607 && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2608 if (metric == PM_LayoutTopMargin) {
2610 Builder would have 14 (= 20 - 6) instead of 12,
2611 but that makes the tab look disproportionate.
2613 return_SIZE(12, 6, 6); // guess
2615 return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2619 Child margins are highly inconsistent in AHIG and Builder.
2621 return_SIZE(12, 8, 6); // guess
2625 case PM_LayoutHorizontalSpacing:
2626 case PM_LayoutVerticalSpacing:
2628 case QStyle::PM_TabBarTabHSpace:
2629 switch (d->aquaSizeConstrain(opt, widget)) {
2630 case QAquaSizeLarge:
2631 case QAquaSizeUnknown:
2632 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2634 case QAquaSizeSmall:
2642 case PM_MenuHMargin:
2646 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2653 QPalette QMacStyle::standardPalette() const
2655 QPalette pal = QWindowsStyle::standardPalette();
2656 pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2657 pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2658 pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2663 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2664 QStyleHintReturn *hret) const
2668 case SH_Menu_SelectionWrap:
2671 case SH_Menu_KeyboardSearch:
2674 case SH_Menu_SpaceActivatesItem:
2677 case SH_Slider_AbsoluteSetButtons:
2678 ret = Qt::LeftButton|Qt::MidButton;
2680 case SH_Slider_PageSetButtons:
2683 case SH_ScrollBar_ContextMenu:
2686 case SH_TitleBar_AutoRaise:
2689 case SH_Menu_AllowActiveAndDisabled:
2692 case SH_Menu_SubMenuPopupDelay:
2695 case SH_ScrollBar_LeftClickAbsolutePosition: {
2696 extern bool qt_scrollbar_jump_to_pos; //qapplication_mac.cpp
2697 if(QApplication::keyboardModifiers() & Qt::AltModifier)
2698 ret = !qt_scrollbar_jump_to_pos;
2700 ret = qt_scrollbar_jump_to_pos;
2702 case SH_TabBar_PreferNoArrows:
2705 case SH_LineEdit_PasswordCharacter:
2706 ret = kBulletUnicode;
2709 case SH_DialogButtons_DefaultButton:
2710 ret = QDialogButtons::Reject;
2713 case SH_Menu_SloppySubMenus:
2716 case SH_GroupBox_TextLabelVerticalAlignment:
2719 case SH_ScrollView_FrameOnlyAroundContents:
2720 if (w && (w->isWindow() || !w->parentWidget() || w->parentWidget()->isWindow())
2721 && (w->inherits("QWorkspaceChild")
2723 || w->inherits("QScrollView")
2728 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2730 case SH_Menu_FillScreenWithScroll:
2733 case SH_Menu_Scrollable:
2736 case SH_RichText_FullWidthSelection:
2739 case SH_BlinkCursorWhenTextSelected:
2742 case SH_ScrollBar_StopMouseOverSlider:
2745 case SH_Q3ListViewExpand_SelectMouseType:
2746 ret = QEvent::MouseButtonRelease;
2748 case SH_TabBar_SelectMouseType:
2749 if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2750 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2752 ret = QEvent::MouseButtonRelease;
2755 case SH_ComboBox_Popup:
2756 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2757 ret = !cmb->editable;
2761 case SH_Workspace_FillSpaceOnMaximize:
2764 case SH_Widget_ShareActivation:
2767 case SH_Header_ArrowAlignment:
2768 ret = Qt::AlignRight;
2770 case SH_TabBar_Alignment: {
2771 if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2772 if (tab->documentMode()) {
2773 ret = Qt::AlignLeft;
2777 if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2778 if (tab->documentMode()) {
2779 ret = Qt::AlignLeft;
2783 ret = Qt::AlignCenter;
2785 case SH_UnderlineShortcut:
2788 case SH_ToolTipLabel_Opacity:
2789 ret = 242; // About 95%
2791 case SH_Button_FocusPolicy:
2794 case SH_EtchDisabledText:
2797 case SH_FocusFrame_Mask: {
2799 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2800 const uchar fillR = 192, fillG = 191, fillB = 190;
2803 QSize pixmapSize = opt->rect.size();
2804 if (pixmapSize.isValid()) {
2805 QPixmap pix(pixmapSize);
2806 pix.fill(QColor(fillR, fillG, fillB));
2807 QPainter pix_paint(&pix);
2808 drawControl(CE_FocusFrame, opt, &pix_paint, w);
2810 img = pix.toImage();
2813 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2814 const int sbpl = img.bytesPerLine();
2815 const int w = sbpl/4, h = img.height();
2817 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2818 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2819 const int dbpl = img_mask.bytesPerLine();
2821 for (int y = 0; y < h; ++y) {
2822 srow = sptr+((y*sbpl)/4);
2823 drow = dptr+((y*dbpl)/4);
2824 for (int x = 0; x < w; ++x) {
2825 const int diff = (((qRed(*srow)-fillR)*(qRed(*srow)-fillR)) +
2826 ((qGreen(*srow)-fillG)*((qGreen(*srow)-fillG))) +
2827 ((qBlue(*srow)-fillB)*((qBlue(*srow)-fillB))));
2828 (*drow++) = (diff < 100) ? 0xffffffff : 0xff000000;
2832 QBitmap qmask = QBitmap::fromImage(img_mask);
2833 mask->region = QRegion(qmask);
2836 case SH_TitleBar_NoBorder:
2839 case SH_RubberBand_Mask:
2842 case SH_ComboBox_LayoutDirection:
2843 ret = Qt::LeftToRight;
2845 case SH_ItemView_EllipsisLocation:
2846 ret = Qt::AlignHCenter;
2848 case SH_ItemView_ShowDecorationSelected:
2851 case SH_TitleBar_ModifyNotification:
2854 case SH_ScrollBar_RollBetweenButtons:
2857 case SH_WindowFrame_Mask:
2859 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2860 mask->region = opt->rect;
2861 mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2862 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2863 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2864 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2866 mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2867 mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2868 mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2869 mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2872 case SH_TabBar_ElideMode:
2873 ret = Qt::ElideRight;
2875 case SH_DialogButtonLayout:
2876 ret = QDialogButtonBox::MacLayout;
2878 case SH_FormLayoutWrapPolicy:
2879 ret = QFormLayout::DontWrapRows;
2881 case SH_FormLayoutFieldGrowthPolicy:
2882 ret = QFormLayout::FieldsStayAtSizeHint;
2884 case SH_FormLayoutFormAlignment:
2885 ret = Qt::AlignHCenter | Qt::AlignTop;
2887 case SH_FormLayoutLabelAlignment:
2888 ret = Qt::AlignRight;
2890 case SH_ComboBox_PopupFrameStyle:
2891 ret = QFrame::NoFrame | QFrame::Plain;
2893 case SH_MessageBox_TextInteractionFlags:
2894 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2896 case SH_SpellCheckUnderlineStyle:
2897 ret = QTextCharFormat::DashUnderline;
2899 case SH_MessageBox_CenterButtons:
2902 case SH_MenuBar_AltKeyNavigation:
2905 case SH_ItemView_MovementWithoutUpdatingSelection:
2908 case SH_FocusFrame_AboveWidget:
2911 case SH_WizardStyle:
2912 ret = QWizard::MacStyle;
2914 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2917 case SH_Menu_FlashTriggeredItem:
2920 case SH_Menu_FadeOutOnHide:
2925 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2927 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2928 opt->rect.width(), opt->rect.height() - 8);
2929 HIThemeMenuDrawInfo mdi;
2931 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2932 mdi.menuType = kThemeMenuTypeHierarchical;
2934 mdi.menuType = kThemeMenuTypePopUp;
2935 QCFType<HIShapeRef> shape;
2936 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2937 mask->region = QRegion::fromHIShapeRef(shape);
2941 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2944 case SH_TabBar_CloseButtonPosition:
2945 ret = QTabBar::LeftSide;
2947 case SH_DockWidget_ButtonsHaveFrame:
2951 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2958 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2959 const QStyleOption *opt) const
2962 case QIcon::Disabled: {
2963 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2964 int imgh = img.height();
2965 int imgw = img.width();
2967 for (int y = 0; y < imgh; ++y) {
2968 for (int x = 0; x < imgw; ++x) {
2969 pixel = img.pixel(x, y);
2970 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2971 qAlpha(pixel) / 2));
2974 return QPixmap::fromImage(img);
2979 return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt);
2984 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2985 const QWidget *widget) const
2987 // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2988 // I don't want infinite recursion so if we do get in that situation, just return the Window's
2989 // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2990 // someone changes how Windows standard
2992 static bool recursionGuard = false;
2995 return QWindowsStyle::standardPixmap(standardPixmap, opt, widget);
2997 recursionGuard = true;
2998 QIcon icon = standardIconImplementation(standardPixmap, opt, widget);
2999 recursionGuard = false;
3001 switch (standardPixmap) {
3005 case SP_MessageBoxCritical:
3006 case SP_MessageBoxQuestion:
3007 case SP_MessageBoxInformation:
3008 case SP_MessageBoxWarning:
3012 return icon.pixmap(size, size);
3015 \enum QMacStyle::FocusRectPolicy
3017 This type is used to signify a widget's focus rectangle policy.
3019 \value FocusEnabled show a focus rectangle when the widget has focus.
3020 \value FocusDisabled never show a focus rectangle for the widget.
3021 \value FocusDefault show a focus rectangle when the widget has
3022 focus and the widget is a QSpinWidget, QDateTimeEdit, QLineEdit,
3023 QListBox, QListView, editable QTextEdit, or one of their
3029 Sets the focus rectangle policy of \a w. The \a policy can be one of
3030 \l{QMacStyle::FocusRectPolicy}.
3032 This is now simply an interface to the Qt::WA_MacShowFocusRect attribute and the
3033 FocusDefault value does nothing anymore. If you want to set a widget back
3034 to its default value, you must save the old value of the attribute before
3037 \sa focusRectPolicy() QWidget::setAttribute()
3039 void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
3046 w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
3053 Returns the focus rectangle policy for the widget \a w.
3055 The focus rectangle policy can be one of \l{QMacStyle::FocusRectPolicy}.
3057 In 4.3 and up this function will simply test for the
3058 Qt::WA_MacShowFocusRect attribute and will never return
3059 QMacStyle::FocusDefault.
3061 \sa setFocusRectPolicy(), QWidget::testAttribute()
3063 QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
3065 return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
3071 Call QWidget::setAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize,
3072 or Qt::WA_MacNormalSize instead.
3074 void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
3076 QWidget *wadget = const_cast<QWidget *>(widget);
3077 wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge);
3078 wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall);
3079 wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini);
3085 Call QWidget::testAttribute() with Qt::WA_MacMiniSize, Qt::WA_MacSmallSize,
3086 or Qt::WA_MacNormalSize instead.
3088 QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget)
3091 if (widget->testAttribute(Qt::WA_MacMiniSize)) {
3093 } else if (widget->testAttribute(Qt::WA_MacSmallSize)) {
3095 } else if (widget->testAttribute(Qt::WA_MacNormalSize)) {
3098 widget = widget->parentWidget();
3104 void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
3105 const QWidget *w) const
3107 ThemeDrawState tds = d->getDrawState(opt->state);
3108 QMacCGContext cg(p);
3110 case PE_IndicatorArrowUp:
3111 case PE_IndicatorArrowDown:
3112 case PE_IndicatorArrowRight:
3113 case PE_IndicatorArrowLeft: {
3115 p->setRenderHint(QPainter::Antialiasing);
3116 int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
3118 matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
3122 case PE_IndicatorArrowDown:
3124 case PE_IndicatorArrowUp:
3127 case PE_IndicatorArrowLeft:
3130 case PE_IndicatorArrowRight:
3135 path.lineTo(-4, -3);
3137 p->setMatrix(matrix);
3138 p->setPen(Qt::NoPen);
3139 p->setBrush(QColor(0, 0, 0, 135));
3143 case PE_FrameTabBarBase:
3144 if (const QStyleOptionTabBarBaseV2 *tbb
3145 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
3146 if (tbb->documentMode) {
3148 drawTabBase(p, tbb, w);
3153 QRegion region(tbb->rect);
3154 region -= tbb->tabBarRect;
3156 p->setClipRegion(region);
3157 QStyleOptionTabWidgetFrame twf;
3158 twf.QStyleOption::operator=(*tbb);
3159 twf.shape = tbb->shape;
3160 switch (getTabDirection(twf.shape)) {
3161 case kThemeTabNorth:
3162 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
3164 case kThemeTabSouth:
3165 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3168 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
3171 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
3174 drawPrimitive(PE_FrameTabWidget, &twf, p, w);
3178 case PE_PanelTipLabel:
3179 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
3181 case PE_FrameGroupBox:
3182 if (const QStyleOptionFrame *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3183 const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt);
3184 if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) {
3185 QWindowsStyle::drawPrimitive(pe, groupBox, p, w);
3187 HIThemeGroupBoxDrawInfo gdi;
3188 gdi.version = qt_mac_hitheme_version;
3190 if (w && qobject_cast<QGroupBox *>(w->parentWidget()))
3191 gdi.kind = kHIThemeGroupBoxKindSecondary;
3193 gdi.kind = kHIThemeGroupBoxKindPrimary;
3194 HIRect hirect = qt_hirectForQRect(opt->rect);
3195 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
3199 case PE_IndicatorToolBarSeparator: {
3201 if (opt->state & State_Horizontal) {
3202 int xpoint = opt->rect.center().x();
3203 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
3204 path.lineTo(xpoint + 0.5, opt->rect.bottom());
3206 int ypoint = opt->rect.center().y();
3207 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
3208 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3210 QPainterPathStroker theStroker;
3211 theStroker.setCapStyle(Qt::FlatCap);
3212 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3213 path = theStroker.createStroke(path);
3214 p->fillPath(path, QColor(0, 0, 0, 119));
3217 case PE_FrameWindow:
3219 case PE_IndicatorDockWidgetResizeHandle: {
3220 // The docwidget resize handle is drawn as a one-pixel wide line.
3222 if (opt->state & State_Horizontal) {
3223 p->setPen(QColor(160, 160, 160));
3224 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3226 p->setPen(QColor(145, 145, 145));
3227 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3231 case PE_IndicatorToolBarHandle: {
3234 int x = opt->rect.x() + 6;
3235 int y = opt->rect.y() + 5;
3236 static const int RectHeight = 2;
3237 if (opt->state & State_Horizontal) {
3238 while (y < opt->rect.height() - RectHeight - 6) {
3240 path.addRect(x, y, RectHeight, RectHeight);
3244 while (x < opt->rect.width() - RectHeight - 6) {
3246 path.addRect(x, y, RectHeight, RectHeight);
3250 p->setPen(Qt::NoPen);
3251 QColor dark = opt->palette.dark().color();
3252 dark.setAlphaF(0.75);
3253 QColor light = opt->palette.light().color();
3254 light.setAlphaF(0.6);
3255 p->fillPath(path, light);
3258 p->fillPath(path, dark);
3261 p->fillPath(path, light);
3263 p->fillPath(path, dark);
3268 case PE_IndicatorHeaderArrow:
3269 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3270 // In HITheme, up is down, down is up and hamburgers eat people.
3271 if (header->sortIndicator != QStyleOptionHeader::None)
3273 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3274 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3277 case PE_IndicatorMenuCheckMark: {
3278 const int checkw = 8;
3279 const int checkh = 8;
3280 const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
3281 const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
3282 const int x1 = xoff + opt->rect.x();
3283 const int y1 = yoff + opt->rect.y() + checkw/2;
3284 const int x2 = xoff + opt->rect.x() + checkw/4;
3285 const int y2 = yoff + opt->rect.y() + checkh;
3286 const int x3 = xoff + opt->rect.x() + checkw;
3287 const int y3 = yoff + opt->rect.y();
3289 QVector<QLineF> a(2);
3290 a << QLineF(x1, y1, x2, y2);
3291 a << QLineF(x2, y2, x3, y3);
3292 if (opt->palette.currentColorGroup() == QPalette::Active)
3293 p->setPen(QPen(Qt::white, 3));
3295 p->setPen(QPen(QColor(100, 100, 100), 3));
3297 p->setRenderHint(QPainter::Antialiasing);
3301 case PE_IndicatorViewItemCheck:
3302 case PE_Q3CheckListExclusiveIndicator:
3303 case PE_Q3CheckListIndicator:
3304 case PE_IndicatorRadioButton:
3305 case PE_IndicatorCheckBox: {
3306 bool drawColorless = (!(opt->state & State_Active))
3307 && opt->palette.currentColorGroup() == QPalette::Active;
3308 HIThemeButtonDrawInfo bdi;
3309 bdi.version = qt_mac_hitheme_version;
3311 if (drawColorless && tds == kThemeStateInactive)
3312 bdi.state = kThemeStateActive;
3313 bdi.adornment = kThemeDrawIndicatorOnly;
3314 if (opt->state & State_HasFocus)
3315 bdi.adornment |= kThemeAdornmentFocus;
3316 bool isRadioButton = (pe == PE_Q3CheckListExclusiveIndicator
3317 || pe == PE_IndicatorRadioButton);
3318 switch (d->aquaSizeConstrain(opt, w)) {
3319 case QAquaSizeUnknown:
3320 case QAquaSizeLarge:
3322 bdi.kind = kThemeRadioButton;
3324 bdi.kind = kThemeCheckBox;
3328 bdi.kind = kThemeMiniRadioButton;
3330 bdi.kind = kThemeMiniCheckBox;
3332 case QAquaSizeSmall:
3334 bdi.kind = kThemeSmallRadioButton;
3336 bdi.kind = kThemeSmallCheckBox;
3339 if (opt->state & State_NoChange)
3340 bdi.value = kThemeButtonMixed;
3341 else if (opt->state & State_On)
3342 bdi.value = kThemeButtonOn;
3344 bdi.value = kThemeButtonOff;
3346 if (pe == PE_Q3CheckListExclusiveIndicator || pe == PE_Q3CheckListIndicator)
3347 macRect = qt_hirectForQRect(opt->rect);
3349 macRect = qt_hirectForQRect(opt->rect);
3351 HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3353 d->drawColorlessButton(macRect, &bdi, p, opt);
3355 case PE_FrameFocusRect:
3356 // Use the our own focus widget stuff.
3358 case PE_IndicatorBranch: {
3359 if (!(opt->state & State_Children))
3361 HIThemeButtonDrawInfo bi;
3362 bi.version = qt_mac_hitheme_version;
3364 if (tds == kThemeStateInactive && opt->palette.currentColorGroup() == QPalette::Active)
3365 bi.state = kThemeStateActive;
3366 if (opt->state & State_Sunken)
3367 bi.state |= kThemeStatePressed;
3368 bi.kind = kThemeDisclosureButton;
3369 if (opt->state & State_Open)
3370 bi.value = kThemeDisclosureDown;
3372 bi.value = opt->direction == Qt::LeftToRight ? kThemeDisclosureRight : kThemeDisclosureLeft;
3373 bi.adornment = kThemeAdornmentNone;
3374 HIRect hirect = qt_hirectForQRect(opt->rect);
3375 HIThemeDrawButton(&hirect, &bi, cg, kHIThemeOrientationNormal, 0);
3378 QPen oldPen = p->pen();
3380 newPen.setBrush(opt->palette.dark());
3382 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3385 case PE_FrameLineEdit:
3386 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3387 if (frame->state & State_Sunken) {
3388 QColor baseColor(frame->palette.background().color());
3389 HIThemeFrameDrawInfo fdi;
3390 fdi.version = qt_mac_hitheme_version;
3393 if (pe == PE_FrameLineEdit) {
3394 fdi.kind = kHIThemeFrameTextFieldSquare;
3395 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
3396 if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled))
3397 fdi.state = kThemeStateInactive;
3399 baseColor = QColor(150, 150, 150); //hardcoded since no query function --Sam
3400 fdi.kind = kHIThemeFrameListBox;
3401 GetThemeMetric(kThemeMetricListBoxFrameOutset, &frame_size);
3403 fdi.isFocused = (frame->state & State_HasFocus);
3404 int lw = frame->lineWidth;
3406 lw = pixelMetric(PM_DefaultFrameWidth, frame, w);
3407 { //clear to base color
3409 p->setPen(QPen(baseColor, lw));
3410 p->setBrush(Qt::NoBrush);
3411 p->drawRect(frame->rect);
3414 HIRect hirect = qt_hirectForQRect(frame->rect,
3415 QRect(frame_size, frame_size,
3416 frame_size * 2, frame_size * 2));
3418 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
3420 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3424 case PE_PanelLineEdit:
3425 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3427 case PE_FrameTabWidget:
3428 if (const QStyleOptionTabWidgetFrame *twf
3429 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
3430 HIRect hirect = qt_hirectForQRect(twf->rect);
3431 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
3432 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
3433 HIThemeTabPaneDrawInfo tpdi;
3434 tpdi.version = qt_mac_hitheme_tab_version();
3436 tpdi.direction = getTabDirection(twf->shape);
3437 tpdi.size = kHIThemeTabSizeNormal;
3438 if (tpdi.version == 1) {
3439 tpdi.kind = kHIThemeTabKindNormal;
3440 tpdi.adornment = kHIThemeTabPaneAdornmentNormal;
3442 HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal);
3446 HIThemeGroupBoxDrawInfo gdi;
3447 gdi.version = qt_mac_hitheme_version;
3449 gdi.kind = kHIThemeGroupBoxKindSecondary;
3450 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
3454 case PE_PanelScrollAreaCorner: {
3455 const QBrush brush(qApp->palette().brush(QPalette::Base));
3456 p->fillRect(opt->rect, brush);
3457 p->setPen(QPen(QColor(217, 217, 217)));
3458 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3459 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3461 case PE_FrameStatusBarItem:
3462 QCommonStyle::drawPrimitive(pe, opt, p, w);
3464 case PE_IndicatorTabClose: {
3465 bool hover = (opt->state & State_MouseOver);
3466 bool selected = (opt->state & State_Selected);
3467 bool active = (opt->state & State_Active);
3468 drawTabCloseButton(p, hover, active, selected);
3470 case PE_PanelStatusBar: {
3471 if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) {
3472 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3476 // Use the Leopard style only if the status bar is the status bar for a
3477 // QMainWindow with a unifed toolbar.
3478 if (w == 0 || w->parent() == 0 || qobject_cast<QMainWindow *>(w->parent()) == 0 ||
3479 qobject_cast<QMainWindow *>(w->parent())->unifiedTitleAndToolBarOnMac() == false ) {
3480 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3484 // Fill the status bar with the titlebar gradient.
3485 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3486 if (opt->state & QStyle::State_Active) {
3487 linearGrad.setColorAt(0, titlebarGradientActiveBegin);
3488 linearGrad.setColorAt(1, titlebarGradientActiveEnd);
3490 linearGrad.setColorAt(0, titlebarGradientInactiveBegin);
3491 linearGrad.setColorAt(1, titlebarGradientInactiveEnd);
3493 p->fillRect(opt->rect, linearGrad);
3495 // Draw the black separator line at the top of the status bar.
3496 if (opt->state & QStyle::State_Active)
3497 p->setPen(titlebarSeparatorLineActive);
3499 p->setPen(titlebarSeparatorLineInactive);
3500 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3506 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3511 static inline QPixmap darkenPixmap(const QPixmap &pixmap)
3513 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
3514 int imgh = img.height();
3515 int imgw = img.width();
3518 for (int y = 0; y < imgh; ++y) {
3519 for (int x = 0; x < imgw; ++x) {
3520 pixel = img.pixel(x, y);
3522 QColor hsvColor(pixel);
3523 hsvColor.getHsv(&h, &s, &v);
3524 s = qMin(100, s * 2);
3526 hsvColor.setHsv(h, s, v);
3527 pixel = hsvColor.rgb();
3528 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3531 return QPixmap::fromImage(img);
3537 void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3538 const QWidget *w) const
3540 ThemeDrawState tds = d->getDrawState(opt->state);
3541 QMacCGContext cg(p);
3543 case CE_HeaderSection:
3544 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3545 HIThemeButtonDrawInfo bdi;
3546 bdi.version = qt_mac_hitheme_version;
3547 State flags = header->state;
3548 QRect ir = header->rect;
3549 bdi.kind = kThemeListHeaderButton;
3550 bdi.adornment = kThemeAdornmentNone;
3551 bdi.state = kThemeStateActive;
3553 if (flags & State_On)
3554 bdi.value = kThemeButtonOn;
3556 bdi.value = kThemeButtonOff;
3558 if (header->orientation == Qt::Horizontal){
3559 switch (header->position) {
3560 case QStyleOptionHeader::Beginning:
3562 case QStyleOptionHeader::Middle:
3563 case QStyleOptionHeader::End:
3564 ir.adjust(-1, 0, 0, 0);
3570 if (header->position != QStyleOptionHeader::Beginning
3571 && header->position != QStyleOptionHeader::OnlyOneSection) {
3572 bdi.adornment = header->direction == Qt::LeftToRight
3573 ? kThemeAdornmentHeaderButtonLeftNeighborSelected
3574 : kThemeAdornmentHeaderButtonRightNeighborSelected;
3578 if (flags & State_Active) {
3579 if (!(flags & State_Enabled))
3580 bdi.state = kThemeStateUnavailable;
3581 else if (flags & State_Sunken)
3582 bdi.state = kThemeStatePressed;
3584 if (flags & State_Enabled)
3585 bdi.state = kThemeStateInactive;
3587 bdi.state = kThemeStateUnavailableInactive;
3590 if (header->sortIndicator != QStyleOptionHeader::None) {
3591 bdi.value = kThemeButtonOn;
3592 if (header->sortIndicator == QStyleOptionHeader::SortDown)
3593 bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
3595 if (flags & State_HasFocus)
3596 bdi.adornment = kThemeAdornmentFocus;
3598 ir = visualRect(header->direction, header->rect, ir);
3599 HIRect bounds = qt_hirectForQRect(ir);
3601 bool noVerticalHeader = true;
3603 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3604 noVerticalHeader = !table->verticalHeader()->isVisible();
3606 bool drawTopBorder = header->orientation == Qt::Horizontal;
3607 bool drawLeftBorder = header->orientation == Qt::Vertical
3608 || header->position == QStyleOptionHeader::OnlyOneSection
3609 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3610 d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
3613 case CE_HeaderLabel:
3614 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3615 QRect textr = header->rect;
3616 if (!header->icon.isNull()) {
3617 QIcon::Mode mode = QIcon::Disabled;
3618 if (opt->state & State_Enabled)
3619 mode = QIcon::Normal;
3620 QPixmap pixmap = header->icon.pixmap(pixelMetric(PM_SmallIconSize), mode);
3622 QRect pixr = header->rect;
3623 pixr.setY(header->rect.center().y() - (pixmap.height() - 1) / 2);
3624 drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
3625 textr.translate(pixmap.width() + 2, 0);
3628 drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
3629 header->state & State_Enabled, header->text, QPalette::ButtonText);
3632 case CE_ToolButtonLabel:
3633 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3634 QStyleOptionToolButton myTb = *tb;
3635 myTb.state &= ~State_AutoRaise;
3636 if (w && qobject_cast<QToolBar *>(w->parentWidget())) {
3637 QRect cr = tb->rect;
3640 bool needText = false;
3642 bool down = tb->state & (State_Sunken | State_On);
3644 shiftX = pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3645 shiftY = pixelMetric(PM_ButtonShiftVertical, tb, w);
3647 // The down state is special for QToolButtons in a toolbar on the Mac
3648 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3649 // This doesn't really fit into any particular case in QIcon, so we
3650 // do the majority of the work ourselves.
3651 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3652 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3653 if (tb->icon.isNull() && !tb->text.isEmpty())
3654 tbstyle = Qt::ToolButtonTextOnly;
3657 case Qt::ToolButtonTextOnly: {
3659 alignment = Qt::AlignCenter;
3661 case Qt::ToolButtonIconOnly:
3662 case Qt::ToolButtonTextBesideIcon:
3663 case Qt::ToolButtonTextUnderIcon: {
3665 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3667 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3669 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), iconMode, iconState);
3671 // Draw the text if it's needed.
3672 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3674 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3675 pr.setHeight(pixmap.size().height() + 6);
3676 cr.adjust(0, pr.bottom(), 0, -3);
3677 alignment |= Qt::AlignCenter;
3679 pr.setWidth(pixmap.width() + 8);
3680 cr.adjust(pr.right(), 0, 0, 0);
3681 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3685 pr.translate(shiftX, shiftY);
3686 pixmap = darkenPixmap(pixmap);
3688 drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3693 QPalette pal = tb->palette;
3694 QPalette::ColorRole role = QPalette::NoRole;
3696 cr.translate(shiftX, shiftY);
3697 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5
3698 && (tbstyle == Qt::ToolButtonTextOnly
3699 || (tbstyle != Qt::ToolButtonTextOnly && !down))) {
3700 QPen pen = p->pen();
3701 QColor light = down ? Qt::black : Qt::white;
3702 light.setAlphaF(0.375f);
3704 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3706 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3707 pal = QApplication::palette("QMenu");
3708 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3709 role = QPalette::HighlightedText;
3712 drawItemText(p, cr, alignment, pal,
3713 tb->state & State_Enabled, tb->text, role);
3714 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && down) {
3715 // Draw a "drop shadow" in earlier versions.
3716 drawItemText(p, cr.adjusted(0, 1, 0, 1), alignment,
3717 tb->palette, tb->state & State_Enabled, tb->text);
3721 QWindowsStyle::drawControl(ce, &myTb, p, w);
3724 QWindowsStyle::drawControl(ce, &myTb, p, w);
3728 case CE_ToolBoxTabShape:
3729 QCommonStyle::drawControl(ce, opt, p, w);
3731 case CE_PushButtonBevel:
3732 if (const QStyleOptionButton *btn = ::qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3733 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3736 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3737 QWindowsStyle::drawControl(ce, opt, p, w);
3741 HIThemeButtonDrawInfo bdi;
3742 d->initHIThemePushButton(btn, w, tds, &bdi);
3743 if (btn->features & QStyleOptionButton::DefaultButton
3744 && d->animatable(QMacStylePrivate::AquaPushButton, w)) {
3745 bdi.adornment |= kThemeAdornmentDefault;
3746 bdi.animation.time.start = d->defaultButtonStart;
3747 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
3748 if (d->timerID <= -1)
3749 QMetaObject::invokeMethod(d, "startAnimationTimer", Qt::QueuedConnection);
3751 // Unlike Carbon, we want the button to always be drawn inside its bounds.
3752 // Therefore, make the button a bit smaller, so that even if it got focus,
3753 // the focus 'shadow' will be inside.
3754 HIRect newRect = qt_hirectForQRect(btn->rect);
3755 if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) {
3756 newRect.origin.x += PushButtonLeftOffset;
3757 newRect.origin.y += PushButtonTopOffset;
3758 newRect.size.width -= PushButtonRightOffset;
3759 newRect.size.height -= PushButtonBottomOffset;
3760 } else if (bdi.kind == kThemePushButtonMini) {
3761 newRect.origin.x += PushButtonLeftOffset - 2;
3762 newRect.origin.y += PushButtonTopOffset;
3763 newRect.size.width -= PushButtonRightOffset - 4;
3765 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3767 if (btn->features & QStyleOptionButton::HasMenu) {
3768 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3769 QRect ir = btn->rect;
3770 HIRect arrowRect = CGRectMake(ir.right() - mbi - PushButtonRightOffset,
3771 ir.height() / 2 - 4, mbi, ir.height() / 2);
3772 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
3773 if (drawColorless && tds == kThemeStateInactive)
3774 tds = kThemeStateActive;
3776 HIThemePopupArrowDrawInfo pdi;
3777 pdi.version = qt_mac_hitheme_version;
3779 pdi.orientation = kThemeArrowDown;
3780 if (arrowRect.size.width < 8.)
3781 pdi.size = kThemeArrow5pt;
3783 pdi.size = kThemeArrow9pt;
3784 HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal);
3788 case CE_PushButtonLabel:
3789 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3790 // We really don't want the label to be drawn the same as on
3791 // windows style if it has an icon and text, then it should be more like a
3792 // tab. So, cheat a little here. However, if it *is* only an icon
3793 // the windows style works great, so just use that implementation.
3794 bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3795 bool hasIcon = !btn->icon.isNull();
3796 bool hasText = !btn->text.isEmpty();
3797 if (!hasIcon && !hasMenu) {
3798 // ### this is really overly difficult, simplify.
3799 // It basically tries to get the right font for "small" and "mini" icons.
3800 QFont oldFont = p->font();
3801 QFont newFont = qt_app_fonts_hash()->value("QPushButton", QFont());
3802 ThemeFontID themeId = kThemePushButtonFont;
3803 if (oldFont == newFont) { // Yes, use HITheme to draw the text for small sizes.
3804 switch (d->aquaSizeConstrain(opt, w)) {
3807 case QAquaSizeSmall:
3808 themeId = kThemeSmallSystemFont;
3811 themeId = kThemeMiniSystemFont;
3815 if (themeId == kThemePushButtonFont) {
3816 QWindowsStyle::drawControl(ce, btn, p, w);
3819 CGContextSetShouldAntialias(cg, true);
3820 CGContextSetShouldSmoothFonts(cg, true);
3821 HIThemeTextInfo tti;
3822 tti.version = qt_mac_hitheme_version;
3824 QColor textColor = btn->palette.buttonText().color();
3825 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3826 textColor.blueF(), textColor.alphaF() };
3827 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
3828 CGContextSetFillColor(cg, colorComp);
3829 tti.fontID = themeId;
3830 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3831 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3832 tti.options = kHIThemeTextBoxOptionNone;
3833 tti.truncationPosition = kHIThemeTextTruncationNone;
3834 tti.truncationMaxLines = 1 + btn->text.count(QLatin1Char('\n'));
3835 QCFString buttonText = qt_mac_removeMnemonics(btn->text);
3836 QRect r = btn->rect;
3837 HIRect bounds = qt_hirectForQRect(r);
3838 HIThemeDrawTextBox(buttonText, &bounds, &tti,
3839 cg, kHIThemeOrientationNormal);
3843 if (hasIcon && !hasText) {
3844 QWindowsStyle::drawControl(ce, btn, p, w);
3846 QRect freeContentRect = btn->rect;
3847 QRect textRect = itemTextRect(
3848 btn->fontMetrics, freeContentRect, Qt::AlignCenter, btn->state & State_Enabled, btn->text);
3850 textRect.adjust(-1, 0, -1, 0);
3853 int contentW = textRect.width();
3855 contentW += pixelMetric(PM_MenuButtonIndicator) + 4;
3856 QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3857 if (mode == QIcon::Normal && btn->state & State_HasFocus)
3858 mode = QIcon::Active;
3859 // Decide if the icon is should be on or off:
3860 QIcon::State state = QIcon::Off;
3861 if (btn->state & State_On)
3863 QPixmap pixmap = btn->icon.pixmap(btn->iconSize, mode, state);
3864 contentW += pixmap.width() + PushButtonContentPadding;
3865 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3866 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmap.height()) / 2;
3867 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmap.width(), pixmap.height());
3868 QRect visualIconDestRect = visualRect(btn->direction, freeContentRect, iconDestRect);
3869 drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3870 int newOffset = iconDestRect.x() + iconDestRect.width()
3871 + PushButtonContentPadding - textRect.x();
3872 textRect.adjust(newOffset, 0, newOffset, 0);
3876 textRect = visualRect(btn->direction, freeContentRect, textRect);
3877 drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn->palette,
3878 (btn->state & State_Enabled), btn->text, QPalette::ButtonText);
3884 case CE_ComboBoxLabel:
3885 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3886 QStyleOptionComboBox comboCopy = *cb;
3887 comboCopy.direction = Qt::LeftToRight;
3888 QWindowsStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
3891 case CE_TabBarTabShape:
3892 if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3894 if (const QStyleOptionTabV3 *tabOptV3 = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
3895 if (tabOptV3->documentMode) {
3897 QRect tabRect = tabOptV3->rect;
3898 drawTabShape(p, tabOptV3);
3904 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
3905 if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_3) {
3906 HIThemeTabDrawInfo tdi;
3908 tdi.style = kThemeTabNonFront;
3909 tdi.direction = getTabDirection(tabOpt->shape);
3910 switch (d->aquaSizeConstrain(opt, w)) {
3912 case QAquaSizeUnknown:
3913 case QAquaSizeLarge:
3914 tdi.size = kHIThemeTabSizeNormal;
3916 case QAquaSizeSmall:
3917 tdi.size = kHIThemeTabSizeSmall;
3920 tdi.size = kHIThemeTabSizeMini;
3923 bool verticalTabs = tdi.direction == kThemeTabWest || tdi.direction == kThemeTabEast;
3924 QRect tabRect = tabOpt->rect;
3926 if ((!verticalTabs && tabRect.height() > 21 || verticalTabs && tabRect.width() > 21)) {
3927 d->drawPantherTab(tabOpt, p, w);
3931 bool selected = tabOpt->state & State_Selected;
3933 if (!(tabOpt->state & State_Active))
3934 tdi.style = kThemeTabFrontUnavailable;
3935 else if (!(tabOpt->state & State_Enabled))
3936 tdi.style = kThemeTabFrontInactive;
3938 tdi.style = kThemeTabFront;
3939 } else if (!(tabOpt->state & State_Active)) {
3940 tdi.style = kThemeTabNonFrontUnavailable;
3941 } else if (!(tabOpt->state & State_Enabled)) {
3942 tdi.style = kThemeTabNonFrontInactive;
3943 } else if (tabOpt->state & State_Sunken) {
3944 tdi.style = kThemeTabFrontInactive; // (should be kThemeTabNonFrontPressed)
3946 if (tabOpt->state & State_HasFocus)
3947 tdi.adornment = kHIThemeTabAdornmentFocus;
3949 tdi.adornment = kHIThemeTabAdornmentNone;
3950 tdi.kind = kHIThemeTabKindNormal;
3952 tabRect.setY(tabRect.y() - 1);
3954 tabRect.setX(tabRect.x() - 1);
3955 QStyleOptionTab::TabPosition tp = tabOpt->position;
3956 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3957 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3958 if (sp == QStyleOptionTab::NextIsSelected)
3959 sp = QStyleOptionTab::PreviousIsSelected;
3960 else if (sp == QStyleOptionTab::PreviousIsSelected)
3961 sp = QStyleOptionTab::NextIsSelected;
3963 case QStyleOptionTab::Beginning:
3964 tp = QStyleOptionTab::End;
3966 case QStyleOptionTab::End:
3967 tp = QStyleOptionTab::Beginning;
3974 case QStyleOptionTab::Beginning:
3975 tdi.position = kHIThemeTabPositionFirst;
3976 if (sp != QStyleOptionTab::NextIsSelected)
3977 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3979 case QStyleOptionTab::Middle:
3980 tdi.position = kHIThemeTabPositionMiddle;
3982 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3983 if (sp != QStyleOptionTab::NextIsSelected) // Also when we're selected.
3984 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3986 case QStyleOptionTab::End:
3987 tdi.position = kHIThemeTabPositionLast;
3989 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3991 case QStyleOptionTab::OnlyOneTab:
3992 tdi.position = kHIThemeTabPositionOnly;
3995 HIRect hirect = qt_hirectForQRect(tabRect);
3996 HIThemeDrawTab(&hirect, &tdi, cg, kHIThemeOrientationNormal, 0);
4000 d->drawPantherTab(tabOpt, p, w);
4004 case CE_TabBarTabLabel:
4005 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
4006 QStyleOptionTabV3 myTab = *tab;
4007 ThemeTabDirection ttd = getTabDirection(myTab.shape);
4008 bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
4010 // Check to see if we use have the same as the system font
4011 // (QComboMenuItem is internal and should never be seen by the
4012 // outside world, unless they read the source, in which case, it's
4013 // their own fault).
4014 bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
4015 if (verticalTabs || nonDefaultFont || !tab->icon.isNull()
4016 || !myTab.leftButtonSize.isNull() || !myTab.rightButtonSize.isNull()) {
4017 int heightOffset = 0;
4020 } else if (nonDefaultFont) {
4021 if (p->fontMetrics().height() == myTab.rect.height())
4024 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
4026 if (myTab.documentMode) {
4028 rotateTabPainter(p, myTab.shape, myTab.rect);
4030 QPalette np = tab->palette;
4031 np.setColor(QPalette::WindowText, QColor(255, 255, 255, 75));
4032 QRect nr = subElementRect(SE_TabBarTabText, opt, w);
4034 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic;
4035 drawItemText(p, nr, alignment, np, tab->state & State_Enabled, tab->text, QPalette::WindowText);
4039 QCommonStyle::drawControl(ce, &myTab, p, w);
4042 CGContextSetShouldAntialias(cg, true);
4043 CGContextSetShouldSmoothFonts(cg, true);
4044 HIThemeTextInfo tti;
4045 tti.version = qt_mac_hitheme_version;
4047 QColor textColor = myTab.palette.windowText().color();
4048 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4049 textColor.blueF(), textColor.alphaF() };
4050 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
4051 CGContextSetFillColor(cg, colorComp);
4052 switch (d->aquaSizeConstrain(opt, w)) {
4054 case QAquaSizeUnknown:
4055 case QAquaSizeLarge:
4056 tti.fontID = kThemeSystemFont;
4058 case QAquaSizeSmall:
4059 tti.fontID = kThemeSmallSystemFont;
4062 tti.fontID = kThemeMiniSystemFont;
4065 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
4066 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4067 tti.options = verticalTabs ? kHIThemeTextBoxOptionStronglyVertical : kHIThemeTextBoxOptionNone;
4068 tti.truncationPosition = kHIThemeTextTruncationNone;
4069 tti.truncationMaxLines = 1 + myTab.text.count(QLatin1Char('\n'));
4070 QCFString tabText = qt_mac_removeMnemonics(myTab.text);
4071 QRect r = myTab.rect.adjusted(0, 0, 0, -1);
4072 HIRect bounds = qt_hirectForQRect(r);
4073 HIThemeDrawTextBox(tabText, &bounds, &tti, cg, kHIThemeOrientationNormal);
4078 case CE_DockWidgetTitle:
4079 if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(w)) {
4080 bool floating = dockWidget->isFloating();
4082 ThemeDrawState tds = d->getDrawState(opt->state);
4083 HIThemeWindowDrawInfo wdi;
4084 wdi.version = qt_mac_hitheme_version;
4086 wdi.windowType = kThemeMovableDialogWindow;
4087 wdi.titleHeight = opt->rect.height();
4088 wdi.titleWidth = opt->rect.width();
4091 HIRect titleBarRect;
4092 HIRect tmpRect = qt_hirectForQRect(opt->rect);
4094 QCFType<HIShapeRef> titleRegion;
4095 QRect newr = opt->rect.adjusted(0, 0, 2, 0);
4096 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
4097 ptrHIShapeGetBounds(titleRegion, &tmpRect);
4098 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
4099 titleBarRect = qt_hirectForQRect(newr);
4101 QMacCGContext cg(p);
4102 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
4104 // fill title bar background
4105 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
4106 linearGrad.setColorAt(0, mainWindowGradientBegin);
4107 linearGrad.setColorAt(1, mainWindowGradientEnd);
4108 p->fillRect(opt->rect, linearGrad);
4110 // draw horizontal lines at top and bottom
4112 p->setPen(mainWindowGradientBegin.lighter(114));
4113 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4114 p->setPen(mainWindowGradientEnd.darker(114));
4115 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4121 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
4122 if (!dwOpt->title.isEmpty()) {
4123 const QStyleOptionDockWidgetV2 *v2
4124 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt);
4125 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
4127 QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w);
4128 if (verticalTitleBar) {
4129 QRect rect = dwOpt->rect;
4135 titleRect = QRect(r.left() + rect.bottom()
4136 - titleRect.bottom(),
4137 r.top() + titleRect.left() - rect.left(),
4138 titleRect.height(), titleRect.width());
4140 p->translate(r.left(), r.top() + r.width());
4142 p->translate(-r.left(), -r.top());
4145 QFont oldFont = p->font();
4146 p->setFont(qt_app_fonts_hash()->value("QToolButton", p->font()));
4147 QString text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
4149 drawItemText(p, titleRect,
4150 Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette,
4151 dwOpt->state & State_Enabled, text,
4152 QPalette::WindowText);
4153 p->setFont(oldFont);
4157 case CE_FocusFrame: {
4158 int xOff = pixelMetric(PM_FocusFrameHMargin, opt, w) + 1;
4159 int yOff = pixelMetric(PM_FocusFrameVMargin, opt, w) + 1;
4160 HIRect hirect = CGRectMake(xOff+opt->rect.x(), yOff+opt->rect.y(), opt->rect.width() - 2 * xOff,
4161 opt->rect.height() - 2 * yOff);
4162 HIThemeDrawFocusRect(&hirect, true, QMacCGContext(p), kHIThemeOrientationNormal);
4165 case CE_MenuEmptyArea:
4166 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4167 p->fillRect(mi->rect, opt->palette.background());
4168 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, w);
4169 int tabwidth = mi->tabWidth;
4170 int maxpmw = mi->maxIconWidth;
4171 bool active = mi->state & State_Selected;
4172 bool enabled = mi->state & State_Enabled;
4173 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4174 HIRect itemRect = qt_hirectForQRect(mi->rect);
4175 HIThemeMenuItemDrawInfo mdi;
4176 mdi.version = qt_mac_hitheme_version;
4177 mdi.itemType = kThemeMenuItemPlain;
4178 if (!mi->icon.isNull())
4179 mdi.itemType |= kThemeMenuItemHasIcon;
4180 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
4181 mdi.itemType |= kThemeMenuItemHierarchical | kThemeMenuItemHierBackground;
4183 mdi.itemType |= kThemeMenuItemPopUpBackground;
4185 mdi.state = kThemeMenuActive;
4187 mdi.state = kThemeMenuDisabled;
4189 mdi.state |= kThemeMenuSelected;
4191 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4192 // First arg should be &menurect, but wacky stuff happens then.
4193 HIThemeDrawMenuSeparator(&itemRect, &itemRect, &mdi,
4194 cg, kHIThemeOrientationNormal);
4198 bool needAlpha = mi->palette.color(QPalette::Button) == Qt::transparent;
4201 CGContextSaveGState(cg);
4202 CGContextSetAlpha(cg, 0.0);
4204 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4205 cg, kHIThemeOrientationNormal, &cr);
4207 CGContextRestoreGState(cg);
4208 if (ce == CE_MenuEmptyArea)
4210 contentRect = qt_qrectForHIRect(cr);
4212 int xpos = contentRect.x() + 18;
4213 int checkcol = maxpmw;
4215 p->setPen(mi->palette.text().color());
4217 p->setPen(mi->palette.highlightedText().color());
4219 p->setPen(mi->palette.buttonText().color());
4222 // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it,
4223 // we somehow need to use a special encoding as it doesn't look right with our
4226 CGContextSetShouldAntialias(cg, true);
4227 CGContextSetShouldSmoothFonts(cg, true);
4228 QColor textColor = p->pen().color();
4229 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4230 textColor.blueF(), textColor.alphaF() };
4231 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
4232 CGContextSetFillColor(cg, colorComp);
4233 HIThemeTextInfo tti;
4234 tti.version = qt_mac_hitheme_version;
4236 if (active && enabled)
4237 tti.state = kThemeStatePressed;
4238 switch (widgetSize) {
4239 case QAquaSizeUnknown:
4240 case QAquaSizeLarge:
4241 tti.fontID = kThemeMenuItemMarkFont;
4243 case QAquaSizeSmall:
4244 tti.fontID = kThemeSmallSystemFont;
4247 tti.fontID = kThemeMiniSystemFont;
4250 tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft;
4251 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4252 tti.options = kHIThemeTextBoxOptionNone;
4253 tti.truncationPosition = kHIThemeTextTruncationNone;
4254 tti.truncationMaxLines = 1;
4255 QCFString checkmark;
4257 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
4258 checkmark = QString(QChar(kDiamondUnicode));
4261 checkmark = QString(QChar(kCheckUnicode));
4262 int mw = checkcol + macItemFrame;
4263 int mh = contentRect.height() - 2 * macItemFrame;
4264 int xp = contentRect.x();
4266 CGFloat outWidth, outHeight, outBaseline;
4267 HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight,
4269 if (widgetSize == QAquaSizeMini)
4271 QRect r(xp, contentRect.y(), mw, mh);
4272 r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1);
4273 HIRect bounds = qt_hirectForQRect(r);
4274 HIThemeDrawTextBox(checkmark, &bounds, &tti,
4275 cg, kHIThemeOrientationNormal);
4278 if (!mi->icon.isNull()) {
4279 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4281 // Always be normal or disabled to follow the Mac style.
4282 int smallIconSize = pixelMetric(PM_SmallIconSize);
4283 QSize iconSize(smallIconSize, smallIconSize);
4284 if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
4285 iconSize = comboBox->iconSize();
4287 QPixmap pixmap = mi->icon.pixmap(iconSize, mode);
4288 int pixw = pixmap.width();
4289 int pixh = pixmap.height();
4290 QRect cr(xpos, contentRect.y(), checkcol, contentRect.height());
4291 QRect pmr(0, 0, pixw, pixh);
4292 pmr.moveCenter(cr.center());
4293 p->drawPixmap(pmr.topLeft(), pixmap);
4297 QString s = mi->text;
4299 int t = s.indexOf(QLatin1Char('\t'));
4300 int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic
4301 | Qt::TextSingleLine | Qt::AlignAbsolute;
4302 int yPos = contentRect.y();
4303 if (widgetSize == QAquaSizeMini)
4307 p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
4308 int xp = contentRect.right() - tabwidth - macRightBorder
4309 - macItemHMargin - macItemFrame + 1;
4310 p->drawText(xp, yPos, tabwidth, contentRect.height(), text_flags,
4315 const int xm = macItemFrame + maxpmw + macItemHMargin;
4316 QFont myFont = mi->font;
4317 if (mi->state & QStyle::State_Mini)
4318 myFont.setPointSize(mi->font.pointSize());
4320 p->drawText(xpos, yPos, contentRect.width() - xm - tabwidth + 1,
4321 contentRect.height(), text_flags ^ Qt::AlignRight, s);
4326 case CE_MenuHMargin:
4327 case CE_MenuVMargin:
4328 case CE_MenuTearoff:
4329 case CE_MenuScroller:
4330 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4331 p->fillRect(mi->rect, opt->palette.background());
4333 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4334 HIRect itemRect = qt_hirectForQRect(mi->rect);
4335 HIThemeMenuItemDrawInfo mdi;
4336 mdi.version = qt_mac_hitheme_version;
4337 if (!(opt->state & State_Enabled))
4338 mdi.state = kThemeMenuDisabled;
4339 else if (opt->state & State_Selected)
4340 mdi.state = kThemeMenuSelected;
4342 mdi.state = kThemeMenuActive;
4343 if (ce == CE_MenuScroller) {
4344 if (opt->state & State_DownArrow)
4345 mdi.itemType = kThemeMenuItemScrollDownArrow;
4347 mdi.itemType = kThemeMenuItemScrollUpArrow;
4349 mdi.itemType = kThemeMenuItemPlain;
4351 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4353 kHIThemeOrientationNormal, 0);
4354 if (ce == CE_MenuTearoff) {
4355 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4356 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4357 mi->rect.x() + mi->rect.width() - 4,
4358 mi->rect.y() + mi->rect.height() / 2 - 1);
4359 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4360 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4361 mi->rect.x() + mi->rect.width() - 4,
4362 mi->rect.y() + mi->rect.height() / 2);
4366 case CE_MenuBarItem:
4367 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4368 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4369 HIRect itemRect = qt_hirectForQRect(mi->rect);
4371 if ((opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken)){
4372 // Draw a selected menu item background:
4373 HIThemeMenuItemDrawInfo mdi;
4374 mdi.version = qt_mac_hitheme_version;
4375 mdi.state = kThemeMenuSelected;
4376 mdi.itemType = kThemeMenuItemPlain;
4377 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, cg, kHIThemeOrientationNormal, 0);
4379 // Draw the toolbar background:
4380 HIThemeMenuBarDrawInfo bdi;
4381 bdi.version = qt_mac_hitheme_version;
4382 bdi.state = kThemeMenuBarNormal;
4384 HIRect hirect = qt_hirectForQRect(mi->rect);
4385 HIThemeDrawMenuBarBackground(&menuRect, &bdi, cg, kHIThemeOrientationNormal);
4388 if (!mi->icon.isNull()) {
4389 drawItemPixmap(p, mi->rect,
4390 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4391 | Qt::TextSingleLine,
4392 mi->icon.pixmap(pixelMetric(PM_SmallIconSize),
4393 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4395 drawItemText(p, mi->rect,
4396 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4397 | Qt::TextSingleLine,
4398 mi->palette, mi->state & State_Enabled,
4399 mi->text, QPalette::ButtonText);
4403 case CE_MenuBarEmptyArea:
4404 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4405 HIThemeMenuBarDrawInfo bdi;
4406 bdi.version = qt_mac_hitheme_version;
4407 bdi.state = kThemeMenuBarNormal;
4409 HIRect hirect = qt_hirectForQRect(mi->rect);
4410 HIThemeDrawMenuBarBackground(&hirect, &bdi, cg,
4411 kHIThemeOrientationNormal);
4414 case CE_ProgressBarContents:
4415 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4416 HIThemeTrackDrawInfo tdi;
4417 tdi.version = qt_mac_hitheme_version;
4419 bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4420 bool vertical = false;
4421 bool inverted = false;
4422 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
4423 vertical = (pb2->orientation == Qt::Vertical);
4424 inverted = pb2->invertedAppearance;
4426 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4429 switch (d->aquaSizeConstrain(opt, w)) {
4430 case QAquaSizeUnknown:
4431 case QAquaSizeLarge:
4432 tdi.kind = !isIndeterminate ? kThemeLargeProgressBar
4433 : kThemeLargeIndeterminateBar;
4436 case QAquaSizeSmall:
4437 tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar;
4440 tdi.bounds = qt_hirectForQRect(pb->rect);
4441 tdi.max = pb->maximum;
4442 tdi.min = pb->minimum;
4443 tdi.value = pb->progress;
4444 tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
4445 tdi.trackInfo.progress.phase = d->progressFrame;
4446 if (!(pb->state & State_Active))
4447 tdi.enableState = kThemeTrackInactive;
4448 else if (!(pb->state & State_Enabled))
4449 tdi.enableState = kThemeTrackDisabled;
4451 tdi.enableState = kThemeTrackActive;
4452 HIThemeDrawTrack(&tdi, 0, cg, kHIThemeOrientationNormal);
4455 case CE_ProgressBarLabel:
4456 case CE_ProgressBarGroove:
4459 if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) {
4460 HIThemeGrowBoxDrawInfo gdi;
4461 gdi.version = qt_mac_hitheme_version;
4463 gdi.kind = kHIThemeGrowBoxKindNormal;
4464 gdi.direction = kThemeGrowRight | kThemeGrowDown;
4465 gdi.size = kHIThemeGrowBoxSizeNormal;
4466 HIPoint pt = CGPointMake(opt->rect.x(), opt->rect.y());
4467 HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal);
4469 // It isn't possible to draw a transparent size grip with the
4470 // native API, so we do it ourselves here.
4471 const bool metal = qt_mac_is_metal(w);
4472 QPen lineColor = metal ? QColor(236, 236, 236) : QColor(82, 82, 82, 192);
4473 QPen metalHighlight = QColor(5, 5, 5, 192);
4474 lineColor.setWidth(1);
4476 p->setRenderHint(QPainter::Antialiasing);
4477 p->setPen(lineColor);
4478 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4479 const int NumLines = metal ? 4 : 3;
4480 for (int l = 0; l < NumLines; ++l) {
4481 const int offset = (l * 4 + (metal ? 2 : 3));
4483 if (layoutDirection == Qt::LeftToRight) {
4484 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4485 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4487 start = QPoint(offset, opt->rect.height() - 1);
4488 end = QPoint(1, opt->rect.height() - offset);
4490 p->drawLine(start, end);
4492 p->setPen(metalHighlight);
4493 p->setRenderHint(QPainter::Antialiasing, false);
4494 p->drawLine(start + QPoint(0, -1), end + QPoint(0, -1));
4495 p->setRenderHint(QPainter::Antialiasing, true);
4496 p->setPen(lineColor);
4504 HIThemeSplitterDrawInfo sdi;
4505 sdi.version = qt_mac_hitheme_version;
4507 sdi.adornment = qt_mac_is_metal(w) ? kHIThemeSplitterAdornmentMetal
4508 : kHIThemeSplitterAdornmentNone;
4509 HIRect hirect = qt_hirectForQRect(opt->rect);
4510 HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal);
4513 if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
4514 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4515 if (!rubber->opaque) {
4517 // I retrieved these colors from the Carbon-Dev mailing list
4518 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4519 fillColor.setHsvF(0, 0, 0.53, 0.25);
4520 if (opt->rect.width() * opt->rect.height() <= 3) {
4521 p->fillRect(opt->rect, strokeColor);
4523 QPen oldPen = p->pen();
4524 QBrush oldBrush = p->brush();
4525 QPen pen(strokeColor);
4527 p->setBrush(fillColor);
4528 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
4530 p->setBrush(oldBrush);
4533 p->fillRect(opt->rect, fillColor);
4538 // For unified tool bars, draw nothing.
4540 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window()))
4541 if (mainWindow->unifiedTitleAndToolBarOnMac())
4545 // draw background gradient
4546 QLinearGradient linearGrad;
4547 if (opt->state & State_Horizontal)
4548 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4550 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
4552 linearGrad.setColorAt(0, mainWindowGradientBegin);
4553 linearGrad.setColorAt(1, mainWindowGradientEnd);
4554 p->fillRect(opt->rect, linearGrad);
4557 if (opt->state & State_Horizontal) {
4558 p->setPen(mainWindowGradientBegin.lighter(114));
4559 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4560 p->setPen(mainWindowGradientEnd.darker(114));
4561 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4564 p->setPen(mainWindowGradientBegin.lighter(114));
4565 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4566 p->setPen(mainWindowGradientEnd.darker(114));
4567 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
4574 QWindowsStyle::drawControl(ce, opt, p, w);
4579 static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
4581 if (dir == Qt::RightToLeft) {
4582 rect->adjust(-right, top, -left, bottom);
4584 rect->adjust(left, top, right, bottom);
4588 QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
4589 const QWidget *widget) const
4592 int controlSize = getControlSize(opt, widget);
4595 case SE_ToolBoxTabContents:
4596 rect = QCommonStyle::subElementRect(sr, opt, widget);
4598 case SE_PushButtonContents:
4599 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4600 // Unlike Carbon, we want the button to always be drawn inside its bounds.
4601 // Therefore, the button is a bit smaller, so that even if it got focus,
4602 // the focus 'shadow' will be inside. Adjust the content rect likewise.
4603 HIThemeButtonDrawInfo bdi;
4604 d->initHIThemePushButton(btn, widget, d->getDrawState(opt->state), &bdi);
4605 HIRect contentRect = d->pushButtonContentBounds(btn, &bdi);
4606 rect = qt_qrectForHIRect(contentRect);
4609 case SE_HeaderLabel:
4610 if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4611 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4612 if (widget && widget->height() <= qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight)){
4613 // We need to allow the text a bit more space when the header is as
4614 // small as kThemeMetricListHeaderHeight, otherwise it gets clipped:
4616 rect.setHeight(widget->height());
4618 if (opt->direction == Qt::RightToLeft)
4619 rect.adjust(15, 0, -20, 0);
4622 case SE_ProgressBarGroove:
4623 case SE_ProgressBarLabel:
4625 case SE_ProgressBarContents:
4628 case SE_TreeViewDisclosureItem: {
4629 HIRect inRect = CGRectMake(opt->rect.x(), opt->rect.y(),
4630 opt->rect.width(), opt->rect.height());
4631 HIThemeButtonDrawInfo bdi;
4632 bdi.version = qt_mac_hitheme_version;
4633 bdi.state = kThemeStateActive;
4634 bdi.kind = kThemeDisclosureButton;
4635 bdi.value = kThemeDisclosureRight;
4636 bdi.adornment = kThemeAdornmentNone;
4638 HIThemeGetButtonContentBounds(&inRect, &bdi, &contentRect);
4639 QCFType<HIShapeRef> shape;
4641 HIThemeGetButtonShape(&inRect, &bdi, &shape);
4642 ptrHIShapeGetBounds(shape, &outRect);
4643 rect = QRect(int(outRect.origin.x), int(outRect.origin.y),
4644 int(contentRect.origin.x - outRect.origin.x), int(outRect.size.height));
4647 case SE_TabWidgetLeftCorner:
4648 if (const QStyleOptionTabWidgetFrame *twf
4649 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4650 switch (twf->shape) {
4651 case QTabBar::RoundedNorth:
4652 case QTabBar::TriangularNorth:
4653 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4655 case QTabBar::RoundedSouth:
4656 case QTabBar::TriangularSouth:
4657 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4658 twf->leftCornerWidgetSize);
4663 rect = visualRect(twf->direction, twf->rect, rect);
4666 case SE_TabWidgetRightCorner:
4667 if (const QStyleOptionTabWidgetFrame *twf
4668 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4669 switch (twf->shape) {
4670 case QTabBar::RoundedNorth:
4671 case QTabBar::TriangularNorth:
4672 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4673 twf->rightCornerWidgetSize);
4675 case QTabBar::RoundedSouth:
4676 case QTabBar::TriangularSouth:
4677 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4678 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4679 twf->rightCornerWidgetSize);
4684 rect = visualRect(twf->direction, twf->rect, rect);
4687 case SE_TabWidgetTabContents:
4688 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4689 if (const QStyleOptionTabWidgetFrame *twf
4690 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4691 if (twf->lineWidth != 0) {
4692 switch (getTabDirection(twf->shape)) {
4693 case kThemeTabNorth:
4694 rect.adjust(+1, +14, -1, -1);
4696 case kThemeTabSouth:
4697 rect.adjust(+1, +1, -1, -14);
4700 rect.adjust(+14, +1, -1, -1);
4703 rect.adjust(+1, +1, -14, -1);
4708 case SE_LineEditContents:
4709 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4710 if(widget->parentWidget() && qobject_cast<const QComboBox*>(widget->parentWidget()))
4711 rect.adjust(-1, -2, 0, 0);
4713 rect.adjust(-1, 0, 0, +1);
4715 case SE_CheckBoxLayoutItem:
4717 if (controlSize == QAquaSizeLarge) {
4718 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4719 } else if (controlSize == QAquaSizeSmall) {
4720 setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction);
4722 setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction);
4725 case SE_ComboBoxLayoutItem:
4726 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4727 // Do nothing, because QToolbar needs the entire widget rect.
4728 // Otherwise it will be clipped. Equivalent to
4729 // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4733 if (controlSize == QAquaSizeLarge) {
4734 rect.adjust(+3, +2, -3, -4);
4735 } else if (controlSize == QAquaSizeSmall) {
4736 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4738 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4742 case SE_LabelLayoutItem:
4744 setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4746 case SE_ProgressBarLayoutItem: {
4748 int bottom = SIZE(3, 8, 8);
4749 if (opt->state & State_Horizontal) {
4750 rect.adjust(0, +1, 0, -bottom);
4752 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
4756 case SE_PushButtonLayoutItem:
4757 if (const QStyleOptionButton *buttonOpt
4758 = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4759 if ((buttonOpt->features & QStyleOptionButton::Flat))
4760 break; // leave rect alone
4763 if (controlSize == QAquaSizeLarge) {
4764 rect.adjust(+6, +4, -6, -8);
4765 } else if (controlSize == QAquaSizeSmall) {
4766 rect.adjust(+5, +4, -5, -6);
4768 rect.adjust(+1, 0, -1, -2);
4771 case SE_RadioButtonLayoutItem:
4773 if (controlSize == QAquaSizeLarge) {
4774 setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */,
4775 0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction);
4776 } else if (controlSize == QAquaSizeSmall) {
4777 rect.adjust(0, +6, 0 /* fix */, -5);
4779 rect.adjust(0, +6, 0 /* fix */, -7);
4782 case SE_SliderLayoutItem:
4783 if (const QStyleOptionSlider *sliderOpt
4784 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4786 if (sliderOpt->tickPosition == QSlider::NoTicks) {
4787 int above = SIZE(3, 0, 2);
4788 int below = SIZE(4, 3, 0);
4789 if (sliderOpt->orientation == Qt::Horizontal) {
4790 rect.adjust(0, +above, 0, -below);
4792 rect.adjust(+above, 0, -below, 0); //### Seems that QSlider flip the position of the ticks in reverse mode.
4794 } else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4795 int below = SIZE(3, 2, 0);
4796 if (sliderOpt->orientation == Qt::Horizontal) {
4797 rect.setHeight(rect.height() - below);
4799 rect.setWidth(rect.width() - below);
4801 } else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4802 int above = SIZE(3, 2, 0);
4803 if (sliderOpt->orientation == Qt::Horizontal) {
4804 rect.setTop(rect.top() + above);
4806 rect.setLeft(rect.left() + above);
4811 case SE_FrameLayoutItem:
4812 // hack because QStyleOptionFrameV2 doesn't have a frameStyle member
4813 if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4815 switch (frame->frameStyle() & QFrame::Shape_Mask) {
4817 rect.adjust(0, +1, 0, -1);
4820 rect.adjust(+1, 0, -1, 0);
4827 case SE_GroupBoxLayoutItem:
4829 if (const QStyleOptionGroupBox *groupBoxOpt =
4830 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4832 AHIG is very inconsistent when it comes to group boxes.
4833 Basically, we make sure that (non-checkable) group boxes
4834 and tab widgets look good when laid out side by side.
4836 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4837 | QStyle::SC_GroupBoxLabel)) {
4839 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4840 delta = SIZE(8, 4, 4); // guess
4842 delta = SIZE(15, 12, 12); // guess
4844 rect.setTop(rect.top() + delta);
4847 rect.setBottom(rect.bottom() - 1);
4849 case SE_TabWidgetLayoutItem:
4850 if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4851 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4853 AHIG specifies "12 or 14" as the distance from the window
4854 edge. We choose 14 and since the default top margin is 20,
4857 rect = tabWidgetOpt->rect;
4858 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4859 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4863 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4869 static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDrawState tds, CGContextRef cg)
4871 QRect arrowRect = QRect(toolButtonRect.right() - 9, toolButtonRect.bottom() - 9, 7, 5);
4872 HIThemePopupArrowDrawInfo padi;
4873 padi.version = qt_mac_hitheme_version;
4875 padi.orientation = kThemeArrowDown;
4876 padi.size = kThemeArrow7pt;
4877 HIRect hirect = qt_hirectForQRect(arrowRect);
4878 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
4882 void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
4883 const QWidget *widget) const
4885 ThemeDrawState tds = d->getDrawState(opt->state);
4886 QMacCGContext cg(p);
4890 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4891 HIThemeTrackDrawInfo tdi;
4892 d->getSliderInfo(cc, slider, &tdi, widget);
4893 if (slider->state & State_Sunken) {
4894 if (cc == CC_Slider) {
4895 if (slider->activeSubControls == SC_SliderHandle)
4896 tdi.trackInfo.slider.pressState = kThemeThumbPressed;
4897 else if (slider->activeSubControls == SC_SliderGroove)
4898 tdi.trackInfo.slider.pressState = kThemeLeftTrackPressed;
4900 if (slider->activeSubControls == SC_ScrollBarSubLine
4901 || slider->activeSubControls == SC_ScrollBarAddLine) {
4902 // This test looks complex but it basically boils down
4903 // to the following: The "RTL look" on the mac also
4904 // changed the directions of the controls, that's not
4905 // what people expect (an arrow is an arrow), so we
4906 // kind of fake and say the opposite button is hit.
4907 // This works great, up until 10.4 which broke the
4908 // scroll bars, so I also have actually do something
4909 // similar when I have an upside down scroll bar
4910 // because on Tiger I only "fake" the reverse stuff.
4911 bool reverseHorizontal = (slider->direction == Qt::RightToLeft
4912 && slider->orientation == Qt::Horizontal
4913 && (!slider->upsideDown
4914 || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
4915 && slider->upsideDown)));
4916 if ((reverseHorizontal
4917 && slider->activeSubControls == SC_ScrollBarAddLine)
4918 || (!reverseHorizontal
4919 && slider->activeSubControls == SC_ScrollBarSubLine)) {
4920 tdi.trackInfo.scrollbar.pressState = kThemeRightInsideArrowPressed
4921 | kThemeLeftOutsideArrowPressed;
4923 tdi.trackInfo.scrollbar.pressState = kThemeLeftInsideArrowPressed
4924 | kThemeRightOutsideArrowPressed;
4926 } else if (slider->activeSubControls == SC_ScrollBarAddPage) {
4927 tdi.trackInfo.scrollbar.pressState = kThemeRightTrackPressed;
4928 } else if (slider->activeSubControls == SC_ScrollBarSubPage) {
4929 tdi.trackInfo.scrollbar.pressState = kThemeLeftTrackPressed;
4930 } else if (slider->activeSubControls == SC_ScrollBarSlider) {
4931 tdi.trackInfo.scrollbar.pressState = kThemeThumbPressed;
4936 bool tracking = slider->sliderPosition == slider->sliderValue;
4938 // Small optimization, the same as q->subControlRect
4939 QCFType<HIShapeRef> shape;
4940 HIThemeGetTrackThumbShape(&tdi, &shape);
4941 ptrHIShapeGetBounds(shape, &macRect);
4942 tdi.value = slider->sliderValue;
4945 // Remove controls from the scroll bar if it is to short to draw them correctly.
4946 // This is done in two stages: first the thumb indicator is removed when it is
4947 // no longer possible to move it, second the up/down buttons are removed when
4948 // there is not enough space for them.
4949 if (cc == CC_ScrollBar) {
4950 const int scrollBarLenght = (slider->orientation == Qt::Horizontal)
4951 ? slider->rect.width() : slider->rect.height();
4952 const QMacStyle::WidgetSizePolicy sizePolicy = widgetSizePolicy(widget);
4953 if (scrollBarLenght < scrollButtonsCutoffSize(thumbIndicatorCutoff, sizePolicy))
4954 tdi.attributes &= ~kThemeTrackShowThumb;
4955 if (scrollBarLenght < scrollButtonsCutoffSize(scrollButtonsCutoff, sizePolicy))
4956 tdi.enableState = kThemeTrackNothingToScroll;
4959 HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg,
4960 kHIThemeOrientationNormal);
4961 if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
4962 if (qt_mac_is_metal(widget)) {
4963 if (tdi.enableState == kThemeTrackInactive)
4964 tdi.enableState = kThemeTrackActive; // Looks more Cocoa-like
4966 int interval = slider->tickInterval;
4967 if (interval == 0) {
4968 interval = slider->pageStep;
4970 interval = slider->singleStep;
4974 int numMarks = 1 + ((slider->maximum - slider->minimum) / interval);
4976 if (tdi.trackInfo.slider.thumbDir == kThemeThumbPlain) {
4977 // They asked for both, so we'll give it to them.
4978 tdi.trackInfo.slider.thumbDir = kThemeThumbDownward;
4979 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4981 kHIThemeOrientationNormal);
4982 tdi.trackInfo.slider.thumbDir = kThemeThumbUpward;
4983 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4985 kHIThemeOrientationNormal);
4987 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4989 kHIThemeOrientationNormal);
4996 if (const QStyleOptionQ3ListView *lv = qstyleoption_cast<const QStyleOptionQ3ListView *>(opt)) {
4997 if (lv->subControls & SC_Q3ListView)
4998 QWindowsStyle::drawComplexControl(cc, lv, p, widget);
4999 if (lv->subControls & (SC_Q3ListViewBranch | SC_Q3ListViewExpand)) {
5000 int y = lv->rect.y();
5001 int h = lv->rect.height();
5002 int x = lv->rect.right() - 10;
5003 for (int i = 1; i < lv->items.size() && y < h; ++i) {
5004 QStyleOptionQ3ListViewItem item = lv->items.at(i);
5005 if (y + item.height > 0 && (item.childCount > 0
5006 || (item.features & (QStyleOptionQ3ListViewItem::Expandable
5007 | QStyleOptionQ3ListViewItem::Visible))
5008 == (QStyleOptionQ3ListViewItem::Expandable
5009 | QStyleOptionQ3ListViewItem::Visible))) {
5010 QStyleOption treeOpt(0);
5011 treeOpt.rect.setRect(x, y + item.height / 2 - 4, 9, 9);
5012 treeOpt.palette = lv->palette;
5013 treeOpt.state = lv->state;
5014 treeOpt.state |= State_Children;
5015 if (item.state & State_Open)
5016 treeOpt.state |= State_Open;
5017 drawPrimitive(PE_IndicatorBranch, &treeOpt, p, widget);
5019 y += item.totalHeight;
5025 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5026 QStyleOptionSpinBox newSB = *sb;
5027 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
5029 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
5031 QRect lineeditRect = subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
5032 lineeditRect.adjust(-frame_size, -frame_size, +frame_size, +frame_size);
5034 HIThemeFrameDrawInfo fdi;
5035 fdi.version = qt_mac_hitheme_version;
5036 fdi.state = kThemeStateInactive;
5037 fdi.kind = kHIThemeFrameTextFieldSquare;
5038 fdi.isFocused = false;
5039 HIRect hirect = qt_hirectForQRect(lineeditRect);
5040 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
5042 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
5043 HIThemeButtonDrawInfo bdi;
5044 bdi.version = qt_mac_hitheme_version;
5045 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
5047 case QAquaSizeUnknown:
5048 case QAquaSizeLarge:
5049 bdi.kind = kThemeIncDecButton;
5052 case QAquaSizeSmall:
5053 if (aquaSize == QAquaSizeMini)
5054 bdi.kind = kThemeIncDecButtonMini;
5056 bdi.kind = kThemeIncDecButtonSmall;
5059 if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled
5060 | QAbstractSpinBox::StepDownEnabled)))
5061 tds = kThemeStateUnavailable;
5062 if (sb->activeSubControls == SC_SpinBoxDown
5063 && (sb->state & State_Sunken))
5064 tds = kThemeStatePressedDown;
5065 else if (sb->activeSubControls == SC_SpinBoxUp
5066 && (sb->state & State_Sunken))
5067 tds = kThemeStatePressedUp;
5069 if (!(sb->state & State_Active)
5070 && sb->palette.currentColorGroup() == QPalette::Active
5071 && tds == kThemeStateInactive)
5072 bdi.state = kThemeStateActive;
5073 bdi.value = kThemeButtonOff;
5074 bdi.adornment = kThemeAdornmentNone;
5076 QRect updown = subControlRect(CC_SpinBox, sb, SC_SpinBoxUp,
5078 updown |= subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5079 HIRect newRect = qt_hirectForQRect(updown);
5082 HIThemeGetButtonBackgroundBounds(&newRect, &bdi, &outRect);
5083 off_rct.setRect(int(newRect.origin.x - outRect.origin.x),
5084 int(newRect.origin.y - outRect.origin.y),
5085 int(outRect.size.width - newRect.size.width),
5086 int(outRect.size.height - newRect.size.height));
5088 // HIThemeGetButtonBackgroundBounds offsets non-focused normal sized
5089 // buttons by one in de y direction, account for that here.
5090 if (bdi.adornment == kThemeAdornmentNone && bdi.kind == kThemeIncDecButton)
5091 off_rct.adjust(0, 1, 0, 0);
5093 // Adjust the rect for small buttos also.
5094 if (bdi.adornment == kThemeAdornmentFocus && bdi.kind == kThemeIncDecButtonSmall)
5095 off_rct.adjust(0, 0, 0, -1);
5097 newRect = qt_hirectForQRect(updown, off_rct);
5098 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5103 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
5104 HIThemeButtonDrawInfo bdi;
5105 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5106 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
5108 QMacStylePrivate::drawCombobox(qt_hirectForQRect(combo->rect), bdi, p);
5110 d->drawColorlessButton(qt_hirectForQRect(combo->rect), &bdi, p, opt);
5114 if (const QStyleOptionTitleBar *titlebar
5115 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5116 if (titlebar->state & State_Active) {
5117 if (titlebar->titleBarState & State_Active)
5118 tds = kThemeStateActive;
5120 tds = kThemeStateInactive;
5122 tds = kThemeStateInactive;
5125 HIThemeWindowDrawInfo wdi;
5126 wdi.version = qt_mac_hitheme_version;
5128 wdi.windowType = QtWinType;
5129 wdi.titleHeight = titlebar->rect.height();
5130 wdi.titleWidth = titlebar->rect.width();
5131 wdi.attributes = kThemeWindowHasTitleText;
5132 // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty
5133 // close button, so use HIThemeDrawWindowFrame instead.
5134 if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton)
5135 wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty;
5137 HIRect titleBarRect;
5138 HIRect tmpRect = qt_hirectForQRect(titlebar->rect);
5140 QCFType<HIShapeRef> titleRegion;
5141 QRect newr = titlebar->rect.adjusted(0, 0, 2, 0);
5142 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
5143 ptrHIShapeGetBounds(titleRegion, &tmpRect);
5144 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
5145 titleBarRect = qt_hirectForQRect(newr);
5147 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
5148 if (titlebar->subControls & (SC_TitleBarCloseButton
5149 | SC_TitleBarMaxButton
5150 | SC_TitleBarMinButton
5151 | SC_TitleBarNormalButton)) {
5152 HIThemeWindowWidgetDrawInfo wwdi;
5153 wwdi.version = qt_mac_hitheme_version;
5154 wwdi.widgetState = tds;
5155 if (titlebar->state & State_MouseOver)
5156 wwdi.widgetState = kThemeStateRollover;
5157 wwdi.windowType = QtWinType;
5158 wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox;
5159 wwdi.windowState = wdi.state;
5160 wwdi.titleHeight = wdi.titleHeight;
5161 wwdi.titleWidth = wdi.titleWidth;
5162 ThemeDrawState savedControlState = wwdi.widgetState;
5163 uint sc = SC_TitleBarMinButton;
5164 ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox;
5165 bool active = titlebar->state & State_Active;
5167 titleBarRect.origin.x += border;
5168 titleBarRect.origin.y -= border;
5170 while (sc <= SC_TitleBarCloseButton) {
5171 if (sc & titlebar->subControls) {
5173 wwdi.widgetState = savedControlState;
5174 wwdi.widgetType = tbw;
5175 if (sc == SC_TitleBarMinButton)
5176 tmp |= SC_TitleBarNormalButton;
5177 if (active && (titlebar->activeSubControls & tmp)
5178 && (titlebar->state & State_Sunken))
5179 wwdi.widgetState = kThemeStatePressed;
5180 // Draw all sub controllers except the dirty close button
5181 // (it is already handled by HIThemeDrawWindowFrame).
5182 if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) {
5183 HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal);
5184 p->paintEngine()->syncState();
5191 p->paintEngine()->syncState();
5192 if (titlebar->subControls & SC_TitleBarLabel) {
5194 if (!titlebar->icon.isNull()) {
5195 QCFType<HIShapeRef> titleRegion2;
5196 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn,
5198 ptrHIShapeGetBounds(titleRegion2, &tmpRect);
5199 if (tmpRect.size.width != 1) {
5200 int iconExtent = pixelMetric(PM_SmallIconSize);
5201 iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width();
5204 if (!titlebar->text.isEmpty()) {
5206 QCFType<HIShapeRef> titleRegion3;
5207 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3);
5208 ptrHIShapeGetBounds(titleRegion3, &tmpRect);
5209 p->setClipRect(qt_qrectForHIRect(tmpRect));
5210 QRect br = p->clipRegion().boundingRect();
5212 y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2);
5213 if (br.width() <= (p->fontMetrics().width(titlebar->text) + iw * 2))
5216 x += br.width() / 2 - p->fontMetrics().width(titlebar->text) / 2;
5218 p->drawPixmap(x - iw, y, titlebar->icon.pixmap(pixelMetric(PM_SmallIconSize), QIcon::Normal));
5219 drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive,
5220 titlebar->text, QPalette::Text);
5227 if (const QStyleOptionGroupBox *groupBox
5228 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5230 QStyleOptionGroupBox groupBoxCopy(*groupBox);
5231 if ((widget && !widget->testAttribute(Qt::WA_SetFont))
5232 && QApplication::desktopSettingsAware())
5233 groupBoxCopy.subControls = groupBoxCopy.subControls & ~SC_GroupBoxLabel;
5234 QWindowsStyle::drawComplexControl(cc, &groupBoxCopy, p, widget);
5235 if (groupBoxCopy.subControls != groupBox->subControls) {
5236 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5238 CGContextSetShouldAntialias(cg, true);
5239 CGContextSetShouldSmoothFonts(cg, true);
5240 HIThemeTextInfo tti;
5241 tti.version = qt_mac_hitheme_version;
5243 QColor textColor = groupBox->palette.windowText().color();
5244 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
5245 textColor.blueF(), textColor.alphaF() };
5246 CGContextSetFillColorSpace(cg, QCoreGraphicsPaintEngine::macGenericColorSpace());
5247 CGContextSetFillColor(cg, colorComp);
5248 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5249 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5250 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5251 tti.options = kHIThemeTextBoxOptionNone;
5252 tti.truncationPosition = kHIThemeTextTruncationNone;
5253 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5254 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5255 QRect r = subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget);
5256 HIRect bounds = qt_hirectForQRect(r);
5257 HIThemeDrawTextBox(groupText, &bounds, &tti, cg, kHIThemeOrientationNormal);
5263 if (const QStyleOptionToolButton *tb
5264 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5265 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5266 if (tb->subControls & SC_ToolButtonMenu) {
5267 QStyleOption arrowOpt(0);
5268 arrowOpt.rect = subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5269 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5270 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5271 arrowOpt.state = tb->state;
5272 arrowOpt.palette = tb->palette;
5273 drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5274 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5275 drawToolbarButtonArrow(tb->rect, tds, cg);
5277 if (tb->state & State_On) {
5278 QPen oldPen = p->pen();
5279 p->setPen(QColor(0, 0, 0, 0x3a));
5280 p->fillRect(tb->rect.adjusted(1, 1, -1, -1), QColor(0, 0, 0, 0x12));
5281 p->drawLine(tb->rect.left() + 1, tb->rect.top(),
5282 tb->rect.right() - 1, tb->rect.top());
5283 p->drawLine(tb->rect.left() + 1, tb->rect.bottom(),
5284 tb->rect.right() - 1, tb->rect.bottom());
5285 p->drawLine(tb->rect.topLeft(), tb->rect.bottomLeft());
5286 p->drawLine(tb->rect.topRight(), tb->rect.bottomRight());
5289 drawControl(CE_ToolButtonLabel, opt, p, widget);
5291 ThemeButtonKind bkind = kThemeBevelButton;
5292 switch (d->aquaSizeConstrain(opt, widget)) {
5293 case QAquaSizeUnknown:
5294 case QAquaSizeLarge:
5295 bkind = kThemeBevelButton;
5298 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3) && 0
5299 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3) {
5300 bkind = kThemeMiniBevelButton;
5304 case QAquaSizeSmall:
5305 bkind = kThemeSmallBevelButton;
5309 QRect button, menuarea;
5310 button = subControlRect(cc, tb, SC_ToolButton, widget);
5311 menuarea = subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5312 State bflags = tb->state,
5314 if (tb->subControls & SC_ToolButton)
5315 bflags |= State_Sunken;
5316 if (tb->subControls & SC_ToolButtonMenu)
5317 mflags |= State_Sunken;
5319 if (tb->subControls & SC_ToolButton) {
5320 if (bflags & (State_Sunken | State_On | State_Raised)) {
5321 HIThemeButtonDrawInfo bdi;
5322 bdi.version = qt_mac_hitheme_version;
5324 bdi.adornment = kThemeAdornmentNone;
5326 bdi.value = kThemeButtonOff;
5327 if (tb->state & State_HasFocus)
5328 bdi.adornment = kThemeAdornmentFocus;
5329 if (tb->state & State_Sunken)
5330 bdi.state = kThemeStatePressed;
5331 if (tb->state & State_On)
5332 bdi.value = kThemeButtonOn;
5334 QRect off_rct(0, 0, 0, 0);
5335 HIRect myRect, macRect;
5336 myRect = CGRectMake(tb->rect.x(), tb->rect.y(),
5337 tb->rect.width(), tb->rect.height());
5338 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
5339 off_rct.setRect(int(myRect.origin.x - macRect.origin.x),
5340 int(myRect.origin.y - macRect.origin.y),
5341 int(macRect.size.width - myRect.size.width),
5342 int(macRect.size.height - myRect.size.height));
5344 myRect = qt_hirectForQRect(button, off_rct);
5345 HIThemeDrawButton(&myRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5349 if (tb->subControls & SC_ToolButtonMenu) {
5350 HIThemeButtonDrawInfo bdi;
5351 bdi.version = qt_mac_hitheme_version;
5353 bdi.value = kThemeButtonOff;
5354 bdi.adornment = kThemeAdornmentNone;
5356 if (tb->state & State_HasFocus)
5357 bdi.adornment = kThemeAdornmentFocus;
5358 if (tb->state & (State_On | State_Sunken)
5359 || (tb->activeSubControls & SC_ToolButtonMenu))
5360 bdi.state = kThemeStatePressed;
5361 HIRect hirect = qt_hirectForQRect(menuarea);
5362 HIThemeDrawButton(&hirect, &bdi, cg, kHIThemeOrientationNormal, 0);
5363 QRect r(menuarea.x() + ((menuarea.width() / 2) - 3), menuarea.height() - 8, 8, 8);
5364 HIThemePopupArrowDrawInfo padi;
5365 padi.version = qt_mac_hitheme_version;
5367 padi.orientation = kThemeArrowDown;
5368 padi.size = kThemeArrow7pt;
5369 hirect = qt_hirectForQRect(r);
5370 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
5371 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5372 drawToolbarButtonArrow(tb->rect, tds, cg);
5374 QRect buttonRect = subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
5375 int fw = pixelMetric(PM_DefaultFrameWidth, opt, widget);
5376 QStyleOptionToolButton label = *tb;
5377 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5378 drawControl(CE_ToolButtonLabel, &label, p, widget);
5383 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5384 QStyleHelper::drawDial(dial, p);
5387 QWindowsStyle::drawComplexControl(cc, opt, p, widget);
5393 QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
5394 const QStyleOptionComplex *opt,
5395 const QPoint &pt, const QWidget *widget) const
5397 SubControl sc = QStyle::SC_None;
5400 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5401 sc = QWindowsStyle::hitTestComplexControl(cc, cmb, pt, widget);
5402 if (!cmb->editable && sc != QStyle::SC_None)
5403 sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
5407 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5408 HIThemeTrackDrawInfo tdi;
5409 d->getSliderInfo(cc, slider, &tdi, widget);
5410 ControlPartCode part;
5411 HIPoint pos = CGPointMake(pt.x(), pt.y());
5412 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5413 if (part == kControlPageUpPart || part == kControlPageDownPart)
5414 sc = SC_SliderGroove;
5416 sc = SC_SliderHandle;
5421 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5422 HIScrollBarTrackInfo sbi;
5423 sbi.version = qt_mac_hitheme_version;
5424 if (!(sb->state & State_Active))
5425 sbi.enableState = kThemeTrackInactive;
5426 else if (sb->state & State_Enabled)
5427 sbi.enableState = kThemeTrackActive;
5429 sbi.enableState = kThemeTrackDisabled;
5431 // The arrow buttons are not drawn if the scroll bar is to short,
5432 // exclude them from the hit test.
5433 const int scrollBarLenght = (sb->orientation == Qt::Horizontal)
5434 ? sb->rect.width() : sb->rect.height();
5435 if (scrollBarLenght < scrollButtonsCutoffSize(scrollButtonsCutoff, widgetSizePolicy(widget)))
5436 sbi.enableState = kThemeTrackNothingToScroll;
5438 sbi.viewsize = sb->pageStep;
5439 HIPoint pos = CGPointMake(pt.x(), pt.y());
5441 HIRect macSBRect = qt_hirectForQRect(sb->rect);
5442 ControlPartCode part;
5443 bool reverseHorizontal = (sb->direction == Qt::RightToLeft
5444 && sb->orientation == Qt::Horizontal
5445 && (!sb->upsideDown ||
5446 (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5447 && sb->upsideDown)));
5448 if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal,
5450 if (part == kControlUpButtonPart)
5451 sc = reverseHorizontal ? SC_ScrollBarAddLine : SC_ScrollBarSubLine;
5452 else if (part == kControlDownButtonPart)
5453 sc = reverseHorizontal ? SC_ScrollBarSubLine : SC_ScrollBarAddLine;
5455 HIThemeTrackDrawInfo tdi;
5456 d->getSliderInfo(cc, sb, &tdi, widget);
5457 if(tdi.enableState == kThemeTrackInactive)
5458 tdi.enableState = kThemeTrackActive;
5459 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5460 if (part == kControlPageUpPart)
5461 sc = reverseHorizontal ? SC_ScrollBarAddPage
5462 : SC_ScrollBarSubPage;
5463 else if (part == kControlPageDownPart)
5464 sc = reverseHorizontal ? SC_ScrollBarSubPage
5465 : SC_ScrollBarAddPage;
5467 sc = SC_ScrollBarSlider;
5473 I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all.
5474 It would be very nice if this would work.
5475 case QStyle::CC_TitleBar:
5476 if (const QStyleOptionTitleBar *tbar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5477 HIThemeWindowDrawInfo wdi;
5478 memset(&wdi, 0, sizeof(wdi));
5479 wdi.version = qt_mac_hitheme_version;
5480 wdi.state = kThemeStateActive;
5481 wdi.windowType = QtWinType;
5482 wdi.titleWidth = tbar->rect.width();
5483 wdi.titleHeight = tbar->rect.height();
5484 if (tbar->titleBarState)
5485 wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
5486 | kThemeWindowHasCollapseBox;
5487 else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint)
5488 wdi.attributes |= kThemeWindowHasCloseBox;
5489 QRect tmpRect = tbar->rect;
5490 tmpRect.setHeight(tmpRect.height() + 100);
5491 HIRect hirect = qt_hirectForQRect(tmpRect);
5492 WindowRegionCode hit;
5493 HIPoint hipt = CGPointMake(pt.x(), pt.y());
5494 if (HIThemeGetWindowRegionHit(&hirect, &wdi, &hipt, &hit)) {
5496 case kWindowCloseBoxRgn:
5497 sc = QStyle::SC_TitleBarCloseButton;
5499 case kWindowCollapseBoxRgn:
5500 sc = QStyle::SC_TitleBarMinButton;
5502 case kWindowZoomBoxRgn:
5503 sc = QStyle::SC_TitleBarMaxButton;
5505 case kWindowTitleTextRgn:
5506 sc = QStyle::SC_TitleBarLabel;
5509 qDebug("got something else %d", hit);
5517 sc = QWindowsStyle::hitTestComplexControl(cc, opt, pt, widget);
5524 QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5525 const QWidget *widget) const
5531 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5532 HIThemeTrackDrawInfo tdi;
5533 d->getSliderInfo(cc, slider, &tdi, widget);
5535 QCFType<HIShapeRef> shape;
5536 bool scrollBar = cc == CC_ScrollBar;
5537 if ((scrollBar && sc == SC_ScrollBarSlider)
5538 || (!scrollBar && sc == SC_SliderHandle)) {
5539 HIThemeGetTrackThumbShape(&tdi, &shape);
5540 ptrHIShapeGetBounds(shape, &macRect);
5541 } else if (!scrollBar && sc == SC_SliderGroove) {
5542 HIThemeGetTrackBounds(&tdi, &macRect);
5543 } else if (sc == SC_ScrollBarGroove) { // Only scroll bar parts available...
5544 HIThemeGetTrackDragRect(&tdi, &macRect);
5546 ControlPartCode cpc;
5547 if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5548 cpc = sc == SC_ScrollBarSubPage ? kControlPageDownPart
5549 : kControlPageUpPart;
5551 cpc = sc == SC_ScrollBarSubLine ? kControlUpButtonPart
5552 : kControlDownButtonPart;
5553 if (slider->direction == Qt::RightToLeft
5554 && slider->orientation == Qt::Horizontal
5555 && (!slider->upsideDown
5556 || (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5557 && slider->upsideDown))
5559 if (cpc == kControlDownButtonPart)
5560 cpc = kControlUpButtonPart;
5561 else if (cpc == kControlUpButtonPart)
5562 cpc = kControlDownButtonPart;
5565 HIThemeGetTrackPartBounds(&tdi, cpc, &macRect);
5567 ret = qt_qrectForHIRect(macRect);
5569 // Tweak: the dark line between the sub/add line buttons belong to only one of the buttons
5570 // when doing hit-testing, but both of them have to repaint it. Extend the rect to cover
5571 // the line in the cases where HIThemeGetTrackPartBounds returns a rect that doesn't.
5572 if (slider->orientation == Qt::Horizontal) {
5573 if (slider->direction == Qt::LeftToRight && sc == SC_ScrollBarSubLine)
5574 ret.adjust(0, 0, 1, 0);
5575 else if (slider->direction == Qt::RightToLeft && sc == SC_ScrollBarAddLine)
5576 ret.adjust(-1, 0, 1, 0);
5577 } else if (sc == SC_ScrollBarAddLine) {
5578 ret.adjust(0, -1, 0, 1);
5583 if (const QStyleOptionTitleBar *titlebar
5584 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5585 HIThemeWindowDrawInfo wdi;
5586 memset(&wdi, 0, sizeof(wdi));
5587 wdi.version = qt_mac_hitheme_version;
5588 wdi.state = kThemeStateActive;
5589 wdi.windowType = QtWinType;
5590 wdi.titleHeight = titlebar->rect.height();
5591 wdi.titleWidth = titlebar->rect.width();
5592 wdi.attributes = kThemeWindowHasTitleText;
5593 if (titlebar->subControls & SC_TitleBarCloseButton)
5594 wdi.attributes |= kThemeWindowHasCloseBox;
5595 if (titlebar->subControls & SC_TitleBarMaxButton
5596 | SC_TitleBarNormalButton)
5597 wdi.attributes |= kThemeWindowHasFullZoom;
5598 if (titlebar->subControls & SC_TitleBarMinButton)
5599 wdi.attributes |= kThemeWindowHasCollapseBox;
5600 WindowRegionCode wrc = kWindowGlobalPortRgn;
5602 if (sc == SC_TitleBarCloseButton)
5603 wrc = kWindowCloseBoxRgn;
5604 else if (sc == SC_TitleBarMinButton)
5605 wrc = kWindowCollapseBoxRgn;
5606 else if (sc == SC_TitleBarMaxButton)
5607 wrc = kWindowZoomBoxRgn;
5608 else if (sc == SC_TitleBarLabel)
5609 wrc = kWindowTitleTextRgn;
5610 else if (sc == SC_TitleBarSysMenu)
5611 ret.setRect(-1024, -1024, 10, pixelMetric(PM_TitleBarHeight,
5613 if (wrc != kWindowGlobalPortRgn) {
5614 QCFType<HIShapeRef> region;
5615 QRect tmpRect = titlebar->rect;
5616 HIRect titleRect = qt_hirectForQRect(tmpRect);
5617 HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, ®ion);
5618 ptrHIShapeGetBounds(region, &titleRect);
5620 tmpRect.translate(tmpRect.x() - int(titleRect.origin.x),
5621 tmpRect.y() - int(titleRect.origin.y));
5622 titleRect = qt_hirectForQRect(tmpRect);
5623 HIThemeGetWindowShape(&titleRect, &wdi, wrc, ®ion);
5624 ptrHIShapeGetBounds(region, &titleRect);
5625 ret = qt_qrectForHIRect(titleRect);
5630 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5631 HIThemeButtonDrawInfo bdi;
5632 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5635 case SC_ComboBoxEditField:{
5636 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5637 // hack to posistion the edit feld correctly for QDateTimeEdits
5638 // in calendarPopup mode.
5639 if (qobject_cast<const QDateTimeEdit *>(widget)) {
5640 ret.moveTop(ret.top() - 2);
5641 ret.setHeight(ret.height() +1);
5644 case SC_ComboBoxArrow:{
5645 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5646 ret.setX(ret.x() + ret.width());
5647 ret.setWidth(combo->rect.width() - ret.width() - ret.x());
5649 case SC_ComboBoxListBoxPopup:{
5650 if (combo->editable) {
5651 HIRect inner = QMacStylePrivate::comboboxInnerBounds(qt_hirectForQRect(combo->rect), bdi.kind);
5652 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5653 ret.adjust(qRound(inner.origin.x), 0, qRound(inner.origin.x + inner.size.width), editRect.y() + editRect.height() + 2);
5655 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5656 ret.adjust(4 - 11, 1, editRect.width() + 10 + 11, 1);
5665 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5666 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5667 bool flat = (groupBox->features & QStyleOptionFrameV2::Flat);
5668 bool hasNoText = !checkable && groupBox->text.isEmpty();
5670 case SC_GroupBoxLabel:
5671 case SC_GroupBoxCheckBox: {
5672 // Cheat and use the smaller font if we need to
5673 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5674 bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont)
5675 || !QApplication::desktopSettingsAware());
5678 int margin = flat || hasNoText ? 0 : 12;
5679 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5682 HIThemeTextInfo tti;
5683 tti.version = qt_mac_hitheme_version;
5684 tti.state = kThemeStateActive;
5685 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5686 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5687 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5688 tti.options = kHIThemeTextBoxOptionNone;
5689 tti.truncationPosition = kHIThemeTextTruncationNone;
5690 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5693 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5694 HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0);
5698 QFontMetrics fm = groupBox->fontMetrics;
5699 if (!checkable && !fontIsSet)
5700 fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5702 tw = fm.size(Qt::TextShowMnemonic, groupBox->text).width();
5706 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5708 int indicatorWidth = pixelMetric(PM_IndicatorWidth, opt, widget);
5709 bool rtl = groupBox->direction == Qt::RightToLeft;
5710 if (sc == SC_GroupBoxLabel) {
5712 int newSum = indicatorWidth + 1;
5713 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5714 labelRect.moveLeft(newLeft);
5716 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5717 labelRect.moveLeft(newLeft);
5718 labelRect.moveTop(labelRect.top() + 3);
5720 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5721 labelRect.moveLeft(newLeft);
5722 labelRect.moveTop(labelRect.top() + 5);
5727 if (sc == SC_GroupBoxCheckBox) {
5728 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left();
5729 ret.setRect(left, ret.top(),
5730 indicatorWidth, pixelMetric(PM_IndicatorHeight, opt, widget));
5734 case SC_GroupBoxContents:
5735 case SC_GroupBoxFrame: {
5737 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5740 QFontMetrics fm = groupBox->fontMetrics;
5741 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5744 if (widget && !widget->testAttribute(Qt::WA_SetFont)
5745 && QApplication::desktopSettingsAware())
5746 fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5749 yOffset = -fm.height();
5752 ret = opt->rect.adjusted(0, fm.height() + yOffset, 0, 0);
5753 if (sc == SC_GroupBoxContents)
5754 ret.adjust(3, 3, -3, -4); // guess
5758 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5764 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5765 const int spinner_w = 14,
5766 fw = pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5769 case SC_SpinBoxDown: {
5770 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
5772 const int frameWidth = pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5773 const int spinner_w = 18;
5774 const int y = frameWidth;
5775 const int x = spin->rect.width() - spinner_w + frameWidth;
5776 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
5777 HIThemeButtonDrawInfo bdi;
5778 bdi.version = qt_mac_hitheme_version;
5779 bdi.kind = kThemeIncDecButton;
5780 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
5782 case QAquaSizeUnknown:
5783 case QAquaSizeLarge:
5784 bdi.kind = kThemeIncDecButton;
5787 case QAquaSizeSmall:
5788 if (aquaSize == QAquaSizeMini)
5789 bdi.kind = kThemeIncDecButtonMini;
5791 bdi.kind = kThemeIncDecButtonSmall;
5794 bdi.state = kThemeStateActive;
5795 bdi.value = kThemeButtonOff;
5796 bdi.adornment = kThemeAdornmentNone;
5797 HIRect hirect = qt_hirectForQRect(ret);
5799 HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect);
5800 ret = qt_qrectForHIRect(outRect);
5803 ret.setHeight(ret.height() / 2);
5805 case SC_SpinBoxDown:
5806 ret.setY(ret.y() + ret.height() / 2);
5812 ret.translate(-1, -2); // hack: position the buttons correctly (weird that we need this)
5813 ret = visualRect(spin->direction, spin->rect, ret);
5816 case SC_SpinBoxEditField:
5818 spin->rect.width() - spinner_w - fw * 2 - macSpinBoxSep + 1,
5819 spin->rect.height() - fw * 2);
5820 ret = visualRect(spin->direction, spin->rect, ret);
5823 ret = QWindowsStyle::subControlRect(cc, spin, sc, widget);
5829 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5830 if (sc == SC_ToolButtonMenu && widget && !qobject_cast<QToolBar*>(widget->parentWidget())) {
5831 ret.adjust(-1, 0, 0, 0);
5835 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5842 QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5843 const QSize &csz, const QWidget *widget) const
5846 bool useAquaGuideline = true;
5849 case QStyle::CT_SpinBox:
5850 sz.setWidth(sz.width() + macSpinBoxSep);
5851 sz.setHeight(sz.height() - 3); // hack to work around horrible sizeHint() code in QAbstractSpinBox
5853 case QStyle::CT_TabBarTab:
5854 if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
5856 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
5857 QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 ? true :
5860 const QAquaWidgetSize AquaSize = d->aquaSizeConstrain(opt, widget);
5861 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
5862 || !QApplication::desktopSettingsAware();
5863 ThemeTabDirection ttd = getTabDirection(tab->shape);
5864 bool vertTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
5868 int defaultTabHeight;
5869 int defaultExtraSpace = pixelMetric(PM_TabBarTabHSpace, tab, widget); // Remove spurious gcc warning (AFAIK)
5870 QFontMetrics fm = opt->fontMetrics;
5872 case QAquaSizeUnknown:
5873 case QAquaSizeLarge:
5874 if (tab->documentMode)
5875 defaultTabHeight = 23;
5877 defaultTabHeight = 21;
5879 case QAquaSizeSmall:
5880 defaultTabHeight = 18;
5883 defaultTabHeight = 16;
5887 bool setWidth = false;
5888 if (differentFont || !tab->icon.isNull()) {
5889 sz.rheight() = qMax(defaultTabHeight, sz.height());
5891 QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text);
5892 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5893 sz.rwidth() = textSize.width() + defaultExtraSpace;
5900 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5901 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5903 int widgetWidth = 0;
5904 int widgetHeight = 0;
5906 if (tab->leftButtonSize.isValid()) {
5908 widgetWidth += tab->leftButtonSize.width();
5909 widgetHeight += tab->leftButtonSize.height();
5911 if (tab->rightButtonSize.isValid()) {
5913 widgetWidth += tab->rightButtonSize.width();
5914 widgetHeight += tab->rightButtonSize.height();
5918 sz.setHeight(sz.height() + widgetHeight + padding);
5919 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5922 sz.setWidth(sz.width() + widgetWidth + padding);
5923 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5926 SInt32 tabh = sz.height();
5930 case QAquaSizeUnknown:
5931 case QAquaSizeLarge:
5932 GetThemeMetric(kThemeLargeTabHeight, &tabh);
5933 GetThemeMetric(kThemeMetricTabFrameOverlap, &overlap);
5936 GetThemeMetric(kThemeMetricMiniTabHeight, &tabh);
5937 GetThemeMetric(kThemeMetricMiniTabFrameOverlap, &overlap);
5939 case QAquaSizeSmall:
5940 GetThemeMetric(kThemeSmallTabHeight, &tabh);
5941 GetThemeMetric(kThemeMetricSmallTabFrameOverlap, &overlap);
5945 if (sz.height() < tabh)
5946 sz.rheight() = tabh;
5950 case QStyle::CT_PushButton:
5951 // By default, we fit the contents inside a normal rounded push button.
5952 // Do this by add enough space around the contents so that rounded
5953 // borders (including highlighting when active) will show.
5954 sz.rwidth() += PushButtonLeftOffset + PushButtonRightOffset + 12;
5955 sz.rheight() += PushButtonTopOffset + PushButtonBottomOffset;
5957 case QStyle::CT_MenuItem:
5958 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5959 int maxpmw = mi->maxIconWidth;
5960 const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
5963 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5966 GetThemeMenuSeparatorHeight(&ash);
5969 h = mi->fontMetrics.height() + 2;
5970 if (!mi->icon.isNull()) {
5972 const QSize &iconSize = comboBox->iconSize();
5973 h = qMax(h, iconSize.height() + 4);
5974 maxpmw = qMax(maxpmw, iconSize.width());
5976 int iconExtent = pixelMetric(PM_SmallIconSize);
5977 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5981 if (mi->text.contains(QLatin1Char('\t')))
5983 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5987 // add space for a check. All items have place for a check too.
5989 if (comboBox && comboBox->isVisible()) {
5990 QStyleOptionComboBox cmb;
5991 cmb.initFrom(comboBox);
5992 cmb.editable = false;
5993 cmb.subControls = QStyle::SC_ComboBoxEditField;
5994 cmb.activeSubControls = QStyle::SC_None;
5995 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
5996 QStyle::SC_ComboBoxEditField,
6012 QStyleHintReturnMask menuMask;
6013 QStyleOption myOption = *opt;
6014 myOption.rect.setSize(sz);
6015 if (styleHint(SH_Menu_Mask, &myOption, widget, &menuMask)) {
6016 sz = menuMask.region.boundingRect().size();
6019 case CT_HeaderSection:{
6020 const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
6021 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6022 if (header->text.contains(QLatin1Char('\n')))
6023 useAquaGuideline = false;
6026 // Make sure that the scroll bar is large enough to display the thumb indicator.
6027 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6028 const int minimumSize = scrollButtonsCutoffSize(thumbIndicatorCutoff, widgetSizePolicy(widget));
6029 if (slider->orientation == Qt::Horizontal)
6030 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6032 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6036 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6039 if (useAquaGuideline){
6041 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QAquaSizeUnknown) {
6042 if (macsz.width() != -1)
6043 sz.setWidth(macsz.width());
6044 if (macsz.height() != -1)
6045 sz.setHeight(macsz.height());
6049 // The sizes that Carbon and the guidelines gives us excludes the focus frame.
6050 // We compensate for this by adding some extra space here to make room for the frame when drawing:
6051 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
6052 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6054 switch (widgetSize) {
6056 case QAquaSizeLarge:
6057 bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
6059 case QAquaSizeSmall:
6060 bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
6063 bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
6066 HIRect tmpRect = {{0, 0}, {0, 0}};
6067 HIRect diffRect = QMacStylePrivate::comboboxInnerBounds(tmpRect, bkind);
6068 sz.rwidth() -= qRound(diffRect.size.width);
6069 sz.rheight() -= qRound(diffRect.size.height);
6070 } else if (ct == CT_PushButton || ct == CT_ToolButton){
6071 ThemeButtonKind bkind;
6072 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6076 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6077 if (btn->features & QStyleOptionButton::CommandLinkButton) {
6078 return QWindowsStyle::sizeFromContents(ct, opt, sz, widget);
6082 switch (widgetSize) {
6084 case QAquaSizeLarge:
6085 bkind = kThemePushButton;
6087 case QAquaSizeSmall:
6088 bkind = kThemePushButtonSmall;
6091 bkind = kThemePushButtonMini;
6096 switch (widgetSize) {
6098 case QAquaSizeLarge:
6099 bkind = kThemeLargeBevelButton;
6102 case QAquaSizeSmall:
6103 bkind = kThemeSmallBevelButton;
6108 HIThemeButtonDrawInfo bdi;
6109 bdi.version = qt_mac_hitheme_version;
6110 bdi.state = kThemeStateActive;
6112 bdi.value = kThemeButtonOff;
6113 bdi.adornment = kThemeAdornmentNone;
6114 HIRect macRect, myRect;
6115 myRect = CGRectMake(0, 0, sz.width(), sz.height());
6116 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
6117 // Mini buttons only return their actual size in HIThemeGetButtonBackgroundBounds, so help them out a bit (guess),
6118 if (bkind == kThemePushButtonMini)
6119 macRect.size.height += 8.;
6120 else if (bkind == kThemePushButtonSmall)
6121 macRect.size.height -= 10;
6122 sz.setWidth(sz.width() + int(macRect.size.width - myRect.size.width));
6123 sz.setHeight(sz.height() + int(macRect.size.height - myRect.size.height));
6131 void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
6132 bool enabled, const QString &text, QPalette::ColorRole textRole) const
6134 if(flags & Qt::TextShowMnemonic)
6135 flags |= Qt::TextHideMnemonic;
6136 QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6142 bool QMacStyle::event(QEvent *e)
6144 if(e->type() == QEvent::FocusIn) {
6146 QWidget *focusWidget = QApplication::focusWidget();
6147 #ifndef QT_NO_GRAPHICSVIEW
6148 if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
6149 QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
6150 if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
6151 QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(focusItem);
6152 if (proxy->widget())
6153 focusWidget = proxy->widget()->focusWidget();
6157 if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) {
6159 QWidget *top = f->parentWidget();
6160 while (top && !top->isWindow() && !(top->windowType() == Qt::SubWindow))
6161 top = top->parentWidget();
6162 #ifndef QT_NO_MAINWINDOW
6163 if (qobject_cast<QMainWindow *>(top)) {
6164 QWidget *central = static_cast<QMainWindow *>(top)->centralWidget();
6165 for (const QWidget *par = f; par; par = par->parentWidget()) {
6166 if (par == central) {
6170 if (par->isWindow())
6178 d->focusWidget = new QFocusFrame(f);
6179 d->focusWidget->setWidget(f);
6180 } else if(d->focusWidget) {
6181 d->focusWidget->setWidget(0);
6183 } else if(e->type() == QEvent::FocusOut) {
6185 d->focusWidget->setWidget(0);
6190 void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase)
6193 while (size <= 128) {
6195 const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size);
6197 if (standardIcon >= QStyle::SP_CustomBase) {
6198 mainIcon = qt_mac_convert_iconref(icon, size, size);
6199 } else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
6200 mainIcon = qt_mac_convert_iconref(icon, size, size);
6201 QPixmapCache::insert(cacheKey, mainIcon);
6205 int littleSize = size / 2;
6206 QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize);
6207 QPainter painter(&mainIcon);
6208 painter.drawPixmap(size - littleSize, size - littleSize, overlayPix);
6211 retIcon->addPixmap(mainIcon);
6212 size += size; // 16 -> 32 -> 64 -> 128
6219 QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt,
6220 const QWidget *widget) const
6222 OSType iconType = 0;
6223 switch (standardIcon) {
6224 case QStyle::SP_MessageBoxQuestion:
6225 case QStyle::SP_MessageBoxInformation:
6226 case QStyle::SP_MessageBoxWarning:
6227 case QStyle::SP_MessageBoxCritical:
6228 iconType = kGenericApplicationIcon;
6230 case SP_DesktopIcon:
6231 iconType = kDesktopIcon;
6234 iconType = kTrashIcon;
6236 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
6237 case SP_ComputerIcon:
6238 iconType = kComputerIcon;
6241 case SP_DriveFDIcon:
6242 iconType = kGenericFloppyIcon;
6244 case SP_DriveHDIcon:
6245 iconType = kGenericHardDiskIcon;
6247 case SP_DriveCDIcon:
6248 case SP_DriveDVDIcon:
6249 iconType = kGenericCDROMIcon;
6251 case SP_DriveNetIcon:
6252 iconType = kGenericNetworkIcon;
6254 case SP_DirOpenIcon:
6255 iconType = kOpenFolderIcon;
6257 case SP_DirClosedIcon:
6258 case SP_DirLinkIcon:
6259 iconType = kGenericFolderIcon;
6261 case SP_FileLinkIcon:
6263 iconType = kGenericDocumentIcon;
6265 case SP_ToolBarHorizontalExtensionButton:
6266 case SP_ToolBarVerticalExtensionButton: {
6267 QPixmap pixmap(qt_mac_toolbar_ext);
6268 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6269 QPixmap pix2(pixmap.height(), pixmap.width());
6270 pix2.fill(Qt::transparent);
6272 p.translate(pix2.width(), 0);
6274 p.drawPixmap(0, 0, pixmap);
6281 // A rather special case
6282 QIcon closeIcon = QStyle::standardIcon(SP_DirClosedIcon, opt, widget);
6283 QIcon openIcon = QStyle::standardIcon(SP_DirOpenIcon, opt, widget);
6284 closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On);
6285 closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On);
6286 closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On);
6287 closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On);
6290 case SP_TitleBarNormalButton:
6291 case SP_TitleBarCloseButton: {
6293 if (standardIcon == SP_TitleBarCloseButton) {
6294 titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-16.png"));
6295 titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
6297 titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-16.png"));
6298 titleBarIcon.addFile(QLatin1String(":/trolltech/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
6300 return titleBarIcon;
6305 if (iconType != 0) {
6308 IconRef overlayIcon = 0;
6309 if (iconType != kGenericApplicationIcon) {
6310 GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
6313 ProcessSerialNumber psn = { 0, kCurrentProcess };
6314 GetProcessBundleLocation(&psn, &fsRef);
6315 GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0);
6316 if (standardIcon == SP_MessageBoxCritical) {
6318 GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon);
6322 qt_mac_constructQIconFromIconRef(icon, overlayIcon, &retIcon, standardIcon);
6323 ReleaseIconRef(icon);
6326 ReleaseIconRef(overlayIcon);
6329 return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget);
6335 int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
6336 QSizePolicy::ControlType control2,
6337 Qt::Orientation orientation,
6338 const QStyleOption *option,
6339 const QWidget *widget) const
6341 const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton;
6342 bool isMetal = (widget && widget->testAttribute(Qt::WA_MacBrushedMetal));
6343 int controlSize = getControlSize(option, widget);
6345 if (control2 == QSizePolicy::ButtonBox) {
6347 AHIG seems to prefer a 12-pixel margin between group
6348 boxes and the row of buttons. The 20 pixel comes from
6351 if (isMetal // (AHIG, guess, guess)
6352 || (control1 & (QSizePolicy::Frame // guess
6353 | QSizePolicy::GroupBox // (AHIG, guess, guess)
6354 | QSizePolicy::TabWidget // guess
6355 | ButtonMask))) { // AHIG
6356 return_SIZE(14, 8, 8);
6357 } else if (control1 == QSizePolicy::LineEdit) {
6358 return_SIZE(8, 8, 8); // Interface Builder
6360 return_SIZE(20, 7, 7); // Interface Builder
6364 if ((control1 | control2) & ButtonMask) {
6365 if (control1 == QSizePolicy::LineEdit)
6366 return_SIZE(8, 8, 8); // Interface Builder
6367 else if (control2 == QSizePolicy::LineEdit) {
6368 if (orientation == Qt::Vertical)
6369 return_SIZE(20, 7, 7); // Interface Builder
6371 return_SIZE(20, 8, 8);
6373 return_SIZE(14, 8, 8); // Interface Builder
6376 switch (CT2(control1, control2)) {
6377 case CT1(QSizePolicy::Label): // guess
6378 case CT2(QSizePolicy::Label, QSizePolicy::DefaultType): // guess
6379 case CT2(QSizePolicy::Label, QSizePolicy::CheckBox): // AHIG
6380 case CT2(QSizePolicy::Label, QSizePolicy::ComboBox): // AHIG
6381 case CT2(QSizePolicy::Label, QSizePolicy::LineEdit): // guess
6382 case CT2(QSizePolicy::Label, QSizePolicy::RadioButton): // AHIG
6383 case CT2(QSizePolicy::Label, QSizePolicy::Slider): // guess
6384 case CT2(QSizePolicy::Label, QSizePolicy::SpinBox): // guess
6385 case CT2(QSizePolicy::Label, QSizePolicy::ToolButton): // guess
6386 return_SIZE(8, 6, 5);
6387 case CT1(QSizePolicy::ToolButton):
6389 case CT1(QSizePolicy::CheckBox):
6390 case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton):
6391 case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox):
6392 if (orientation == Qt::Vertical)
6393 return_SIZE(8, 8, 7); // AHIG and Builder
6395 case CT1(QSizePolicy::RadioButton):
6396 if (orientation == Qt::Vertical)
6397 return 5; // (Builder, guess, AHIG)
6400 if (orientation == Qt::Horizontal
6401 && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton)))
6402 return_SIZE(12, 10, 8); // guess
6404 if ((control1 | control2) & (QSizePolicy::Frame
6405 | QSizePolicy::GroupBox
6406 | QSizePolicy::TabWidget)) {
6408 These values were chosen so that nested container widgets
6409 look good side by side. Builder uses 8, which looks way
6410 too small, and AHIG doesn't say anything.
6412 return_SIZE(16, 10, 10); // guess
6415 if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider))
6416 return_SIZE(12, 10, 8); // AHIG
6418 if ((control1 | control2) & QSizePolicy::LineEdit)
6419 return_SIZE(10, 8, 8); // AHIG
6422 AHIG and Builder differ by up to 4 pixels for stacked editable
6423 comboboxes. We use some values that work fairly well in all
6426 if ((control1 | control2) & QSizePolicy::ComboBox)
6427 return_SIZE(10, 8, 7); // guess
6430 Builder defaults to 8, 6, 5 in lots of cases, but most of the time the
6431 result looks too cramped.
6433 return_SIZE(10, 8, 6); // guess