1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 Note: The qdoc comments for QMacStyle are contained in
44 .../doc/src/qstyles.qdoc.
47 #include <Cocoa/Cocoa.h>
49 #include "qmacstyle_mac.h"
50 #include "qmacstyle_mac_p.h"
51 #include "qmacstylepixmaps_mac_p.h"
53 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
54 //#define DEBUG_SIZE_CONSTRAINT
56 #include <private/qcore_mac_p.h>
57 #include <private/qcombobox_p.h>
58 #include <private/qpainter_p.h>
59 #include <qapplication.h>
61 #include <qcheckbox.h>
62 #include <qcombobox.h>
63 #include <qdialogbuttonbox.h>
64 #include <qdockwidget.h>
66 #include <qfocusframe.h>
67 #include <qformlayout.h>
68 #include <qgroupbox.h>
70 #include <qheaderview.h>
72 #include <qlineedit.h>
73 #include <qlistview.h>
74 #include <qmainwindow.h>
77 #include <qpaintdevice.h>
79 #include <qpixmapcache.h>
81 #include <qprogressbar.h>
82 #include <qpushbutton.h>
83 #include <qradiobutton.h>
84 #include <qrubberband.h>
85 #include <qsizegrip.h>
87 #include <qsplitter.h>
88 #include <qstyleoption.h>
89 #include <qtextedit.h>
90 #include <qtextstream.h>
92 #include <qtoolbutton.h>
93 #include <qtreeview.h>
94 #include <qtableview.h>
98 #include <qdatetimeedit.h>
100 #include <QtWidgets/qgraphicsproxywidget.h>
101 #include <QtWidgets/qgraphicsview.h>
102 #include <private/qstylehelper_p.h>
103 #include <QtGui/QPlatformFontDatabase>
107 // The following constants are used for adjusting the size
108 // of push buttons so that they are drawn inside their bounds.
109 const int QMacStylePrivate::PushButtonLeftOffset = 6;
110 const int QMacStylePrivate::PushButtonTopOffset = 4;
111 const int QMacStylePrivate::PushButtonRightOffset = 12;
112 const int QMacStylePrivate::PushButtonBottomOffset = 12;
113 const int QMacStylePrivate::MiniButtonH = 26;
114 const int QMacStylePrivate::SmallButtonH = 30;
115 const int QMacStylePrivate::BevelButtonW = 50;
116 const int QMacStylePrivate::BevelButtonH = 22;
117 const int QMacStylePrivate::PushButtonContentPadding = 6;
119 // These colors specify the titlebar gradient colors on
120 // Leopard. Ideally we should get them from the system.
121 static const QColor titlebarGradientActiveBegin(220, 220, 220);
122 static const QColor titlebarGradientActiveEnd(151, 151, 151);
123 static const QColor titlebarSeparatorLineActive(111, 111, 111);
124 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
125 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
126 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
128 // Gradient colors used for the dock widget title bar and
129 // non-unifed tool bar bacground.
130 static const QColor mainWindowGradientBegin(240, 240, 240);
131 static const QColor mainWindowGradientEnd(200, 200, 200);
133 static const int DisclosureOffset = 4;
135 // Resolve these at run-time, since the functions was moved in Leopard.
136 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
137 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
139 static int closeButtonSize = 12;
140 static bool isVerticalTabs(const QTabBar::Shape shape) {
141 return (shape == QTabBar::RoundedEast
142 || shape == QTabBar::TriangularEast
143 || shape == QTabBar::RoundedWest
144 || shape == QTabBar::TriangularWest);
147 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
149 // draw background circle
150 p->setRenderHints(QPainter::Antialiasing);
151 QRect rect(0, 0, closeButtonSize, closeButtonSize);
154 background = QColor(124, 124, 124);
158 background = QColor(104, 104, 104);
160 background = QColor(83, 83, 83);
163 background = QColor(144, 144, 144);
165 background = QColor(114, 114, 114);
168 p->setPen(Qt::transparent);
169 p->setBrush(background);
170 p->drawEllipse(rect);
176 crossPen.setColor(QColor(194, 194, 194));
177 crossPen.setWidthF(1.3);
178 crossPen.setCapStyle(Qt::FlatCap);
180 p->drawLine(min, min, max, max);
181 p->drawLine(min, max, max, min);
184 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
186 if (isVerticalTabs(shape)) {
187 int newX, newY, newRot;
188 if (shape == QTabBar::RoundedEast
189 || shape == QTabBar::TriangularEast) {
190 newX = tabRect.width();
195 newY = tabRect.y() + tabRect.height();
198 tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
200 m.translate(newX, newY);
202 p->setMatrix(m, true);
207 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt)
209 QRect r = tabOpt->rect;
210 p->translate(tabOpt->rect.x(), tabOpt->rect.y());
213 QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
215 int width = tabRect.width();
217 bool active = (tabOpt->state & QStyle::State_Active);
218 bool selected = (tabOpt->state & QStyle::State_Selected);
221 QRect rect(1, 0, width - 2, height);
225 int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 16 : 0;
226 p->fillRect(rect, QColor(151 + d, 151 + d, 151 + d));
228 int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 9 : 0;
229 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
230 gradient.setColorAt(0, QColor(207 + d, 207 + d, 207 + d));
231 gradient.setColorAt(0.5, QColor(206 + d, 206 + d, 206 + d));
232 gradient.setColorAt(1, QColor(201 + d, 201 + d, 201 + d));
233 p->fillRect(rect, gradient);
240 borderSides = QColor(88, 88, 88);
241 borderBottom = QColor(88, 88, 88);
243 borderSides = QColor(121, 121, 121);
244 borderBottom = QColor(116, 116, 116);
247 p->setPen(borderSides);
251 p->drawLine(0, 1, 0, bottom-2);
253 p->drawLine(width-1, 1, width-1, bottom-2);
257 p->setPen(QColor(168, 168, 168));
258 p->drawLine(3, bottom-1, width-3, bottom-1);
260 p->setPen(borderBottom);
261 p->drawLine(2, bottom, width-2, bottom);
264 QRectF rectangleLeft(1, height - w, w, w);
265 QRectF rectangleRight(width - 2, height - 1, w, w);
266 int startAngle = 180 * 16;
267 int spanAngle = 90 * 16;
268 p->setRenderHint(QPainter::Antialiasing);
269 p->drawArc(rectangleLeft, startAngle, spanAngle);
270 p->drawArc(rectangleRight, startAngle, -spanAngle);
272 // when the mouse is over non selected tabs they get a new color
273 bool hover = (tabOpt->state & QStyle::State_MouseOver);
275 QRect rect(1, 2, width - 1, height - 1);
276 p->fillRect(rect, QColor(110, 110, 110));
279 // seperator lines between tabs
280 bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
281 bool drawOnRight = !west;
282 if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
283 || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
285 QColor borderHighlightColor;
287 borderColor = QColor(64, 64, 64);
288 borderHighlightColor = QColor(140, 140, 140);
290 borderColor = QColor(135, 135, 135);
291 borderHighlightColor = QColor(178, 178, 178);
294 int x = drawOnRight ? width : 0;
296 // tab seperator line
297 p->setPen(borderColor);
298 p->drawLine(x, 2, x, height + 1);
300 // tab seperator highlight
301 p->setPen(borderHighlightColor);
302 p->drawLine(x-1, 2, x-1, height + 1);
303 p->drawLine(x+1, 2, x+1, height + 1);
308 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
311 if (isVerticalTabs(tbb->shape)) {
312 r.setWidth(w->width());
314 r.setHeight(w->height());
316 QRect tabRect = rotateTabPainter(p, tbb->shape, r);
317 int width = tabRect.width();
318 int height = tabRect.height();
319 bool active = (tbb->state & QStyle::State_Active);
322 QColor borderHighlightTop;
325 borderTop = QColor(64, 64, 64);
326 borderHighlightTop = QColor(174, 174, 174);
328 borderTop = QColor(135, 135, 135);
329 borderHighlightTop = QColor(207, 207, 207);
331 p->setPen(borderHighlightTop);
332 p->drawLine(tabRect.x(), 0, width, 0);
333 p->setPen(borderTop);
334 p->drawLine(tabRect.x(), 1, width, 1);
337 QRect centralRect(tabRect.x(), 2, width, height - 2);
339 QColor mainColor = QColor(120, 120, 120);
340 p->fillRect(centralRect, mainColor);
342 QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
343 gradient.setColorAt(0, QColor(165, 165, 165));
344 gradient.setColorAt(0.5, QColor(164, 164, 164));
345 gradient.setColorAt(1, QColor(158, 158, 158));
346 p->fillRect(centralRect, gradient);
349 // bottom border lines
350 QColor borderHighlightBottom;
353 borderHighlightBottom = QColor(153, 153, 153);
354 borderBottom = QColor(64, 64, 64);
356 borderHighlightBottom = QColor(177, 177, 177);
357 borderBottom = QColor(127, 127, 127);
359 p->setPen(borderHighlightBottom);
360 p->drawLine(tabRect.x(), height - 2, width, height - 2);
361 p->setPen(borderBottom);
362 p->drawLine(tabRect.x(), height - 1, width, height - 1);
365 static int getControlSize(const QStyleOption *option, const QWidget *widget)
368 if (option->state & (QStyle::State_Small | QStyle::State_Mini))
369 return (option->state & QStyle::State_Mini) ? QAquaSizeMini : QAquaSizeSmall;
371 switch (QMacStyle::widgetSizePolicy(widget)) {
372 case QMacStyle::SizeSmall:
373 return QAquaSizeSmall;
374 case QMacStyle::SizeMini:
375 return QAquaSizeMini;
380 return QAquaSizeLarge;
384 static inline bool isTreeView(const QWidget *widget)
386 return (widget && widget->parentWidget() &&
387 (qobject_cast<const QTreeView *>(widget->parentWidget())
391 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
393 ThemeTabDirection ttd;
395 case QTabBar::RoundedSouth:
396 case QTabBar::TriangularSouth:
397 ttd = kThemeTabSouth;
399 default: // Added to remove the warning, since all values are taken care of, really!
400 case QTabBar::RoundedNorth:
401 case QTabBar::TriangularNorth:
402 ttd = kThemeTabNorth;
404 case QTabBar::RoundedWest:
405 case QTabBar::TriangularWest:
408 case QTabBar::RoundedEast:
409 case QTabBar::TriangularEast:
416 static QString qt_mac_removeMnemonics(const QString &original)
418 QString returnText(original.size(), 0);
421 int l = original.length();
423 if (original.at(currPos) == QLatin1Char('&')
424 && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) {
430 returnText[finalDest] = original.at(currPos);
435 returnText.truncate(finalDest);
441 CGContextRef context;
443 QMacCGContext(QPainter *p); //qpaintengine_mac.cpp
444 inline QMacCGContext() { context = 0; }
445 inline QMacCGContext(const QPaintDevice *pdev) {
446 extern CGContextRef qt_mac_cg_context(const QPaintDevice *);
447 context = qt_mac_cg_context(pdev);
449 inline QMacCGContext(CGContextRef cg, bool takeOwnership=false) {
452 CGContextRetain(context);
454 inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; }
455 inline ~QMacCGContext() {
457 CGContextRelease(context);
459 inline bool isNull() const { return context; }
460 inline operator CGContextRef() { return context; }
461 inline QMacCGContext &operator=(const QMacCGContext ©) {
463 CGContextRelease(context);
464 context = copy.context;
465 CGContextRetain(context);
468 inline QMacCGContext &operator=(CGContextRef cg) {
470 CGContextRelease(context);
472 CGContextRetain(context); //we do not take ownership
477 static QColor qcolorFromCGColor(CGColorRef cgcolor)
480 CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor));
481 const CGFloat *components = CGColorGetComponents(cgcolor);
482 if (model == kCGColorSpaceModelRGB) {
483 pc.setRgbF(components[0], components[1], components[2], components[3]);
484 } else if (model == kCGColorSpaceModelCMYK) {
485 pc.setCmykF(components[0], components[1], components[2], components[3]);
486 } else if (model == kCGColorSpaceModelMonochrome) {
487 pc.setRgbF(components[0], components[0], components[0], components[1]);
489 // Colorspace we can't deal with.
490 qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model);
496 static inline QColor leopardBrush(ThemeBrush brush)
498 QCFType<CGColorRef> cgClr = 0;
499 HIThemeBrushCreateCGColor(brush, &cgClr);
500 return qcolorFromCGColor(cgClr);
503 QColor qcolorForTheme(ThemeBrush brush)
505 return leopardBrush(brush);
508 OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon)
510 QRegion *region = static_cast<QRegion *>(inRefcon);
515 case kHIShapeEnumerateRect:
516 *region += QRect(inRect->origin.x, inRect->origin.y,
517 inRect->size.width, inRect->size.height);
519 case kHIShapeEnumerateInit:
520 // Assume the region is already setup correctly
521 case kHIShapeEnumerateTerminate:
531 Create's a mutable shape, it's the caller's responsibility to release.
532 WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below.
534 HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion ®ion)
536 HIMutableShapeRef shape = HIShapeCreateMutable();
537 if (region.rectCount() < 2 ) {
538 QRect qtRect = region.boundingRect();
539 CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
540 HIShapeUnionWithRect(shape, &cgRect);
542 foreach (const QRect &qtRect, region.rects()) {
543 CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
544 HIShapeUnionWithRect(shape, &cgRect);
550 QRegion qt_mac_fromHIShapeRef(HIShapeRef shape)
552 QRegion returnRegion;
553 //returnRegion.detach();
554 HIShapeEnumerate(shape, kHIShapeParseFromTopLeft, qt_mac_shape2QRegionHelper, &returnRegion);
558 CGColorSpaceRef m_genericColorSpace = 0;
559 QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
560 bool m_postRoutineRegistered = false;
562 CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget);
563 CGColorSpaceRef qt_mac_genericColorSpace()
566 if (!m_genericColorSpace) {
567 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
568 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
569 m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
573 m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
575 if (!m_postRoutineRegistered) {
576 m_postRoutineRegistered = true;
577 qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
580 return m_genericColorSpace;
582 // Just return the main display colorspace for the moment.
583 return qt_mac_displayColorSpace(0);
588 Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc.
589 to support multiple displays correctly.
591 CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget)
593 CGColorSpaceRef colorSpace;
595 CGDirectDisplayID displayID;
596 CMProfileRef displayProfile = 0;
598 displayID = CGMainDisplayID();
600 displayID = CGMainDisplayID();
602 ### get correct display
603 const QRect &qrect = widget->window()->geometry();
604 CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height());
605 CGDisplayCount throwAway;
606 CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway);
607 if (dErr != kCGErrorSuccess)
608 return macDisplayColorSpace(0); // fall back on main display
611 if ((colorSpace = m_displayColorSpaceHash.value(displayID)))
614 CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile);
616 colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile);
618 return qt_mac_displayColorSpace(0); // fall back on main display
622 colorSpace = CGColorSpaceCreateDeviceRGB();
624 m_displayColorSpaceHash.insert(displayID, colorSpace);
625 CMCloseProfile(displayProfile);
626 if (!m_postRoutineRegistered) {
627 m_postRoutineRegistered = true;
628 void qt_mac_cleanUpMacColorSpaces();
629 qAddPostRoutine(qt_mac_cleanUpMacColorSpaces);
634 void qt_mac_cleanUpMacColorSpaces()
636 if (m_genericColorSpace) {
637 CFRelease(m_genericColorSpace);
638 m_genericColorSpace = 0;
640 QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin();
641 while (it != m_displayColorSpaceHash.constEnd()) {
643 CFRelease(it.value());
646 m_displayColorSpaceHash.clear();
649 bool qt_macWindowIsTextured(const QWidget *window)
651 NSWindow *nswindow = static_cast<NSWindow*>(
652 QApplication::platformNativeInterface()->nativeResourceForWindow("NSWindow", window->windowHandle()));
655 return ([nswindow styleMask] & NSTexturedBackgroundWindowMask) ? true : false;
658 /*****************************************************************************
660 *****************************************************************************/
661 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
662 const int macItemFrame = 2; // menu item frame width
663 const int macItemHMargin = 3; // menu item hor text margin
664 const int macItemVMargin = 2; // menu item ver text margin
665 const int macRightBorder = 12; // right border on mac
666 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
667 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
669 /*****************************************************************************
670 QMacCGStyle utility functions
671 *****************************************************************************/
672 static inline int qt_mac_hitheme_tab_version()
677 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
679 return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
680 convertRect.width() - rect.width(), convertRect.height() - rect.height());
683 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
685 return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
686 QSize(int(hirect.size.width), int(hirect.size.height)));
689 inline bool qt_mac_is_metal(const QWidget *w)
691 for (; w; w = w->parentWidget()) {
692 if (w->testAttribute(Qt::WA_MacBrushedMetal))
694 if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) { // If not created will fall through to the opaque check and be fine anyway.
695 return qt_macWindowIsTextured(w);
697 if (w->d_func()->isOpaque)
703 static int qt_mac_aqua_get_metric(ThemeMetric met)
706 GetThemeMetric(met, &ret);
710 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
714 if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
715 qDebug("Not sure how to return this...");
718 if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
719 // If you're using a custom font and it's bigger than the default font,
720 // then no constraints for you. If you are smaller, we can try to help you out
721 QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
722 if (widg->font().pointSize() > font.pointSize())
726 if (ct == QStyle::CT_CustomBase && widg) {
727 if (qobject_cast<const QPushButton *>(widg))
728 ct = QStyle::CT_PushButton;
729 else if (qobject_cast<const QRadioButton *>(widg))
730 ct = QStyle::CT_RadioButton;
731 else if (qobject_cast<const QCheckBox *>(widg))
732 ct = QStyle::CT_CheckBox;
733 else if (qobject_cast<const QComboBox *>(widg))
734 ct = QStyle::CT_ComboBox;
735 else if (qobject_cast<const QToolButton *>(widg))
736 ct = QStyle::CT_ToolButton;
737 else if (qobject_cast<const QSlider *>(widg))
738 ct = QStyle::CT_Slider;
739 else if (qobject_cast<const QProgressBar *>(widg))
740 ct = QStyle::CT_ProgressBar;
741 else if (qobject_cast<const QLineEdit *>(widg))
742 ct = QStyle::CT_LineEdit;
743 else if (qobject_cast<const QHeaderView *>(widg))
744 ct = QStyle::CT_HeaderSection;
745 else if (qobject_cast<const QMenuBar *>(widg))
746 ct = QStyle::CT_MenuBar;
747 else if (qobject_cast<const QSizeGrip *>(widg))
748 ct = QStyle::CT_SizeGrip;
754 case QStyle::CT_PushButton: {
755 const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
756 // If this comparison is false, then the widget was not a push button.
757 // This is bad and there's very little we can do since we were requested to find a
758 // sensible size for a widget that pretends to be a QPushButton but is not.
760 QString buttonText = qt_mac_removeMnemonics(psh->text());
761 if (buttonText.contains(QLatin1Char('\n')))
763 else if (sz == QAquaSizeLarge)
764 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
765 else if (sz == QAquaSizeSmall)
766 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
767 else if (sz == QAquaSizeMini)
768 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
770 if (!psh->icon().isNull()){
771 // If the button got an icon, and the icon is larger than the
772 // button, we can't decide on a default size
774 if (ret.height() < psh->iconSize().height())
777 else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
778 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
779 // However, this doesn't work for German, therefore only do it for English,
780 // I suppose it would be better to do some sort of lookups for languages
781 // that like to have really long words.
782 ret.setWidth(77 - 8);
785 // The only sensible thing to do is to return whatever the style suggests...
786 if (sz == QAquaSizeLarge)
787 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
788 else if (sz == QAquaSizeSmall)
789 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
790 else if (sz == QAquaSizeMini)
791 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
793 // Since there's no default size we return the large size...
794 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
796 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
797 } else if (ct == QStyle::CT_RadioButton) {
798 QRadioButton *rdo = static_cast<QRadioButton *>(widg);
799 // Exception for case where multiline radio button text requires no size constrainment
800 if (rdo->text().find('\n') != -1)
802 if (sz == QAquaSizeLarge)
803 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
804 else if (sz == QAquaSizeSmall)
805 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
806 else if (sz == QAquaSizeMini)
807 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
808 } else if (ct == QStyle::CT_CheckBox) {
809 if (sz == QAquaSizeLarge)
810 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
811 else if (sz == QAquaSizeSmall)
812 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
813 else if (sz == QAquaSizeMini)
814 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
818 case QStyle::CT_SizeGrip:
819 if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
821 HIPoint p = { 0, 0 };
822 HIThemeGrowBoxDrawInfo gbi;
824 gbi.state = kThemeStateActive;
825 gbi.kind = kHIThemeGrowBoxKindNormal;
826 gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
827 : kThemeGrowRight | kThemeGrowDown;
828 gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
829 if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr)
830 ret = QSize(r.size.width, r.size.height);
833 case QStyle::CT_ComboBox:
836 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
839 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
842 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
848 case QStyle::CT_ToolButton:
849 if (sz == QAquaSizeSmall) {
850 int width = 0, height = 0;
851 if (szHint == QSize(-1, -1)) { //just 'guess'..
852 const QToolButton *bt = qobject_cast<const QToolButton *>(widg);
853 // If this conversion fails then the widget was not what it claimed to be.
855 if (!bt->icon().isNull()) {
856 QSize iconSize = bt->iconSize();
857 QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
858 width = qMax(width, qMax(iconSize.width(), pmSize.width()));
859 height = qMax(height, qMax(iconSize.height(), pmSize.height()));
861 if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
862 int text_width = bt->fontMetrics().width(bt->text()),
863 text_height = bt->fontMetrics().height();
864 if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
865 width = qMax(width, text_width);
866 height += text_height;
869 width = qMax(height, text_height);
873 // Let's return the size hint...
874 width = szHint.width();
875 height = szHint.height();
878 width = szHint.width();
879 height = szHint.height();
881 width = qMax(20, width + 5); //border
882 height = qMax(20, height + 5); //border
883 ret = QSize(width, height);
886 case QStyle::CT_Slider: {
888 const QSlider *sld = qobject_cast<const QSlider *>(widg);
889 // If this conversion fails then the widget was not what it claimed to be.
891 if (sz == QAquaSizeLarge) {
892 if (sld->orientation() == Qt::Horizontal) {
893 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
894 if (sld->tickPosition() != QSlider::NoTicks)
895 w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
897 w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
898 if (sld->tickPosition() != QSlider::NoTicks)
899 w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
901 } else if (sz == QAquaSizeSmall) {
902 if (sld->orientation() == Qt::Horizontal) {
903 w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
904 if (sld->tickPosition() != QSlider::NoTicks)
905 w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
907 w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
908 if (sld->tickPosition() != QSlider::NoTicks)
909 w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
911 } else if (sz == QAquaSizeMini) {
912 if (sld->orientation() == Qt::Horizontal) {
913 w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
914 if (sld->tickPosition() != QSlider::NoTicks)
915 w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
917 w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
918 if (sld->tickPosition() != QSlider::NoTicks)
919 w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
923 // This is tricky, we were requested to find a size for a slider which is not
924 // a slider. We don't know if this is vertical or horizontal or if we need to
925 // have tick marks or not.
926 // For this case we will return an horizontal slider without tick marks.
927 w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
928 w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
930 if (sld->orientation() == Qt::Horizontal)
936 case QStyle::CT_ProgressBar: {
938 Qt::Orientation orient = Qt::Horizontal;
939 if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
940 orient = pb->orientation();
942 if (sz == QAquaSizeLarge)
943 finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
944 + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
946 finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
947 + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
948 if (orient == Qt::Horizontal)
949 ret.setHeight(finalValue);
951 ret.setWidth(finalValue);
954 case QStyle::CT_LineEdit:
955 if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
956 //should I take into account the font dimentions of the lineedit? -Sam
957 if (sz == QAquaSizeLarge)
963 case QStyle::CT_HeaderSection:
964 if (isTreeView(widg))
965 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
967 case QStyle::CT_MenuBar:
968 if (sz == QAquaSizeLarge) {
969 ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
970 // In the qt_mac_set_native_menubar(false) case,
971 // we come it here with a zero-height main menu,
972 // preventing the in-window menu from displaying.
973 // Use 22 pixels for the height, by observation.
974 if (ret.height() <= 0)
985 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
986 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
988 if (large == QSize(-1, -1)) {
989 if (small != QSize(-1, -1))
990 return QAquaSizeSmall;
991 if (mini != QSize(-1, -1))
992 return QAquaSizeMini;
993 return QAquaSizeUnknown;
994 } else if (small == QSize(-1, -1)) {
995 if (mini != QSize(-1, -1))
996 return QAquaSizeMini;
997 return QAquaSizeLarge;
998 } else if (mini == QSize(-1, -1)) {
999 return QAquaSizeLarge;
1002 #ifndef QT_NO_MAINWINDOW
1003 if (qobject_cast<QDockWidget *>(widg->window()) || !qgetenv("QWIDGET_ALL_SMALL").isNull()) {
1004 //if (small.width() != -1 || small.height() != -1)
1005 return QAquaSizeSmall;
1006 } else if (!qgetenv("QWIDGET_ALL_MINI").isNull()) {
1007 return QAquaSizeMini;
1012 /* Figure out which size we're closer to, I just hacked this in, I haven't
1013 tested it as it would probably look pretty strange to have some widgets
1014 big and some widgets small in the same window?? -Sam */
1016 if (large.width() != -1) {
1017 int delta = large.width() - widg->width();
1018 large_delta += delta * delta;
1020 if (large.height() != -1) {
1021 int delta = large.height() - widg->height();
1022 large_delta += delta * delta;
1025 if (small.width() != -1) {
1026 int delta = small.width() - widg->width();
1027 small_delta += delta * delta;
1029 if (small.height() != -1) {
1030 int delta = small.height() - widg->height();
1031 small_delta += delta * delta;
1034 if (mini.width() != -1) {
1035 int delta = mini.width() - widg->width();
1036 mini_delta += delta * delta;
1038 if (mini.height() != -1) {
1039 int delta = mini.height() - widg->height();
1040 mini_delta += delta * delta;
1042 if (mini_delta < small_delta && mini_delta < large_delta)
1043 return QAquaSizeMini;
1044 else if (small_delta < large_delta)
1045 return QAquaSizeSmall;
1047 return QAquaSizeLarge;
1051 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
1052 QStyle::ContentsType ct, QSize szHint, QSize *insz) const
1054 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1056 if (option->state & QStyle::State_Small)
1057 return QAquaSizeSmall;
1058 if (option->state & QStyle::State_Mini)
1059 return QAquaSizeMini;
1065 if (!qgetenv("QWIDGET_ALL_SMALL").isNull())
1066 return QAquaSizeSmall;
1067 if (!qgetenv("QWIDGET_ALL_MINI").isNull())
1068 return QAquaSizeMini;
1069 return QAquaSizeUnknown;
1071 QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
1072 small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
1073 mini = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
1074 bool guess_size = false;
1075 QAquaWidgetSize ret = QAquaSizeUnknown;
1076 QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
1077 if (wsp == QMacStyle::SizeDefault)
1079 else if (wsp == QMacStyle::SizeMini)
1080 ret = QAquaSizeMini;
1081 else if (wsp == QMacStyle::SizeSmall)
1082 ret = QAquaSizeSmall;
1083 else if (wsp == QMacStyle::SizeLarge)
1084 ret = QAquaSizeLarge;
1086 ret = qt_aqua_guess_size(widg, large, small, mini);
1089 if (ret == QAquaSizeSmall)
1091 else if (ret == QAquaSizeLarge)
1093 else if (ret == QAquaSizeMini)
1096 *insz = sz ? *sz : QSize(-1, -1);
1097 #ifdef DEBUG_SIZE_CONSTRAINT
1099 const char *size_desc = "Unknown";
1101 size_desc = "Small";
1102 else if (sz == &large)
1103 size_desc = "Large";
1104 else if (sz == &mini)
1106 qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
1107 widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
1108 widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
1109 sz->width(), sz->height());
1119 return QAquaSizeUnknown;
1124 Returns the free space awailable for contents inside the
1125 button (and not the size of the contents itself)
1127 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
1128 const HIThemeButtonDrawInfo *bdi) const
1130 HIRect outerBounds = qt_hirectForQRect(btn->rect);
1131 // Adjust the bounds to correct for
1132 // carbon not calculating the content bounds fully correct
1133 if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
1134 outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1135 outerBounds.size.height -= QMacStylePrivate::PushButtonBottomOffset;
1136 } else if (bdi->kind == kThemePushButtonMini) {
1137 outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1140 HIRect contentBounds;
1141 HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
1142 return contentBounds;
1146 Calculates the size of the button contents.
1147 This includes both the text and the icon.
1149 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
1152 QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
1153 : (btn->iconSize + QSize(QMacStylePrivate::PushButtonContentPadding, 0));
1154 QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
1155 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
1156 csz.setWidth(iconSize.width() + textRect.width()
1157 + ((btn->features & QStyleOptionButton::HasMenu)
1158 ? q->proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
1159 csz.setHeight(qMax(iconSize.height(), textRect.height()));
1164 Checks if the actual contents of btn fits inside the free content bounds of
1165 'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
1166 for determining which button kind to use for drawing.
1168 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
1169 HIThemeButtonDrawInfo *bdi,
1170 ThemeButtonKind buttonKindToCheck) const
1172 ThemeButtonKind tmp = bdi->kind;
1173 bdi->kind = buttonKindToCheck;
1174 QSize contentSize = pushButtonSizeFromContents(btn);
1175 QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
1177 return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
1178 contentSize.width(), contentSize.height()));
1182 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1183 kind and other details to use for drawing the given push button. Which
1184 button kind depends on the size of the button, the size of the contents,
1185 explicit user style settings, etc.
1187 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1188 const QWidget *widget,
1189 const ThemeDrawState tds,
1190 HIThemeButtonDrawInfo *bdi) const
1192 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
1193 ThemeDrawState tdsModified = tds;
1194 if (btn->state & QStyle::State_On)
1195 tdsModified = kThemeStatePressed;
1196 bdi->version = qt_mac_hitheme_version;
1197 bdi->state = tdsModified;
1198 bdi->value = kThemeButtonOff;
1200 if (drawColorless && tdsModified == kThemeStateInactive)
1201 bdi->state = kThemeStateActive;
1202 if (btn->state & QStyle::State_HasFocus)
1203 bdi->adornment = kThemeAdornmentFocus;
1205 bdi->adornment = kThemeAdornmentNone;
1208 if (btn->features & (QStyleOptionButton::Flat)) {
1209 bdi->kind = kThemeBevelButton;
1211 switch (aquaSizeConstrain(btn, widget)) {
1212 case QAquaSizeSmall:
1213 bdi->kind = kThemePushButtonSmall;
1216 bdi->kind = kThemePushButtonMini;
1218 case QAquaSizeLarge:
1219 // ... We should honor if the user is explicit about using the
1220 // large button. But right now Qt will specify the large button
1221 // as default rather than QAquaSizeUnknown.
1222 // So we treat it like QAquaSizeUnknown
1223 // to get the dynamic choosing of button kind.
1224 case QAquaSizeUnknown:
1225 // Choose the button kind that closest match the button rect, but at the
1226 // same time displays the button contents without clipping.
1227 bdi->kind = kThemeBevelButton;
1228 if (btn->rect.width() >= QMacStylePrivate::BevelButtonW && btn->rect.height() >= QMacStylePrivate::BevelButtonH){
1229 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1230 if (btn->rect.height() <= QMacStylePrivate::MiniButtonH){
1231 if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1232 bdi->kind = kThemePushButtonMini;
1233 } else if (btn->rect.height() <= QMacStylePrivate::SmallButtonH){
1234 if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1235 bdi->kind = kThemePushButtonSmall;
1236 } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1237 bdi->kind = kThemePushButton;
1240 bdi->kind = kThemePushButton;
1247 bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
1249 QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
1252 HIThemeButtonDrawInfo bdi;
1253 macStyle->d->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
1254 return bdi.kind == kThemeBevelButton;
1258 Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1259 kind and other details to use for drawing the given combobox. Which button
1260 kind depends on the size of the combo, wether or not it is editable,
1261 explicit user style settings, etc.
1263 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1264 const QWidget *widget, const ThemeDrawState &tds)
1266 bdi->version = qt_mac_hitheme_version;
1267 bdi->adornment = kThemeAdornmentArrowLeftArrow;
1268 bdi->value = kThemeButtonOff;
1269 if (combo->state & QStyle::State_HasFocus)
1270 bdi->adornment = kThemeAdornmentFocus;
1271 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
1272 if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1273 bdi->state = kThemeStatePressed;
1274 else if (drawColorless)
1275 bdi->state = kThemeStateActive;
1279 QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1282 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1283 : ThemeButtonKind(kThemePopupButtonMini);
1285 case QAquaSizeSmall:
1286 bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1287 : ThemeButtonKind(kThemePopupButtonSmall);
1289 case QAquaSizeUnknown:
1290 case QAquaSizeLarge:
1291 // Unless the user explicitly specified large buttons, determine the
1292 // kind by looking at the combox size.
1293 // ... specifying small and mini-buttons it not a current feature of
1294 // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1295 // an extra check here before using the mini and small buttons.
1296 int h = combo->rect.size().height();
1297 if (combo->editable){
1299 bdi->kind = kThemeComboBoxMini;
1301 bdi->kind = kThemeComboBoxSmall;
1303 bdi->kind = kThemeComboBox;
1305 // Even if we specify that we want the kThemePopupButton, Carbon
1306 // will use the kThemePopupButtonSmall if the size matches. So we
1307 // do the same size check explicit to have the size of the inner
1308 // text field be correct. Therefore, do this even if the user specifies
1309 // the use of LargeButtons explicit.
1311 bdi->kind = kThemePopupButtonMini;
1313 bdi->kind = kThemePopupButtonSmall;
1315 bdi->kind = kThemePopupButton;
1322 Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1323 the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1325 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1327 HIRect innerBounds = outerBounds;
1328 // Carbon draw parts of the view outside the rect.
1329 // So make the rect a bit smaller to compensate
1330 // (I wish HIThemeGetButtonBackgroundBounds worked)
1331 switch (buttonKind){
1332 case kThemePopupButton:
1333 innerBounds.origin.x += 2;
1334 innerBounds.origin.y += 3;
1335 innerBounds.size.width -= 5;
1336 innerBounds.size.height -= 6;
1338 case kThemePopupButtonSmall:
1339 innerBounds.origin.x += 3;
1340 innerBounds.origin.y += 3;
1341 innerBounds.size.width -= 6;
1342 innerBounds.size.height -= 7;
1344 case kThemePopupButtonMini:
1345 innerBounds.origin.x += 2;
1346 innerBounds.origin.y += 2;
1347 innerBounds.size.width -= 5;
1348 innerBounds.size.height -= 6;
1350 case kThemeComboBox:
1351 innerBounds.origin.x += 3;
1352 innerBounds.origin.y += 3;
1353 innerBounds.size.width -= 6;
1354 innerBounds.size.height -= 6;
1356 case kThemeComboBoxSmall:
1357 innerBounds.origin.x += 3;
1358 innerBounds.origin.y += 3;
1359 innerBounds.size.width -= 7;
1360 innerBounds.size.height -= 8;
1362 case kThemeComboBoxMini:
1363 innerBounds.origin.x += 3;
1364 innerBounds.origin.y += 3;
1365 innerBounds.size.width -= 4;
1366 innerBounds.size.height -= 8;
1375 Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1376 of combobox we choose to draw. This function calculates and returns this size.
1378 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1380 QRect ret = outerBounds;
1382 case kThemeComboBox:
1383 ret.adjust(5, 8, -21, -4);
1385 case kThemeComboBoxSmall:
1386 ret.adjust(4, 5, -18, 0);
1389 case kThemeComboBoxMini:
1390 ret.adjust(4, 5, -16, 0);
1393 case kThemePopupButton:
1394 ret.adjust(10, 3, -23, -3);
1396 case kThemePopupButtonSmall:
1397 ret.adjust(9, 3, -20, -3);
1399 case kThemePopupButtonMini:
1400 ret.adjust(8, 3, -19, 0);
1408 Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1409 create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1410 it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1412 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1414 if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1415 // We have an unscaled combobox, or popup-button; use Carbon directly.
1416 HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1417 HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1420 QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1421 if (!QPixmapCache::find(key, buffer)) {
1422 HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1423 buffer = QPixmap(35, 28);
1424 buffer.fill(Qt::transparent);
1425 QPainter buffPainter(&buffer);
1426 HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1428 QPixmapCache::insert(key, buffer);
1431 const int bwidth = 20;
1432 const int fwidth = 10;
1433 const int fheight = 10;
1434 int w = qRound(outerBounds.size.width);
1435 int h = qRound(outerBounds.size.height);
1436 int bstart = w - bwidth;
1437 int blower = fheight + 1;
1438 int flower = h - fheight;
1439 int sheight = flower - fheight;
1440 int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1442 // Draw upper and lower gap
1443 p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1444 p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1445 // Draw left and right gap. Right gap is drawn top and bottom separatly
1446 p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1447 p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1448 p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1450 p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1452 p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1453 p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1454 p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1455 p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1460 Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1461 onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1463 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1464 bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1466 static SInt32 headerHeight = 0;
1467 static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1471 QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1472 if (!QPixmapCache::find(key, buffer)) {
1473 HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1474 buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1475 buffer.fill(Qt::transparent);
1476 QPainter buffPainter(&buffer);
1477 HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1479 QPixmapCache::insert(key, buffer);
1481 const int buttonw = qRound(outerBounds.size.width);
1482 const int buttonh = qRound(outerBounds.size.height);
1483 const int framew = 1;
1484 const int frameh_n = 4;
1485 const int frameh_s = 3;
1486 const int transh = buffer.height() - frameh_n - frameh_s;
1487 int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1489 int skipTopBorder = 0;
1493 p->translate(outerBounds.origin.x, outerBounds.origin.y);
1495 p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1496 p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1497 // Draw upper and lower center blocks
1498 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1499 p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1500 // Draw right center block borders
1501 p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1502 p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1503 // Draw right corners
1504 p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1505 p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1506 // Draw center transition block
1507 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));
1508 // Draw right center transition block border
1509 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));
1510 if (drawLeftBorder){
1511 // Draw left center block borders
1512 p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1513 p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1514 // Draw left corners
1515 p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1516 p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1517 // Draw left center transition block border
1518 p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1521 p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1525 Returns cutoff sizes for scroll bars.
1526 thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1527 scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1529 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1530 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1532 // Mini scroll bars do not exist as of version 10.4.
1533 if (widgetSize == QMacStyle::SizeMini)
1536 const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1537 static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1538 return sizeTable[sizeIndex][cutoffType];
1541 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1542 HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe)
1544 memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1545 tdi->version = qt_mac_hitheme_version;
1548 bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1549 switch (aquaSizeConstrain(0, needToRemoveMe)) {
1550 case QAquaSizeUnknown:
1551 case QAquaSizeLarge:
1553 tdi->kind = kThemeMediumScrollBar;
1555 tdi->kind = kThemeMediumSlider;
1559 tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1561 tdi->kind = kThemeMiniSlider;
1563 case QAquaSizeSmall:
1565 tdi->kind = kThemeSmallScrollBar;
1567 tdi->kind = kThemeSmallSlider;
1570 tdi->bounds = qt_hirectForQRect(slider->rect);
1571 tdi->min = slider->minimum;
1572 tdi->max = slider->maximum;
1573 tdi->value = slider->sliderPosition;
1574 tdi->attributes = kThemeTrackShowThumb;
1575 if (slider->upsideDown)
1576 tdi->attributes |= kThemeTrackRightToLeft;
1577 if (slider->orientation == Qt::Horizontal) {
1578 tdi->attributes |= kThemeTrackHorizontal;
1579 if (isScrollbar && slider->direction == Qt::RightToLeft) {
1580 if (!slider->upsideDown)
1581 tdi->attributes |= kThemeTrackRightToLeft;
1583 tdi->attributes &= ~kThemeTrackRightToLeft;
1587 // Tiger broke reverse scroll bars so put them back and "fake it"
1588 if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)) {
1589 tdi->attributes &= ~kThemeTrackRightToLeft;
1590 tdi->value = tdi->max - slider->sliderPosition;
1593 tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1594 : kThemeTrackDisabled;
1595 if (!(slider->state & QStyle::State_Active))
1596 tdi->enableState = kThemeTrackInactive;
1598 if (slider->state & QStyle::QStyle::State_HasFocus)
1599 tdi->attributes |= kThemeTrackHasFocus;
1600 if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1601 tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1602 else if (slider->tickPosition == QSlider::TicksAbove)
1603 tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1605 tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1607 tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1611 QMacStylePrivate::QMacStylePrivate(QMacStyle *style)
1612 : timerID(-1), progressFrame(0), q(style), mouseDown(false)
1614 defaultButtonStart = CFAbsoluteTimeGetCurrent();
1615 memset(&buttonState, 0, sizeof(ButtonState));
1617 if (ptrHIShapeGetBounds == 0) {
1618 QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1619 library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1620 ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1625 bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QWidget *w) const
1630 if (as == AquaPushButton) {
1631 QPushButton *pb = const_cast<QPushButton *>(static_cast<const QPushButton *>(w));
1632 if (w->window()->isActiveWindow() && pb && !mouseDown) {
1633 if (static_cast<const QPushButton *>(w) != defaultButton) {
1634 // Changed on its own, update the value.
1635 const_cast<QMacStylePrivate *>(this)->stopAnimate(as, defaultButton);
1636 const_cast<QMacStylePrivate *>(this)->startAnimate(as, pb);
1640 } else if (as == AquaProgressBar) {
1641 if (progressBars.contains((const_cast<QWidget *>(w))))
1647 void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QWidget *w)
1649 if (as == AquaPushButton && defaultButton) {
1650 QPushButton *tmp = defaultButton;
1653 } else if (as == AquaProgressBar) {
1654 progressBars.removeAll(w);
1658 void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QWidget *w)
1660 if (as == AquaPushButton)
1661 defaultButton = static_cast<QPushButton *>(w);
1662 else if (as == AquaProgressBar)
1663 progressBars.append(w);
1664 startAnimationTimer();
1667 void QMacStylePrivate::startAnimationTimer()
1669 if ((defaultButton || !progressBars.isEmpty()) && timerID <= -1)
1670 timerID = startTimer(animateSpeed(AquaListViewItemOpen));
1673 bool QMacStylePrivate::addWidget(QWidget *w)
1675 //already knew of it
1676 if (static_cast<QPushButton*>(w) == defaultButton
1677 || progressBars.contains(static_cast<QProgressBar*>(w)))
1680 if (QPushButton *btn = qobject_cast<QPushButton *>(w)) {
1681 btn->installEventFilter(this);
1682 if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus()))
1683 startAnimate(AquaPushButton, btn);
1686 bool isProgressBar = (qobject_cast<QProgressBar *>(w));
1687 if (isProgressBar) {
1688 w->installEventFilter(this);
1689 startAnimate(AquaProgressBar, w);
1693 if (w->isWindow()) {
1694 w->installEventFilter(this);
1700 void QMacStylePrivate::removeWidget(QWidget *w)
1702 QPushButton *btn = qobject_cast<QPushButton *>(w);
1703 if (btn && btn == defaultButton) {
1704 stopAnimate(AquaPushButton, btn);
1705 } else if (qobject_cast<QProgressBar *>(w)) {
1706 stopAnimate(AquaProgressBar, w);
1710 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1712 ThemeDrawState tds = kThemeStateActive;
1713 if (flags & QStyle::State_Sunken) {
1714 tds = kThemeStatePressed;
1715 } else if (flags & QStyle::State_Active) {
1716 if (!(flags & QStyle::State_Enabled))
1717 tds = kThemeStateUnavailable;
1719 if (flags & QStyle::State_Enabled)
1720 tds = kThemeStateInactive;
1722 tds = kThemeStateUnavailableInactive;
1727 void QMacStylePrivate::timerEvent(QTimerEvent *)
1730 if (defaultButton && defaultButton->isEnabled() && defaultButton->window()->isActiveWindow()
1731 && defaultButton->isVisibleTo(0) && (defaultButton->isDefault()
1732 || (defaultButton->autoDefault() && defaultButton->hasFocus()))
1733 && doAnimate(AquaPushButton)) {
1735 defaultButton->update();
1737 if (!progressBars.isEmpty()) {
1739 while (i < progressBars.size()) {
1740 QWidget *maybeProgress = progressBars.at(i);
1741 if (!maybeProgress) {
1742 progressBars.removeAt(i);
1744 if (QProgressBar *pb = qobject_cast<QProgressBar *>(maybeProgress)) {
1745 if (pb->maximum() == 0 || (pb->value() > 0 && pb->value() < pb->maximum())) {
1746 if (doAnimate(AquaProgressBar))
1758 if (animated <= 0) {
1764 bool QMacStylePrivate::eventFilter(QObject *o, QEvent *e)
1767 if (QProgressBar *pb = qobject_cast<QProgressBar *>(o)) {
1768 switch (e->type()) {
1772 if (!progressBars.contains(pb))
1773 startAnimate(AquaProgressBar, pb);
1775 case QEvent::Destroy:
1777 progressBars.removeAll(pb);
1779 } else if (QPushButton *btn = qobject_cast<QPushButton *>(o)) {
1780 switch (e->type()) {
1783 case QEvent::FocusIn:
1784 if (btn->autoDefault())
1785 startAnimate(AquaPushButton, btn);
1787 case QEvent::Destroy:
1789 if (btn == defaultButton)
1790 stopAnimate(AquaPushButton, btn);
1792 case QEvent::MouseButtonPress:
1793 // It is very confusing to keep the button pulsing, so just stop the animation.
1794 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1796 stopAnimate(AquaPushButton, btn);
1798 case QEvent::MouseButtonRelease:
1799 if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1802 case QEvent::FocusOut:
1804 case QEvent::WindowActivate: {
1805 QList<QPushButton *> list = btn->window()->findChildren<QPushButton *>();
1806 for (int i = 0; i < list.size(); ++i) {
1807 QPushButton *pBtn = list.at(i);
1808 if ((e->type() == QEvent::FocusOut
1809 && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus()))
1811 || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease
1812 || e->type() == QEvent::WindowActivate)
1813 && pBtn->isDefault())) {
1814 if (pBtn->window()->isActiveWindow()) {
1815 startAnimate(AquaPushButton, pBtn);
1826 bool QMacStylePrivate::doAnimate(QMacStylePrivate::Animates as)
1828 if (as == AquaPushButton) {
1829 } else if (as == AquaProgressBar) {
1830 // something for later...
1831 } else if (as == AquaListViewItemOpen) {
1832 // To be revived later...
1837 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1838 QPainter *p, const QStyleOption *opt) const
1846 const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
1847 int width = int(macRect.size.width) + extraWidth;
1848 int height = int(macRect.size.height) + extraHeight;
1850 if (width <= 0 || height <= 0)
1851 return; // nothing to draw
1853 QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1854 + QString::number(bdi->value) + QLatin1Char('_') + QString::number(width)
1855 + QLatin1Char('_') + QString::number(height);
1857 if (!QPixmapCache::find(key, pm)) {
1858 QPixmap activePixmap(width, height);
1859 activePixmap.fill(Qt::transparent);
1862 // Carbon combos don't scale. Therefore we draw it
1863 // ourselves, if a scaled version is needed.
1864 QPainter tmpPainter(&activePixmap);
1865 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1868 QMacCGContext cg(&activePixmap);
1869 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1870 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1874 if (!combo && bdi->value == kThemeButtonOff) {
1877 QImage image = activePixmap.toImage();
1879 for (int y = 0; y < height; ++y) {
1880 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1882 for (int x = 0; x < width; ++x) {
1883 QRgb &pixel = scanLine[x];
1885 int darkest = qRed(pixel);
1886 int mid = qGreen(pixel);
1887 int lightest = qBlue(pixel);
1890 qSwap(darkest, mid);
1892 qSwap(mid, lightest);
1894 qSwap(darkest, mid);
1896 int gray = (mid + 2 * lightest) / 3;
1897 pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1900 pm = QPixmap::fromImage(image);
1902 QImage activeImage = activePixmap.toImage();
1903 QImage colorlessImage;
1905 QPixmap colorlessPixmap(width, height);
1906 colorlessPixmap.fill(Qt::transparent);
1908 QMacCGContext cg(&colorlessPixmap);
1909 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1910 int oldValue = bdi->value;
1911 bdi->value = kThemeButtonOff;
1912 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1913 bdi->value = oldValue;
1914 colorlessImage = colorlessPixmap.toImage();
1917 for (int y = 0; y < height; ++y) {
1918 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1919 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1921 for (int x = 0; x < width; ++x) {
1922 QRgb &colorlessPixel = colorlessScanLine[x];
1923 QRgb activePixel = activeScanLine[x];
1925 if (activePixel != colorlessPixel) {
1926 int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1927 qBlue(activePixel));
1928 QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1929 if (qGray(newPixel) < qGray(colorlessPixel)
1930 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1931 colorlessPixel = newPixel;
1935 pm = QPixmap::fromImage(colorlessImage);
1937 QPixmapCache::insert(key, pm);
1939 p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm);
1942 QMacStyle::QMacStyle()
1945 d = new QMacStylePrivate(this);
1948 QMacStyle::~QMacStyle()
1950 delete qt_mac_backgroundPattern;
1951 qt_mac_backgroundPattern = 0;
1956 Generates the standard widget background pattern.
1958 QPixmap QMacStylePrivate::generateBackgroundPattern() const
1961 QMacCGContext cg(&px);
1962 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
1963 const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
1964 CGContextFillRect(cg, cgRect);
1969 Fills the given \a rect with the pattern stored in \a brush. As an optimization,
1970 HIThemeSetFill us used directly if we are filling with the standard background.
1972 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
1975 const QPaintDevice *target = painter->device();
1976 const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
1977 //const bool usePainter = redirected && redirected != target;
1980 if (!usePainter && qt_mac_backgroundPattern
1981 && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
1983 painter->setClipRegion(rgn);
1985 QCFType<CGContextRef> cg = qt_mac_cg_context(target);
1986 CGContextSaveGState(cg);
1987 HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
1989 const QVector<QRect> &rects = rgn.rects();
1990 for (int i = 0; i < rects.size(); ++i) {
1991 const QRect rect(rects.at(i));
1992 // Anchor the pattern to the top so it stays put when the window is resized.
1993 CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
1994 CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1995 CGContextFillRect(cg, mac_rect);
1998 CGContextRestoreGState(cg);
2001 const QRect rect(rgn.boundingRect());
2002 painter->setClipRegion(rgn);
2003 painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
2007 void QMacStyle::polish(QPalette &pal)
2009 if (!qt_mac_backgroundPattern) {
2012 qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
2015 QColor pc(Qt::black);
2016 pc = qcolorForTheme(kThemeBrushDialogBackgroundActive);
2017 QBrush background(pc, *qt_mac_backgroundPattern);
2018 pal.setBrush(QPalette::All, QPalette::Window, background);
2019 pal.setBrush(QPalette::All, QPalette::Button, background);
2022 const OSErr err = CopyThemeIdentifier(&theme);
2023 if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
2024 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
2026 pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
2030 void QMacStyle::polish(QApplication *)
2034 void QMacStyle::unpolish(QApplication *)
2038 void QMacStyle::polish(QWidget* w)
2041 if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
2042 // Set a clear brush so that the metal shines through.
2043 QPalette pal = w->palette();
2044 QBrush background(Qt::transparent);
2045 pal.setBrush(QPalette::All, QPalette::Window, background);
2046 pal.setBrush(QPalette::All, QPalette::Button, background);
2048 w->setAttribute(Qt::WA_SetPalette, false);
2051 if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
2052 w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
2053 if (!w->testAttribute(Qt::WA_SetPalette)) {
2056 HIThemeMenuDrawInfo mtinfo;
2057 mtinfo.version = qt_mac_hitheme_version;
2058 mtinfo.menuType = kThemeMenuTypePopUp;
2059 HIRect rect = CGRectMake(0, 0, px.width(), px.height());
2061 //HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
2062 // kHIThemeOrientationNormal);
2063 QPalette pal = w->palette();
2064 QBrush background(px);
2065 pal.setBrush(QPalette::All, QPalette::Window, background);
2066 pal.setBrush(QPalette::All, QPalette::Button, background);
2068 w->setAttribute(Qt::WA_SetPalette, false);
2072 if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
2073 if (tb->documentMode()) {
2074 w->setAttribute(Qt::WA_Hover);
2075 w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2076 QPalette p = w->palette();
2077 p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2082 QWindowsStyle::polish(w);
2084 if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2085 rubber->setWindowOpacity(0.25);
2086 rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2087 rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2091 void QMacStyle::unpolish(QWidget* w)
2094 if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
2095 QPalette pal = qApp->palette(w);
2097 w->setAttribute(Qt::WA_SetPalette, false);
2098 w->setWindowOpacity(1.0);
2101 if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2102 if (!combo->isEditable()) {
2103 if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
2104 widget->setWindowOpacity(1.0);
2108 if (QRubberBand *rubber = ::qobject_cast<QRubberBand*>(w)) {
2109 rubber->setWindowOpacity(1.0);
2110 rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2111 rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2114 if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
2115 frame->setAttribute(Qt::WA_NoSystemBackground, true);
2117 QWindowsStyle::unpolish(w);
2120 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
2122 int controlSize = getControlSize(opt, widget);
2126 case PM_TabCloseIndicatorWidth:
2127 case PM_TabCloseIndicatorHeight:
2128 ret = closeButtonSize;
2130 case PM_ToolBarIconSize:
2131 ret = proxy()->pixelMetric(PM_LargeIconSize);
2133 case PM_FocusFrameVMargin:
2134 case PM_FocusFrameHMargin:
2135 GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
2137 case PM_DialogButtonsSeparator:
2140 case PM_DialogButtonsButtonHeight: {
2142 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2143 if (sz == QSize(-1, -1))
2148 case PM_CheckListButtonSize: {
2149 switch (d->aquaSizeConstrain(opt, widget)) {
2150 case QAquaSizeUnknown:
2151 case QAquaSizeLarge:
2152 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2155 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2157 case QAquaSizeSmall:
2158 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2162 case PM_DialogButtonsButtonWidth: {
2164 ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2165 if (sz == QSize(-1, -1))
2171 case PM_MenuBarHMargin:
2175 case PM_MenuBarVMargin:
2179 case QStyle::PM_MenuDesktopFrameWidth:
2183 case PM_CheckBoxLabelSpacing:
2184 case PM_RadioButtonLabelSpacing:
2187 case PM_MenuScrollerHeight:
2190 GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2193 ret = 15; // I hate having magic numbers in here...
2196 case PM_DefaultFrameWidth:
2197 #ifndef QT_NO_MAINWINDOW
2198 if (widget && (widget->isWindow() || !widget->parentWidget()
2199 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2200 && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2201 && (qobject_cast<const QAbstractScrollArea *>(widget)
2202 || widget->inherits("QWorkspaceChild")))
2206 // The combo box popup has no frame.
2207 if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2209 // Frame of mac style line edits is two pixels on top and one on the bottom
2210 else if (qobject_cast<const QLineEdit *>(widget) != 0)
2215 case PM_MaximumDragDistance:
2218 case PM_ScrollBarSliderMin:
2221 case PM_SpinBoxFrameWidth:
2222 GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2223 switch (d->aquaSizeConstrain(opt, widget)) {
2232 case PM_ButtonShiftHorizontal:
2233 case PM_ButtonShiftVertical:
2236 case PM_SliderLength:
2239 case PM_ButtonDefaultIndicator:
2242 case PM_TitleBarHeight:
2243 if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2244 HIThemeWindowDrawInfo wdi;
2245 wdi.version = qt_mac_hitheme_version;
2246 wdi.state = kThemeStateActive;
2247 wdi.windowType = QtWinType;
2248 if (tb->titleBarState)
2249 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2250 | kThemeWindowHasCollapseBox;
2251 else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2252 wdi.attributes = kThemeWindowHasCloseBox;
2255 wdi.titleHeight = tb->rect.height();
2256 wdi.titleWidth = tb->rect.width();
2257 QCFType<HIShapeRef> region;
2258 HIRect hirect = qt_hirectForQRect(tb->rect);
2259 if (hirect.size.width <= 0)
2260 hirect.size.width = 100;
2261 if (hirect.size.height <= 0)
2262 hirect.size.height = 30;
2264 HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, ®ion);
2266 ptrHIShapeGetBounds(region, &rect);
2267 ret = int(rect.size.height);
2271 case PM_TabBarTabVSpace:
2274 case PM_TabBarTabShiftHorizontal:
2275 case PM_TabBarTabShiftVertical:
2278 case PM_TabBarBaseHeight:
2281 case PM_TabBarTabOverlap:
2284 case PM_TabBarBaseOverlap:
2285 switch (d->aquaSizeConstrain(opt, widget)) {
2286 case QAquaSizeUnknown:
2287 case QAquaSizeLarge:
2290 case QAquaSizeSmall:
2298 case PM_ScrollBarExtent: {
2299 switch (d->aquaSizeConstrain(opt, widget)) {
2300 case QAquaSizeUnknown:
2301 case QAquaSizeLarge:
2302 GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2305 case QAquaSizeSmall:
2306 GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2310 case PM_IndicatorHeight: {
2311 switch (d->aquaSizeConstrain(opt, widget)) {
2312 case QAquaSizeUnknown:
2313 case QAquaSizeLarge:
2314 GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2317 GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2319 case QAquaSizeSmall:
2320 GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2324 case PM_IndicatorWidth: {
2325 switch (d->aquaSizeConstrain(opt, widget)) {
2326 case QAquaSizeUnknown:
2327 case QAquaSizeLarge:
2328 GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2331 GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2333 case QAquaSizeSmall:
2334 GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2339 case PM_ExclusiveIndicatorHeight: {
2340 switch (d->aquaSizeConstrain(opt, widget)) {
2341 case QAquaSizeUnknown:
2342 case QAquaSizeLarge:
2343 GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2346 GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2348 case QAquaSizeSmall:
2349 GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2353 case PM_ExclusiveIndicatorWidth: {
2354 switch (d->aquaSizeConstrain(opt, widget)) {
2355 case QAquaSizeUnknown:
2356 case QAquaSizeLarge:
2357 GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2360 GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2362 case QAquaSizeSmall:
2363 GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2368 case PM_MenuVMargin:
2371 case PM_MenuPanelWidth:
2374 case PM_ToolTipLabelFrameWidth:
2377 case PM_SizeGripSize: {
2378 QAquaWidgetSize aSize;
2379 if (widget && widget->window()->windowType() == Qt::Tool)
2380 aSize = QAquaSizeSmall;
2382 aSize = QAquaSizeLarge;
2383 const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2386 case PM_MdiSubWindowFrameWidth:
2389 case PM_DockWidgetFrameWidth:
2392 case PM_DockWidgetTitleMargin:
2395 case PM_DockWidgetSeparatorExtent:
2398 case PM_ToolBarHandleExtent:
2401 case PM_ToolBarItemMargin:
2404 case PM_ToolBarItemSpacing:
2407 case PM_SplitterWidth:
2408 ret = qMax(7, QApplication::globalStrut().width());
2410 case PM_LayoutLeftMargin:
2411 case PM_LayoutTopMargin:
2412 case PM_LayoutRightMargin:
2413 case PM_LayoutBottomMargin:
2415 bool isWindow = false;
2417 isWindow = (opt->state & State_Window);
2418 } else if (widget) {
2419 isWindow = widget->isWindow();
2423 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2425 if (metric == PM_LayoutTopMargin) {
2426 return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2427 } else if (metric == PM_LayoutBottomMargin) {
2428 return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2430 return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2434 AHIG would have (20, 8, 10) here but that makes
2435 no sense. It would also have 14 for the top margin
2436 but this contradicts both Builder and most
2439 return_SIZE(20, 10, 10); // AHIG
2442 // hack to detect QTabWidget
2443 if (widget && widget->parentWidget()
2444 && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2445 if (metric == PM_LayoutTopMargin) {
2447 Builder would have 14 (= 20 - 6) instead of 12,
2448 but that makes the tab look disproportionate.
2450 return_SIZE(12, 6, 6); // guess
2452 return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2456 Child margins are highly inconsistent in AHIG and Builder.
2458 return_SIZE(12, 8, 6); // guess
2462 case PM_LayoutHorizontalSpacing:
2463 case PM_LayoutVerticalSpacing:
2465 case QStyle::PM_TabBarTabHSpace:
2466 switch (d->aquaSizeConstrain(opt, widget)) {
2467 case QAquaSizeLarge:
2468 case QAquaSizeUnknown:
2469 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2471 case QAquaSizeSmall:
2479 case PM_MenuHMargin:
2482 case PM_ToolBarFrameWidth:
2485 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->parent()))
2486 if (mainWindow->unifiedTitleAndToolBarOnMac())
2491 ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2497 QPalette QMacStyle::standardPalette() const
2499 QPalette pal = QWindowsStyle::standardPalette();
2500 pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2501 pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2502 pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2506 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2507 QStyleHintReturn *hret) const
2511 case SH_Menu_SelectionWrap:
2514 case SH_Menu_KeyboardSearch:
2517 case SH_Menu_SpaceActivatesItem:
2520 case SH_Slider_AbsoluteSetButtons:
2521 ret = Qt::LeftButton|Qt::MidButton;
2523 case SH_Slider_PageSetButtons:
2526 case SH_ScrollBar_ContextMenu:
2529 case SH_TitleBar_AutoRaise:
2532 case SH_Menu_AllowActiveAndDisabled:
2535 case SH_Menu_SubMenuPopupDelay:
2538 case SH_ScrollBar_LeftClickAbsolutePosition: {
2539 if(QApplication::keyboardModifiers() & Qt::AltModifier)
2541 //ret = !qt_scrollbar_jump_to_pos;
2544 //ret = qt_scrollbar_jump_to_pos;
2546 case SH_TabBar_PreferNoArrows:
2549 case SH_LineEdit_PasswordCharacter:
2550 ret = kBulletUnicode;
2553 case SH_DialogButtons_DefaultButton:
2554 ret = QDialogButtons::Reject;
2557 case SH_Menu_SloppySubMenus:
2560 case SH_GroupBox_TextLabelVerticalAlignment:
2563 case SH_ScrollView_FrameOnlyAroundContents:
2564 if (w && (w->isWindow() || !w->parentWidget() || w->parentWidget()->isWindow())
2565 && (w->inherits("QWorkspaceChild")
2569 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2571 case SH_Menu_FillScreenWithScroll:
2574 case SH_Menu_Scrollable:
2577 case SH_RichText_FullWidthSelection:
2580 case SH_BlinkCursorWhenTextSelected:
2583 case SH_ScrollBar_StopMouseOverSlider:
2586 case SH_Q3ListViewExpand_SelectMouseType:
2587 ret = QEvent::MouseButtonRelease;
2589 case SH_TabBar_SelectMouseType:
2590 if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2591 ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2593 ret = QEvent::MouseButtonRelease;
2596 case SH_ComboBox_Popup:
2597 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2598 ret = !cmb->editable;
2602 case SH_Workspace_FillSpaceOnMaximize:
2605 case SH_Widget_ShareActivation:
2608 case SH_Header_ArrowAlignment:
2609 ret = Qt::AlignRight;
2611 case SH_TabBar_Alignment: {
2612 if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2613 if (tab->documentMode()) {
2614 ret = Qt::AlignLeft;
2618 if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2619 if (tab->documentMode()) {
2620 ret = Qt::AlignLeft;
2624 ret = Qt::AlignCenter;
2626 case SH_UnderlineShortcut:
2629 case SH_ToolTipLabel_Opacity:
2630 ret = 242; // About 95%
2632 case SH_Button_FocusPolicy:
2635 case SH_EtchDisabledText:
2638 case SH_FocusFrame_Mask: {
2640 if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2641 const uchar fillR = 192, fillG = 191, fillB = 190;
2644 QSize pixmapSize = opt->rect.size();
2645 if (pixmapSize.isValid()) {
2646 QPixmap pix(pixmapSize);
2647 pix.fill(QColor(fillR, fillG, fillB));
2648 QPainter pix_paint(&pix);
2649 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w);
2651 img = pix.toImage();
2654 const QRgb *sptr = (QRgb*)img.bits(), *srow;
2655 const int sbpl = img.bytesPerLine();
2656 const int w = sbpl/4, h = img.height();
2658 QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2659 QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2660 const int dbpl = img_mask.bytesPerLine();
2662 for (int y = 0; y < h; ++y) {
2663 srow = sptr+((y*sbpl)/4);
2664 drow = dptr+((y*dbpl)/4);
2665 for (int x = 0; x < w; ++x) {
2666 const int diff = (((qRed(*srow)-fillR)*(qRed(*srow)-fillR)) +
2667 ((qGreen(*srow)-fillG)*((qGreen(*srow)-fillG))) +
2668 ((qBlue(*srow)-fillB)*((qBlue(*srow)-fillB))));
2669 (*drow++) = (diff < 100) ? 0xffffffff : 0xff000000;
2673 QBitmap qmask = QBitmap::fromImage(img_mask);
2674 mask->region = QRegion(qmask);
2677 case SH_TitleBar_NoBorder:
2680 case SH_RubberBand_Mask:
2683 case SH_ComboBox_LayoutDirection:
2684 ret = Qt::LeftToRight;
2686 case SH_ItemView_EllipsisLocation:
2687 ret = Qt::AlignHCenter;
2689 case SH_ItemView_ShowDecorationSelected:
2692 case SH_TitleBar_ModifyNotification:
2695 case SH_ScrollBar_RollBetweenButtons:
2698 case SH_WindowFrame_Mask:
2700 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2701 mask->region = opt->rect;
2702 mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2703 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2704 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2705 mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2707 mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2708 mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2709 mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2710 mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2713 case SH_TabBar_ElideMode:
2714 ret = Qt::ElideRight;
2716 case SH_DialogButtonLayout:
2717 ret = QDialogButtonBox::MacLayout;
2719 case SH_FormLayoutWrapPolicy:
2720 ret = QFormLayout::DontWrapRows;
2722 case SH_FormLayoutFieldGrowthPolicy:
2723 ret = QFormLayout::FieldsStayAtSizeHint;
2725 case SH_FormLayoutFormAlignment:
2726 ret = Qt::AlignHCenter | Qt::AlignTop;
2728 case SH_FormLayoutLabelAlignment:
2729 ret = Qt::AlignRight;
2731 case SH_ComboBox_PopupFrameStyle:
2732 ret = QFrame::NoFrame | QFrame::Plain;
2734 case SH_MessageBox_TextInteractionFlags:
2735 ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2737 case SH_SpellCheckUnderlineStyle:
2738 ret = QTextCharFormat::DashUnderline;
2740 case SH_MessageBox_CenterButtons:
2743 case SH_MenuBar_AltKeyNavigation:
2746 case SH_ItemView_MovementWithoutUpdatingSelection:
2749 case SH_FocusFrame_AboveWidget:
2752 case SH_WizardStyle:
2753 ret = QWizard::MacStyle;
2755 case SH_ItemView_ArrowKeysNavigateIntoChildren:
2758 case SH_Menu_FlashTriggeredItem:
2761 case SH_Menu_FadeOutOnHide:
2766 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2768 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2769 opt->rect.width(), opt->rect.height() - 8);
2770 HIThemeMenuDrawInfo mdi;
2772 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2773 mdi.menuType = kThemeMenuTypeHierarchical;
2775 mdi.menuType = kThemeMenuTypePopUp;
2776 QCFType<HIShapeRef> shape;
2777 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2779 mask->region = qt_mac_fromHIShapeRef(shape);
2783 case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2786 case SH_TabBar_CloseButtonPosition:
2787 ret = QTabBar::LeftSide;
2789 case SH_DockWidget_ButtonsHaveFrame:
2793 ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2799 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2800 const QStyleOption *opt) const
2803 case QIcon::Disabled: {
2804 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2805 int imgh = img.height();
2806 int imgw = img.width();
2808 for (int y = 0; y < imgh; ++y) {
2809 for (int x = 0; x < imgw; ++x) {
2810 pixel = img.pixel(x, y);
2811 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2812 qAlpha(pixel) / 2));
2815 return QPixmap::fromImage(img);
2820 return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt);
2824 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2825 const QWidget *widget) const
2827 // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2828 // I don't want infinite recursion so if we do get in that situation, just return the Window's
2829 // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2830 // someone changes how Windows standard
2832 static bool recursionGuard = false;
2835 return QWindowsStyle::standardPixmap(standardPixmap, opt, widget);
2837 recursionGuard = true;
2838 QIcon icon = standardIconImplementation(standardPixmap, opt, widget);
2839 recursionGuard = false;
2841 switch (standardPixmap) {
2845 case SP_MessageBoxCritical:
2846 case SP_MessageBoxQuestion:
2847 case SP_MessageBoxInformation:
2848 case SP_MessageBoxWarning:
2852 return icon.pixmap(size, size);
2855 void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
2862 w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
2867 QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
2869 return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
2872 void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
2874 QWidget *wadget = const_cast<QWidget *>(widget);
2875 wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge);
2876 wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall);
2877 wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini);
2880 QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget)
2883 if (widget->testAttribute(Qt::WA_MacMiniSize)) {
2885 } else if (widget->testAttribute(Qt::WA_MacSmallSize)) {
2887 } else if (widget->testAttribute(Qt::WA_MacNormalSize)) {
2890 widget = widget->parentWidget();
2895 void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
2896 const QWidget *w) const
2898 ThemeDrawState tds = d->getDrawState(opt->state);
2899 QMacCGContext cg(p);
2901 case PE_IndicatorArrowUp:
2902 case PE_IndicatorArrowDown:
2903 case PE_IndicatorArrowRight:
2904 case PE_IndicatorArrowLeft: {
2906 p->setRenderHint(QPainter::Antialiasing);
2907 int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
2909 matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2913 case PE_IndicatorArrowDown:
2915 case PE_IndicatorArrowUp:
2918 case PE_IndicatorArrowLeft:
2921 case PE_IndicatorArrowRight:
2926 path.lineTo(-4, -3);
2928 p->setMatrix(matrix);
2929 p->setPen(Qt::NoPen);
2930 p->setBrush(QColor(0, 0, 0, 135));
2934 case PE_FrameTabBarBase:
2935 if (const QStyleOptionTabBarBaseV2 *tbb
2936 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2937 if (tbb->documentMode) {
2939 drawTabBase(p, tbb, w);
2944 QRegion region(tbb->rect);
2945 region -= tbb->tabBarRect;
2947 p->setClipRegion(region);
2948 QStyleOptionTabWidgetFrame twf;
2949 twf.QStyleOption::operator=(*tbb);
2950 twf.shape = tbb->shape;
2951 switch (getTabDirection(twf.shape)) {
2952 case kThemeTabNorth:
2953 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2955 case kThemeTabSouth:
2956 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2959 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2962 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2965 proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
2969 case PE_PanelTipLabel:
2970 p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2972 case PE_FrameGroupBox:
2973 if (const QStyleOptionFrame *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2974 const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt);
2975 if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) {
2976 QWindowsStyle::drawPrimitive(pe, groupBox, p, w);
2978 HIThemeGroupBoxDrawInfo gdi;
2979 gdi.version = qt_mac_hitheme_version;
2981 if (w && qobject_cast<QGroupBox *>(w->parentWidget()))
2982 gdi.kind = kHIThemeGroupBoxKindSecondary;
2984 gdi.kind = kHIThemeGroupBoxKindPrimary;
2985 HIRect hirect = qt_hirectForQRect(opt->rect);
2986 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
2990 case PE_IndicatorToolBarSeparator: {
2992 if (opt->state & State_Horizontal) {
2993 int xpoint = opt->rect.center().x();
2994 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2995 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2997 int ypoint = opt->rect.center().y();
2998 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2999 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
3001 QPainterPathStroker theStroker;
3002 theStroker.setCapStyle(Qt::FlatCap);
3003 theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
3004 path = theStroker.createStroke(path);
3005 p->fillPath(path, QColor(0, 0, 0, 119));
3008 case PE_FrameWindow:
3010 case PE_IndicatorDockWidgetResizeHandle: {
3011 // The docwidget resize handle is drawn as a one-pixel wide line.
3013 if (opt->state & State_Horizontal) {
3014 p->setPen(QColor(160, 160, 160));
3015 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3017 p->setPen(QColor(145, 145, 145));
3018 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
3022 case PE_IndicatorToolBarHandle: {
3025 int x = opt->rect.x() + 6;
3026 int y = opt->rect.y() + 5;
3027 static const int RectHeight = 2;
3028 if (opt->state & State_Horizontal) {
3029 while (y < opt->rect.height() - RectHeight - 6) {
3031 path.addRect(x, y, RectHeight, RectHeight);
3035 while (x < opt->rect.width() - RectHeight - 6) {
3037 path.addRect(x, y, RectHeight, RectHeight);
3041 p->setPen(Qt::NoPen);
3042 QColor dark = opt->palette.dark().color();
3043 dark.setAlphaF(0.75);
3044 QColor light = opt->palette.light().color();
3045 light.setAlphaF(0.6);
3046 p->fillPath(path, light);
3049 p->fillPath(path, dark);
3052 p->fillPath(path, light);
3054 p->fillPath(path, dark);
3059 case PE_IndicatorHeaderArrow:
3060 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3061 // In HITheme, up is down, down is up and hamburgers eat people.
3062 if (header->sortIndicator != QStyleOptionHeader::None)
3063 proxy()->drawPrimitive(
3064 (header->sortIndicator == QStyleOptionHeader::SortDown) ?
3065 PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
3068 case PE_IndicatorMenuCheckMark: {
3069 const int checkw = 8;
3070 const int checkh = 8;
3071 const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
3072 const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
3073 const int x1 = xoff + opt->rect.x();
3074 const int y1 = yoff + opt->rect.y() + checkw/2;
3075 const int x2 = xoff + opt->rect.x() + checkw/4;
3076 const int y2 = yoff + opt->rect.y() + checkh;
3077 const int x3 = xoff + opt->rect.x() + checkw;
3078 const int y3 = yoff + opt->rect.y();
3080 QVector<QLineF> a(2);
3081 a << QLineF(x1, y1, x2, y2);
3082 a << QLineF(x2, y2, x3, y3);
3083 if (opt->palette.currentColorGroup() == QPalette::Active) {
3084 if (opt->state & State_On)
3085 p->setPen(QPen(opt->palette.highlightedText().color(), 3));
3087 p->setPen(QPen(opt->palette.text().color(), 3));
3089 p->setPen(QPen(QColor(100, 100, 100), 3));
3092 p->setRenderHint(QPainter::Antialiasing);
3096 case PE_IndicatorViewItemCheck:
3097 case PE_Q3CheckListExclusiveIndicator:
3098 case PE_Q3CheckListIndicator:
3099 case PE_IndicatorRadioButton:
3100 case PE_IndicatorCheckBox: {
3101 bool drawColorless = (!(opt->state & State_Active))
3102 && opt->palette.currentColorGroup() == QPalette::Active;
3103 HIThemeButtonDrawInfo bdi;
3104 bdi.version = qt_mac_hitheme_version;
3106 if (drawColorless && tds == kThemeStateInactive)
3107 bdi.state = kThemeStateActive;
3108 bdi.adornment = kThemeDrawIndicatorOnly;
3109 if (opt->state & State_HasFocus)
3110 bdi.adornment |= kThemeAdornmentFocus;
3111 bool isRadioButton = (pe == PE_Q3CheckListExclusiveIndicator
3112 || pe == PE_IndicatorRadioButton);
3113 switch (d->aquaSizeConstrain(opt, w)) {
3114 case QAquaSizeUnknown:
3115 case QAquaSizeLarge:
3117 bdi.kind = kThemeRadioButton;
3119 bdi.kind = kThemeCheckBox;
3123 bdi.kind = kThemeMiniRadioButton;
3125 bdi.kind = kThemeMiniCheckBox;
3127 case QAquaSizeSmall:
3129 bdi.kind = kThemeSmallRadioButton;
3131 bdi.kind = kThemeSmallCheckBox;
3134 if (opt->state & State_NoChange)
3135 bdi.value = kThemeButtonMixed;
3136 else if (opt->state & State_On)
3137 bdi.value = kThemeButtonOn;
3139 bdi.value = kThemeButtonOff;
3141 if (pe == PE_Q3CheckListExclusiveIndicator || pe == PE_Q3CheckListIndicator)
3142 macRect = qt_hirectForQRect(opt->rect);
3144 macRect = qt_hirectForQRect(opt->rect);
3146 HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3148 d->drawColorlessButton(macRect, &bdi, p, opt);
3150 case PE_FrameFocusRect:
3151 // Use the our own focus widget stuff.
3153 case PE_IndicatorBranch: {
3154 if (!(opt->state & State_Children))
3156 HIThemeButtonDrawInfo bi;
3157 bi.version = qt_mac_hitheme_version;
3159 if (tds == kThemeStateInactive && opt->palette.currentColorGroup() == QPalette::Active)
3160 bi.state = kThemeStateActive;
3161 if (opt->state & State_Sunken)
3162 bi.state |= kThemeStatePressed;
3163 bi.kind = kThemeDisclosureButton;
3164 if (opt->state & State_Open)
3165 bi.value = kThemeDisclosureDown;
3167 bi.value = opt->direction == Qt::LeftToRight ? kThemeDisclosureRight : kThemeDisclosureLeft;
3168 bi.adornment = kThemeAdornmentNone;
3169 HIRect hirect = qt_hirectForQRect(opt->rect.adjusted(DisclosureOffset,0,-DisclosureOffset,0));
3170 HIThemeDrawButton(&hirect, &bi, cg, kHIThemeOrientationNormal, 0);
3174 QPen oldPen = p->pen();
3175 p->setPen(opt->palette.base().color().darker(140));
3176 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3177 p->setPen(opt->palette.base().color().darker(180));
3178 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3182 case PE_FrameLineEdit:
3183 if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3184 if (frame->state & State_Sunken) {
3185 QColor baseColor(frame->palette.background().color());
3186 HIThemeFrameDrawInfo fdi;
3187 fdi.version = qt_mac_hitheme_version;
3190 if (pe == PE_FrameLineEdit) {
3191 fdi.kind = kHIThemeFrameTextFieldSquare;
3192 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
3193 if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled))
3194 fdi.state = kThemeStateInactive;
3196 baseColor = QColor(150, 150, 150); //hardcoded since no query function --Sam
3197 fdi.kind = kHIThemeFrameListBox;
3198 GetThemeMetric(kThemeMetricListBoxFrameOutset, &frame_size);
3200 fdi.isFocused = (frame->state & State_HasFocus);
3201 int lw = frame->lineWidth;
3203 lw = proxy()->pixelMetric(PM_DefaultFrameWidth, frame, w);
3204 { //clear to base color
3206 p->setPen(QPen(baseColor, lw));
3207 p->setBrush(Qt::NoBrush);
3208 p->drawRect(frame->rect);
3211 HIRect hirect = qt_hirectForQRect(frame->rect,
3212 QRect(frame_size, frame_size,
3213 frame_size * 2, frame_size * 2));
3215 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
3217 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3221 case PE_PanelLineEdit:
3222 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3223 // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit).
3224 // Focus frame is drawn outside the rectangle passed in the option-rect.
3225 if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3226 if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(w)) {
3227 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3228 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3229 QStyleOptionFrame focusFrame = *panel;
3230 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3231 drawControl(CE_FocusFrame, &focusFrame, p, w);
3236 case PE_FrameTabWidget:
3237 if (const QStyleOptionTabWidgetFrame *twf
3238 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
3239 HIRect hirect = qt_hirectForQRect(twf->rect);
3240 HIThemeTabPaneDrawInfo tpdi;
3241 tpdi.version = qt_mac_hitheme_tab_version();
3243 tpdi.direction = getTabDirection(twf->shape);
3244 tpdi.size = kHIThemeTabSizeNormal;
3245 tpdi.kind = kHIThemeTabKindNormal;
3246 tpdi.adornment = kHIThemeTabPaneAdornmentNormal;
3247 HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal);
3250 case PE_PanelScrollAreaCorner: {
3251 const QBrush brush(opt->palette.brush(QPalette::Base));
3252 p->fillRect(opt->rect, brush);
3253 p->setPen(QPen(QColor(217, 217, 217)));
3254 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3255 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3257 case PE_FrameStatusBarItem:
3259 case PE_IndicatorTabClose: {
3260 bool hover = (opt->state & State_MouseOver);
3261 bool selected = (opt->state & State_Selected);
3262 bool active = (opt->state & State_Active);
3263 drawTabCloseButton(p, hover, active, selected);
3265 case PE_PanelStatusBar: {
3266 if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) {
3267 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3270 // Use the Leopard style only if the status bar is the status bar for a
3271 // QMainWindow with a unifed toolbar.
3272 if (w == 0 || w->parent() == 0 || qobject_cast<QMainWindow *>(w->parent()) == 0 ||
3273 qobject_cast<QMainWindow *>(w->parent())->unifiedTitleAndToolBarOnMac() == false ) {
3274 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3278 // Fill the status bar with the titlebar gradient.
3279 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3280 if (opt->state & QStyle::State_Active) {
3281 linearGrad.setColorAt(0, titlebarGradientActiveBegin);
3282 linearGrad.setColorAt(1, titlebarGradientActiveEnd);
3284 linearGrad.setColorAt(0, titlebarGradientInactiveBegin);
3285 linearGrad.setColorAt(1, titlebarGradientInactiveEnd);
3287 p->fillRect(opt->rect, linearGrad);
3289 // Draw the black separator line at the top of the status bar.
3290 if (opt->state & QStyle::State_Active)
3291 p->setPen(titlebarSeparatorLineActive);
3293 p->setPen(titlebarSeparatorLineInactive);
3294 p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3300 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3305 static inline QPixmap darkenPixmap(const QPixmap &pixmap)
3307 QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
3308 int imgh = img.height();
3309 int imgw = img.width();
3312 for (int y = 0; y < imgh; ++y) {
3313 for (int x = 0; x < imgw; ++x) {
3314 pixel = img.pixel(x, y);
3316 QColor hsvColor(pixel);
3317 hsvColor.getHsv(&h, &s, &v);
3318 s = qMin(100, s * 2);
3320 hsvColor.setHsv(h, s, v);
3321 pixel = hsvColor.rgb();
3322 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3325 return QPixmap::fromImage(img);
3330 void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3331 const QWidget *w) const
3333 ThemeDrawState tds = d->getDrawState(opt->state);
3334 QMacCGContext cg(p);
3336 case CE_HeaderSection:
3337 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3338 HIThemeButtonDrawInfo bdi;
3339 bdi.version = qt_mac_hitheme_version;
3340 State flags = header->state;
3341 QRect ir = header->rect;
3342 bdi.kind = kThemeListHeaderButton;
3343 bdi.adornment = kThemeAdornmentNone;
3344 bdi.state = kThemeStateActive;
3346 if (flags & State_On)
3347 bdi.value = kThemeButtonOn;
3349 bdi.value = kThemeButtonOff;
3351 if (header->orientation == Qt::Horizontal){
3352 switch (header->position) {
3353 case QStyleOptionHeader::Beginning:
3354 ir.adjust(-1, -1, 0, 0);
3356 case QStyleOptionHeader::Middle:
3357 ir.adjust(-1, -1, 0, 0);
3359 case QStyleOptionHeader::OnlyOneSection:
3360 case QStyleOptionHeader::End:
3361 ir.adjust(-1, -1, 1, 0);
3367 if (header->position != QStyleOptionHeader::Beginning
3368 && header->position != QStyleOptionHeader::OnlyOneSection) {
3369 bdi.adornment = header->direction == Qt::LeftToRight
3370 ? kThemeAdornmentHeaderButtonLeftNeighborSelected
3371 : kThemeAdornmentHeaderButtonRightNeighborSelected;
3375 if (flags & State_Active) {
3376 if (!(flags & State_Enabled))
3377 bdi.state = kThemeStateUnavailable;
3378 else if (flags & State_Sunken)
3379 bdi.state = kThemeStatePressed;
3381 if (flags & State_Enabled)
3382 bdi.state = kThemeStateInactive;
3384 bdi.state = kThemeStateUnavailableInactive;
3387 if (header->sortIndicator != QStyleOptionHeader::None) {
3388 bdi.value = kThemeButtonOn;
3389 if (header->sortIndicator == QStyleOptionHeader::SortDown)
3390 bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
3392 if (flags & State_HasFocus)
3393 bdi.adornment = kThemeAdornmentFocus;
3395 ir = visualRect(header->direction, header->rect, ir);
3396 HIRect bounds = qt_hirectForQRect(ir);
3398 bool noVerticalHeader = true;
3400 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3401 noVerticalHeader = !table->verticalHeader()->isVisible();
3403 bool drawTopBorder = header->orientation == Qt::Horizontal;
3404 bool drawLeftBorder = header->orientation == Qt::Vertical
3405 || header->position == QStyleOptionHeader::OnlyOneSection
3406 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3407 d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
3410 case CE_HeaderLabel:
3411 if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3412 QRect textr = header->rect;
3413 if (!header->icon.isNull()) {
3414 QIcon::Mode mode = QIcon::Disabled;
3415 if (opt->state & State_Enabled)
3416 mode = QIcon::Normal;
3417 QPixmap pixmap = header->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), mode);
3419 QRect pixr = header->rect;
3420 pixr.setY(header->rect.center().y() - (pixmap.height() - 1) / 2);
3421 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
3422 textr.translate(pixmap.width() + 2, 0);
3425 proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
3426 header->state & State_Enabled, header->text, QPalette::ButtonText);
3429 case CE_ToolButtonLabel:
3430 if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3431 QStyleOptionToolButton myTb = *tb;
3432 myTb.state &= ~State_AutoRaise;
3433 if (w && qobject_cast<QToolBar *>(w->parentWidget())) {
3434 QRect cr = tb->rect;
3437 bool needText = false;
3439 bool down = tb->state & (State_Sunken | State_On);
3441 shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3442 shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3444 // The down state is special for QToolButtons in a toolbar on the Mac
3445 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3446 // This doesn't really fit into any particular case in QIcon, so we
3447 // do the majority of the work ourselves.
3448 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3449 Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3450 if (tb->icon.isNull() && !tb->text.isEmpty())
3451 tbstyle = Qt::ToolButtonTextOnly;
3454 case Qt::ToolButtonTextOnly: {
3456 alignment = Qt::AlignCenter;
3458 case Qt::ToolButtonIconOnly:
3459 case Qt::ToolButtonTextBesideIcon:
3460 case Qt::ToolButtonTextUnderIcon: {
3462 QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3464 QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3466 QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), iconMode, iconState);
3468 // Draw the text if it's needed.
3469 if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3471 if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3472 QMainWindow *mw = qobject_cast<QMainWindow *>(w->window());
3473 if (mw && mw->unifiedTitleAndToolBarOnMac()) {
3474 pr.setHeight(pixmap.size().height());
3475 cr.adjust(0, pr.bottom() + 1, 0, 1);
3477 pr.setHeight(pixmap.size().height() + 6);
3478 cr.adjust(0, pr.bottom(), 0, -3);
3480 alignment |= Qt::AlignCenter;
3482 pr.setWidth(pixmap.width() + 8);
3483 cr.adjust(pr.right(), 0, 0, 0);
3484 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3487 if (opt->state & State_Sunken) {
3488 pr.translate(shiftX, shiftY);
3489 pixmap = darkenPixmap(pixmap);
3491 proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
3499 QPalette pal = tb->palette;
3500 QPalette::ColorRole role = QPalette::NoRole;
3501 if (!proxy()->styleHint(SH_UnderlineShortcut, tb, w))
3502 alignment |= Qt::TextHideMnemonic;
3504 cr.translate(shiftX, shiftY);
3505 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5
3506 && (tbstyle == Qt::ToolButtonTextOnly
3507 || (tbstyle != Qt::ToolButtonTextOnly && !down))) {
3508 QPen pen = p->pen();
3509 QColor light = down ? Qt::black : Qt::white;
3510 light.setAlphaF(0.375f);
3512 p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
3514 if (down && tbstyle == Qt::ToolButtonTextOnly) {
3515 pal = QApplication::palette("QMenu");
3516 pal.setCurrentColorGroup(tb->palette.currentColorGroup());
3517 role = QPalette::HighlightedText;
3520 proxy()->drawItemText(p, cr, alignment, pal,
3521 tb->state & State_Enabled, tb->text, role);
3522 if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 &&
3523 (tb->state & State_Sunken)) {
3524 // Draw a "drop shadow" in earlier versions.
3525 proxy()->drawItemText(p, cr.adjusted(0, 1, 0, 1), alignment,
3526 tb->palette, tb->state & State_Enabled, tb->text);
3530 QWindowsStyle::drawControl(ce, &myTb, p, w);
3533 QWindowsStyle::drawControl(ce, &myTb, p, w);
3537 case CE_ToolBoxTabShape:
3538 QCommonStyle::drawControl(ce, opt, p, w);
3540 case CE_PushButtonBevel:
3541 if (const QStyleOptionButton *btn = ::qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3542 if (!(btn->state & (State_Raised | State_Sunken | State_On)))
3545 if (btn->features & QStyleOptionButton::CommandLinkButton) {
3546 QWindowsStyle::drawControl(ce, opt, p, w);
3550 HIThemeButtonDrawInfo bdi;
3551 d->initHIThemePushButton(btn, w, tds, &bdi);
3552 if (btn->features & QStyleOptionButton::DefaultButton
3553 && d->animatable(QMacStylePrivate::AquaPushButton, w)) {
3554 bdi.adornment |= kThemeAdornmentDefault;
3555 bdi.animation.time.start = d->defaultButtonStart;
3556 bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
3557 if (d->timerID <= -1)
3558 QMetaObject::invokeMethod(d, "startAnimationTimer", Qt::QueuedConnection);
3560 // Unlike Carbon, we want the button to always be drawn inside its bounds.
3561 // Therefore, make the button a bit smaller, so that even if it got focus,
3562 // the focus 'shadow' will be inside.
3563 HIRect newRect = qt_hirectForQRect(btn->rect);
3564 if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) {
3565 newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset;
3566 newRect.origin.y += QMacStylePrivate::PushButtonTopOffset;
3567 newRect.size.width -= QMacStylePrivate::PushButtonRightOffset;
3568 newRect.size.height -= QMacStylePrivate::PushButtonBottomOffset;
3569 } else if (bdi.kind == kThemePushButtonMini) {
3570 newRect.origin.x += QMacStylePrivate::PushButtonLeftOffset - 2;
3571 newRect.origin.y += QMacStylePrivate::PushButtonTopOffset;
3572 newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4;
3574 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
3576 if (btn->features & QStyleOptionButton::HasMenu) {
3577 int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
3578 QRect ir = btn->rect;
3579 HIRect arrowRect = CGRectMake(ir.right() - mbi - QMacStylePrivate::PushButtonRightOffset,
3580 ir.height() / 2 - 4, mbi, ir.height() / 2);
3581 bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
3582 if (drawColorless && tds == kThemeStateInactive)
3583 tds = kThemeStateActive;
3585 HIThemePopupArrowDrawInfo pdi;
3586 pdi.version = qt_mac_hitheme_version;
3588 pdi.orientation = kThemeArrowDown;
3589 if (arrowRect.size.width < 8.)
3590 pdi.size = kThemeArrow5pt;
3592 pdi.size = kThemeArrow9pt;
3593 HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal);
3597 case CE_PushButtonLabel:
3598 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
3599 // We really don't want the label to be drawn the same as on
3600 // windows style if it has an icon and text, then it should be more like a
3601 // tab. So, cheat a little here. However, if it *is* only an icon
3602 // the windows style works great, so just use that implementation.
3603 bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
3604 bool hasIcon = !btn->icon.isNull();
3605 bool hasText = !btn->text.isEmpty();
3606 if (!hasIcon && !hasMenu) {
3607 // ### this is really overly difficult, simplify.
3608 // It basically tries to get the right font for "small" and "mini" icons.
3609 QFont oldFont = p->font();
3610 QFont newFont = qt_app_fonts_hash()->value("QPushButton", QFont());
3611 ThemeFontID themeId = kThemePushButtonFont;
3612 if (oldFont == newFont) { // Yes, use HITheme to draw the text for small sizes.
3613 switch (d->aquaSizeConstrain(opt, w)) {
3616 case QAquaSizeSmall:
3617 themeId = kThemeSmallSystemFont;
3620 themeId = kThemeMiniSystemFont;
3624 if (themeId == kThemePushButtonFont) {
3625 QWindowsStyle::drawControl(ce, btn, p, w);
3628 CGContextSetShouldAntialias(cg, true);
3629 CGContextSetShouldSmoothFonts(cg, true);
3630 HIThemeTextInfo tti;
3631 tti.version = qt_mac_hitheme_version;
3633 QColor textColor = btn->palette.buttonText().color();
3634 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3635 textColor.blueF(), textColor.alphaF() };
3636 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
3637 CGContextSetFillColor(cg, colorComp);
3638 tti.fontID = themeId;
3639 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3640 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3641 tti.options = kHIThemeTextBoxOptionNone;
3642 tti.truncationPosition = kHIThemeTextTruncationNone;
3643 tti.truncationMaxLines = 1 + btn->text.count(QLatin1Char('\n'));
3644 QCFString buttonText = qt_mac_removeMnemonics(btn->text);
3645 QRect r = btn->rect;
3646 HIRect bounds = qt_hirectForQRect(r);
3647 HIThemeDrawTextBox(buttonText, &bounds, &tti,
3648 cg, kHIThemeOrientationNormal);
3652 if (hasIcon && !hasText) {
3653 QWindowsStyle::drawControl(ce, btn, p, w);
3655 QRect freeContentRect = btn->rect;
3656 QRect textRect = itemTextRect(
3657 btn->fontMetrics, freeContentRect, Qt::AlignCenter, btn->state & State_Enabled, btn->text);
3659 textRect.adjust(-1, 0, -1, 0);
3662 int contentW = textRect.width();
3664 contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
3665 QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
3666 if (mode == QIcon::Normal && btn->state & State_HasFocus)
3667 mode = QIcon::Active;
3668 // Decide if the icon is should be on or off:
3669 QIcon::State state = QIcon::Off;
3670 if (btn->state & State_On)
3672 QPixmap pixmap = btn->icon.pixmap(btn->iconSize, mode, state);
3673 contentW += pixmap.width() + QMacStylePrivate::PushButtonContentPadding;
3674 int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
3675 int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmap.height()) / 2;
3676 QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmap.width(), pixmap.height());
3677 QRect visualIconDestRect = visualRect(btn->direction, freeContentRect, iconDestRect);
3678 proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
3679 int newOffset = iconDestRect.x() + iconDestRect.width()
3680 + QMacStylePrivate::PushButtonContentPadding - textRect.x();
3681 textRect.adjust(newOffset, 0, newOffset, 0);
3685 textRect = visualRect(btn->direction, freeContentRect, textRect);
3686 proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn->palette,
3687 (btn->state & State_Enabled), btn->text, QPalette::ButtonText);
3693 case CE_ComboBoxLabel:
3694 if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
3695 QStyleOptionComboBox comboCopy = *cb;
3696 comboCopy.direction = Qt::LeftToRight;
3697 QWindowsStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
3700 case CE_TabBarTabShape:
3701 if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3703 if (const QStyleOptionTabV3 *tabOptV3 = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
3704 if (tabOptV3->documentMode) {
3706 QRect tabRect = tabOptV3->rect;
3707 drawTabShape(p, tabOptV3);
3712 HIThemeTabDrawInfo tdi;
3714 tdi.style = kThemeTabNonFront;
3715 tdi.direction = getTabDirection(tabOpt->shape);
3716 switch (d->aquaSizeConstrain(opt, w)) {
3718 case QAquaSizeUnknown:
3719 case QAquaSizeLarge:
3720 tdi.size = kHIThemeTabSizeNormal;
3722 case QAquaSizeSmall:
3723 tdi.size = kHIThemeTabSizeSmall;
3726 tdi.size = kHIThemeTabSizeMini;
3729 bool verticalTabs = tdi.direction == kThemeTabWest || tdi.direction == kThemeTabEast;
3730 QRect tabRect = tabOpt->rect;
3732 bool selected = tabOpt->state & State_Selected;
3734 if (!(tabOpt->state & State_Active))
3735 tdi.style = kThemeTabFrontUnavailable;
3736 else if (!(tabOpt->state & State_Enabled))
3737 tdi.style = kThemeTabFrontInactive;
3739 tdi.style = kThemeTabFront;
3740 } else if (!(tabOpt->state & State_Active)) {
3741 tdi.style = kThemeTabNonFrontUnavailable;
3742 } else if (!(tabOpt->state & State_Enabled)) {
3743 tdi.style = kThemeTabNonFrontInactive;
3744 } else if (tabOpt->state & State_Sunken) {
3745 tdi.style = kThemeTabFrontInactive; // (should be kThemeTabNonFrontPressed)
3747 if (tabOpt->state & State_HasFocus)
3748 tdi.adornment = kHIThemeTabAdornmentFocus;
3750 tdi.adornment = kHIThemeTabAdornmentNone;
3751 tdi.kind = kHIThemeTabKindNormal;
3753 tabRect.setY(tabRect.y() - 1);
3755 tabRect.setX(tabRect.x() - 1);
3756 QStyleOptionTab::TabPosition tp = tabOpt->position;
3757 QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
3758 if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
3759 if (sp == QStyleOptionTab::NextIsSelected)
3760 sp = QStyleOptionTab::PreviousIsSelected;
3761 else if (sp == QStyleOptionTab::PreviousIsSelected)
3762 sp = QStyleOptionTab::NextIsSelected;
3764 case QStyleOptionTab::Beginning:
3765 tp = QStyleOptionTab::End;
3767 case QStyleOptionTab::End:
3768 tp = QStyleOptionTab::Beginning;
3774 bool stretchTabs = (!verticalTabs && tabRect.height() > 22) || (verticalTabs && tabRect.width() > 22);
3777 case QStyleOptionTab::Beginning:
3778 tdi.position = kHIThemeTabPositionFirst;
3779 if (sp != QStyleOptionTab::NextIsSelected || stretchTabs)
3780 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3782 case QStyleOptionTab::Middle:
3783 tdi.position = kHIThemeTabPositionMiddle;
3785 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3786 if (sp != QStyleOptionTab::NextIsSelected || stretchTabs) // Also when we're selected.
3787 tdi.adornment |= kHIThemeTabAdornmentTrailingSeparator;
3789 case QStyleOptionTab::End:
3790 tdi.position = kHIThemeTabPositionLast;
3792 tdi.adornment |= kHIThemeTabAdornmentLeadingSeparator;
3794 case QStyleOptionTab::OnlyOneTab:
3795 tdi.position = kHIThemeTabPositionOnly;
3798 // HITheme doesn't stretch its tabs. Therefore we have to cheat and do the job ourselves.
3800 HIRect hirect = CGRectMake(0, 0, 23, 23);
3802 pm.fill(Qt::transparent);
3804 QMacCGContext pmcg(&pm);
3805 HIThemeDrawTab(&hirect, &tdi, pmcg, kHIThemeOrientationNormal, 0);
3807 QStyleHelper::drawBorderPixmap(pm, p, tabRect, 7, 7, 7, 7);
3809 HIRect hirect = qt_hirectForQRect(tabRect);
3810 HIThemeDrawTab(&hirect, &tdi, cg, kHIThemeOrientationNormal, 0);
3814 case CE_TabBarTabLabel:
3815 if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
3816 QStyleOptionTabV3 myTab = *tab;
3817 ThemeTabDirection ttd = getTabDirection(myTab.shape);
3818 bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
3820 // Check to see if we use have the same as the system font
3821 // (QComboMenuItem is internal and should never be seen by the
3822 // outside world, unless they read the source, in which case, it's
3823 // their own fault).
3824 bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
3825 if (verticalTabs || nonDefaultFont || !tab->icon.isNull()
3826 || !myTab.leftButtonSize.isNull() || !myTab.rightButtonSize.isNull()) {
3827 int heightOffset = 0;
3830 } else if (nonDefaultFont) {
3831 if (p->fontMetrics().height() == myTab.rect.height())
3834 myTab.rect.setHeight(myTab.rect.height() + heightOffset);
3836 if (myTab.documentMode) {
3838 rotateTabPainter(p, myTab.shape, myTab.rect);
3840 QPalette np = tab->palette;
3841 np.setColor(QPalette::WindowText, QColor(255, 255, 255, 75));
3842 QRect nr = subElementRect(SE_TabBarTabText, opt, w);
3844 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic;
3845 proxy()->drawItemText(p, nr, alignment, np, tab->state & State_Enabled,
3846 tab->text, QPalette::WindowText);
3850 QCommonStyle::drawControl(ce, &myTab, p, w);
3853 CGContextSetShouldAntialias(cg, true);
3854 CGContextSetShouldSmoothFonts(cg, true);
3855 HIThemeTextInfo tti;
3856 tti.version = qt_mac_hitheme_version;
3858 QColor textColor = myTab.palette.windowText().color();
3859 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
3860 textColor.blueF(), textColor.alphaF() };
3861 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
3862 CGContextSetFillColor(cg, colorComp);
3863 switch (d->aquaSizeConstrain(opt, w)) {
3865 case QAquaSizeUnknown:
3866 case QAquaSizeLarge:
3867 tti.fontID = kThemeSystemFont;
3869 case QAquaSizeSmall:
3870 tti.fontID = kThemeSmallSystemFont;
3873 tti.fontID = kThemeMiniSystemFont;
3876 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
3877 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
3878 tti.options = verticalTabs ? kHIThemeTextBoxOptionStronglyVertical : kHIThemeTextBoxOptionNone;
3879 tti.truncationPosition = kHIThemeTextTruncationNone;
3880 tti.truncationMaxLines = 1 + myTab.text.count(QLatin1Char('\n'));
3881 QCFString tabText = qt_mac_removeMnemonics(myTab.text);
3882 QRect r = myTab.rect.adjusted(0, 0, 0, -1);
3883 HIRect bounds = qt_hirectForQRect(r);
3884 HIThemeDrawTextBox(tabText, &bounds, &tti, cg, kHIThemeOrientationNormal);
3889 case CE_DockWidgetTitle:
3890 if (const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(w)) {
3891 bool floating = dockWidget->isFloating();
3893 ThemeDrawState tds = d->getDrawState(opt->state);
3894 HIThemeWindowDrawInfo wdi;
3895 wdi.version = qt_mac_hitheme_version;
3897 wdi.windowType = kThemeMovableDialogWindow;
3898 wdi.titleHeight = opt->rect.height();
3899 wdi.titleWidth = opt->rect.width();
3902 HIRect titleBarRect;
3903 HIRect tmpRect = qt_hirectForQRect(opt->rect);
3905 QCFType<HIShapeRef> titleRegion;
3906 QRect newr = opt->rect.adjusted(0, 0, 2, 0);
3907 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
3908 ptrHIShapeGetBounds(titleRegion, &tmpRect);
3909 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
3910 titleBarRect = qt_hirectForQRect(newr);
3912 QMacCGContext cg(p);
3913 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
3915 // fill title bar background
3916 QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3917 linearGrad.setColorAt(0, mainWindowGradientBegin);
3918 linearGrad.setColorAt(1, mainWindowGradientEnd);
3919 p->fillRect(opt->rect, linearGrad);
3921 // draw horizontal lines at top and bottom
3923 p->setPen(mainWindowGradientBegin.lighter(114));
3924 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3925 p->setPen(mainWindowGradientEnd.darker(114));
3926 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
3932 if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
3933 if (!dwOpt->title.isEmpty()) {
3934 const QStyleOptionDockWidgetV2 *v2
3935 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(dwOpt);
3936 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
3938 QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, w);
3939 if (verticalTitleBar) {
3940 QRect rect = dwOpt->rect;
3946 titleRect = QRect(r.left() + rect.bottom()
3947 - titleRect.bottom(),
3948 r.top() + titleRect.left() - rect.left(),
3949 titleRect.height(), titleRect.width());
3951 p->translate(r.left(), r.top() + r.width());
3953 p->translate(-r.left(), -r.top());
3956 QFont oldFont = p->font();
3957 p->setFont(qt_app_fonts_hash()->value("QToolButton", p->font()));
3958 QString text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
3960 drawItemText(p, titleRect,
3961 Qt::AlignCenter | Qt::TextShowMnemonic, dwOpt->palette,
3962 dwOpt->state & State_Enabled, text,
3963 QPalette::WindowText);
3964 p->setFont(oldFont);
3968 case CE_FocusFrame: {
3969 int xOff = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, w) + 1;
3970 int yOff = proxy()->pixelMetric(PM_FocusFrameVMargin, opt, w) + 1;
3971 HIRect hirect = CGRectMake(xOff+opt->rect.x(), yOff+opt->rect.y(), opt->rect.width() - 2 * xOff,
3972 opt->rect.height() - 2 * yOff);
3973 HIThemeDrawFocusRect(&hirect, true, QMacCGContext(p), kHIThemeOrientationNormal);
3976 case CE_MenuEmptyArea:
3977 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
3978 p->fillRect(mi->rect, opt->palette.background());
3979 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, w);
3980 int tabwidth = mi->tabWidth;
3981 int maxpmw = mi->maxIconWidth;
3982 bool active = mi->state & State_Selected;
3983 bool enabled = mi->state & State_Enabled;
3984 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
3985 HIRect itemRect = qt_hirectForQRect(mi->rect);
3986 HIThemeMenuItemDrawInfo mdi;
3987 mdi.version = qt_mac_hitheme_version;
3988 mdi.itemType = kThemeMenuItemPlain;
3989 if (!mi->icon.isNull())
3990 mdi.itemType |= kThemeMenuItemHasIcon;
3991 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
3992 mdi.itemType |= kThemeMenuItemHierarchical | kThemeMenuItemHierBackground;
3994 mdi.itemType |= kThemeMenuItemPopUpBackground;
3996 mdi.state = kThemeMenuActive;
3998 mdi.state = kThemeMenuDisabled;
4000 mdi.state |= kThemeMenuSelected;
4002 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
4003 // First arg should be &menurect, but wacky stuff happens then.
4004 HIThemeDrawMenuSeparator(&itemRect, &itemRect, &mdi,
4005 cg, kHIThemeOrientationNormal);
4009 bool needAlpha = mi->palette.color(QPalette::Button) == Qt::transparent;
4012 CGContextSaveGState(cg);
4013 CGContextSetAlpha(cg, 0.0);
4015 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4016 cg, kHIThemeOrientationNormal, &cr);
4018 CGContextRestoreGState(cg);
4019 if (ce == CE_MenuEmptyArea)
4021 contentRect = qt_qrectForHIRect(cr);
4023 int xpos = contentRect.x() + 18;
4024 int checkcol = maxpmw;
4026 p->setPen(mi->palette.text().color());
4028 p->setPen(mi->palette.highlightedText().color());
4030 p->setPen(mi->palette.buttonText().color());
4033 // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it,
4034 // we somehow need to use a special encoding as it doesn't look right with our
4037 CGContextSetShouldAntialias(cg, true);
4038 CGContextSetShouldSmoothFonts(cg, true);
4039 QColor textColor = p->pen().color();
4040 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
4041 textColor.blueF(), textColor.alphaF() };
4042 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
4043 CGContextSetFillColor(cg, colorComp);
4044 HIThemeTextInfo tti;
4045 tti.version = qt_mac_hitheme_version;
4047 if (active && enabled)
4048 tti.state = kThemeStatePressed;
4049 switch (widgetSize) {
4050 case QAquaSizeUnknown:
4051 case QAquaSizeLarge:
4052 tti.fontID = kThemeMenuItemMarkFont;
4054 case QAquaSizeSmall:
4055 tti.fontID = kThemeSmallSystemFont;
4058 tti.fontID = kThemeMiniSystemFont;
4061 tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft;
4062 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
4063 tti.options = kHIThemeTextBoxOptionNone;
4064 tti.truncationPosition = kHIThemeTextTruncationNone;
4065 tti.truncationMaxLines = 1;
4066 QCFString checkmark;
4068 if (mi->checkType == QStyleOptionMenuItem::Exclusive)
4069 checkmark = QString(QChar(kDiamondUnicode));
4072 checkmark = QString(QChar(kCheckUnicode));
4073 int mw = checkcol + macItemFrame;
4074 int mh = contentRect.height() - 2 * macItemFrame;
4075 int xp = contentRect.x();
4077 CGFloat outWidth, outHeight, outBaseline;
4078 HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight,
4080 if (widgetSize == QAquaSizeMini)
4082 QRect r(xp, contentRect.y(), mw, mh);
4083 r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1);
4084 HIRect bounds = qt_hirectForQRect(r);
4085 HIThemeDrawTextBox(checkmark, &bounds, &tti,
4086 cg, kHIThemeOrientationNormal);
4089 if (!mi->icon.isNull()) {
4090 QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
4092 // Always be normal or disabled to follow the Mac style.
4093 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
4094 QSize iconSize(smallIconSize, smallIconSize);
4095 if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
4096 iconSize = comboBox->iconSize();
4098 QPixmap pixmap = mi->icon.pixmap(iconSize, mode);
4099 int pixw = pixmap.width();
4100 int pixh = pixmap.height();
4101 QRect cr(xpos, contentRect.y(), checkcol, contentRect.height());
4102 QRect pmr(0, 0, pixw, pixh);
4103 pmr.moveCenter(cr.center());
4104 p->drawPixmap(pmr.topLeft(), pixmap);
4108 QString s = mi->text;
4110 int t = s.indexOf(QLatin1Char('\t'));
4111 int text_flags = Qt::AlignRight | Qt::AlignVCenter | Qt::TextHideMnemonic
4112 | Qt::TextSingleLine | Qt::AlignAbsolute;
4113 int yPos = contentRect.y();
4114 if (widgetSize == QAquaSizeMini)
4118 p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
4119 int xp = contentRect.right() - tabwidth - macRightBorder
4120 - macItemHMargin - macItemFrame + 1;
4121 p->drawText(xp, yPos, tabwidth, contentRect.height(), text_flags,
4126 const int xm = macItemFrame + maxpmw + macItemHMargin;
4127 QFont myFont = mi->font;
4128 // myFont may not have any "hard" flags set. We override
4129 // the point size so that when it is resolved against the device, this font will win.
4130 // This is mainly to handle cases where someone sets the font on the window
4131 // and then the combo inherits it and passes it onward. At that point the resolve mask
4132 // is very, very weak. This makes it stonger.
4133 myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
4135 p->drawText(xpos, yPos, contentRect.width() - xm - tabwidth + 1,
4136 contentRect.height(), text_flags ^ Qt::AlignRight, s);
4141 case CE_MenuHMargin:
4142 case CE_MenuVMargin:
4143 case CE_MenuTearoff:
4144 case CE_MenuScroller:
4145 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4146 p->fillRect(mi->rect, opt->palette.background());
4148 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4149 HIRect itemRect = qt_hirectForQRect(mi->rect);
4150 HIThemeMenuItemDrawInfo mdi;
4151 mdi.version = qt_mac_hitheme_version;
4152 if (!(opt->state & State_Enabled))
4153 mdi.state = kThemeMenuDisabled;
4154 else if (opt->state & State_Selected)
4155 mdi.state = kThemeMenuSelected;
4157 mdi.state = kThemeMenuActive;
4158 if (ce == CE_MenuScroller) {
4159 if (opt->state & State_DownArrow)
4160 mdi.itemType = kThemeMenuItemScrollDownArrow;
4162 mdi.itemType = kThemeMenuItemScrollUpArrow;
4164 mdi.itemType = kThemeMenuItemPlain;
4166 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi,
4168 kHIThemeOrientationNormal, 0);
4169 if (ce == CE_MenuTearoff) {
4170 p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
4171 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
4172 mi->rect.x() + mi->rect.width() - 4,
4173 mi->rect.y() + mi->rect.height() / 2 - 1);
4174 p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
4175 p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
4176 mi->rect.x() + mi->rect.width() - 4,
4177 mi->rect.y() + mi->rect.height() / 2);
4181 case CE_MenuBarItem:
4182 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4183 HIRect menuRect = qt_hirectForQRect(mi->menuRect);
4184 HIRect itemRect = qt_hirectForQRect(mi->rect);
4186 if ((opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken)){
4187 // Draw a selected menu item background:
4188 HIThemeMenuItemDrawInfo mdi;
4189 mdi.version = qt_mac_hitheme_version;
4190 mdi.state = kThemeMenuSelected;
4191 mdi.itemType = kThemeMenuItemPlain;
4192 HIThemeDrawMenuItem(&menuRect, &itemRect, &mdi, cg, kHIThemeOrientationNormal, 0);
4194 // Draw the toolbar background:
4195 HIThemeMenuBarDrawInfo bdi;
4196 bdi.version = qt_mac_hitheme_version;
4197 bdi.state = kThemeMenuBarNormal;
4199 HIThemeDrawMenuBarBackground(&menuRect, &bdi, cg, kHIThemeOrientationNormal);
4202 if (!mi->icon.isNull()) {
4203 drawItemPixmap(p, mi->rect,
4204 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4205 | Qt::TextSingleLine,
4206 mi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize),
4207 (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
4209 drawItemText(p, mi->rect,
4210 Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
4211 | Qt::TextSingleLine,
4212 mi->palette, mi->state & State_Enabled,
4213 mi->text, QPalette::ButtonText);
4217 case CE_MenuBarEmptyArea:
4218 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
4219 HIThemeMenuBarDrawInfo bdi;
4220 bdi.version = qt_mac_hitheme_version;
4221 bdi.state = kThemeMenuBarNormal;
4223 HIRect hirect = qt_hirectForQRect(mi->rect);
4224 HIThemeDrawMenuBarBackground(&hirect, &bdi, cg,
4225 kHIThemeOrientationNormal);
4228 case CE_ProgressBarContents:
4229 if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
4230 HIThemeTrackDrawInfo tdi;
4231 tdi.version = qt_mac_hitheme_version;
4233 bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
4234 bool vertical = false;
4235 bool inverted = false;
4236 if (const QStyleOptionProgressBarV2 *pb2 = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(opt)) {
4237 vertical = (pb2->orientation == Qt::Vertical);
4238 inverted = pb2->invertedAppearance;
4240 bool reverse = (!vertical && (pb->direction == Qt::RightToLeft));
4243 switch (d->aquaSizeConstrain(opt, w)) {
4244 case QAquaSizeUnknown:
4245 case QAquaSizeLarge:
4246 tdi.kind = !isIndeterminate ? kThemeLargeProgressBar
4247 : kThemeLargeIndeterminateBar;
4250 case QAquaSizeSmall:
4251 tdi.kind = !isIndeterminate ? kThemeProgressBar : kThemeIndeterminateBar;
4254 tdi.bounds = qt_hirectForQRect(pb->rect);
4255 tdi.max = pb->maximum;
4256 tdi.min = pb->minimum;
4257 tdi.value = pb->progress;
4258 tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
4259 tdi.trackInfo.progress.phase = d->progressFrame;
4260 if (!(pb->state & State_Active))
4261 tdi.enableState = kThemeTrackInactive;
4262 else if (!(pb->state & State_Enabled))
4263 tdi.enableState = kThemeTrackDisabled;
4265 tdi.enableState = kThemeTrackActive;
4266 HIThemeOrientation drawOrientation = kHIThemeOrientationNormal;
4269 drawOrientation = kHIThemeOrientationInverted;
4271 CGContextSaveGState(cg);
4272 CGContextTranslateCTM(cg, pb->rect.width(), 0);
4273 CGContextScaleCTM(cg, -1, 1);
4276 HIThemeDrawTrack(&tdi, 0, cg, drawOrientation);
4277 if (reverse && !vertical)
4278 CGContextRestoreGState(cg);
4281 case CE_ProgressBarLabel:
4282 case CE_ProgressBarGroove:
4285 if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) {
4286 HIThemeGrowBoxDrawInfo gdi;
4287 gdi.version = qt_mac_hitheme_version;
4289 gdi.kind = kHIThemeGrowBoxKindNormal;
4290 gdi.direction = kThemeGrowRight | kThemeGrowDown;
4291 gdi.size = kHIThemeGrowBoxSizeNormal;
4292 HIPoint pt = CGPointMake(opt->rect.x(), opt->rect.y());
4293 HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal);
4295 // It isn't possible to draw a transparent size grip with the
4296 // native API, so we do it ourselves here.
4297 const bool metal = qt_mac_is_metal(w);
4298 QPen lineColor = metal ? QColor(236, 236, 236) : QColor(82, 82, 82, 192);
4299 QPen metalHighlight = QColor(5, 5, 5, 192);
4300 lineColor.setWidth(1);
4302 p->setRenderHint(QPainter::Antialiasing);
4303 p->setPen(lineColor);
4304 const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
4305 const int NumLines = metal ? 4 : 3;
4306 for (int l = 0; l < NumLines; ++l) {
4307 const int offset = (l * 4 + (metal ? 2 : 3));
4309 if (layoutDirection == Qt::LeftToRight) {
4310 start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
4311 end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
4313 start = QPoint(offset, opt->rect.height() - 1);
4314 end = QPoint(1, opt->rect.height() - offset);
4316 p->drawLine(start, end);
4318 p->setPen(metalHighlight);
4319 p->setRenderHint(QPainter::Antialiasing, false);
4320 p->drawLine(start + QPoint(0, -1), end + QPoint(0, -1));
4321 p->setRenderHint(QPainter::Antialiasing, true);
4322 p->setPen(lineColor);
4330 HIThemeSplitterDrawInfo sdi;
4331 sdi.version = qt_mac_hitheme_version;
4333 sdi.adornment = qt_mac_is_metal(w) ? kHIThemeSplitterAdornmentMetal
4334 : kHIThemeSplitterAdornmentNone;
4335 HIRect hirect = qt_hirectForQRect(opt->rect);
4336 HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal);
4339 if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
4340 QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
4341 if (!rubber->opaque) {
4343 // I retrieved these colors from the Carbon-Dev mailing list
4344 strokeColor.setHsvF(0, 0, 0.86, 1.0);
4345 fillColor.setHsvF(0, 0, 0.53, 0.25);
4346 if (opt->rect.width() * opt->rect.height() <= 3) {
4347 p->fillRect(opt->rect, strokeColor);
4349 QPen oldPen = p->pen();
4350 QBrush oldBrush = p->brush();
4351 QPen pen(strokeColor);
4353 p->setBrush(fillColor);
4354 p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
4356 p->setBrush(oldBrush);
4359 p->fillRect(opt->rect, fillColor);
4364 // For unified tool bars, draw nothing.
4366 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
4367 if (mainWindow->unifiedTitleAndToolBarOnMac())
4372 // draw background gradient
4373 QLinearGradient linearGrad;
4374 if (opt->state & State_Horizontal)
4375 linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
4377 linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
4379 linearGrad.setColorAt(0, mainWindowGradientBegin);
4380 linearGrad.setColorAt(1, mainWindowGradientEnd);
4381 p->fillRect(opt->rect, linearGrad);
4384 if (opt->state & State_Horizontal) {
4385 p->setPen(mainWindowGradientBegin.lighter(114));
4386 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
4387 p->setPen(mainWindowGradientEnd.darker(114));
4388 p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
4391 p->setPen(mainWindowGradientBegin.lighter(114));
4392 p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
4393 p->setPen(mainWindowGradientEnd.darker(114));
4394 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
4401 QWindowsStyle::drawControl(ce, opt, p, w);
4406 static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
4408 if (dir == Qt::RightToLeft) {
4409 rect->adjust(-right, top, -left, bottom);
4411 rect->adjust(left, top, right, bottom);
4415 QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
4416 const QWidget *widget) const
4419 int controlSize = getControlSize(opt, widget);
4422 case SE_ItemViewItemText:
4423 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
4424 int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget);
4425 // We add the focusframeargin between icon and text in commonstyle
4426 rect = QCommonStyle::subElementRect(sr, opt, widget);
4427 if (vopt->features & QStyleOptionViewItemV2::HasDecoration)
4428 rect.adjust(-fw, 0, 0, 0);
4431 case SE_ToolBoxTabContents:
4432 rect = QCommonStyle::subElementRect(sr, opt, widget);
4434 case SE_PushButtonContents:
4435 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4436 // Unlike Carbon, we want the button to always be drawn inside its bounds.
4437 // Therefore, the button is a bit smaller, so that even if it got focus,
4438 // the focus 'shadow' will be inside. Adjust the content rect likewise.
4439 HIThemeButtonDrawInfo bdi;
4440 d->initHIThemePushButton(btn, widget, d->getDrawState(opt->state), &bdi);
4441 HIRect contentRect = d->pushButtonContentBounds(btn, &bdi);
4442 rect = qt_qrectForHIRect(contentRect);
4445 case SE_HeaderLabel:
4446 if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
4447 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4448 if (widget && widget->height() <= 22){
4449 // We need to allow the text a bit more space when the header is
4450 // small, otherwise it gets clipped:
4452 rect.setHeight(widget->height());
4456 case SE_ProgressBarGroove:
4457 case SE_ProgressBarLabel:
4459 case SE_ProgressBarContents:
4462 case SE_TreeViewDisclosureItem: {
4463 HIRect inRect = CGRectMake(opt->rect.x(), opt->rect.y(),
4464 opt->rect.width(), opt->rect.height());
4465 HIThemeButtonDrawInfo bdi;
4466 bdi.version = qt_mac_hitheme_version;
4467 bdi.state = kThemeStateActive;
4468 bdi.kind = kThemeDisclosureButton;
4469 bdi.value = kThemeDisclosureRight;
4470 bdi.adornment = kThemeAdornmentNone;
4472 HIThemeGetButtonContentBounds(&inRect, &bdi, &contentRect);
4473 QCFType<HIShapeRef> shape;
4475 HIThemeGetButtonShape(&inRect, &bdi, &shape);
4476 ptrHIShapeGetBounds(shape, &outRect);
4477 rect = QRect(int(outRect.origin.x + DisclosureOffset), int(outRect.origin.y),
4478 int(contentRect.origin.x - outRect.origin.x + DisclosureOffset),
4479 int(outRect.size.height));
4482 case SE_TabWidgetLeftCorner:
4483 if (const QStyleOptionTabWidgetFrame *twf
4484 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4485 switch (twf->shape) {
4486 case QTabBar::RoundedNorth:
4487 case QTabBar::TriangularNorth:
4488 rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
4490 case QTabBar::RoundedSouth:
4491 case QTabBar::TriangularSouth:
4492 rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
4493 twf->leftCornerWidgetSize);
4498 rect = visualRect(twf->direction, twf->rect, rect);
4501 case SE_TabWidgetRightCorner:
4502 if (const QStyleOptionTabWidgetFrame *twf
4503 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4504 switch (twf->shape) {
4505 case QTabBar::RoundedNorth:
4506 case QTabBar::TriangularNorth:
4507 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
4508 twf->rightCornerWidgetSize);
4510 case QTabBar::RoundedSouth:
4511 case QTabBar::TriangularSouth:
4512 rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
4513 twf->rect.height() - twf->rightCornerWidgetSize.height()),
4514 twf->rightCornerWidgetSize);
4519 rect = visualRect(twf->direction, twf->rect, rect);
4522 case SE_TabWidgetTabContents:
4523 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4524 if (const QStyleOptionTabWidgetFrame *twf
4525 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4526 if (twf->lineWidth != 0) {
4527 switch (getTabDirection(twf->shape)) {
4528 case kThemeTabNorth:
4529 rect.adjust(+1, +14, -1, -1);
4531 case kThemeTabSouth:
4532 rect.adjust(+1, +1, -1, -14);
4535 rect.adjust(+14, +1, -1, -1);
4538 rect.adjust(+1, +1, -14, -1);
4543 case SE_LineEditContents:
4544 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4545 if(widget->parentWidget() && qobject_cast<const QComboBox*>(widget->parentWidget()))
4546 rect.adjust(-1, -2, 0, 0);
4548 rect.adjust(-1, 0, 0, +1);
4550 case SE_CheckBoxLayoutItem:
4552 if (controlSize == QAquaSizeLarge) {
4553 setLayoutItemMargins(+2, +3, -9, -4, &rect, opt->direction);
4554 } else if (controlSize == QAquaSizeSmall) {
4555 setLayoutItemMargins(+1, +5, 0 /* fix */, -6, &rect, opt->direction);
4557 setLayoutItemMargins(0, +7, 0 /* fix */, -6, &rect, opt->direction);
4560 case SE_ComboBoxLayoutItem:
4561 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
4562 // Do nothing, because QToolbar needs the entire widget rect.
4563 // Otherwise it will be clipped. Equivalent to
4564 // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
4568 if (controlSize == QAquaSizeLarge) {
4569 rect.adjust(+3, +2, -3, -4);
4570 } else if (controlSize == QAquaSizeSmall) {
4571 setLayoutItemMargins(+2, +1, -3, -4, &rect, opt->direction);
4573 setLayoutItemMargins(+1, 0, -2, 0, &rect, opt->direction);
4577 case SE_LabelLayoutItem:
4579 setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
4581 case SE_ProgressBarLayoutItem: {
4583 int bottom = SIZE(3, 8, 8);
4584 if (opt->state & State_Horizontal) {
4585 rect.adjust(0, +1, 0, -bottom);
4587 setLayoutItemMargins(+1, 0, -bottom, 0, &rect, opt->direction);
4591 case SE_PushButtonLayoutItem:
4592 if (const QStyleOptionButton *buttonOpt
4593 = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
4594 if ((buttonOpt->features & QStyleOptionButton::Flat))
4595 break; // leave rect alone
4598 if (controlSize == QAquaSizeLarge) {
4599 rect.adjust(+6, +4, -6, -8);
4600 } else if (controlSize == QAquaSizeSmall) {
4601 rect.adjust(+5, +4, -5, -6);
4603 rect.adjust(+1, 0, -1, -2);
4606 case SE_RadioButtonLayoutItem:
4608 if (controlSize == QAquaSizeLarge) {
4609 setLayoutItemMargins(+2, +2 /* SHOULD BE +3, done for alignment */,
4610 0, -4 /* SHOULD BE -3, done for alignment */, &rect, opt->direction);
4611 } else if (controlSize == QAquaSizeSmall) {
4612 rect.adjust(0, +6, 0 /* fix */, -5);
4614 rect.adjust(0, +6, 0 /* fix */, -7);
4617 case SE_SliderLayoutItem:
4618 if (const QStyleOptionSlider *sliderOpt
4619 = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4621 if (sliderOpt->tickPosition == QSlider::NoTicks) {
4622 int above = SIZE(3, 0, 2);
4623 int below = SIZE(4, 3, 0);
4624 if (sliderOpt->orientation == Qt::Horizontal) {
4625 rect.adjust(0, +above, 0, -below);
4627 rect.adjust(+above, 0, -below, 0); //### Seems that QSlider flip the position of the ticks in reverse mode.
4629 } else if (sliderOpt->tickPosition == QSlider::TicksAbove) {
4630 int below = SIZE(3, 2, 0);
4631 if (sliderOpt->orientation == Qt::Horizontal) {
4632 rect.setHeight(rect.height() - below);
4634 rect.setWidth(rect.width() - below);
4636 } else if (sliderOpt->tickPosition == QSlider::TicksBelow) {
4637 int above = SIZE(3, 2, 0);
4638 if (sliderOpt->orientation == Qt::Horizontal) {
4639 rect.setTop(rect.top() + above);
4641 rect.setLeft(rect.left() + above);
4646 case SE_FrameLayoutItem:
4647 // hack because QStyleOptionFrameV2 doesn't have a frameStyle member
4648 if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
4650 switch (frame->frameStyle() & QFrame::Shape_Mask) {
4652 rect.adjust(0, +1, 0, -1);
4655 rect.adjust(+1, 0, -1, 0);
4662 case SE_GroupBoxLayoutItem:
4664 if (const QStyleOptionGroupBox *groupBoxOpt =
4665 qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
4667 AHIG is very inconsistent when it comes to group boxes.
4668 Basically, we make sure that (non-checkable) group boxes
4669 and tab widgets look good when laid out side by side.
4671 if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
4672 | QStyle::SC_GroupBoxLabel)) {
4674 if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
4675 delta = SIZE(8, 4, 4); // guess
4677 delta = SIZE(15, 12, 12); // guess
4679 rect.setTop(rect.top() + delta);
4682 rect.setBottom(rect.bottom() - 1);
4684 case SE_TabWidgetLayoutItem:
4685 if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
4686 qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
4688 AHIG specifies "12 or 14" as the distance from the window
4689 edge. We choose 14 and since the default top margin is 20,
4692 rect = tabWidgetOpt->rect;
4693 if (tabWidgetOpt->shape == QTabBar::RoundedNorth)
4694 rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
4697 #ifndef QT_NO_DOCKWIDGET
4698 case SE_DockWidgetCloseButton:
4699 case SE_DockWidgetFloatButton:
4700 case SE_DockWidgetTitleBarText:
4701 case SE_DockWidgetIcon: {
4702 int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
4703 int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt, widget);
4704 QRect srect = opt->rect;
4706 const QStyleOptionDockWidget *dwOpt
4707 = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
4708 bool canClose = dwOpt == 0 ? true : dwOpt->closable;
4709 bool canFloat = dwOpt == 0 ? false : dwOpt->floatable;
4710 const QStyleOptionDockWidgetV2 *v2
4711 = qstyleoption_cast<const QStyleOptionDockWidgetV2*>(opt);
4712 bool verticalTitleBar = v2 == 0 ? false : v2->verticalTitleBar;
4714 // If this is a vertical titlebar, we transpose and work as if it was
4715 // horizontal, then transpose again.
4716 if (verticalTitleBar) {
4717 QSize size = srect.size();
4719 srect.setSize(size);
4723 int right = srect.right();
4724 int left = srect.left();
4728 QSize sz = standardIcon(QStyle::SP_TitleBarCloseButton,
4729 opt, widget).actualSize(QSize(iconSize, iconSize));
4730 sz += QSize(buttonMargin, buttonMargin);
4731 if (verticalTitleBar)
4733 closeRect = QRect(left,
4734 srect.center().y() - sz.height()/2,
4735 sz.width(), sz.height());
4736 left = closeRect.right() + 1;
4738 if (sr == SE_DockWidgetCloseButton) {
4745 QSize sz = standardIcon(QStyle::SP_TitleBarNormalButton,
4746 opt, widget).actualSize(QSize(iconSize, iconSize));
4747 sz += QSize(buttonMargin, buttonMargin);
4748 if (verticalTitleBar)
4750 floatRect = QRect(left,
4751 srect.center().y() - sz.height()/2,
4752 sz.width(), sz.height());
4753 left = floatRect.right() + 1;
4755 if (sr == SE_DockWidgetFloatButton) {
4761 if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(widget)) {
4763 if (dw->isFloating())
4764 icon = dw->windowIcon();
4766 && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
4767 QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
4768 if (verticalTitleBar)
4770 iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
4771 sz.width(), sz.height());
4772 right = iconRect.left() - 1;
4775 if (sr == SE_DockWidgetIcon) {
4780 QRect textRect = QRect(left, srect.top(),
4781 right - left, srect.height());
4782 if (sr == SE_DockWidgetTitleBarText) {
4788 if (verticalTitleBar) {
4789 rect = QRect(srect.left() + rect.top() - srect.top(),
4790 srect.top() + srect.right() - rect.right(),
4791 rect.height(), rect.width());
4793 rect = visualRect(opt->direction, srect, rect);
4799 rect = QWindowsStyle::subElementRect(sr, opt, widget);
4805 static inline void drawToolbarButtonArrow(const QRect &toolButtonRect, ThemeDrawState tds, CGContextRef cg)
4807 QRect arrowRect = QRect(toolButtonRect.right() - 9, toolButtonRect.bottom() - 9, 7, 5);
4808 HIThemePopupArrowDrawInfo padi;
4809 padi.version = qt_mac_hitheme_version;
4811 padi.orientation = kThemeArrowDown;
4812 padi.size = kThemeArrow7pt;
4813 HIRect hirect = qt_hirectForQRect(arrowRect);
4814 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
4817 void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
4818 const QWidget *widget) const
4820 ThemeDrawState tds = d->getDrawState(opt->state);
4821 QMacCGContext cg(p);
4825 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
4826 HIThemeTrackDrawInfo tdi;
4827 d->getSliderInfo(cc, slider, &tdi, widget);
4828 if (slider->state & State_Sunken) {
4829 if (cc == CC_Slider) {
4830 if (slider->activeSubControls == SC_SliderHandle)
4831 tdi.trackInfo.slider.pressState = kThemeThumbPressed;
4832 else if (slider->activeSubControls == SC_SliderGroove)
4833 tdi.trackInfo.slider.pressState = kThemeLeftTrackPressed;
4835 if (slider->activeSubControls == SC_ScrollBarSubLine
4836 || slider->activeSubControls == SC_ScrollBarAddLine) {
4837 // This test looks complex but it basically boils down
4838 // to the following: The "RTL look" on the mac also
4839 // changed the directions of the controls, that's not
4840 // what people expect (an arrow is an arrow), so we
4841 // kind of fake and say the opposite button is hit.
4842 // This works great, up until 10.4 which broke the
4843 // scroll bars, so I also have actually do something
4844 // similar when I have an upside down scroll bar
4845 // because on Tiger I only "fake" the reverse stuff.
4846 bool reverseHorizontal = (slider->direction == Qt::RightToLeft
4847 && slider->orientation == Qt::Horizontal);
4848 if ((reverseHorizontal
4849 && slider->activeSubControls == SC_ScrollBarAddLine)
4850 || (!reverseHorizontal
4851 && slider->activeSubControls == SC_ScrollBarSubLine)) {
4852 tdi.trackInfo.scrollbar.pressState = kThemeRightInsideArrowPressed
4853 | kThemeLeftOutsideArrowPressed;
4855 tdi.trackInfo.scrollbar.pressState = kThemeLeftInsideArrowPressed
4856 | kThemeRightOutsideArrowPressed;
4858 } else if (slider->activeSubControls == SC_ScrollBarAddPage) {
4859 tdi.trackInfo.scrollbar.pressState = kThemeRightTrackPressed;
4860 } else if (slider->activeSubControls == SC_ScrollBarSubPage) {
4861 tdi.trackInfo.scrollbar.pressState = kThemeLeftTrackPressed;
4862 } else if (slider->activeSubControls == SC_ScrollBarSlider) {
4863 tdi.trackInfo.scrollbar.pressState = kThemeThumbPressed;
4868 bool tracking = slider->sliderPosition == slider->sliderValue;
4870 // Small optimization, the same as q->subControlRect
4871 QCFType<HIShapeRef> shape;
4872 HIThemeGetTrackThumbShape(&tdi, &shape);
4873 ptrHIShapeGetBounds(shape, &macRect);
4874 tdi.value = slider->sliderValue;
4877 // Remove controls from the scroll bar if it is to short to draw them correctly.
4878 // This is done in two stages: first the thumb indicator is removed when it is
4879 // no longer possible to move it, second the up/down buttons are removed when
4880 // there is not enough space for them.
4881 if (cc == CC_ScrollBar) {
4882 const int scrollBarLength = (slider->orientation == Qt::Horizontal)
4883 ? slider->rect.width() : slider->rect.height();
4884 const QMacStyle::WidgetSizePolicy sizePolicy = widgetSizePolicy(widget);
4885 if (scrollBarLength < scrollButtonsCutoffSize(thumbIndicatorCutoff, sizePolicy))
4886 tdi.attributes &= ~kThemeTrackShowThumb;
4887 if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, sizePolicy))
4888 tdi.enableState = kThemeTrackNothingToScroll;
4890 if (!(slider->subControls & SC_SliderHandle))
4891 tdi.attributes &= ~kThemeTrackShowThumb;
4892 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4893 if (!(slider->subControls & SC_SliderGroove))
4894 tdi.attributes |= kThemeTrackHideTrack;
4898 HIThemeDrawTrack(&tdi, tracking ? 0 : &macRect, cg,
4899 kHIThemeOrientationNormal);
4900 if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
4901 if (qt_mac_is_metal(widget)) {
4902 if (tdi.enableState == kThemeTrackInactive)
4903 tdi.enableState = kThemeTrackActive; // Looks more Cocoa-like
4905 int interval = slider->tickInterval;
4906 if (interval == 0) {
4907 interval = slider->pageStep;
4909 interval = slider->singleStep;
4913 int numMarks = 1 + ((slider->maximum - slider->minimum) / interval);
4915 if (tdi.trackInfo.slider.thumbDir == kThemeThumbPlain) {
4916 // They asked for both, so we'll give it to them.
4917 tdi.trackInfo.slider.thumbDir = kThemeThumbDownward;
4918 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4920 kHIThemeOrientationNormal);
4921 tdi.trackInfo.slider.thumbDir = kThemeThumbUpward;
4922 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4924 kHIThemeOrientationNormal);
4926 HIThemeDrawTrackTickMarks(&tdi, numMarks,
4928 kHIThemeOrientationNormal);
4935 if (const QStyleOptionQ3ListView *lv = qstyleoption_cast<const QStyleOptionQ3ListView *>(opt)) {
4936 if (lv->subControls & SC_Q3ListView)
4937 QWindowsStyle::drawComplexControl(cc, lv, p, widget);
4938 if (lv->subControls & (SC_Q3ListViewBranch | SC_Q3ListViewExpand)) {
4939 int y = lv->rect.y();
4940 int h = lv->rect.height();
4941 int x = lv->rect.right() - 10;
4942 for (int i = 1; i < lv->items.size() && y < h; ++i) {
4943 QStyleOptionQ3ListViewItem item = lv->items.at(i);
4944 if (y + item.height > 0 && (item.childCount > 0
4945 || (item.features & (QStyleOptionQ3ListViewItem::Expandable
4946 | QStyleOptionQ3ListViewItem::Visible))
4947 == (QStyleOptionQ3ListViewItem::Expandable
4948 | QStyleOptionQ3ListViewItem::Visible))) {
4949 QStyleOption treeOpt(0);
4950 treeOpt.rect.setRect(x, y + item.height / 2 - 4, 9, 9);
4951 treeOpt.palette = lv->palette;
4952 treeOpt.state = lv->state;
4953 treeOpt.state |= State_Children;
4954 if (item.state & State_Open)
4955 treeOpt.state |= State_Open;
4956 proxy()->drawPrimitive(PE_IndicatorBranch, &treeOpt, p, widget);
4958 y += item.totalHeight;
4964 if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
4965 QStyleOptionSpinBox newSB = *sb;
4966 if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
4968 GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
4970 QRect lineeditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField, widget);
4971 lineeditRect.adjust(-frame_size, -frame_size, +frame_size, +frame_size);
4973 HIThemeFrameDrawInfo fdi;
4974 fdi.version = qt_mac_hitheme_version;
4976 fdi.kind = kHIThemeFrameTextFieldSquare;
4977 fdi.isFocused = false;
4978 HIRect hirect = qt_hirectForQRect(lineeditRect);
4979 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
4981 if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
4982 HIThemeButtonDrawInfo bdi;
4983 bdi.version = qt_mac_hitheme_version;
4984 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(opt, widget);
4986 case QAquaSizeUnknown:
4987 case QAquaSizeLarge:
4988 bdi.kind = kThemeIncDecButton;
4991 bdi.kind = kThemeIncDecButtonMini;
4993 case QAquaSizeSmall:
4994 bdi.kind = kThemeIncDecButtonSmall;
4997 if (!(sb->stepEnabled & (QAbstractSpinBox::StepUpEnabled
4998 | QAbstractSpinBox::StepDownEnabled)))
4999 tds = kThemeStateUnavailable;
5000 if (sb->activeSubControls == SC_SpinBoxDown
5001 && (sb->state & State_Sunken))
5002 tds = kThemeStatePressedDown;
5003 else if (sb->activeSubControls == SC_SpinBoxUp
5004 && (sb->state & State_Sunken))
5005 tds = kThemeStatePressedUp;
5007 if (!(sb->state & State_Active)
5008 && sb->palette.currentColorGroup() == QPalette::Active
5009 && tds == kThemeStateInactive)
5010 bdi.state = kThemeStateActive;
5011 bdi.value = kThemeButtonOff;
5012 bdi.adornment = kThemeAdornmentNone;
5014 QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget);
5016 updown |= proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
5017 HIRect newRect = qt_hirectForQRect(updown);
5020 HIThemeGetButtonBackgroundBounds(&newRect, &bdi, &outRect);
5021 off_rct.setRect(int(newRect.origin.x - outRect.origin.x),
5022 int(newRect.origin.y - outRect.origin.y),
5023 int(outRect.size.width - newRect.size.width),
5024 int(outRect.size.height - newRect.size.height));
5026 newRect = qt_hirectForQRect(updown, off_rct);
5027 HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5032 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
5033 HIThemeButtonDrawInfo bdi;
5034 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5035 bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
5037 QMacStylePrivate::drawCombobox(qt_hirectForQRect(combo->rect), bdi, p);
5039 d->drawColorlessButton(qt_hirectForQRect(combo->rect), &bdi, p, opt);
5043 if (const QStyleOptionTitleBar *titlebar
5044 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5045 if (titlebar->state & State_Active) {
5046 if (titlebar->titleBarState & State_Active)
5047 tds = kThemeStateActive;
5049 tds = kThemeStateInactive;
5051 tds = kThemeStateInactive;
5054 HIThemeWindowDrawInfo wdi;
5055 wdi.version = qt_mac_hitheme_version;
5057 wdi.windowType = QtWinType;
5058 wdi.titleHeight = titlebar->rect.height();
5059 wdi.titleWidth = titlebar->rect.width();
5060 wdi.attributes = kThemeWindowHasTitleText;
5061 // It seems HIThemeDrawTitleBarWidget is not able to draw a dirty
5062 // close button, so use HIThemeDrawWindowFrame instead.
5063 if (widget && widget->isWindowModified() && titlebar->subControls & SC_TitleBarCloseButton)
5064 wdi.attributes |= kThemeWindowHasCloseBox | kThemeWindowHasDirty;
5066 HIRect titleBarRect;
5067 HIRect tmpRect = qt_hirectForQRect(titlebar->rect);
5069 QCFType<HIShapeRef> titleRegion;
5070 QRect newr = titlebar->rect.adjusted(0, 0, 2, 0);
5071 HIThemeGetWindowShape(&tmpRect, &wdi, kWindowTitleBarRgn, &titleRegion);
5072 ptrHIShapeGetBounds(titleRegion, &tmpRect);
5073 newr.translate(newr.x() - int(tmpRect.origin.x), newr.y() - int(tmpRect.origin.y));
5074 titleBarRect = qt_hirectForQRect(newr);
5076 HIThemeDrawWindowFrame(&titleBarRect, &wdi, cg, kHIThemeOrientationNormal, 0);
5077 if (titlebar->subControls & (SC_TitleBarCloseButton
5078 | SC_TitleBarMaxButton
5079 | SC_TitleBarMinButton
5080 | SC_TitleBarNormalButton)) {
5081 HIThemeWindowWidgetDrawInfo wwdi;
5082 wwdi.version = qt_mac_hitheme_version;
5083 wwdi.widgetState = tds;
5084 if (titlebar->state & State_MouseOver)
5085 wwdi.widgetState = kThemeStateRollover;
5086 wwdi.windowType = QtWinType;
5087 wwdi.attributes = wdi.attributes | kThemeWindowHasFullZoom | kThemeWindowHasCloseBox | kThemeWindowHasCollapseBox;
5088 wwdi.windowState = wdi.state;
5089 wwdi.titleHeight = wdi.titleHeight;
5090 wwdi.titleWidth = wdi.titleWidth;
5091 ThemeDrawState savedControlState = wwdi.widgetState;
5092 uint sc = SC_TitleBarMinButton;
5093 ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox;
5094 bool active = titlebar->state & State_Active;
5095 if (qMacVersion() < QSysInfo::MV_10_6) {
5097 titleBarRect.origin.x += border;
5098 titleBarRect.origin.y -= border;
5101 while (sc <= SC_TitleBarCloseButton) {
5102 if (sc & titlebar->subControls) {
5104 wwdi.widgetState = savedControlState;
5105 wwdi.widgetType = tbw;
5106 if (sc == SC_TitleBarMinButton)
5107 tmp |= SC_TitleBarNormalButton;
5108 if (active && (titlebar->activeSubControls & tmp)
5109 && (titlebar->state & State_Sunken))
5110 wwdi.widgetState = kThemeStatePressed;
5111 // Draw all sub controllers except the dirty close button
5112 // (it is already handled by HIThemeDrawWindowFrame).
5113 if (!(widget && widget->isWindowModified() && tbw == kThemeWidgetCloseBox)) {
5114 HIThemeDrawTitleBarWidget(&titleBarRect, &wwdi, cg, kHIThemeOrientationNormal);
5115 p->paintEngine()->syncState();
5122 p->paintEngine()->syncState();
5123 if (titlebar->subControls & SC_TitleBarLabel) {
5125 if (!titlebar->icon.isNull()) {
5126 QCFType<HIShapeRef> titleRegion2;
5127 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleProxyIconRgn,
5129 ptrHIShapeGetBounds(titleRegion2, &tmpRect);
5130 if (tmpRect.size.width != 1) {
5131 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5132 iw = titlebar->icon.actualSize(QSize(iconExtent, iconExtent)).width();
5135 if (!titlebar->text.isEmpty()) {
5137 QCFType<HIShapeRef> titleRegion3;
5138 HIThemeGetWindowShape(&titleBarRect, &wdi, kWindowTitleTextRgn, &titleRegion3);
5139 ptrHIShapeGetBounds(titleRegion3, &tmpRect);
5140 p->setClipRect(qt_qrectForHIRect(tmpRect));
5141 QRect br = p->clipRegion().boundingRect();
5143 y = br.y() + (titlebar->rect.height() / 2 - p->fontMetrics().height() / 2);
5144 if (br.width() <= (p->fontMetrics().width(titlebar->text) + iw * 2))
5147 x += br.width() / 2 - p->fontMetrics().width(titlebar->text) / 2;
5149 p->drawPixmap(x - iw, y,
5150 titlebar->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), QIcon::Normal));
5151 drawItemText(p, br, Qt::AlignCenter, opt->palette, tds == kThemeStateActive,
5152 titlebar->text, QPalette::Text);
5159 if (const QStyleOptionGroupBox *groupBox
5160 = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5162 QStyleOptionGroupBox groupBoxCopy(*groupBox);
5163 if ((widget && !widget->testAttribute(Qt::WA_SetFont))
5164 && QApplication::desktopSettingsAware())
5165 groupBoxCopy.subControls = groupBoxCopy.subControls & ~SC_GroupBoxLabel;
5166 QWindowsStyle::drawComplexControl(cc, &groupBoxCopy, p, widget);
5167 if (groupBoxCopy.subControls != groupBox->subControls) {
5168 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5170 CGContextSetShouldAntialias(cg, true);
5171 CGContextSetShouldSmoothFonts(cg, true);
5172 HIThemeTextInfo tti;
5173 tti.version = qt_mac_hitheme_version;
5175 QColor textColor = groupBox->palette.windowText().color();
5176 CGFloat colorComp[] = { textColor.redF(), textColor.greenF(),
5177 textColor.blueF(), textColor.alphaF() };
5178 CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
5179 CGContextSetFillColor(cg, colorComp);
5180 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5181 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5182 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5183 tti.options = kHIThemeTextBoxOptionNone;
5184 tti.truncationPosition = kHIThemeTextTruncationNone;
5185 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5186 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5187 QRect r = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget);
5188 HIRect bounds = qt_hirectForQRect(r);
5189 HIThemeDrawTextBox(groupText, &bounds, &tti, cg, kHIThemeOrientationNormal);
5195 if (const QStyleOptionToolButton *tb
5196 = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
5197 if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
5198 if (tb->subControls & SC_ToolButtonMenu) {
5199 QStyleOption arrowOpt(0);
5200 arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5201 arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
5202 arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
5203 arrowOpt.state = tb->state;
5204 arrowOpt.palette = tb->palette;
5205 proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
5206 } else if ((tb->features & QStyleOptionToolButton::HasMenu)
5207 && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
5208 drawToolbarButtonArrow(tb->rect, tds, cg);
5210 if (tb->state & State_On) {
5211 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
5212 static QPixmap pm(QLatin1String(":/trolltech/mac/style/images/leopard-unified-toolbar-on.png"));
5213 p->setRenderHint(QPainter::SmoothPixmapTransform);
5214 QStyleHelper::drawBorderPixmap(pm, p, tb->rect, 2, 2, 2, 2);
5216 QPen oldPen = p->pen();
5217 p->setPen(QColor(0, 0, 0, 0x3a));
5218 p->fillRect(tb->rect.adjusted(1, 1, -1, -1), QColor(0, 0, 0, 0x12));
5219 p->drawLine(tb->rect.left() + 1, tb->rect.top(),
5220 tb->rect.right() - 1, tb->rect.top());
5221 p->drawLine(tb->rect.left() + 1, tb->rect.bottom(),
5222 tb->rect.right() - 1, tb->rect.bottom());
5223 p->drawLine(tb->rect.topLeft(), tb->rect.bottomLeft());
5224 p->drawLine(tb->rect.topRight(), tb->rect.bottomRight());
5228 proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
5230 ThemeButtonKind bkind = kThemeBevelButton;
5231 switch (d->aquaSizeConstrain(opt, widget)) {
5232 case QAquaSizeUnknown:
5233 case QAquaSizeLarge:
5234 bkind = kThemeBevelButton;
5237 case QAquaSizeSmall:
5238 bkind = kThemeSmallBevelButton;
5242 QRect button, menuarea;
5243 button = proxy()->subControlRect(cc, tb, SC_ToolButton, widget);
5244 menuarea = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget);
5245 State bflags = tb->state,
5247 if (tb->subControls & SC_ToolButton)
5248 bflags |= State_Sunken;
5249 if (tb->subControls & SC_ToolButtonMenu)
5250 mflags |= State_Sunken;
5252 if (tb->subControls & SC_ToolButton) {
5253 if (bflags & (State_Sunken | State_On | State_Raised)) {
5254 HIThemeButtonDrawInfo bdi;
5255 bdi.version = qt_mac_hitheme_version;
5257 bdi.adornment = kThemeAdornmentNone;
5259 bdi.value = kThemeButtonOff;
5260 if (tb->state & State_HasFocus)
5261 bdi.adornment = kThemeAdornmentFocus;
5262 if (tb->state & State_Sunken)
5263 bdi.state = kThemeStatePressed;
5264 if (tb->state & State_On)
5265 bdi.value = kThemeButtonOn;
5267 QRect off_rct(0, 0, 0, 0);
5268 HIRect myRect, macRect;
5269 myRect = CGRectMake(tb->rect.x(), tb->rect.y(),
5270 tb->rect.width(), tb->rect.height());
5271 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
5272 off_rct.setRect(int(myRect.origin.x - macRect.origin.x),
5273 int(myRect.origin.y - macRect.origin.y),
5274 int(macRect.size.width - myRect.size.width),
5275 int(macRect.size.height - myRect.size.height));
5277 myRect = qt_hirectForQRect(button, off_rct);
5278 HIThemeDrawButton(&myRect, &bdi, cg, kHIThemeOrientationNormal, 0);
5282 if (tb->subControls & SC_ToolButtonMenu) {
5283 HIThemeButtonDrawInfo bdi;
5284 bdi.version = qt_mac_hitheme_version;
5286 bdi.value = kThemeButtonOff;
5287 bdi.adornment = kThemeAdornmentNone;
5289 if (tb->state & State_HasFocus)
5290 bdi.adornment = kThemeAdornmentFocus;
5291 if (tb->state & (State_On | State_Sunken)
5292 || (tb->activeSubControls & SC_ToolButtonMenu))
5293 bdi.state = kThemeStatePressed;
5294 HIRect hirect = qt_hirectForQRect(menuarea);
5295 HIThemeDrawButton(&hirect, &bdi, cg, kHIThemeOrientationNormal, 0);
5296 QRect r(menuarea.x() + ((menuarea.width() / 2) - 3), menuarea.height() - 8, 8, 8);
5297 HIThemePopupArrowDrawInfo padi;
5298 padi.version = qt_mac_hitheme_version;
5300 padi.orientation = kThemeArrowDown;
5301 padi.size = kThemeArrow7pt;
5302 hirect = qt_hirectForQRect(r);
5303 HIThemeDrawPopupArrow(&hirect, &padi, cg, kHIThemeOrientationNormal);
5304 } else if (tb->features & QStyleOptionToolButton::HasMenu) {
5305 drawToolbarButtonArrow(tb->rect, tds, cg);
5307 QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton, widget);
5308 int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
5309 QStyleOptionToolButton label = *tb;
5310 label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
5311 proxy()->drawControl(CE_ToolButtonLabel, &label, p, widget);
5316 if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
5317 QStyleHelper::drawDial(dial, p);
5320 QWindowsStyle::drawComplexControl(cc, opt, p, widget);
5325 QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc,
5326 const QStyleOptionComplex *opt,
5327 const QPoint &pt, const QWidget *widget) const
5329 SubControl sc = QStyle::SC_None;
5332 if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5333 sc = QWindowsStyle::hitTestComplexControl(cc, cmb, pt, widget);
5334 if (!cmb->editable && sc != QStyle::SC_None)
5335 sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
5339 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5340 HIThemeTrackDrawInfo tdi;
5341 d->getSliderInfo(cc, slider, &tdi, widget);
5342 ControlPartCode part;
5343 HIPoint pos = CGPointMake(pt.x(), pt.y());
5344 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5345 if (part == kControlPageUpPart || part == kControlPageDownPart)
5346 sc = SC_SliderGroove;
5348 sc = SC_SliderHandle;
5353 if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5354 HIScrollBarTrackInfo sbi;
5355 sbi.version = qt_mac_hitheme_version;
5356 if (!(sb->state & State_Active))
5357 sbi.enableState = kThemeTrackInactive;
5358 else if (sb->state & State_Enabled)
5359 sbi.enableState = kThemeTrackActive;
5361 sbi.enableState = kThemeTrackDisabled;
5363 // The arrow buttons are not drawn if the scroll bar is to short,
5364 // exclude them from the hit test.
5365 const int scrollBarLength = (sb->orientation == Qt::Horizontal)
5366 ? sb->rect.width() : sb->rect.height();
5367 if (scrollBarLength < scrollButtonsCutoffSize(scrollButtonsCutoff, widgetSizePolicy(widget)))
5368 sbi.enableState = kThemeTrackNothingToScroll;
5370 sbi.viewsize = sb->pageStep;
5371 HIPoint pos = CGPointMake(pt.x(), pt.y());
5373 HIRect macSBRect = qt_hirectForQRect(sb->rect);
5374 ControlPartCode part;
5375 bool reverseHorizontal = (sb->direction == Qt::RightToLeft
5376 && sb->orientation == Qt::Horizontal
5377 && (!sb->upsideDown ||
5378 (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4
5379 && sb->upsideDown)));
5380 if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal,
5382 if (part == kControlUpButtonPart)
5383 sc = reverseHorizontal ? SC_ScrollBarAddLine : SC_ScrollBarSubLine;
5384 else if (part == kControlDownButtonPart)
5385 sc = reverseHorizontal ? SC_ScrollBarSubLine : SC_ScrollBarAddLine;
5387 HIThemeTrackDrawInfo tdi;
5388 d->getSliderInfo(cc, sb, &tdi, widget);
5389 if(tdi.enableState == kThemeTrackInactive)
5390 tdi.enableState = kThemeTrackActive;
5391 if (HIThemeHitTestTrack(&tdi, &pos, &part)) {
5392 if (part == kControlPageUpPart)
5393 sc = reverseHorizontal ? SC_ScrollBarAddPage
5394 : SC_ScrollBarSubPage;
5395 else if (part == kControlPageDownPart)
5396 sc = reverseHorizontal ? SC_ScrollBarSubPage
5397 : SC_ScrollBarAddPage;
5399 sc = SC_ScrollBarSlider;
5405 I don't know why, but we only get kWindowContentRgn here, which isn't what we want at all.
5406 It would be very nice if this would work.
5407 case QStyle::CC_TitleBar:
5408 if (const QStyleOptionTitleBar *tbar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5409 HIThemeWindowDrawInfo wdi;
5410 memset(&wdi, 0, sizeof(wdi));
5411 wdi.version = qt_mac_hitheme_version;
5412 wdi.state = kThemeStateActive;
5413 wdi.windowType = QtWinType;
5414 wdi.titleWidth = tbar->rect.width();
5415 wdi.titleHeight = tbar->rect.height();
5416 if (tbar->titleBarState)
5417 wdi.attributes |= kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
5418 | kThemeWindowHasCollapseBox;
5419 else if (tbar->titleBarFlags & Qt::WindowSystemMenuHint)
5420 wdi.attributes |= kThemeWindowHasCloseBox;
5421 QRect tmpRect = tbar->rect;
5422 tmpRect.setHeight(tmpRect.height() + 100);
5423 HIRect hirect = qt_hirectForQRect(tmpRect);
5424 WindowRegionCode hit;
5425 HIPoint hipt = CGPointMake(pt.x(), pt.y());
5426 if (HIThemeGetWindowRegionHit(&hirect, &wdi, &hipt, &hit)) {
5428 case kWindowCloseBoxRgn:
5429 sc = QStyle::SC_TitleBarCloseButton;
5431 case kWindowCollapseBoxRgn:
5432 sc = QStyle::SC_TitleBarMinButton;
5434 case kWindowZoomBoxRgn:
5435 sc = QStyle::SC_TitleBarMaxButton;
5437 case kWindowTitleTextRgn:
5438 sc = QStyle::SC_TitleBarLabel;
5441 qDebug("got something else %d", hit);
5449 sc = QWindowsStyle::hitTestComplexControl(cc, opt, pt, widget);
5455 QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
5456 const QWidget *widget) const
5462 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
5463 HIThemeTrackDrawInfo tdi;
5464 d->getSliderInfo(cc, slider, &tdi, widget);
5466 QCFType<HIShapeRef> shape;
5467 bool scrollBar = cc == CC_ScrollBar;
5468 if ((scrollBar && sc == SC_ScrollBarSlider)
5469 || (!scrollBar && sc == SC_SliderHandle)) {
5470 HIThemeGetTrackThumbShape(&tdi, &shape);
5471 ptrHIShapeGetBounds(shape, &macRect);
5472 } else if (!scrollBar && sc == SC_SliderGroove) {
5473 HIThemeGetTrackBounds(&tdi, &macRect);
5474 } else if (sc == SC_ScrollBarGroove) { // Only scroll bar parts available...
5475 HIThemeGetTrackDragRect(&tdi, &macRect);
5477 ControlPartCode cpc;
5478 if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
5479 cpc = sc == SC_ScrollBarSubPage ? kControlPageDownPart
5480 : kControlPageUpPart;
5482 cpc = sc == SC_ScrollBarSubLine ? kControlUpButtonPart
5483 : kControlDownButtonPart;
5484 if (slider->direction == Qt::RightToLeft
5485 && slider->orientation == Qt::Horizontal) {
5486 if (cpc == kControlDownButtonPart)
5487 cpc = kControlUpButtonPart;
5488 else if (cpc == kControlUpButtonPart)
5489 cpc = kControlDownButtonPart;
5492 HIThemeGetTrackPartBounds(&tdi, cpc, &macRect);
5494 ret = qt_qrectForHIRect(macRect);
5496 // Tweak: the dark line between the sub/add line buttons belong to only one of the buttons
5497 // when doing hit-testing, but both of them have to repaint it. Extend the rect to cover
5498 // the line in the cases where HIThemeGetTrackPartBounds returns a rect that doesn't.
5499 if (slider->orientation == Qt::Horizontal) {
5500 if (slider->direction == Qt::LeftToRight && sc == SC_ScrollBarSubLine)
5501 ret.adjust(0, 0, 1, 0);
5502 else if (slider->direction == Qt::RightToLeft && sc == SC_ScrollBarAddLine)
5503 ret.adjust(-1, 0, 1, 0);
5504 } else if (sc == SC_ScrollBarAddLine) {
5505 ret.adjust(0, -1, 0, 1);
5510 if (const QStyleOptionTitleBar *titlebar
5511 = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
5512 HIThemeWindowDrawInfo wdi;
5513 memset(&wdi, 0, sizeof(wdi));
5514 wdi.version = qt_mac_hitheme_version;
5515 wdi.state = kThemeStateActive;
5516 wdi.windowType = QtWinType;
5517 wdi.titleHeight = titlebar->rect.height();
5518 wdi.titleWidth = titlebar->rect.width();
5519 wdi.attributes = kThemeWindowHasTitleText;
5520 if (titlebar->subControls & SC_TitleBarCloseButton)
5521 wdi.attributes |= kThemeWindowHasCloseBox;
5522 if (titlebar->subControls & SC_TitleBarMaxButton
5523 | SC_TitleBarNormalButton)
5524 wdi.attributes |= kThemeWindowHasFullZoom;
5525 if (titlebar->subControls & SC_TitleBarMinButton)
5526 wdi.attributes |= kThemeWindowHasCollapseBox;
5527 WindowRegionCode wrc = kWindowGlobalPortRgn;
5529 if (sc == SC_TitleBarCloseButton)
5530 wrc = kWindowCloseBoxRgn;
5531 else if (sc == SC_TitleBarMinButton)
5532 wrc = kWindowCollapseBoxRgn;
5533 else if (sc == SC_TitleBarMaxButton)
5534 wrc = kWindowZoomBoxRgn;
5535 else if (sc == SC_TitleBarLabel)
5536 wrc = kWindowTitleTextRgn;
5537 else if (sc == SC_TitleBarSysMenu)
5538 ret.setRect(-1024, -1024, 10, proxy()->pixelMetric(PM_TitleBarHeight,
5540 if (wrc != kWindowGlobalPortRgn) {
5541 QCFType<HIShapeRef> region;
5542 QRect tmpRect = titlebar->rect;
5543 HIRect titleRect = qt_hirectForQRect(tmpRect);
5544 HIThemeGetWindowShape(&titleRect, &wdi, kWindowTitleBarRgn, ®ion);
5545 ptrHIShapeGetBounds(region, &titleRect);
5547 tmpRect.translate(tmpRect.x() - int(titleRect.origin.x),
5548 tmpRect.y() - int(titleRect.origin.y));
5549 titleRect = qt_hirectForQRect(tmpRect);
5550 HIThemeGetWindowShape(&titleRect, &wdi, wrc, ®ion);
5551 ptrHIShapeGetBounds(region, &titleRect);
5552 ret = qt_qrectForHIRect(titleRect);
5557 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
5558 HIThemeButtonDrawInfo bdi;
5559 d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state));
5562 case SC_ComboBoxEditField:{
5563 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5564 // hack to posistion the edit feld correctly for QDateTimeEdits
5565 // in calendarPopup mode.
5566 if (qobject_cast<const QDateTimeEdit *>(widget)) {
5567 ret.moveTop(ret.top() - 2);
5568 ret.setHeight(ret.height() +1);
5571 case SC_ComboBoxArrow:{
5572 ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5573 ret.setX(ret.x() + ret.width());
5574 ret.setWidth(combo->rect.right() - ret.right());
5576 case SC_ComboBoxListBoxPopup:{
5577 if (combo->editable) {
5578 HIRect inner = QMacStylePrivate::comboboxInnerBounds(qt_hirectForQRect(combo->rect), bdi.kind);
5579 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5580 const int comboTop = combo->rect.top();
5581 ret = QRect(qRound(inner.origin.x),
5583 qRound(inner.origin.x - combo->rect.left() + inner.size.width),
5584 editRect.bottom() - comboTop + 2);
5586 QRect editRect = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
5587 ret = QRect(combo->rect.x() + 4 - 11,
5588 combo->rect.y() + 1,
5589 editRect.width() + 10 + 11,
5599 if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
5600 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5601 bool flat = (groupBox->features & QStyleOptionFrameV2::Flat);
5602 bool hasNoText = !checkable && groupBox->text.isEmpty();
5604 case SC_GroupBoxLabel:
5605 case SC_GroupBoxCheckBox: {
5606 // Cheat and use the smaller font if we need to
5607 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5608 bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
5609 || !QApplication::desktopSettingsAware();
5612 int margin = flat || hasNoText ? 0 : 12;
5613 ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
5616 HIThemeTextInfo tti;
5617 tti.version = qt_mac_hitheme_version;
5618 tti.state = kThemeStateActive;
5619 tti.fontID = checkable ? kThemeSystemFont : kThemeSmallSystemFont;
5620 tti.horizontalFlushness = kHIThemeTextHorizontalFlushCenter;
5621 tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
5622 tti.options = kHIThemeTextBoxOptionNone;
5623 tti.truncationPosition = kHIThemeTextTruncationNone;
5624 tti.truncationMaxLines = 1 + groupBox->text.count(QLatin1Char('\n'));
5627 QCFString groupText = qt_mac_removeMnemonics(groupBox->text);
5628 HIThemeGetTextDimensions(groupText, 0, &tti, &width, &height, 0);
5632 QFontMetricsF fm = QFontMetricsF(groupBox->fontMetrics);
5633 h = qCeil(fm.height());
5634 tw = qCeil(fm.size(Qt::TextShowMnemonic, groupBox->text).width());
5638 QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
5640 int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt, widget);
5641 bool rtl = groupBox->direction == Qt::RightToLeft;
5642 if (sc == SC_GroupBoxLabel) {
5644 int newSum = indicatorWidth + 1;
5645 int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
5646 labelRect.moveLeft(newLeft);
5648 int newLeft = labelRect.left() - (rtl ? 3 : -3);
5649 labelRect.moveLeft(newLeft);
5650 labelRect.moveTop(labelRect.top() + 3);
5652 int newLeft = labelRect.left() - (rtl ? 3 : 2);
5653 labelRect.moveLeft(newLeft);
5654 labelRect.moveTop(labelRect.top() + 5);
5659 if (sc == SC_GroupBoxCheckBox) {
5660 int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left();
5661 ret.setRect(left, ret.top(),
5662 indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt, widget));
5666 case SC_GroupBoxContents:
5667 case SC_GroupBoxFrame: {
5669 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5672 QFontMetrics fm = groupBox->fontMetrics;
5673 bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
5676 if (widget && !widget->testAttribute(Qt::WA_SetFont)
5677 && QApplication::desktopSettingsAware())
5678 fm = QFontMetrics(qt_app_fonts_hash()->value("QSmallFont", QFont()));
5681 yOffset = -qCeil(QFontMetricsF(fm).height());
5684 ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
5685 if (sc == SC_GroupBoxContents)
5686 ret.adjust(3, 3, -3, -4); // guess
5690 ret = QWindowsStyle::subControlRect(cc, groupBox, sc, widget);
5696 if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
5697 QAquaWidgetSize aquaSize = d->aquaSizeConstrain(spin, widget);
5700 int fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin, widget);
5703 case QAquaSizeUnknown:
5704 case QAquaSizeLarge:
5708 case QAquaSizeSmall:
5720 case SC_SpinBoxDown: {
5721 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons)
5725 const int x = spin->rect.width() - spinner_w;
5726 ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spin->rect.height() - y * 2);
5727 HIThemeButtonDrawInfo bdi;
5728 bdi.version = qt_mac_hitheme_version;
5729 bdi.kind = kThemeIncDecButton;
5733 case QAquaSizeUnknown:
5734 case QAquaSizeLarge:
5735 bdi.kind = kThemeIncDecButton;
5738 case QAquaSizeSmall:
5739 bdi.kind = kThemeIncDecButtonSmall;
5740 hackTranslateX = -2;
5743 bdi.kind = kThemeIncDecButtonMini;
5744 hackTranslateX = -1;
5747 bdi.state = kThemeStateActive;
5748 bdi.value = kThemeButtonOff;
5749 bdi.adornment = kThemeAdornmentNone;
5750 HIRect hirect = qt_hirectForQRect(ret);
5753 HIThemeGetButtonBackgroundBounds(&hirect, &bdi, &outRect);
5754 ret = qt_qrectForHIRect(outRect);
5757 ret.setHeight(ret.height() / 2);
5759 case SC_SpinBoxDown:
5760 ret.setY(ret.y() + ret.height() / 2);
5766 ret.translate(hackTranslateX, 0); // hack: position the buttons correctly (weird that we need this)
5767 ret = visualRect(spin->direction, spin->rect, ret);
5770 case SC_SpinBoxEditField:
5771 if (spin->buttonSymbols == QAbstractSpinBox::NoButtons) {
5773 spin->rect.width() - fw * 2,
5774 spin->rect.height() - fw * 2);
5777 spin->rect.width() - fw * 2 - spinBoxSep - spinner_w,
5778 spin->rect.height() - fw * 2);
5780 ret = visualRect(spin->direction, spin->rect, ret);
5783 ret = QWindowsStyle::subControlRect(cc, spin, sc, widget);
5789 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5790 if (sc == SC_ToolButtonMenu && widget && !qobject_cast<QToolBar*>(widget->parentWidget())) {
5791 ret.adjust(-1, 0, 0, 0);
5795 ret = QWindowsStyle::subControlRect(cc, opt, sc, widget);
5801 QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
5802 const QSize &csz, const QWidget *widget) const
5805 bool useAquaGuideline = true;
5808 case QStyle::CT_SpinBox:
5809 // hack to work around horrible sizeHint() code in QAbstractSpinBox
5810 sz.setHeight(sz.height() - 3);
5812 case QStyle::CT_TabWidget:
5813 // the size between the pane and the "contentsRect" (+4,+4)
5814 // (the "contentsRect" is on the inside of the pane)
5815 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
5817 This is supposed to show the relationship between the tabBar and
5818 the stack widget of a QTabWidget.
5819 Unfortunately ascii is not a good way of representing graphics.....
5820 PS: The '=' line is the painted frame.
5826 | vvv just outside the painted frame is the "pane"
5827 - -|- - - - - - - - - - <-+
5828 TAB BAR +=====^============ | +2 pixels
5829 - - -|- - -|- - - - - - - <-+
5830 | | ^ ^^^ just inside the painted frame is the "contentsRect"
5834 bottom ------+ <-+ +14 pixels
5837 ------------------------------ <- top of stack widget
5841 * 2 is the distance between the pane and the contentsRect
5842 * The 14 and the 1's are the distance from the contentsRect to the stack widget.
5843 (same value as used in SE_TabWidgetTabContents)
5844 * overlap is how much the pane should overlap the tab bar
5846 // then add the size between the stackwidget and the "contentsRect"
5848 if (const QStyleOptionTabWidgetFrame *twf
5849 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
5851 const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt, widget);
5852 const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
5854 if (getTabDirection(twf->shape) == kThemeTabNorth || getTabDirection(twf->shape) == kThemeTabSouth) {
5855 extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
5857 extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
5863 case QStyle::CT_TabBarTab:
5864 if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(opt)) {
5865 const QAquaWidgetSize AquaSize = d->aquaSizeConstrain(opt, widget);
5866 const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
5867 || !QApplication::desktopSettingsAware();
5868 ThemeTabDirection ttd = getTabDirection(tab->shape);
5869 bool vertTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
5872 int defaultTabHeight;
5873 int defaultExtraSpace = proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget); // Remove spurious gcc warning (AFAIK)
5874 QFontMetrics fm = opt->fontMetrics;
5876 case QAquaSizeUnknown:
5877 case QAquaSizeLarge:
5878 if (tab->documentMode)
5879 defaultTabHeight = 23;
5881 defaultTabHeight = 21;
5883 case QAquaSizeSmall:
5884 defaultTabHeight = 18;
5887 defaultTabHeight = 16;
5890 bool setWidth = false;
5891 if (differentFont || !tab->icon.isNull()) {
5892 sz.rheight() = qMax(defaultTabHeight, sz.height());
5894 QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text);
5895 sz.rheight() = qMax(defaultTabHeight, textSize.height());
5896 sz.rwidth() = textSize.width() + defaultExtraSpace;
5903 int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
5904 int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
5906 int widgetWidth = 0;
5907 int widgetHeight = 0;
5909 if (tab->leftButtonSize.isValid()) {
5911 widgetWidth += tab->leftButtonSize.width();
5912 widgetHeight += tab->leftButtonSize.height();
5914 if (tab->rightButtonSize.isValid()) {
5916 widgetWidth += tab->rightButtonSize.width();
5917 widgetHeight += tab->rightButtonSize.height();
5921 sz.setHeight(sz.height() + widgetHeight + padding);
5922 sz.setWidth(qMax(sz.width(), maxWidgetWidth));
5925 sz.setWidth(sz.width() + widgetWidth + padding);
5926 sz.setHeight(qMax(sz.height(), maxWidgetHeight));
5930 case QStyle::CT_PushButton:
5931 // By default, we fit the contents inside a normal rounded push button.
5932 // Do this by add enough space around the contents so that rounded
5933 // borders (including highlighting when active) will show.
5934 sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
5935 sz.rheight() += QMacStylePrivate::PushButtonTopOffset + QMacStylePrivate::PushButtonBottomOffset;
5937 case QStyle::CT_MenuItem:
5938 if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
5939 int maxpmw = mi->maxIconWidth;
5940 const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
5943 if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
5946 GetThemeMenuSeparatorHeight(&ash);
5949 h = mi->fontMetrics.height() + 2;
5950 if (!mi->icon.isNull()) {
5952 const QSize &iconSize = comboBox->iconSize();
5953 h = qMax(h, iconSize.height() + 4);
5954 maxpmw = qMax(maxpmw, iconSize.width());
5956 int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
5957 h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
5961 if (mi->text.contains(QLatin1Char('\t')))
5963 if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
5967 // add space for a check. All items have place for a check too.
5969 if (comboBox && comboBox->isVisible()) {
5970 QStyleOptionComboBox cmb;
5971 cmb.initFrom(comboBox);
5972 cmb.editable = false;
5973 cmb.subControls = QStyle::SC_ComboBoxEditField;
5974 cmb.activeSubControls = QStyle::SC_None;
5975 w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
5976 QStyle::SC_ComboBoxEditField,
5985 if (widget && qobject_cast<const QToolBar *>(widget->parentWidget())) {
5986 if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->parent())) {
5987 if (mainWindow->unifiedTitleAndToolBarOnMac()) {
5989 if (sz.height() <= 32) {
5990 // Workaround strange HIToolBar bug when getting constraints.
6004 QStyleHintReturnMask menuMask;
6005 QStyleOption myOption = *opt;
6006 myOption.rect.setSize(sz);
6007 if (proxy()->styleHint(SH_Menu_Mask, &myOption, widget, &menuMask)) {
6008 sz = menuMask.region.boundingRect().size();
6011 case CT_HeaderSection:{
6012 const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
6013 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6014 if (header->text.contains(QLatin1Char('\n')))
6015 useAquaGuideline = false;
6018 // Make sure that the scroll bar is large enough to display the thumb indicator.
6019 if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
6020 const int minimumSize = scrollButtonsCutoffSize(thumbIndicatorCutoff, widgetSizePolicy(widget));
6021 if (slider->orientation == Qt::Horizontal)
6022 sz = sz.expandedTo(QSize(minimumSize, sz.height()));
6024 sz = sz.expandedTo(QSize(sz.width(), minimumSize));
6027 case CT_ItemViewItem:
6028 if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) {
6029 sz = QCommonStyle::sizeFromContents(ct, vopt, csz, widget);
6030 sz.setHeight(sz.height() + 2);
6035 sz = QWindowsStyle::sizeFromContents(ct, opt, csz, widget);
6038 if (useAquaGuideline){
6040 if (d->aquaSizeConstrain(opt, widget, ct, sz, &macsz) != QAquaSizeUnknown) {
6041 if (macsz.width() != -1)
6042 sz.setWidth(macsz.width());
6043 if (macsz.height() != -1)
6044 sz.setHeight(macsz.height());
6048 // The sizes that Carbon and the guidelines gives us excludes the focus frame.
6049 // We compensate for this by adding some extra space here to make room for the frame when drawing:
6050 if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
6051 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6053 switch (widgetSize) {
6055 case QAquaSizeLarge:
6056 bkind = combo->editable ? kThemeComboBox : kThemePopupButton;
6058 case QAquaSizeSmall:
6059 bkind = combo->editable ? int(kThemeComboBoxSmall) : int(kThemePopupButtonSmall);
6062 bkind = combo->editable ? kThemeComboBoxMini : kThemePopupButtonMini;
6065 HIRect tmpRect = {{0, 0}, {0, 0}};
6066 HIRect diffRect = QMacStylePrivate::comboboxInnerBounds(tmpRect, bkind);
6067 sz.rwidth() -= qRound(diffRect.size.width);
6068 sz.rheight() -= qRound(diffRect.size.height);
6069 } else if (ct == CT_PushButton || ct == CT_ToolButton){
6070 ThemeButtonKind bkind;
6071 QAquaWidgetSize widgetSize = d->aquaSizeConstrain(opt, widget);
6075 if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
6076 if (btn->features & QStyleOptionButton::CommandLinkButton) {
6077 return QWindowsStyle::sizeFromContents(ct, opt, sz, widget);
6081 switch (widgetSize) {
6083 case QAquaSizeLarge:
6084 bkind = kThemePushButton;
6086 case QAquaSizeSmall:
6087 bkind = kThemePushButtonSmall;
6090 bkind = kThemePushButtonMini;
6095 switch (widgetSize) {
6097 case QAquaSizeLarge:
6098 bkind = kThemeLargeBevelButton;
6101 case QAquaSizeSmall:
6102 bkind = kThemeSmallBevelButton;
6107 HIThemeButtonDrawInfo bdi;
6108 bdi.version = qt_mac_hitheme_version;
6109 bdi.state = kThemeStateActive;
6111 bdi.value = kThemeButtonOff;
6112 bdi.adornment = kThemeAdornmentNone;
6113 HIRect macRect, myRect;
6114 myRect = CGRectMake(0, 0, sz.width(), sz.height());
6115 HIThemeGetButtonBackgroundBounds(&myRect, &bdi, &macRect);
6116 // Mini buttons only return their actual size in HIThemeGetButtonBackgroundBounds, so help them out a bit (guess),
6117 if (bkind == kThemePushButtonMini)
6118 macRect.size.height += 8.;
6119 else if (bkind == kThemePushButtonSmall)
6120 macRect.size.height -= 10;
6121 sz.setWidth(sz.width() + int(macRect.size.width - myRect.size.width));
6122 sz.setHeight(sz.height() + int(macRect.size.height - myRect.size.height));
6127 void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
6128 bool enabled, const QString &text, QPalette::ColorRole textRole) const
6130 if(flags & Qt::TextShowMnemonic)
6131 flags |= Qt::TextHideMnemonic;
6132 QWindowsStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
6135 bool QMacStyle::event(QEvent *e)
6137 if(e->type() == QEvent::FocusIn) {
6139 QWidget *focusWidget = QApplication::focusWidget();
6140 #ifndef QT_NO_GRAPHICSVIEW
6141 if (QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(focusWidget)) {
6142 QGraphicsItem *focusItem = graphicsView->scene() ? graphicsView->scene()->focusItem() : 0;
6143 if (focusItem && focusItem->type() == QGraphicsProxyWidget::Type) {
6144 QGraphicsProxyWidget *proxy = static_cast<QGraphicsProxyWidget *>(focusItem);
6145 if (proxy->widget())
6146 focusWidget = proxy->widget()->focusWidget();
6150 if (focusWidget && focusWidget->testAttribute(Qt::WA_MacShowFocusRect)) {
6152 QWidget *top = f->parentWidget();
6153 while (top && !top->isWindow() && !(top->windowType() == Qt::SubWindow))
6154 top = top->parentWidget();
6155 #ifndef QT_NO_MAINWINDOW
6156 if (qobject_cast<QMainWindow *>(top)) {
6157 QWidget *central = static_cast<QMainWindow *>(top)->centralWidget();
6158 for (const QWidget *par = f; par; par = par->parentWidget()) {
6159 if (par == central) {
6163 if (par->isWindow())
6171 d->focusWidget = new QFocusFrame(f);
6172 d->focusWidget->setWidget(f);
6173 } else if(d->focusWidget) {
6174 d->focusWidget->setWidget(0);
6176 } else if(e->type() == QEvent::FocusOut) {
6178 d->focusWidget->setWidget(0);
6183 QIcon QMacStyle::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *opt,
6184 const QWidget *widget) const
6186 switch (standardIcon) {
6188 return QWindowsStyle::standardIconImplementation(standardIcon, opt, widget);
6189 case SP_ToolBarHorizontalExtensionButton:
6190 case SP_ToolBarVerticalExtensionButton: {
6191 QPixmap pixmap(qt_mac_toolbar_ext);
6192 if (standardIcon == SP_ToolBarVerticalExtensionButton) {
6193 QPixmap pix2(pixmap.height(), pixmap.width());
6194 pix2.fill(Qt::transparent);
6196 p.translate(pix2.width(), 0);
6198 p.drawPixmap(0, 0, pixmap);
6206 int QMacStyle::layoutSpacingImplementation(QSizePolicy::ControlType control1,
6207 QSizePolicy::ControlType control2,
6208 Qt::Orientation orientation,
6209 const QStyleOption *option,
6210 const QWidget *widget) const
6212 const int ButtonMask = QSizePolicy::ButtonBox | QSizePolicy::PushButton;
6213 bool isMetal = (widget && widget->testAttribute(Qt::WA_MacBrushedMetal));
6214 int controlSize = getControlSize(option, widget);
6216 if (control2 == QSizePolicy::ButtonBox) {
6218 AHIG seems to prefer a 12-pixel margin between group
6219 boxes and the row of buttons. The 20 pixel comes from
6222 if (isMetal // (AHIG, guess, guess)
6223 || (control1 & (QSizePolicy::Frame // guess
6224 | QSizePolicy::GroupBox // (AHIG, guess, guess)
6225 | QSizePolicy::TabWidget // guess
6226 | ButtonMask))) { // AHIG
6227 return_SIZE(14, 8, 8);
6228 } else if (control1 == QSizePolicy::LineEdit) {
6229 return_SIZE(8, 8, 8); // Interface Builder
6231 return_SIZE(20, 7, 7); // Interface Builder
6235 if ((control1 | control2) & ButtonMask) {
6236 if (control1 == QSizePolicy::LineEdit)
6237 return_SIZE(8, 8, 8); // Interface Builder
6238 else if (control2 == QSizePolicy::LineEdit) {
6239 if (orientation == Qt::Vertical)
6240 return_SIZE(20, 7, 7); // Interface Builder
6242 return_SIZE(20, 8, 8);
6244 return_SIZE(14, 8, 8); // Interface Builder
6247 switch (CT2(control1, control2)) {
6248 case CT1(QSizePolicy::Label): // guess
6249 case CT2(QSizePolicy::Label, QSizePolicy::DefaultType): // guess
6250 case CT2(QSizePolicy::Label, QSizePolicy::CheckBox): // AHIG
6251 case CT2(QSizePolicy::Label, QSizePolicy::ComboBox): // AHIG
6252 case CT2(QSizePolicy::Label, QSizePolicy::LineEdit): // guess
6253 case CT2(QSizePolicy::Label, QSizePolicy::RadioButton): // AHIG
6254 case CT2(QSizePolicy::Label, QSizePolicy::Slider): // guess
6255 case CT2(QSizePolicy::Label, QSizePolicy::SpinBox): // guess
6256 case CT2(QSizePolicy::Label, QSizePolicy::ToolButton): // guess
6257 return_SIZE(8, 6, 5);
6258 case CT1(QSizePolicy::ToolButton):
6260 case CT1(QSizePolicy::CheckBox):
6261 case CT2(QSizePolicy::CheckBox, QSizePolicy::RadioButton):
6262 case CT2(QSizePolicy::RadioButton, QSizePolicy::CheckBox):
6263 if (orientation == Qt::Vertical)
6264 return_SIZE(8, 8, 7); // AHIG and Builder
6266 case CT1(QSizePolicy::RadioButton):
6267 if (orientation == Qt::Vertical)
6268 return 5; // (Builder, guess, AHIG)
6271 if (orientation == Qt::Horizontal
6272 && (control2 & (QSizePolicy::CheckBox | QSizePolicy::RadioButton)))
6273 return_SIZE(12, 10, 8); // guess
6275 if ((control1 | control2) & (QSizePolicy::Frame
6276 | QSizePolicy::GroupBox
6277 | QSizePolicy::TabWidget)) {
6279 These values were chosen so that nested container widgets
6280 look good side by side. Builder uses 8, which looks way
6281 too small, and AHIG doesn't say anything.
6283 return_SIZE(16, 10, 10); // guess
6286 if ((control1 | control2) & (QSizePolicy::Line | QSizePolicy::Slider))
6287 return_SIZE(12, 10, 8); // AHIG
6289 if ((control1 | control2) & QSizePolicy::LineEdit)
6290 return_SIZE(10, 8, 8); // AHIG
6293 AHIG and Builder differ by up to 4 pixels for stacked editable
6294 comboboxes. We use some values that work fairly well in all
6297 if ((control1 | control2) & QSizePolicy::ComboBox)
6298 return_SIZE(10, 8, 7); // guess
6301 Builder defaults to 8, 6, 5 in lots of cases, but most of the time the
6302 result looks too cramped.
6304 return_SIZE(10, 8, 6); // guess
6307 void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
6309 CGAffineTransform old_xform = CGAffineTransformIdentity;
6310 if (orig_xform) { //setup xforms
6311 old_xform = CGContextGetCTM(hd);
6312 CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
6313 CGContextConcatCTM(hd, *orig_xform);
6317 CGContextBeginPath(hd);
6318 if (rgn.isEmpty()) {
6319 CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
6321 QCFType<HIMutableShapeRef> shape = qt_mac_toHIMutableShape(rgn);
6322 Q_ASSERT(!HIShapeIsEmpty(shape));
6323 HIShapeReplacePathInCGContext(shape, hd);
6327 if (orig_xform) {//reset xforms
6328 CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
6329 CGContextConcatCTM(hd, old_xform);
6333 QMacCGContext::QMacCGContext(QPainter *p)
6335 QPaintEngine *pe = p->paintEngine();
6339 int devType = p->device()->devType();
6340 if (pe->type() == QPaintEngine::Raster
6341 && (devType == QInternal::Widget ||
6342 devType == QInternal::Pixmap ||
6343 devType == QInternal::Image)) {
6345 extern CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice);
6346 CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pe->paintDevice());
6347 uint flags = kCGImageAlphaPremultipliedFirst;
6348 flags |= kCGBitmapByteOrder32Host;
6350 const QImage *image = (const QImage *) pe->paintDevice();
6352 context = CGBitmapContextCreate((void *) image->bits(), image->width(), image->height(),
6353 8, image->bytesPerLine(), colorspace, flags);
6355 CGContextTranslateCTM(context, 0, image->height());
6356 CGContextScaleCTM(context, 1, -1);
6358 if (devType == QInternal::Widget) {
6359 QRegion clip = p->paintEngine()->systemClip();
6360 QTransform native = p->deviceTransform();
6361 QTransform logical = p->combinedTransform();
6363 if (p->hasClipping()) {
6364 QRegion r = p->clipRegion();
6365 r.translate(native.dx(), native.dy());
6371 qt_mac_clip_cg(context, clip, 0);
6373 CGContextTranslateCTM(context, native.dx(), native.dy());
6376 qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType;
6380 CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice)
6382 bool isWidget = (paintDevice->devType() == QInternal::Widget);
6383 return qt_mac_displayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice) : 0);
6388 Returns the CoreGraphics CGContextRef of the paint device. 0 is
6389 returned if it can't be obtained. It is the caller's responsibility to
6390 CGContextRelease the context when finished using it.
6392 \warning This function is only available on Mac OS X.
6395 CGContextRef qt_mac_cg_context(const QPaintDevice *pdev)
6397 if (pdev->devType() == QInternal::Pixmap) {
6398 const QPixmap *pm = static_cast<const QPixmap*>(pdev);
6399 CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev);
6400 uint flags = kCGImageAlphaPremultipliedFirst;
6401 flags |= kCGBitmapByteOrder32Host;
6402 CGContextRef ret = 0;
6404 QPlatformPixmap *data = const_cast<QPixmap *>(pm)->data_ptr().data();
6405 if (data->classId() == QPlatformPixmap::RasterClass) {
6406 QImage *image = data->buffer();
6407 ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(),
6408 8, image->bytesPerLine(), colorspace, flags);
6410 qDebug() << "qt_mac_cg_context: Unsupported pixmap class";
6413 CGContextTranslateCTM(ret, 0, pm->height());
6414 CGContextScaleCTM(ret, 1, -1);
6416 } else if (pdev->devType() == QInternal::Widget) {
6417 //CGContextRef ret = static_cast<CGContextRef>(static_cast<const QWidget *>(pdev)->macCGHandle());
6418 ///CGContextRetain(ret);
6420 qDebug() << "qt_mac_cg_context: not implemented: Widget class";
6427 FontHash::FontHash()
6429 QHash<QByteArray, QFont>::operator=(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFonts());
6432 Q_GLOBAL_STATIC(FontHash, app_fonts)
6433 FontHash *qt_app_fonts_hash()