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

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

trunk: Merged in qt 4.6.1 sources.

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