source: trunk/src/gui/styles/qmacstyle_mac.mm@ 878

Last change on this file since 878 was 846, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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