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