File indexing completed on 2024-05-19 09:28:03
0001 // krazy:excludeall=qclasses 0002 0003 ////////////////////////////////////////////////////////////////////////////// 0004 // oxygenstyle.cpp 0005 // Oxygen widget style for KDE 4 0006 // ------------------- 0007 // 0008 // Copyright ( C ) 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0009 // Copyright ( C ) 2008 Long Huynh Huu <long.upcase@googlemail.com> 0010 // Copyright ( C ) 2007-2008 Casper Boemann <cbr@boemann.dk> 0011 // Copyright ( C ) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net> 0012 // Copyright ( C ) 2003-2005 Sandro Giessl <sandro@giessl.com> 0013 // 0014 // based on the KDE style "dotNET": 0015 // Copyright ( C ) 2001-2002, Chris Lee <clee@kde.org> 0016 // Carsten Pfeiffer <pfeiffer@kde.org> 0017 // Karol Szwed <gallium@kde.org> 0018 // Drawing routines completely reimplemented from KDE3 +HighColor, which was 0019 // originally based on some stuff from the KDE2 HighColor. 0020 // 0021 // based on drawing routines of the style "Keramik": 0022 // Copyright ( c ) 2002 Malte Starostik <malte@kde.org> 0023 // ( c ) 2002,2003 Maksim Orlovich <mo002j@mail.rochester.edu> 0024 // based on the KDE3 HighColor Style 0025 // Copyright ( C ) 2001-2002 Karol Szwed <gallium@kde.org> 0026 // ( C ) 2001-2002 Fredrik H?glund <fredrik@kde.org> 0027 // Drawing routines adapted from the KDE2 HCStyle, 0028 // Copyright ( C ) 2000 Daniel M. Duley <mosfet@kde.org> 0029 // ( C ) 2000 Dirk Mueller <mueller@kde.org> 0030 // ( C ) 2001 Martijn Klingens <klingens@kde.org> 0031 // Progressbar code based on KStyle, 0032 // Copyright ( C ) 2001-2002 Karol Szwed <gallium@kde.org> 0033 // 0034 // SPDX-License-Identifier: LGPL-2.0-only 0035 ////////////////////////////////////////////////////////////////////////////// 0036 0037 #include "oxygenstyle.h" 0038 0039 #include "oxygenanimations.h" 0040 #include "oxygenblurhelper.h" 0041 #include "oxygenframeshadow.h" 0042 #include "oxygenmdiwindowshadow.h" 0043 #include "oxygenmnemonics.h" 0044 #include "oxygenpropertynames.h" 0045 #include "oxygenshadowhelper.h" 0046 #include "oxygensplitterproxy.h" 0047 #include "oxygenstyleconfigdata.h" 0048 #include "oxygentransitions.h" 0049 #include "oxygenwidgetexplorer.h" 0050 #include "oxygenwindowmanager.h" 0051 0052 #include <QAbstractButton> 0053 #include <QAbstractItemView> 0054 #include <QApplication> 0055 #include <QCheckBox> 0056 #include <QComboBox> 0057 #include <QDBusConnection> 0058 #include <QDial> 0059 #include <QDialogButtonBox> 0060 #include <QDoubleSpinBox> 0061 #include <QFormLayout> 0062 #include <QFrame> 0063 #include <QGraphicsView> 0064 #include <QGroupBox> 0065 #include <QItemDelegate> 0066 #include <QLayout> 0067 #include <QLineEdit> 0068 #include <QMainWindow> 0069 #include <QPushButton> 0070 #include <QRadioButton> 0071 #include <QScrollBar> 0072 #include <QSpinBox> 0073 #include <QSplitterHandle> 0074 #include <QTextEdit> 0075 #include <QToolButton> 0076 0077 #include <KColorUtils> 0078 0079 #include <cmath> 0080 0081 static const int s_iconSizes[] = {8, 16, 22, 32, 48}; 0082 0083 namespace OxygenPrivate 0084 { 0085 0086 /*! 0087 tabBar data class needed for 0088 the rendering of tabbars when 0089 one tab is being drawn 0090 */ 0091 class TabBarData : public QObject 0092 { 0093 public: 0094 //* constructor 0095 explicit TabBarData(Oxygen::Style *parent) 0096 : QObject(parent) 0097 , _style(parent) 0098 { 0099 } 0100 0101 //* assign target tabBar 0102 void lock(const QWidget *widget) 0103 { 0104 _tabBar = widget; 0105 } 0106 0107 //* true if tabbar is locked 0108 bool locks(const QWidget *widget) const 0109 { 0110 return _tabBar && _tabBar.data() == widget; 0111 } 0112 0113 //* set dirty 0114 void setDirty(const bool &value = true) 0115 { 0116 _dirty = value; 0117 } 0118 0119 //* release 0120 void release(void) 0121 { 0122 _tabBar.clear(); 0123 } 0124 0125 //* draw tabBarBase 0126 virtual void drawTabBarBaseControl(const QStyleOptionTab *, QPainter *, const QWidget *); 0127 0128 private: 0129 //* pointer to parent style object 0130 Oxygen::WeakPointer<const Oxygen::Style> _style; 0131 0132 //* pointer to target tabBar 0133 Oxygen::WeakPointer<const QWidget> _tabBar; 0134 0135 //* if true, will paint on next TabBarTabShapeControl call 0136 bool _dirty = false; 0137 }; 0138 0139 //* needed to have spacing added to items in combobox 0140 class ComboBoxItemDelegate : public QItemDelegate 0141 { 0142 public: 0143 //* constructor 0144 ComboBoxItemDelegate(QAbstractItemView *parent) 0145 : QItemDelegate(parent) 0146 , _proxy(parent->itemDelegate()) 0147 , _itemMargin(Oxygen::Metrics::ItemView_ItemMarginWidth) 0148 { 0149 } 0150 0151 //* paint 0152 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override 0153 { 0154 // call either proxy or parent class 0155 if (_proxy) 0156 _proxy.data()->paint(painter, option, index); 0157 else 0158 QItemDelegate::paint(painter, option, index); 0159 } 0160 0161 //* size hint for index 0162 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override 0163 { 0164 // get size from either proxy or parent class 0165 QSize size(_proxy ? _proxy.data()->sizeHint(option, index) : QItemDelegate::sizeHint(option, index)); 0166 0167 // adjust and return 0168 if (size.isValid()) { 0169 size.rheight() += _itemMargin * 2; 0170 } 0171 return size; 0172 } 0173 0174 private: 0175 //* proxy 0176 Oxygen::WeakPointer<QAbstractItemDelegate> _proxy; 0177 0178 //* margin 0179 int _itemMargin; 0180 }; 0181 } 0182 0183 namespace Oxygen 0184 { 0185 0186 //* toplevel manager 0187 class TopLevelManager : public QObject 0188 { 0189 public: 0190 //* constructor 0191 TopLevelManager(QObject *parent, const StyleHelper &helper) 0192 : QObject(parent) 0193 , _helper(helper) 0194 { 0195 } 0196 0197 //* event filter 0198 bool eventFilter(QObject *object, QEvent *event) override 0199 { 0200 // cast to QWidget 0201 QWidget *widget = static_cast<QWidget *>(object); 0202 if (event->type() == QEvent::Show && _helper.hasDecoration(widget)) { 0203 _helper.setHasBackgroundGradient(widget->winId(), true); 0204 } 0205 0206 return false; 0207 } 0208 0209 private: 0210 //* helper 0211 const StyleHelper &_helper; 0212 }; 0213 0214 //______________________________________________________________ 0215 Style::Style(void) 0216 : _helper(new StyleHelper(StyleConfigData::self()->sharedConfig())) 0217 , _shadowHelper(new ShadowHelper(this, *_helper)) 0218 , _animations(new Animations(this)) 0219 , _transitions(new Transitions(this)) 0220 , _windowManager(new WindowManager(this)) 0221 , _topLevelManager(new TopLevelManager(this, *_helper)) 0222 , _frameShadowFactory(new FrameShadowFactory(this)) 0223 , _mdiWindowShadowFactory(new MdiWindowShadowFactory(this, *_helper)) 0224 , _mnemonics(new Mnemonics(this)) 0225 , _blurHelper(new BlurHelper(this, *_helper)) 0226 , _widgetExplorer(new WidgetExplorer(this)) 0227 , _tabBarData(new OxygenPrivate::TabBarData(this)) 0228 , _splitterFactory(new SplitterFactory(this)) 0229 , SH_ArgbDndWindow(newStyleHint(QStringLiteral("SH_ArgbDndWindow"))) 0230 , CE_CapacityBar(newControlElement(QStringLiteral("CE_CapacityBar"))) 0231 { 0232 // use DBus connection to update on oxygen configuration change 0233 QDBusConnection dbus = QDBusConnection::sessionBus(); 0234 dbus.connect(QString(), 0235 QStringLiteral("/OxygenStyle"), 0236 QStringLiteral("org.kde.Oxygen.Style"), 0237 QStringLiteral("reparseConfiguration"), 0238 this, 0239 SLOT(configurationChanged())); 0240 0241 // call the slot directly; this initial call will set up things that also 0242 // need to be reset when the system palette changes 0243 loadConfiguration(); 0244 } 0245 0246 //______________________________________________________________ 0247 Style::~Style(void) 0248 { 0249 // _shadowHelper is a child of us, but its destructor uses _helper so we 0250 // delete it manually to ensure it is deleted *before* _helper is 0251 // deleted 0252 delete _shadowHelper; 0253 delete _helper; 0254 } 0255 0256 //______________________________________________________________ 0257 void Style::polish(QWidget *widget) 0258 { 0259 if (!widget) 0260 return; 0261 0262 // register widget to animations 0263 _animations->registerWidget(widget); 0264 _transitions->registerWidget(widget); 0265 _windowManager->registerWidget(widget); 0266 _frameShadowFactory->registerWidget(widget, *_helper); 0267 _mdiWindowShadowFactory->registerWidget(widget); 0268 _shadowHelper->registerWidget(widget); 0269 _splitterFactory->registerWidget(widget); 0270 0271 // scroll areas 0272 if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget)) { 0273 polishScrollArea(scrollArea); 0274 } 0275 0276 // several widgets set autofill background to false, which effectively breaks the background 0277 // gradient rendering. Instead of patching all concerned applications, 0278 // we change the background here 0279 if (widget->inherits("MessageList::Core::Widget")) { 0280 widget->setAutoFillBackground(false); 0281 } 0282 0283 // adjust layout for K3B themed headers 0284 // FIXME: to be removed when fixed upstream 0285 if (widget->inherits("K3b::ThemedHeader") && widget->layout()) { 0286 widget->layout()->setContentsMargins(0, 0, 0, 0); 0287 _frameShadowFactory->setHasContrast(widget, true); 0288 } 0289 0290 // adjust flags for windows and dialogs 0291 switch (widget->windowFlags() & Qt::WindowType_Mask) { 0292 case Qt::Window: 0293 case Qt::Dialog: 0294 0295 // set background as styled 0296 widget->setAttribute(Qt::WA_StyledBackground); 0297 widget->installEventFilter(_topLevelManager); 0298 0299 break; 0300 0301 default: 0302 break; 0303 } 0304 0305 // enforce translucency for drag and drop window 0306 if (widget->testAttribute(Qt::WA_X11NetWmWindowTypeDND) && _helper->compositingActive()) { 0307 widget->setAttribute(Qt::WA_TranslucentBackground); 0308 widget->clearMask(); 0309 } 0310 0311 if (qobject_cast<QAbstractItemView *>(widget) || qobject_cast<QAbstractSpinBox *>(widget) || qobject_cast<QCheckBox *>(widget) 0312 || qobject_cast<QComboBox *>(widget) || qobject_cast<QDial *>(widget) || qobject_cast<QLineEdit *>(widget) || qobject_cast<QPushButton *>(widget) 0313 || qobject_cast<QRadioButton *>(widget) || qobject_cast<QScrollBar *>(widget) || qobject_cast<QSlider *>(widget) 0314 || qobject_cast<QSplitterHandle *>(widget) || qobject_cast<QTabBar *>(widget) || qobject_cast<QTextEdit *>(widget) 0315 || qobject_cast<QToolButton *>(widget) || widget->inherits("KTextEditor::View")) { 0316 widget->setAttribute(Qt::WA_Hover); 0317 } 0318 0319 // transparent tooltips 0320 if (widget->inherits("QTipLabel")) { 0321 widget->setAttribute(Qt::WA_TranslucentBackground); 0322 0323 #ifdef Q_WS_WIN 0324 // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly 0325 widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint); 0326 #endif 0327 } 0328 0329 if (QAbstractItemView *itemView = qobject_cast<QAbstractItemView *>(widget)) { 0330 // enable hover effects in itemviews' viewport 0331 itemView->viewport()->setAttribute(Qt::WA_Hover); 0332 0333 } else if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget)) { 0334 // enable hover effect in sunken scrollareas that support focus 0335 if (scrollArea->frameShadow() == QFrame::Sunken && widget->focusPolicy() & Qt::StrongFocus) { 0336 widget->setAttribute(Qt::WA_Hover); 0337 } 0338 0339 } else if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) { 0340 // checkable group boxes 0341 if (groupBox->isCheckable()) { 0342 groupBox->setAttribute(Qt::WA_Hover); 0343 } 0344 0345 } else if (qobject_cast<QAbstractButton *>(widget) && qobject_cast<QDockWidget *>(widget->parent())) { 0346 widget->setAttribute(Qt::WA_Hover); 0347 0348 } else if (qobject_cast<QAbstractButton *>(widget) && qobject_cast<QToolBox *>(widget->parent())) { 0349 widget->setAttribute(Qt::WA_Hover); 0350 } 0351 0352 if (qobject_cast<QToolButton *>(widget)) { 0353 if (qobject_cast<QToolBar *>(widget->parent())) { 0354 // this hack is needed to have correct text color 0355 // rendered in toolbars. This does not really update nicely when changing styles 0356 // but is the best I can do for now since setting the palette color at painting 0357 // time is not doable 0358 QPalette palette(widget->palette()); 0359 palette.setColor(QPalette::Disabled, QPalette::ButtonText, palette.color(QPalette::Disabled, QPalette::WindowText)); 0360 palette.setColor(QPalette::Active, QPalette::ButtonText, palette.color(QPalette::Active, QPalette::WindowText)); 0361 palette.setColor(QPalette::Inactive, QPalette::ButtonText, palette.color(QPalette::Inactive, QPalette::WindowText)); 0362 widget->setPalette(palette); 0363 } 0364 0365 widget->setBackgroundRole(QPalette::NoRole); 0366 0367 if (widget->parentWidget() && widget->parentWidget()->parentWidget() && widget->parentWidget()->parentWidget()->inherits("Gwenview::SideBarGroup")) { 0368 widget->setProperty(PropertyNames::toolButtonAlignment, Qt::AlignLeft); 0369 } 0370 0371 } else if (qobject_cast<QMenuBar *>(widget)) { 0372 widget->setBackgroundRole(QPalette::NoRole); 0373 0374 } else if (widget->inherits("KMultiTabBar")) { 0375 // kMultiTabBar margins are set to unity for alignment 0376 // with ( usually sunken ) neighbor frames 0377 widget->setContentsMargins(1, 1, 1, 1); 0378 0379 } else if (qobject_cast<QToolBar *>(widget)) { 0380 widget->setBackgroundRole(QPalette::NoRole); 0381 addEventFilter(widget); 0382 0383 } else if (qobject_cast<QTabBar *>(widget)) { 0384 addEventFilter(widget); 0385 0386 } else if (widget->inherits("QTipLabel")) { 0387 widget->setBackgroundRole(QPalette::NoRole); 0388 widget->setAttribute(Qt::WA_TranslucentBackground); 0389 0390 #ifdef Q_WS_WIN 0391 // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly 0392 widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint); 0393 #endif 0394 0395 } else if (qobject_cast<QScrollBar *>(widget)) { 0396 widget->setAttribute(Qt::WA_OpaquePaintEvent, false); 0397 0398 // when painted in konsole, one needs to paint the window background below 0399 // the scrollarea, otherwise an ugly flat background is used 0400 if (widget->parent() && widget->parent()->inherits("Konsole::TerminalDisplay")) { 0401 addEventFilter(widget); 0402 } 0403 0404 } else if (qobject_cast<QDockWidget *>(widget)) { 0405 widget->setBackgroundRole(QPalette::NoRole); 0406 widget->setContentsMargins(3, 3, 3, 3); 0407 addEventFilter(widget); 0408 0409 } else if (qobject_cast<QMdiSubWindow *>(widget)) { 0410 widget->setAutoFillBackground(false); 0411 addEventFilter(widget); 0412 0413 } else if (qobject_cast<QToolBox *>(widget)) { 0414 widget->setBackgroundRole(QPalette::NoRole); 0415 widget->setAutoFillBackground(false); 0416 widget->setContentsMargins(5, 5, 5, 5); 0417 addEventFilter(widget); 0418 0419 } else if (widget->parentWidget() && widget->parentWidget()->parentWidget() 0420 && qobject_cast<QToolBox *>(widget->parentWidget()->parentWidget()->parentWidget())) { 0421 widget->setBackgroundRole(QPalette::NoRole); 0422 widget->setAutoFillBackground(false); 0423 widget->parentWidget()->setAutoFillBackground(false); 0424 0425 } else if (qobject_cast<QMenu *>(widget)) { 0426 widget->setAttribute(Qt::WA_TranslucentBackground); 0427 #ifdef Q_WS_WIN 0428 // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly 0429 widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint); 0430 #endif 0431 0432 } else if (qobject_cast<QCommandLinkButton *>(widget)) { 0433 addEventFilter(widget); 0434 0435 } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) { 0436 if (!hasParent(widget, "QWebView")) { 0437 QAbstractItemView *itemView(comboBox->view()); 0438 if (itemView && itemView->itemDelegate() && itemView->itemDelegate()->inherits("QComboBoxDelegate")) { 0439 itemView->setItemDelegate(new OxygenPrivate::ComboBoxItemDelegate(itemView)); 0440 } 0441 } 0442 0443 } else if (widget->inherits("QComboBoxPrivateContainer")) { 0444 addEventFilter(widget); 0445 widget->setAttribute(Qt::WA_TranslucentBackground); 0446 #ifdef Q_WS_WIN 0447 // FramelessWindowHint is needed on windows to make WA_TranslucentBackground work properly 0448 widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint); 0449 #endif 0450 0451 } else if (qobject_cast<QFrame *>(widget) && widget->parent() && widget->parent()->inherits("KTitleWidget")) { 0452 widget->setAutoFillBackground(false); 0453 widget->setBackgroundRole(QPalette::Window); 0454 } 0455 0456 // base class polishing 0457 KStyle::polish(widget); 0458 } 0459 0460 //_______________________________________________________________ 0461 void Style::unpolish(QWidget *widget) 0462 { 0463 // register widget to animations 0464 _animations->unregisterWidget(widget); 0465 _transitions->unregisterWidget(widget); 0466 _windowManager->unregisterWidget(widget); 0467 _frameShadowFactory->unregisterWidget(widget); 0468 _mdiWindowShadowFactory->unregisterWidget(widget); 0469 _shadowHelper->unregisterWidget(widget); 0470 _splitterFactory->unregisterWidget(widget); 0471 _blurHelper->unregisterWidget(widget); 0472 0473 // event filters 0474 switch (widget->windowFlags() & Qt::WindowType_Mask) { 0475 case Qt::Window: 0476 case Qt::Dialog: 0477 widget->removeEventFilter(this); 0478 widget->setAttribute(Qt::WA_StyledBackground, false); 0479 break; 0480 0481 default: 0482 break; 0483 } 0484 0485 // checkable group boxes 0486 if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) { 0487 if (groupBox->isCheckable()) { 0488 groupBox->setAttribute(Qt::WA_Hover, false); 0489 } 0490 } 0491 0492 // hover flags 0493 if (qobject_cast<QAbstractItemView *>(widget) || qobject_cast<QAbstractSpinBox *>(widget) || qobject_cast<QCheckBox *>(widget) 0494 || qobject_cast<QComboBox *>(widget) || qobject_cast<QDial *>(widget) || qobject_cast<QLineEdit *>(widget) || qobject_cast<QPushButton *>(widget) 0495 || qobject_cast<QRadioButton *>(widget) || qobject_cast<QScrollBar *>(widget) || qobject_cast<QSlider *>(widget) 0496 || qobject_cast<QSplitterHandle *>(widget) || qobject_cast<QTabBar *>(widget) || qobject_cast<QTextEdit *>(widget) 0497 || qobject_cast<QToolButton *>(widget)) { 0498 widget->setAttribute(Qt::WA_Hover, false); 0499 } 0500 0501 // checkable group boxes 0502 if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget)) { 0503 if (groupBox->isCheckable()) { 0504 groupBox->setAttribute(Qt::WA_Hover, false); 0505 } 0506 } 0507 0508 if (qobject_cast<QMenuBar *>(widget) || qobject_cast<QToolBar *>(widget) || (widget && qobject_cast<QToolBar *>(widget->parent())) 0509 || qobject_cast<QToolBox *>(widget)) { 0510 widget->setBackgroundRole(QPalette::Button); 0511 widget->removeEventFilter(this); 0512 widget->clearMask(); 0513 } 0514 0515 if (qobject_cast<QTabBar *>(widget)) { 0516 widget->removeEventFilter(this); 0517 0518 } else if (widget->inherits("QTipLabel")) { 0519 widget->setAttribute(Qt::WA_PaintOnScreen, false); 0520 widget->setAttribute(Qt::WA_NoSystemBackground, false); 0521 widget->clearMask(); 0522 0523 } else if (qobject_cast<QScrollBar *>(widget)) { 0524 widget->setAttribute(Qt::WA_OpaquePaintEvent); 0525 0526 } else if (qobject_cast<QDockWidget *>(widget)) { 0527 widget->setContentsMargins(0, 0, 0, 0); 0528 widget->clearMask(); 0529 0530 } else if (qobject_cast<QToolBox *>(widget)) { 0531 widget->setBackgroundRole(QPalette::Button); 0532 widget->setContentsMargins(0, 0, 0, 0); 0533 widget->removeEventFilter(this); 0534 0535 } else if (qobject_cast<QMenu *>(widget)) { 0536 widget->setAttribute(Qt::WA_PaintOnScreen, false); 0537 widget->setAttribute(Qt::WA_NoSystemBackground, false); 0538 widget->clearMask(); 0539 0540 } else if (widget->inherits("QComboBoxPrivateContainer")) 0541 widget->removeEventFilter(this); 0542 0543 KStyle::unpolish(widget); 0544 } 0545 0546 //______________________________________________________________ 0547 int Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const 0548 { 0549 // handle special cases 0550 switch (metric) { 0551 case PM_DefaultFrameWidth: 0552 if (qobject_cast<const QLineEdit *>(widget)) 0553 return Metrics::LineEdit_FrameWidth; 0554 else if (isQtQuickControl(option, widget)) { 0555 const QString &elementType = option->styleObject->property("elementType").toString(); 0556 if (elementType == QLatin1String("edit") || elementType == QLatin1String("spinbox")) { 0557 return Metrics::LineEdit_FrameWidth; 0558 0559 } else if (elementType == QLatin1String("combobox")) { 0560 return Metrics::ComboBox_FrameWidth; 0561 } 0562 } 0563 0564 // fallback 0565 return Metrics::Frame_FrameWidth; 0566 0567 case PM_ComboBoxFrameWidth: { 0568 const QStyleOptionComboBox *comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); 0569 return comboBoxOption && comboBoxOption->editable ? Metrics::LineEdit_FrameWidth : Metrics::ComboBox_FrameWidth; 0570 } 0571 0572 case PM_SpinBoxFrameWidth: 0573 return Metrics::SpinBox_FrameWidth; 0574 case PM_ToolBarFrameWidth: 0575 return Metrics::ToolBar_FrameWidth; 0576 case PM_ToolTipLabelFrameWidth: 0577 return Metrics::ToolTip_FrameWidth; 0578 0579 // layout 0580 case PM_LayoutLeftMargin: 0581 case PM_LayoutTopMargin: 0582 case PM_LayoutRightMargin: 0583 case PM_LayoutBottomMargin: { 0584 /* 0585 use either Child margin or TopLevel margin, 0586 depending on widget type 0587 */ 0588 if ((option && (option->state & QStyle::State_Window)) || (widget && widget->isWindow())) { 0589 return Metrics::Layout_TopLevelMarginWidth; 0590 0591 } else { 0592 return Metrics::Layout_ChildMarginWidth; 0593 } 0594 } 0595 0596 case PM_LayoutHorizontalSpacing: 0597 return Metrics::Layout_DefaultSpacing; 0598 case PM_LayoutVerticalSpacing: 0599 return Metrics::Layout_DefaultSpacing; 0600 0601 // buttons 0602 case PM_ButtonMargin: { 0603 /* HACK: needs special case for kcalc buttons, to prevent the application to set too small margins */ 0604 if (widget && widget->inherits("KCalcButton")) 0605 return Metrics::Button_MarginWidth + 4; 0606 else 0607 return Metrics::Button_MarginWidth; 0608 } 0609 0610 // buttons 0611 case PM_ButtonDefaultIndicator: 0612 return 0; 0613 case PM_ButtonShiftHorizontal: 0614 return 0; 0615 case PM_ButtonShiftVertical: 0616 return 0; 0617 0618 // menubars 0619 case PM_MenuBarPanelWidth: 0620 return 0; 0621 case PM_MenuBarHMargin: 0622 return 0; 0623 case PM_MenuBarVMargin: 0624 return 0; 0625 case PM_MenuBarItemSpacing: 0626 return 0; 0627 case PM_MenuDesktopFrameWidth: 0628 return 0; 0629 0630 // menu buttons 0631 case PM_MenuButtonIndicator: 0632 return Metrics::MenuButton_IndicatorWidth; 0633 0634 // toolbars 0635 case PM_ToolBarHandleExtent: 0636 return Metrics::ToolBar_HandleExtent; 0637 case PM_ToolBarSeparatorExtent: 0638 return Metrics::ToolBar_SeparatorWidth; 0639 case PM_ToolBarExtensionExtent: 0640 return pixelMetric(PM_SmallIconSize, option, widget) + 2 * Metrics::ToolButton_MarginWidth; 0641 0642 case PM_ToolBarItemMargin: 0643 return Metrics::ToolBar_MarginSpacing; 0644 case PM_ToolBarItemSpacing: 0645 return Metrics::ToolBar_ItemSpacing; 0646 0647 // tabbars 0648 case PM_TabBarTabShiftVertical: 0649 return 0; 0650 case PM_TabBarTabShiftHorizontal: 0651 return 0; 0652 case PM_TabBarTabOverlap: 0653 return Metrics::TabBar_TabOverlap; 0654 case PM_TabBarBaseOverlap: 0655 return Metrics::TabBar_BaseOverlap; 0656 case PM_TabBarTabHSpace: 0657 return 2 * Metrics::TabBar_TabMarginWidth; 0658 case PM_TabBarTabVSpace: 0659 return 2 * Metrics::TabBar_TabMarginHeight; 0660 case PM_TabCloseIndicatorWidth: 0661 case PM_TabCloseIndicatorHeight: 0662 return pixelMetric(PM_SmallIconSize, option, widget); 0663 0664 // scrollbars 0665 case PM_ScrollBarExtent: 0666 return StyleConfigData::scrollBarWidth() + 2; 0667 case PM_ScrollBarSliderMin: 0668 return Metrics::ScrollBar_MinSliderHeight; 0669 0670 // title bar 0671 case PM_TitleBarHeight: 0672 return 2 * Metrics::TitleBar_MarginWidth + pixelMetric(PM_SmallIconSize, option, widget); 0673 0674 // sliders 0675 case PM_SliderThickness: 0676 return Metrics::Slider_ControlThickness; 0677 case PM_SliderControlThickness: 0678 return Metrics::Slider_ControlThickness; 0679 case PM_SliderLength: 0680 return Metrics::Slider_ControlThickness; 0681 0682 // checkboxes and radio buttons 0683 case PM_IndicatorWidth: 0684 return Metrics::CheckBox_Size; 0685 case PM_IndicatorHeight: 0686 return Metrics::CheckBox_Size; 0687 case PM_ExclusiveIndicatorWidth: 0688 return Metrics::CheckBox_Size; 0689 case PM_ExclusiveIndicatorHeight: 0690 return Metrics::CheckBox_Size; 0691 0692 // list heaaders 0693 case PM_HeaderMarkSize: 0694 return Metrics::Header_ArrowSize; 0695 case PM_HeaderMargin: 0696 return Metrics::Header_MarginWidth; 0697 0698 // dock widget 0699 // return 0 here, since frame is handled directly in polish 0700 case PM_DockWidgetFrameWidth: 0701 return 0; 0702 case PM_DockWidgetTitleMargin: 0703 return Metrics::Frame_FrameWidth; 0704 case PM_DockWidgetTitleBarButtonMargin: 0705 return Metrics::ToolButton_MarginWidth; 0706 0707 case PM_SplitterWidth: 0708 return Metrics::Splitter_SplitterWidth; 0709 case PM_DockWidgetSeparatorExtent: 0710 return Metrics::Splitter_SplitterWidth; 0711 0712 // spacing between widget and scrollbars 0713 case PM_ScrollView_ScrollBarSpacing: 0714 if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) { 0715 const bool framed(frame->frameShape() != QFrame::NoFrame); 0716 return framed ? -1 : 0; 0717 0718 } else 0719 return -1; 0720 0721 // fallback 0722 default: 0723 return KStyle::pixelMetric(metric, option, widget); 0724 } 0725 } 0726 0727 //______________________________________________________________ 0728 int Style::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const 0729 { 0730 /* 0731 special cases, that cannot be registered in styleHint map, 0732 because of conditional statements 0733 */ 0734 switch (hint) { 0735 case SH_RubberBand_Mask: { 0736 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData)) { 0737 mask->region = option->rect; 0738 0739 // need to check on widget before removing inner region 0740 // in order to still preserve rubberband in MainWindow and QGraphicsView 0741 // in QMainWindow because it looks better 0742 // in QGraphicsView because the painting fails completely otherwise 0743 if (widget 0744 && (qobject_cast<const QAbstractItemView *>(widget->parent()) || qobject_cast<const QGraphicsView *>(widget->parent()) 0745 || qobject_cast<const QMainWindow *>(widget->parent()))) { 0746 return true; 0747 } 0748 0749 // also check if widget's parent is some itemView viewport 0750 if (widget && widget->parent() && qobject_cast<const QAbstractItemView *>(widget->parent()->parent()) 0751 && static_cast<const QAbstractItemView *>(widget->parent()->parent())->viewport() == widget->parent()) { 0752 return true; 0753 } 0754 0755 // mask out center 0756 mask->region -= insideMargin(option->rect, 1); 0757 0758 return true; 0759 } 0760 return false; 0761 } 0762 0763 case SH_ToolTip_Mask: 0764 case SH_Menu_Mask: { 0765 if (!_helper->hasAlphaChannel(widget) && (!widget || widget->isWindow())) { 0766 // mask should be set only if compositing is disabled 0767 if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData)) { 0768 mask->region = _helper->roundedMask(option->rect); 0769 } 0770 } 0771 0772 return true; 0773 } 0774 0775 // mouse tracking 0776 case SH_ComboBox_ListMouseTracking: 0777 return true; 0778 case SH_MenuBar_MouseTracking: 0779 return true; 0780 case SH_Menu_MouseTracking: 0781 return true; 0782 case SH_Menu_SubMenuPopupDelay: 0783 return 150; 0784 case SH_Menu_SloppySubMenus: 0785 return true; 0786 case SH_ToolBox_SelectedPageTitleBold: 0787 return false; 0788 0789 case SH_Widget_Animate: 0790 return StyleConfigData::animationsEnabled(); 0791 case SH_Menu_SupportsSections: 0792 return true; 0793 0794 case SH_TitleBar_NoBorder: 0795 return false; 0796 case SH_GroupBox_TextLabelVerticalAlignment: 0797 return Qt::AlignVCenter; 0798 case SH_ScrollBar_MiddleClickAbsolutePosition: 0799 return true; 0800 case SH_ScrollView_FrameOnlyAroundContents: 0801 return true; 0802 case SH_FormLayoutFormAlignment: 0803 return Qt::AlignLeft | Qt::AlignTop; 0804 case SH_FormLayoutLabelAlignment: 0805 return Qt::AlignRight; 0806 case SH_FormLayoutFieldGrowthPolicy: 0807 return QFormLayout::ExpandingFieldsGrow; 0808 case SH_FormLayoutWrapPolicy: 0809 return QFormLayout::DontWrapRows; 0810 case SH_MessageBox_TextInteractionFlags: 0811 return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; 0812 case SH_RequestSoftwareInputPanel: 0813 return RSIP_OnMouseClick; 0814 case SH_ProgressDialog_CenterCancelButton: 0815 case SH_MessageBox_CenterButtons: 0816 return false; 0817 0818 default: 0819 return KStyle::styleHint(hint, option, widget, returnData); 0820 } 0821 } 0822 0823 //______________________________________________________________ 0824 QRect Style::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const 0825 { 0826 switch (element) { 0827 case SE_PushButtonContents: 0828 return pushButtonContentsRect(option, widget); 0829 case SE_CheckBoxContents: 0830 return checkBoxContentsRect(option, widget); 0831 case SE_RadioButtonContents: 0832 return checkBoxContentsRect(option, widget); 0833 case SE_LineEditContents: 0834 return lineEditContentsRect(option, widget); 0835 case SE_ProgressBarGroove: 0836 return progressBarGrooveRect(option, widget); 0837 case SE_ProgressBarContents: 0838 return progressBarContentsRect(option, widget); 0839 case SE_ProgressBarLabel: 0840 return defaultSubElementRect(option, widget); 0841 case SE_HeaderArrow: 0842 return headerArrowRect(option, widget); 0843 case SE_HeaderLabel: 0844 return headerLabelRect(option, widget); 0845 case SE_TabBarTabLeftButton: 0846 return tabBarTabLeftButtonRect(option, widget); 0847 case SE_TabBarTabRightButton: 0848 return tabBarTabRightButtonRect(option, widget); 0849 case SE_TabWidgetTabBar: 0850 return tabWidgetTabBarRect(option, widget); 0851 case SE_TabWidgetTabContents: 0852 return tabWidgetTabContentsRect(option, widget); 0853 case SE_TabWidgetTabPane: 0854 return tabWidgetTabPaneRect(option, widget); 0855 case SE_TabWidgetLeftCorner: 0856 return tabWidgetCornerRect(SE_TabWidgetLeftCorner, option, widget); 0857 case SE_TabWidgetRightCorner: 0858 return tabWidgetCornerRect(SE_TabWidgetRightCorner, option, widget); 0859 case SE_ToolBoxTabContents: 0860 return toolBoxTabContentsRect(option, widget); 0861 0862 default: 0863 return KStyle::subElementRect(element, option, widget); 0864 } 0865 } 0866 0867 //______________________________________________________________ 0868 QRect Style::subControlRect(ComplexControl element, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 0869 { 0870 switch (element) { 0871 case CC_GroupBox: 0872 return groupBoxSubControlRect(option, subControl, widget); 0873 case CC_ToolButton: 0874 return toolButtonSubControlRect(option, subControl, widget); 0875 case CC_ComboBox: 0876 return comboBoxSubControlRect(option, subControl, widget); 0877 case CC_SpinBox: 0878 return spinBoxSubControlRect(option, subControl, widget); 0879 case CC_ScrollBar: 0880 return scrollBarSubControlRect(option, subControl, widget); 0881 case CC_Slider: 0882 return sliderSubControlRect(option, subControl, widget); 0883 0884 // fallback 0885 default: 0886 return KStyle::subControlRect(element, option, subControl, widget); 0887 } 0888 } 0889 0890 //______________________________________________________________ 0891 QSize Style::sizeFromContents(ContentsType element, const QStyleOption *option, const QSize &size, const QWidget *widget) const 0892 { 0893 switch (element) { 0894 case CT_CheckBox: 0895 return checkBoxSizeFromContents(option, size, widget); 0896 case CT_RadioButton: 0897 return checkBoxSizeFromContents(option, size, widget); 0898 case CT_LineEdit: 0899 return lineEditSizeFromContents(option, size, widget); 0900 case CT_ComboBox: 0901 return comboBoxSizeFromContents(option, size, widget); 0902 case CT_SpinBox: 0903 return spinBoxSizeFromContents(option, size, widget); 0904 case CT_Slider: 0905 return sliderSizeFromContents(option, size, widget); 0906 case CT_PushButton: 0907 return pushButtonSizeFromContents(option, size, widget); 0908 case CT_ToolButton: 0909 return toolButtonSizeFromContents(option, size, widget); 0910 case CT_MenuBar: 0911 return defaultSizeFromContents(option, size, widget); 0912 case CT_MenuBarItem: 0913 return menuBarItemSizeFromContents(option, size, widget); 0914 case CT_MenuItem: 0915 return menuItemSizeFromContents(option, size, widget); 0916 case CT_TabWidget: 0917 return tabWidgetSizeFromContents(option, size, widget); 0918 case CT_TabBarTab: 0919 return tabBarTabSizeFromContents(option, size, widget); 0920 case CT_HeaderSection: 0921 return headerSectionSizeFromContents(option, size, widget); 0922 case CT_ItemViewItem: 0923 return itemViewItemSizeFromContents(option, size, widget); 0924 0925 default: 0926 return KStyle::sizeFromContents(element, option, size, widget); 0927 } 0928 } 0929 0930 //______________________________________________________________ 0931 QStyle::SubControl Style::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &point, const QWidget *widget) const 0932 { 0933 switch (control) { 0934 case CC_ScrollBar: { 0935 QRect grooveRect = subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget); 0936 if (grooveRect.contains(point)) { 0937 // Must be either page up/page down, or just click on the slider. 0938 // Grab the slider to compare 0939 QRect sliderRect = subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget); 0940 0941 if (sliderRect.contains(point)) 0942 return SC_ScrollBarSlider; 0943 else if (preceeds(point, sliderRect, option)) 0944 return SC_ScrollBarSubPage; 0945 else 0946 return SC_ScrollBarAddPage; 0947 } 0948 0949 // This is one of the up/down buttons. First, decide which one it is. 0950 if (preceeds(point, grooveRect, option)) { 0951 if (_subLineButtons == DoubleButton) { 0952 QRect buttonRect = scrollBarInternalSubControlRect(option, SC_ScrollBarSubLine); 0953 return scrollBarHitTest(buttonRect, point, option); 0954 } else 0955 return SC_ScrollBarSubLine; 0956 } 0957 0958 if (_addLineButtons == DoubleButton) { 0959 QRect buttonRect = scrollBarInternalSubControlRect(option, SC_ScrollBarAddLine); 0960 return scrollBarHitTest(buttonRect, point, option); 0961 0962 } else 0963 return SC_ScrollBarAddLine; 0964 } 0965 0966 // fallback 0967 default: 0968 return KStyle::hitTestComplexControl(control, option, point, widget); 0969 } 0970 } 0971 0972 //______________________________________________________________ 0973 void Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const 0974 { 0975 StylePrimitive fcn(nullptr); 0976 switch (element) { 0977 case PE_PanelButtonCommand: 0978 fcn = &Style::drawPanelButtonCommandPrimitive; 0979 break; 0980 case PE_PanelButtonTool: 0981 fcn = &Style::drawPanelButtonToolPrimitive; 0982 break; 0983 case PE_PanelScrollAreaCorner: 0984 fcn = &Style::drawPanelScrollAreaCornerPrimitive; 0985 break; 0986 case PE_PanelMenu: 0987 fcn = &Style::drawPanelMenuPrimitive; 0988 break; 0989 case PE_PanelTipLabel: 0990 fcn = &Style::drawPanelTipLabelPrimitive; 0991 break; 0992 case PE_PanelItemViewItem: 0993 fcn = &Style::drawPanelItemViewItemPrimitive; 0994 break; 0995 case PE_IndicatorCheckBox: 0996 fcn = &Style::drawIndicatorCheckBoxPrimitive; 0997 break; 0998 case PE_IndicatorRadioButton: 0999 fcn = &Style::drawIndicatorRadioButtonPrimitive; 1000 break; 1001 case PE_IndicatorButtonDropDown: 1002 fcn = &Style::drawIndicatorButtonDropDownPrimitive; 1003 break; 1004 case PE_IndicatorTabClose: 1005 fcn = &Style::drawIndicatorTabClosePrimitive; 1006 break; 1007 case PE_IndicatorTabTear: 1008 fcn = &Style::drawIndicatorTabTearPrimitive; 1009 break; 1010 case PE_IndicatorArrowUp: 1011 fcn = &Style::drawIndicatorArrowUpPrimitive; 1012 break; 1013 case PE_IndicatorArrowDown: 1014 fcn = &Style::drawIndicatorArrowDownPrimitive; 1015 break; 1016 case PE_IndicatorArrowLeft: 1017 fcn = &Style::drawIndicatorArrowLeftPrimitive; 1018 break; 1019 case PE_IndicatorArrowRight: 1020 fcn = &Style::drawIndicatorArrowRightPrimitive; 1021 break; 1022 case PE_IndicatorMenuCheckMark: 1023 fcn = &Style::drawIndicatorMenuCheckMarkPrimitive; 1024 break; 1025 case PE_IndicatorHeaderArrow: 1026 fcn = &Style::drawIndicatorHeaderArrowPrimitive; 1027 break; 1028 case PE_IndicatorToolBarHandle: 1029 fcn = &Style::drawIndicatorToolBarHandlePrimitive; 1030 break; 1031 case PE_IndicatorToolBarSeparator: 1032 fcn = &Style::drawIndicatorToolBarSeparatorPrimitive; 1033 break; 1034 case PE_IndicatorBranch: 1035 fcn = &Style::drawIndicatorBranchPrimitive; 1036 break; 1037 case PE_IndicatorDockWidgetResizeHandle: 1038 fcn = &Style::drawIndicatorDockWidgetResizeHandlePrimitive; 1039 break; 1040 case PE_FrameStatusBarItem: 1041 fcn = &Style::emptyPrimitive; 1042 break; 1043 case PE_Frame: 1044 fcn = &Style::drawFramePrimitive; 1045 break; 1046 case PE_FrameLineEdit: 1047 fcn = &Style::drawFrameLineEditPrimitive; 1048 break; 1049 case PE_FrameMenu: 1050 fcn = &Style::drawFrameMenuPrimitive; 1051 break; 1052 case PE_FrameGroupBox: 1053 fcn = &Style::drawFrameGroupBoxPrimitive; 1054 break; 1055 case PE_FrameTabWidget: 1056 fcn = &Style::drawFrameTabWidgetPrimitive; 1057 break; 1058 case PE_FrameTabBarBase: 1059 fcn = &Style::drawFrameTabBarBasePrimitive; 1060 break; 1061 case PE_FrameWindow: 1062 fcn = &Style::drawFrameWindowPrimitive; 1063 break; 1064 case PE_FrameFocusRect: 1065 fcn = _frameFocusPrimitive; 1066 break; 1067 case PE_Widget: 1068 fcn = &Style::drawWidgetPrimitive; 1069 break; 1070 1071 // fallback 1072 default: 1073 break; 1074 } 1075 1076 painter->save(); 1077 1078 // call function if implemented 1079 if (!(fcn && (this->*fcn)(option, painter, widget))) { 1080 KStyle::drawPrimitive(element, option, painter, widget); 1081 } 1082 1083 painter->restore(); 1084 } 1085 1086 //______________________________________________________________ 1087 void Style::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const 1088 { 1089 StyleControl fcn(nullptr); 1090 if (element == CE_CapacityBar) { 1091 fcn = &Style::drawProgressBarControl; 1092 1093 } else 1094 switch (element) { 1095 case CE_ComboBoxLabel: 1096 break; 1097 case CE_DockWidgetTitle: 1098 fcn = &Style::drawDockWidgetTitleControl; 1099 break; 1100 case CE_HeaderEmptyArea: 1101 fcn = &Style::drawHeaderEmptyAreaControl; 1102 break; 1103 case CE_HeaderLabel: 1104 break; 1105 case CE_HeaderSection: 1106 fcn = &Style::drawHeaderSectionControl; 1107 break; 1108 case CE_MenuBarEmptyArea: 1109 fcn = &Style::emptyControl; 1110 break; 1111 case CE_MenuBarItem: 1112 fcn = &Style::drawMenuBarItemControl; 1113 break; 1114 case CE_MenuItem: 1115 fcn = &Style::drawMenuItemControl; 1116 break; 1117 case CE_ProgressBar: 1118 fcn = &Style::drawProgressBarControl; 1119 break; 1120 case CE_ProgressBarContents: 1121 fcn = &Style::drawProgressBarContentsControl; 1122 break; 1123 case CE_ProgressBarGroove: 1124 fcn = &Style::drawProgressBarGrooveControl; 1125 break; 1126 case CE_ProgressBarLabel: 1127 fcn = &Style::drawProgressBarLabelControl; 1128 break; 1129 case CE_PushButtonBevel: 1130 fcn = &Style::drawPanelButtonCommandPrimitive; 1131 break; 1132 case CE_PushButtonLabel: 1133 fcn = &Style::drawPushButtonLabelControl; 1134 break; 1135 case CE_RubberBand: 1136 fcn = &Style::drawRubberBandControl; 1137 break; 1138 case CE_ScrollBarSlider: 1139 fcn = &Style::drawScrollBarSliderControl; 1140 break; 1141 case CE_ScrollBarAddLine: 1142 fcn = &Style::drawScrollBarAddLineControl; 1143 break; 1144 case CE_ScrollBarSubLine: 1145 fcn = &Style::drawScrollBarSubLineControl; 1146 break; 1147 case CE_ScrollBarAddPage: 1148 fcn = &Style::emptyControl; 1149 break; 1150 case CE_ScrollBarSubPage: 1151 fcn = &Style::emptyControl; 1152 break; 1153 case CE_ShapedFrame: 1154 fcn = &Style::drawShapedFrameControl; 1155 break; 1156 case CE_SizeGrip: 1157 fcn = &Style::emptyControl; 1158 break; 1159 case CE_Splitter: 1160 fcn = &Style::drawSplitterControl; 1161 break; 1162 case CE_TabBarTabLabel: 1163 fcn = &Style::drawTabBarTabLabelControl; 1164 break; 1165 case CE_TabBarTabShape: 1166 fcn = &Style::drawTabBarTabShapeControl; 1167 break; 1168 case CE_ToolBar: 1169 fcn = &Style::drawToolBarControl; 1170 break; 1171 case CE_ToolBoxTabLabel: 1172 fcn = &Style::drawToolBoxTabLabelControl; 1173 break; 1174 case CE_ToolBoxTabShape: 1175 fcn = &Style::drawToolBoxTabShapeControl; 1176 break; 1177 case CE_ToolButtonLabel: 1178 fcn = &Style::drawToolButtonLabelControl; 1179 break; 1180 1181 default: 1182 break; 1183 } 1184 1185 painter->save(); 1186 1187 // call function if implemented 1188 if (!(fcn && (this->*fcn)(option, painter, widget))) { 1189 KStyle::drawControl(element, option, painter, widget); 1190 } 1191 1192 painter->restore(); 1193 } 1194 1195 //______________________________________________________________ 1196 void Style::drawComplexControl(ComplexControl element, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 1197 { 1198 StyleComplexControl fcn(nullptr); 1199 switch (element) { 1200 case CC_GroupBox: 1201 break; 1202 case CC_ToolButton: 1203 fcn = &Style::drawToolButtonComplexControl; 1204 break; 1205 case CC_ComboBox: 1206 fcn = &Style::drawComboBoxComplexControl; 1207 break; 1208 case CC_SpinBox: 1209 fcn = &Style::drawSpinBoxComplexControl; 1210 break; 1211 case CC_Slider: 1212 fcn = &Style::drawSliderComplexControl; 1213 break; 1214 case CC_Dial: 1215 fcn = &Style::drawDialComplexControl; 1216 break; 1217 case CC_ScrollBar: 1218 fcn = &Style::drawScrollBarComplexControl; 1219 break; 1220 case CC_TitleBar: 1221 fcn = &Style::drawTitleBarComplexControl; 1222 break; 1223 1224 // fallback 1225 default: 1226 break; 1227 } 1228 1229 painter->save(); 1230 1231 // call function if implemented 1232 if (!(fcn && (this->*fcn)(option, painter, widget))) { 1233 KStyle::drawComplexControl(element, option, painter, widget); 1234 } 1235 1236 painter->restore(); 1237 } 1238 1239 //___________________________________________________________________________________ 1240 void Style::drawItemText(QPainter *painter, 1241 const QRect &rect, 1242 int flags, 1243 const QPalette &palette, 1244 bool enabled, 1245 const QString &text, 1246 QPalette::ColorRole textRole) const 1247 { 1248 // hide mnemonics if requested 1249 if (!_mnemonics->enabled() && (flags & Qt::TextShowMnemonic) && !(flags & Qt::TextHideMnemonic)) { 1250 flags &= ~Qt::TextShowMnemonic; 1251 flags |= Qt::TextHideMnemonic; 1252 } 1253 1254 // make sure vertical alignment is defined 1255 // fallback on Align::VCenter if not 1256 if (!(flags & Qt::AlignVertical_Mask)) 1257 flags |= Qt::AlignVCenter; 1258 1259 if (_animations->widgetEnableStateEngine().enabled()) { 1260 /* 1261 check if painter engine is registered to widgetEnableStateEngine, and animated 1262 if yes, merge the palettes. Note: a static_cast is safe here, since only the address 1263 of the pointer is used, not the actual content. 1264 */ 1265 const QWidget *widget(static_cast<const QWidget *>(painter->device())); 1266 if (_animations->widgetEnableStateEngine().isAnimated(widget, AnimationEnable)) { 1267 const QPalette copy(_helper->disabledPalette(palette, _animations->widgetEnableStateEngine().opacity(widget, AnimationEnable))); 1268 return KStyle::drawItemText(painter, rect, flags, copy, enabled, text, textRole); 1269 } 1270 } 1271 1272 // fallback 1273 return KStyle::drawItemText(painter, rect, flags, palette, enabled, text, textRole); 1274 } 1275 1276 //_____________________________________________________________________ 1277 bool Style::eventFilter(QObject *object, QEvent *event) 1278 { 1279 if (QTabBar *tabBar = qobject_cast<QTabBar *>(object)) { 1280 return eventFilterTabBar(tabBar, event); 1281 } else if (QToolBar *toolBar = qobject_cast<QToolBar *>(object)) { 1282 return eventFilterToolBar(toolBar, event); 1283 } else if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) { 1284 return eventFilterDockWidget(dockWidget, event); 1285 } else if (QToolBox *toolBox = qobject_cast<QToolBox *>(object)) { 1286 return eventFilterToolBox(toolBox, event); 1287 } else if (QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(object)) { 1288 return eventFilterMdiSubWindow(subWindow, event); 1289 } else if (QScrollBar *scrollBar = qobject_cast<QScrollBar *>(object)) { 1290 return eventFilterScrollBar(scrollBar, event); 1291 } else if (QCommandLinkButton *commandLinkButton = qobject_cast<QCommandLinkButton *>(object)) { 1292 return eventFilterCommandLinkButton(commandLinkButton, event); 1293 } 1294 1295 // cast to QWidget 1296 QWidget *widget = static_cast<QWidget *>(object); 1297 if (widget->inherits("QComboBoxPrivateContainer")) { 1298 return eventFilterComboBoxContainer(widget, event); 1299 } 1300 1301 // fallback 1302 return KStyle::eventFilter(object, event); 1303 } 1304 1305 //_________________________________________________________ 1306 bool Style::eventFilterComboBoxContainer(QWidget *widget, QEvent *event) 1307 { 1308 switch (event->type()) { 1309 case QEvent::Show: 1310 case QEvent::Resize: { 1311 if (!_helper->hasAlphaChannel(widget)) 1312 widget->setMask(_helper->roundedMask(widget->size())); 1313 else 1314 widget->clearMask(); 1315 return false; 1316 } 1317 1318 case QEvent::Paint: { 1319 QPainter painter(widget); 1320 QPaintEvent *paintEvent = static_cast<QPaintEvent *>(event); 1321 painter.setClipRegion(paintEvent->region()); 1322 1323 const QRect rect(widget->rect()); 1324 const QColor color(widget->palette().color(widget->window()->backgroundRole())); 1325 const bool hasAlpha(_helper->hasAlphaChannel(widget)); 1326 1327 if (hasAlpha) { 1328 _helper->roundCorner(color).render(rect, &painter); 1329 painter.setCompositionMode(QPainter::CompositionMode_SourceOver); 1330 painter.setClipPath(_helper->roundedPath(insideMargin(rect, 1)), Qt::IntersectClip); 1331 } 1332 1333 // background 1334 _helper->renderMenuBackground(&painter, paintEvent->rect(), widget, widget->palette()); 1335 1336 // frame 1337 if (hasAlpha) 1338 painter.setClipping(false); 1339 1340 _helper->drawFloatFrame(&painter, rect, color, !hasAlpha); 1341 return false; 1342 } 1343 default: 1344 return false; 1345 } 1346 } 1347 1348 //____________________________________________________________________________ 1349 bool Style::eventFilterDockWidget(QDockWidget *dockWidget, QEvent *event) 1350 { 1351 switch (event->type()) { 1352 case QEvent::Show: 1353 case QEvent::Resize: { 1354 // make sure mask is appropriate 1355 if (dockWidget->isFloating()) 1356 dockWidget->setMask(_helper->roundedMask(dockWidget->size())); 1357 else 1358 dockWidget->clearMask(); 1359 return false; 1360 } 1361 1362 case QEvent::Paint: { 1363 QPainter painter(dockWidget); 1364 QPaintEvent *paintEvent = static_cast<QPaintEvent *>(event); 1365 painter.setClipRegion(paintEvent->region()); 1366 1367 const QColor color(dockWidget->palette().color(QPalette::Window)); 1368 const QRect rect(dockWidget->rect()); 1369 if (dockWidget->isWindow()) { 1370 _helper->renderWindowBackground(&painter, rect, dockWidget, color, 0); 1371 1372 #ifndef Q_WS_WIN 1373 _helper->drawFloatFrame(&painter, rect, color, !_helper->compositingActive()); 1374 #endif 1375 1376 } else { 1377 // need to draw window background for autoFilled dockWidgets for better rendering 1378 if (dockWidget->autoFillBackground()) { 1379 _helper->renderWindowBackground(&painter, rect, dockWidget, color); 1380 } 1381 1382 // adjust color 1383 QColor top(_helper->backgroundColor(color, dockWidget, rect.topLeft())); 1384 QColor bottom(_helper->backgroundColor(color, dockWidget, rect.bottomLeft())); 1385 _helper->dockFrame(top, bottom).render(rect, &painter); 1386 } 1387 1388 return false; 1389 } 1390 1391 default: 1392 return false; 1393 } 1394 } 1395 1396 //____________________________________________________________________________ 1397 bool Style::eventFilterMdiSubWindow(QMdiSubWindow *subWindow, QEvent *event) 1398 { 1399 if (event->type() == QEvent::Paint) { 1400 QPainter painter(subWindow); 1401 QRect clip(static_cast<QPaintEvent *>(event)->rect()); 1402 if (subWindow->isMaximized()) 1403 _helper->renderWindowBackground(&painter, clip, subWindow, subWindow->palette()); 1404 else { 1405 painter.setClipRect(clip); 1406 1407 const QRect rect(subWindow->rect()); 1408 _helper->roundCorner(subWindow->palette().color(subWindow->backgroundRole())).render(rect, &painter); 1409 1410 painter.setClipPath(_helper->roundedPath(insideMargin(rect, 1)), Qt::IntersectClip); 1411 _helper->renderWindowBackground(&painter, clip, subWindow, subWindow, subWindow->palette(), 0); 1412 } 1413 } 1414 1415 // continue with normal painting 1416 return false; 1417 } 1418 1419 //____________________________________________________________________________ 1420 bool Style::eventFilterCommandLinkButton(QCommandLinkButton *button, QEvent *event) 1421 { 1422 if (event->type() == QEvent::Paint) { 1423 // painter 1424 QPainter painter(button); 1425 painter.setClipRegion(static_cast<QPaintEvent *>(event)->region()); 1426 1427 const bool isFlat = false; 1428 1429 // option 1430 QStyleOptionButton option; 1431 option.initFrom(button); 1432 option.features |= QStyleOptionButton::CommandLinkButton; 1433 if (isFlat) 1434 option.features |= QStyleOptionButton::Flat; 1435 option.text = QString(); 1436 option.icon = QIcon(); 1437 1438 if (button->isChecked()) 1439 option.state |= State_On; 1440 if (button->isDown()) 1441 option.state |= State_Sunken; 1442 1443 // frame 1444 drawControl(QStyle::CE_PushButton, &option, &painter, button); 1445 1446 // offset 1447 const int margin(Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); 1448 QPoint offset(margin, margin); 1449 1450 // state 1451 const State &state(option.state); 1452 const bool enabled(state & State_Enabled); 1453 1454 // icon 1455 if (!button->icon().isNull()) { 1456 const QSize pixmapSize(button->icon().actualSize(button->iconSize())); 1457 const QRect pixmapRect(QPoint(offset.x(), button->description().isEmpty() ? (button->height() - pixmapSize.height()) / 2 : offset.y()), pixmapSize); 1458 const QPixmap pixmap(button->icon().pixmap(pixmapSize, enabled ? QIcon::Normal : QIcon::Disabled, button->isChecked() ? QIcon::On : QIcon::Off)); 1459 drawItemPixmap(&painter, pixmapRect, Qt::AlignCenter, pixmap); 1460 1461 offset.rx() += pixmapSize.width() + 4; 1462 } 1463 1464 // text rect 1465 QRect textRect(offset, QSize(button->size().width() - offset.x() - margin, button->size().height() - 2 * margin)); 1466 const QPalette::ColorRole textRole = QPalette::ButtonText; 1467 if (!button->text().isEmpty()) { 1468 QFont font(button->font()); 1469 font.setBold(true); 1470 painter.setFont(font); 1471 if (button->description().isEmpty()) { 1472 drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); 1473 1474 } else { 1475 drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextHideMnemonic, button->palette(), enabled, button->text(), textRole); 1476 textRect.setTop(textRect.top() + QFontMetrics(font).height()); 1477 } 1478 1479 painter.setFont(button->font()); 1480 } 1481 1482 if (!button->description().isEmpty()) { 1483 drawItemText(&painter, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, button->palette(), enabled, button->description(), textRole); 1484 } 1485 1486 return true; 1487 } 1488 1489 // continue with normal painting 1490 return false; 1491 } 1492 1493 //_________________________________________________________ 1494 bool Style::eventFilterScrollBar(QWidget *widget, QEvent *event) 1495 { 1496 if (event->type() == QEvent::Paint) { 1497 QPainter painter(widget); 1498 painter.setClipRegion(static_cast<QPaintEvent *>(event)->region()); 1499 _helper->renderWindowBackground(&painter, widget->rect(), widget, widget->palette()); 1500 } 1501 1502 return false; 1503 } 1504 1505 //_____________________________________________________________________ 1506 bool Style::eventFilterTabBar(QWidget *widget, QEvent *event) 1507 { 1508 if (event->type() == QEvent::Paint && _tabBarData->locks(widget)) { 1509 /* 1510 this makes sure that tabBar base is drawn ( and drawn only once ) 1511 every time a replaint is triggered by dragging a tab around 1512 */ 1513 _tabBarData->setDirty(); 1514 } 1515 1516 return false; 1517 } 1518 1519 //_____________________________________________________________________ 1520 bool Style::eventFilterToolBar(QToolBar *toolBar, QEvent *event) 1521 { 1522 switch (event->type()) { 1523 case QEvent::Show: 1524 case QEvent::Resize: { 1525 // make sure mask is appropriate 1526 if (toolBar->isFloating()) { 1527 // TODO: should not be needed 1528 toolBar->setMask(_helper->roundedMask(toolBar->size())); 1529 1530 } else 1531 toolBar->clearMask(); 1532 return false; 1533 } 1534 1535 case QEvent::Paint: { 1536 QPainter painter(toolBar); 1537 QPaintEvent *paintEvent = static_cast<QPaintEvent *>(event); 1538 painter.setClipRegion(paintEvent->region()); 1539 1540 const QRect rect(toolBar->rect()); 1541 const QColor color(toolBar->palette().window().color()); 1542 1543 // default painting when not qrealing 1544 if (!toolBar->isFloating()) { 1545 // background has to be rendered explicitly 1546 // when one of the parent has autofillBackground set to true 1547 if (_helper->checkAutoFillBackground(toolBar)) { 1548 _helper->renderWindowBackground(&painter, rect, toolBar, color, 0); 1549 } 1550 1551 return false; 1552 1553 } else { 1554 // background 1555 _helper->renderWindowBackground(&painter, rect, toolBar, color); 1556 1557 if (toolBar->isMovable()) { 1558 // remaining painting: need to add handle 1559 // this is copied from QToolBar::paintEvent 1560 QStyleOptionToolBar opt; 1561 opt.initFrom(toolBar); 1562 if (toolBar->orientation() == Qt::Horizontal) { 1563 opt.rect = visualRect(&opt, QRect(rect.topLeft(), QSize(8, rect.height()))); 1564 opt.state |= QStyle::State_Horizontal; 1565 1566 } else { 1567 opt.rect = visualRect(&opt, QRect(rect.topLeft(), QSize(rect.width(), 8))); 1568 } 1569 1570 drawPrimitive(PE_IndicatorToolBarHandle, &opt, &painter, toolBar); 1571 } 1572 1573 #ifndef Q_WS_WIN 1574 if (_helper->compositingActive()) 1575 _helper->drawFloatFrame(&painter, insideMargin(rect, -1), color, false); 1576 else 1577 _helper->drawFloatFrame(&painter, rect, color, true); 1578 #endif 1579 1580 // do not propagate 1581 return true; 1582 } 1583 } 1584 default: 1585 return false; 1586 } 1587 } 1588 1589 //____________________________________________________________________________ 1590 bool Style::eventFilterToolBox(QToolBox *toolBox, QEvent *event) 1591 { 1592 if (event->type() == QEvent::Paint) { 1593 if (toolBox->frameShape() != QFrame::NoFrame) { 1594 const QRect rect(toolBox->rect()); 1595 const StyleOptions styleOptions(NoFill); 1596 1597 QPainter painter(toolBox); 1598 painter.setClipRegion(static_cast<QPaintEvent *>(event)->region()); 1599 renderSlab(&painter, rect, toolBox->palette().color(QPalette::Button), styleOptions); 1600 } 1601 } 1602 1603 return false; 1604 } 1605 1606 //_____________________________________________________________________ 1607 void Style::configurationChanged() 1608 { 1609 // reload 1610 StyleConfigData::self()->load(); 1611 1612 _shadowHelper->reparseCacheConfig(); 1613 1614 _helper->invalidateCaches(); 1615 1616 loadConfiguration(); 1617 } 1618 1619 //____________________________________________________________________ 1620 QIcon Style::standardIconImplementation(StandardPixmap standardPixmap, const QStyleOption *option, const QWidget *widget) const 1621 { 1622 // MDI windows buttons 1623 // get button color ( unfortunately option and widget might not be set ) 1624 QColor buttonColor; 1625 QColor iconColor; 1626 if (option) { 1627 buttonColor = option->palette.window().color(); 1628 iconColor = option->palette.windowText().color(); 1629 1630 } else if (widget) { 1631 buttonColor = widget->palette().window().color(); 1632 iconColor = widget->palette().windowText().color(); 1633 1634 } else if (qApp) { 1635 // might not have a QApplication 1636 buttonColor = QPalette().window().color(); 1637 iconColor = QPalette().windowText().color(); 1638 1639 } else { 1640 // KCS is always safe 1641 buttonColor = KColorScheme(QPalette::Active, KColorScheme::Window, _helper->config()).background().color(); 1642 iconColor = KColorScheme(QPalette::Active, KColorScheme::Window, _helper->config()).foreground().color(); 1643 } 1644 1645 // contrast 1646 const QColor contrast(_helper->calcLightColor(buttonColor)); 1647 const int iconSize(pixelMetric(QStyle::PM_SmallIconSize)); 1648 const QRect rect(0, 0, iconSize, iconSize); 1649 1650 switch (standardPixmap) { 1651 case SP_TitleBarNormalButton: { 1652 QPixmap pixmap(_helper->highDpiPixmap(rect.size())); 1653 1654 pixmap.fill(Qt::transparent); 1655 1656 QPainter painter(&pixmap); 1657 renderTitleBarButton(&painter, rect, buttonColor, iconColor, SC_TitleBarNormalButton); 1658 1659 return QIcon(pixmap); 1660 } 1661 1662 case SP_TitleBarShadeButton: { 1663 QPixmap pixmap(_helper->highDpiPixmap(rect.size())); 1664 1665 pixmap.fill(Qt::transparent); 1666 QPainter painter(&pixmap); 1667 renderTitleBarButton(&painter, rect, buttonColor, iconColor, SC_TitleBarShadeButton); 1668 1669 return QIcon(pixmap); 1670 } 1671 1672 case SP_TitleBarUnshadeButton: { 1673 QPixmap pixmap(_helper->highDpiPixmap(rect.size())); 1674 1675 pixmap.fill(Qt::transparent); 1676 QPainter painter(&pixmap); 1677 renderTitleBarButton(&painter, rect, buttonColor, iconColor, SC_TitleBarUnshadeButton); 1678 1679 return QIcon(pixmap); 1680 } 1681 1682 case SP_TitleBarCloseButton: 1683 case SP_DockWidgetCloseButton: { 1684 QPixmap pixmap(_helper->highDpiPixmap(rect.size())); 1685 1686 pixmap.fill(Qt::transparent); 1687 QPainter painter(&pixmap); 1688 renderTitleBarButton(&painter, rect, buttonColor, iconColor, SC_TitleBarCloseButton); 1689 1690 return QIcon(pixmap); 1691 } 1692 1693 case SP_ToolBarHorizontalExtensionButton: { 1694 QIcon icon; 1695 1696 // default icon sizes 1697 for (const int iconSize : s_iconSizes) { 1698 QPixmap pixmap(iconSize, iconSize); 1699 pixmap.fill(Qt::transparent); 1700 QPainter painter(&pixmap); 1701 painter.setRenderHints(QPainter::Antialiasing); 1702 painter.setWindow(rect); 1703 painter.setBrush(Qt::NoBrush); 1704 1705 painter.translate(QRectF(rect).center()); 1706 1707 const bool reverseLayout(option && option->direction == Qt::RightToLeft); 1708 QPolygonF arrow = genericArrow(reverseLayout ? ArrowLeft : ArrowRight, ArrowTiny); 1709 1710 const qreal width(1.1); 1711 painter.translate(0, 0.5); 1712 painter.setBrush(Qt::NoBrush); 1713 painter.setPen(QPen(_helper->calcLightColor(buttonColor), width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 1714 painter.drawPolyline(arrow); 1715 1716 painter.translate(0, -1); 1717 painter.setBrush(Qt::NoBrush); 1718 painter.setPen(QPen(iconColor, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 1719 painter.drawPolyline(arrow); 1720 painter.end(); 1721 icon.addPixmap(pixmap); 1722 } 1723 1724 return icon; 1725 } 1726 1727 case SP_ToolBarVerticalExtensionButton: { 1728 QIcon icon; 1729 1730 // default icon sizes 1731 for (const int iconSize : s_iconSizes) { 1732 QPixmap pixmap(iconSize, iconSize); 1733 pixmap.fill(Qt::transparent); 1734 QPainter painter(&pixmap); 1735 painter.setRenderHints(QPainter::Antialiasing); 1736 painter.setWindow(rect); 1737 painter.setBrush(Qt::NoBrush); 1738 1739 painter.translate(QRectF(rect).center()); 1740 1741 QPolygonF arrow = genericArrow(ArrowDown, ArrowTiny); 1742 1743 const qreal width(1.1); 1744 painter.translate(0, 0.5); 1745 painter.setBrush(Qt::NoBrush); 1746 painter.setPen(QPen(_helper->calcLightColor(buttonColor), width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 1747 painter.drawPolyline(arrow); 1748 1749 painter.translate(0, -1); 1750 painter.setBrush(Qt::NoBrush); 1751 painter.setPen(QPen(iconColor, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 1752 painter.drawPolyline(arrow); 1753 painter.end(); 1754 1755 icon.addPixmap(pixmap); 1756 } 1757 1758 return icon; 1759 } 1760 1761 default: 1762 // do not cache parent style icon, since it may change at runtime 1763 return KStyle::standardIcon(standardPixmap, option, widget); 1764 } 1765 } 1766 1767 //_____________________________________________________________________ 1768 void Style::loadConfiguration() 1769 { 1770 // set helper configuration 1771 _helper->loadConfig(); 1772 1773 // background gradient 1774 _helper->setUseBackgroundGradient(StyleConfigData::useBackgroundGradient()); 1775 1776 // update top level window hints 1777 const auto topWidgets = qApp->topLevelWidgets(); 1778 for (QWidget *widget : topWidgets) { 1779 // make sure widget has a valid WId 1780 if (!(widget->testAttribute(Qt::WA_WState_Created) || widget->internalWinId())) 1781 continue; 1782 1783 // make sure widget has a decoration 1784 if (!_helper->hasDecoration(widget)) 1785 continue; 1786 1787 // update flags 1788 _helper->setHasBackgroundGradient(widget->winId(), true); 1789 } 1790 1791 // update caches size 1792 int cacheSize(StyleConfigData::cacheEnabled() ? StyleConfigData::maxCacheSize() : 0); 1793 1794 _helper->setMaxCacheSize(cacheSize); 1795 1796 // always enable blur helper 1797 _blurHelper->setEnabled(true); 1798 1799 // reinitialize engines 1800 _animations->setupEngines(); 1801 _transitions->setupEngines(); 1802 _windowManager->initialize(); 1803 _shadowHelper->loadConfig(); 1804 1805 // mnemonics 1806 _mnemonics->setMode(StyleConfigData::mnemonicsMode()); 1807 1808 // widget explorer 1809 _widgetExplorer->setEnabled(StyleConfigData::widgetExplorerEnabled()); 1810 _widgetExplorer->setDrawWidgetRects(StyleConfigData::drawWidgetRects()); 1811 1812 // splitter proxy 1813 _splitterFactory->setEnabled(StyleConfigData::splitterProxyEnabled()); 1814 1815 // scrollbar button dimentions. 1816 /* it has to be reinitialized here because scrollbar width might have changed */ 1817 _noButtonHeight = 0; 1818 _singleButtonHeight = qMax(StyleConfigData::scrollBarWidth() * 7 / 10, 14); 1819 _doubleButtonHeight = 2 * _singleButtonHeight; 1820 1821 // scrollbar buttons 1822 switch (StyleConfigData::scrollBarAddLineButtons()) { 1823 case 0: 1824 _addLineButtons = NoButton; 1825 break; 1826 case 1: 1827 _addLineButtons = SingleButton; 1828 break; 1829 1830 default: 1831 case 2: 1832 _addLineButtons = DoubleButton; 1833 break; 1834 } 1835 1836 switch (StyleConfigData::scrollBarSubLineButtons()) { 1837 case 0: 1838 _subLineButtons = NoButton; 1839 break; 1840 case 1: 1841 _subLineButtons = SingleButton; 1842 break; 1843 1844 default: 1845 case 2: 1846 _subLineButtons = DoubleButton; 1847 break; 1848 } 1849 1850 // frame focus 1851 if (StyleConfigData::viewDrawFocusIndicator()) 1852 _frameFocusPrimitive = &Style::drawFrameFocusRectPrimitive; 1853 else 1854 _frameFocusPrimitive = &Style::emptyPrimitive; 1855 } 1856 1857 //___________________________________________________________________________________________________________________ 1858 QRect Style::pushButtonContentsRect(const QStyleOption *option, const QWidget *) const 1859 { 1860 return insideMargin(option->rect, Metrics::Frame_FrameWidth); 1861 } 1862 1863 //___________________________________________________________________________________________________________________ 1864 QRect Style::checkBoxContentsRect(const QStyleOption *option, const QWidget *) const 1865 { 1866 return visualRect(option, option->rect.adjusted(Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0)); 1867 } 1868 1869 //___________________________________________________________________________________________________________________ 1870 QRect Style::lineEditContentsRect(const QStyleOption *option, const QWidget *widget) const 1871 { 1872 // cast option and check 1873 const QStyleOptionFrame *frameOption(qstyleoption_cast<const QStyleOptionFrame *>(option)); 1874 if (!frameOption) 1875 return option->rect; 1876 1877 // check flatness 1878 const bool flat(frameOption->lineWidth == 0); 1879 if (flat) 1880 return option->rect; 1881 1882 // copy rect and take out margins 1883 QRect rect(option->rect); 1884 1885 // take out margins if there is enough room 1886 const int frameWidth(pixelMetric(PM_DefaultFrameWidth, option, widget)); 1887 if (rect.height() > option->fontMetrics.height() + 2 * frameWidth) 1888 return insideMargin(rect, frameWidth); 1889 else 1890 return rect; 1891 } 1892 1893 //____________________________________________________________________ 1894 QRect Style::progressBarGrooveRect(const QStyleOption *option, const QWidget *) const 1895 { 1896 const QRect rect(option->rect); 1897 1898 const auto progressBarOption2(qstyleoption_cast<const QStyleOptionProgressBar *>(option)); 1899 const bool horizontal(!progressBarOption2 || progressBarOption2->state & QStyle::State_Horizontal); 1900 if (horizontal) 1901 return insideMargin(rect, 1, 0); 1902 else 1903 return insideMargin(rect, 0, 1); 1904 } 1905 1906 //____________________________________________________________________ 1907 QRect Style::progressBarContentsRect(const QStyleOption *option, const QWidget *widget) const 1908 { 1909 // cast option and check 1910 const QStyleOptionProgressBar *progressBarOption(qstyleoption_cast<const QStyleOptionProgressBar *>(option)); 1911 if (!progressBarOption) 1912 return QRect(); 1913 1914 // get orientation 1915 const auto progressBarOption2(qstyleoption_cast<const QStyleOptionProgressBar *>(option)); 1916 const bool horizontal(!progressBarOption2 || progressBarOption2->state & QStyle::State_Horizontal); 1917 1918 // check inverted appearance 1919 const bool inverted(progressBarOption2 ? progressBarOption2->invertedAppearance : false); 1920 1921 // get groove rect 1922 const QRect rect(progressBarGrooveRect(option, widget)); 1923 1924 // get progress 1925 qreal progress = progressBarOption->progress - progressBarOption->minimum; 1926 const bool busy = (progressBarOption->minimum == 0 && progressBarOption->maximum == 0); 1927 if (busy) 1928 progress = _animations->busyIndicatorEngine().value(); 1929 if (!(progress || busy)) 1930 return QRect(); 1931 1932 const int steps = qMax(progressBarOption->maximum - progressBarOption->minimum, 1); 1933 1934 // Calculate width fraction 1935 qreal widthFrac(busy ? qreal(Metrics::ProgressBar_BusyIndicatorSize) / 100 : progress / steps); 1936 widthFrac = qMin((qreal)1, widthFrac); 1937 1938 // And now the pixel width 1939 const int indicatorSize(widthFrac * (horizontal ? rect.width() : rect.height())); 1940 1941 // do nothing if indicator size is too small 1942 if (indicatorSize < 4) 1943 return QRect(); 1944 QRect indicatorRect; 1945 if (busy) { 1946 // The space around which we move around... 1947 int remSize = ((1 - widthFrac) * (horizontal ? rect.width() : rect.height())); 1948 remSize = qMax(remSize, 1); 1949 1950 int pstep = remSize * 2 * progress; 1951 if (pstep > remSize) { 1952 pstep = -(pstep - 2 * remSize); 1953 } 1954 1955 if (horizontal) { 1956 indicatorRect = QRect(inverted ? (rect.right() - pstep - indicatorSize + 1) : (rect.left() + pstep), rect.top(), indicatorSize, rect.height()); 1957 indicatorRect = visualRect(option->direction, rect, indicatorRect); 1958 1959 } else { 1960 indicatorRect = QRect(rect.left(), inverted ? (rect.bottom() - pstep - indicatorSize + 1) : (rect.top() + pstep), rect.width(), indicatorSize); 1961 } 1962 1963 } else { 1964 if (horizontal) { 1965 indicatorRect = QRect(inverted ? (rect.right() - indicatorSize + 1) : rect.left(), rect.top(), indicatorSize, rect.height()); 1966 indicatorRect = visualRect(option->direction, rect, indicatorRect); 1967 1968 } else { 1969 indicatorRect = QRect(rect.left(), inverted ? rect.top() : (rect.bottom() - indicatorSize + 1), rect.width(), indicatorSize); 1970 } 1971 } 1972 1973 // adjust 1974 return insideMargin(indicatorRect, 1); 1975 } 1976 1977 //___________________________________________________________________________________________________________________ 1978 QRect Style::headerArrowRect(const QStyleOption *option, const QWidget *) const 1979 { 1980 // cast option and check 1981 const QStyleOptionHeader *headerOption(qstyleoption_cast<const QStyleOptionHeader *>(option)); 1982 if (!headerOption) 1983 return option->rect; 1984 1985 // check if arrow is necessary 1986 if (headerOption->sortIndicator == QStyleOptionHeader::None) 1987 return QRect(); 1988 1989 QRect arrowRect(insideMargin(option->rect, Metrics::Header_MarginWidth)); 1990 arrowRect.setLeft(arrowRect.right() - Metrics::Header_ArrowSize + 1); 1991 1992 return visualRect(option, arrowRect); 1993 } 1994 1995 //___________________________________________________________________________________________________________________ 1996 QRect Style::headerLabelRect(const QStyleOption *option, const QWidget *) const 1997 { 1998 // cast option and check 1999 const QStyleOptionHeader *headerOption(qstyleoption_cast<const QStyleOptionHeader *>(option)); 2000 if (!headerOption) 2001 return option->rect; 2002 2003 // check if arrow is necessary 2004 // QRect labelRect( insideMargin( option->rect, Metrics::Header_MarginWidth ) ); 2005 QRect labelRect(insideMargin(option->rect, Metrics::Header_MarginWidth, 0)); 2006 if (headerOption->sortIndicator == QStyleOptionHeader::None) 2007 return labelRect; 2008 2009 labelRect.adjust(0, 0, -Metrics::Header_ArrowSize - Metrics::Header_ItemSpacing, 0); 2010 return visualRect(option, labelRect); 2011 } 2012 2013 //____________________________________________________________________ 2014 QRect Style::tabBarTabLeftButtonRect(const QStyleOption *option, const QWidget *) const 2015 { 2016 // cast option and check 2017 const auto tabOptionV3(qstyleoption_cast<const QStyleOptionTab *>(option)); 2018 if (!tabOptionV3 || tabOptionV3->leftButtonSize.isEmpty()) 2019 return QRect(); 2020 2021 const QRect rect(option->rect); 2022 const QSize size(tabOptionV3->leftButtonSize); 2023 QRect buttonRect(QPoint(0, 0), size); 2024 2025 // vertical positioning 2026 switch (tabOptionV3->shape) { 2027 case QTabBar::RoundedNorth: 2028 case QTabBar::TriangularNorth: 2029 2030 case QTabBar::RoundedSouth: 2031 case QTabBar::TriangularSouth: 2032 buttonRect.moveLeft(rect.left() + Metrics::TabBar_TabMarginWidth); 2033 buttonRect.moveTop((rect.height() - buttonRect.height()) / 2); 2034 buttonRect = visualRect(option, buttonRect); 2035 break; 2036 2037 case QTabBar::RoundedWest: 2038 case QTabBar::TriangularWest: 2039 buttonRect.moveBottom(rect.bottom() - Metrics::TabBar_TabMarginWidth); 2040 buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); 2041 break; 2042 2043 case QTabBar::RoundedEast: 2044 case QTabBar::TriangularEast: 2045 buttonRect.moveTop(rect.top() + Metrics::TabBar_TabMarginWidth); 2046 buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); 2047 break; 2048 2049 default: 2050 break; 2051 } 2052 2053 return buttonRect; 2054 } 2055 2056 //____________________________________________________________________ 2057 QRect Style::tabBarTabRightButtonRect(const QStyleOption *option, const QWidget *) const 2058 { 2059 // cast option and check 2060 const auto tabOptionV3(qstyleoption_cast<const QStyleOptionTab *>(option)); 2061 if (!tabOptionV3 || tabOptionV3->rightButtonSize.isEmpty()) 2062 return QRect(); 2063 2064 const QRect rect(option->rect); 2065 const QSize size(tabOptionV3->rightButtonSize); 2066 QRect buttonRect(QPoint(0, 0), size); 2067 2068 // vertical positioning 2069 switch (tabOptionV3->shape) { 2070 case QTabBar::RoundedNorth: 2071 case QTabBar::TriangularNorth: 2072 2073 case QTabBar::RoundedSouth: 2074 case QTabBar::TriangularSouth: 2075 buttonRect.moveRight(rect.right() - Metrics::TabBar_TabMarginWidth); 2076 buttonRect.moveTop((rect.height() - buttonRect.height()) / 2); 2077 buttonRect = visualRect(option, buttonRect); 2078 break; 2079 2080 case QTabBar::RoundedWest: 2081 case QTabBar::TriangularWest: 2082 buttonRect.moveTop(rect.top() + Metrics::TabBar_TabMarginWidth); 2083 buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); 2084 break; 2085 2086 case QTabBar::RoundedEast: 2087 case QTabBar::TriangularEast: 2088 buttonRect.moveBottom(rect.bottom() - Metrics::TabBar_TabMarginWidth); 2089 buttonRect.moveLeft((rect.width() - buttonRect.width()) / 2); 2090 break; 2091 2092 default: 2093 break; 2094 } 2095 2096 return buttonRect; 2097 } 2098 2099 //____________________________________________________________________ 2100 QRect Style::tabWidgetTabBarRect(const QStyleOption *option, const QWidget *widget) const 2101 { 2102 // cast option and check 2103 const QStyleOptionTabWidgetFrame *tabOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option); 2104 if (!tabOption) 2105 return KStyle::subElementRect(SE_TabWidgetTabBar, option, widget); 2106 2107 // do nothing if tabbar is hidden 2108 const QSize tabBarSize(tabOption->tabBarSize); 2109 2110 QRect rect(option->rect); 2111 QRect tabBarRect(QPoint(0, 0), tabBarSize); 2112 2113 // horizontal positioning 2114 const bool verticalTabs(isVerticalTab(tabOption->shape)); 2115 if (verticalTabs) { 2116 tabBarRect.setHeight(qMin(tabBarRect.height(), rect.height() - 2)); 2117 tabBarRect.moveTop(rect.top() + 1); 2118 2119 } else { 2120 // account for corner rects 2121 // need to re-run visualRect to remove right-to-left handling, since it is re-added on tabBarRect at the end 2122 const QRect leftButtonRect(visualRect(option, subElementRect(SE_TabWidgetLeftCorner, option, widget))); 2123 const QRect rightButtonRect(visualRect(option, subElementRect(SE_TabWidgetRightCorner, option, widget))); 2124 2125 rect.setLeft(leftButtonRect.width()); 2126 rect.setRight(rightButtonRect.left() - 1); 2127 2128 tabBarRect.setWidth(qMin(tabBarRect.width(), rect.width() - 2)); 2129 tabBarRect.moveLeft(rect.left() + 1); 2130 2131 tabBarRect = visualRect(option, tabBarRect); 2132 } 2133 2134 // vertical positioning 2135 switch (tabOption->shape) { 2136 case QTabBar::RoundedNorth: 2137 case QTabBar::TriangularNorth: 2138 tabBarRect.moveTop(rect.top() + 1); 2139 break; 2140 2141 case QTabBar::RoundedSouth: 2142 case QTabBar::TriangularSouth: 2143 tabBarRect.moveBottom(rect.bottom() - 1); 2144 break; 2145 2146 case QTabBar::RoundedWest: 2147 case QTabBar::TriangularWest: 2148 tabBarRect.moveLeft(rect.left() + 1); 2149 break; 2150 2151 case QTabBar::RoundedEast: 2152 case QTabBar::TriangularEast: 2153 tabBarRect.moveRight(rect.right() - 1); 2154 break; 2155 2156 default: 2157 break; 2158 } 2159 2160 return tabBarRect; 2161 } 2162 2163 //____________________________________________________________________ 2164 QRect Style::tabWidgetTabContentsRect(const QStyleOption *option, const QWidget *widget) const 2165 { 2166 // cast option and check 2167 const QStyleOptionTabWidgetFrame *tabOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option); 2168 if (!tabOption) 2169 return option->rect; 2170 2171 // do nothing if tabbar is hidden 2172 if (tabOption->tabBarSize.isEmpty()) 2173 return option->rect; 2174 const QRect rect = tabWidgetTabPaneRect(option, widget); 2175 2176 const bool documentMode(tabOption->lineWidth == 0); 2177 if (documentMode) { 2178 // add margin only to the relevant side 2179 switch (tabOption->shape) { 2180 case QTabBar::RoundedNorth: 2181 case QTabBar::TriangularNorth: 2182 return rect.adjusted(0, Metrics::TabWidget_MarginWidth, 0, 0); 2183 2184 case QTabBar::RoundedSouth: 2185 case QTabBar::TriangularSouth: 2186 return rect.adjusted(0, 0, 0, -Metrics::TabWidget_MarginWidth); 2187 2188 case QTabBar::RoundedWest: 2189 case QTabBar::TriangularWest: 2190 return rect.adjusted(Metrics::TabWidget_MarginWidth, 0, 0, 0); 2191 2192 case QTabBar::RoundedEast: 2193 case QTabBar::TriangularEast: 2194 return rect.adjusted(0, 0, -Metrics::TabWidget_MarginWidth, 0); 2195 2196 default: 2197 return rect; 2198 } 2199 2200 } else 2201 return insideMargin(rect, Metrics::TabWidget_MarginWidth); 2202 } 2203 2204 //____________________________________________________________________ 2205 QRect Style::tabWidgetTabPaneRect(const QStyleOption *option, const QWidget *) const 2206 { 2207 const QStyleOptionTabWidgetFrame *tabOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option); 2208 if (!tabOption || tabOption->tabBarSize.isEmpty()) 2209 return option->rect; 2210 2211 const int overlap = Metrics::TabBar_BaseOverlap - 1; 2212 const QSize tabBarSize(tabOption->tabBarSize - QSize(overlap, overlap)); 2213 2214 QRect rect(option->rect); 2215 switch (tabOption->shape) { 2216 case QTabBar::RoundedNorth: 2217 case QTabBar::TriangularNorth: 2218 rect.adjust(0, tabBarSize.height(), 0, 0); 2219 break; 2220 2221 case QTabBar::RoundedSouth: 2222 case QTabBar::TriangularSouth: 2223 rect.adjust(0, 0, 0, -tabBarSize.height()); 2224 break; 2225 2226 case QTabBar::RoundedWest: 2227 case QTabBar::TriangularWest: 2228 rect.adjust(tabBarSize.width(), 0, 0, 0); 2229 break; 2230 2231 case QTabBar::RoundedEast: 2232 case QTabBar::TriangularEast: 2233 rect.adjust(0, 0, -tabBarSize.width(), 0); 2234 break; 2235 2236 default: 2237 break; 2238 } 2239 2240 return rect; 2241 } 2242 2243 //____________________________________________________________________ 2244 QRect Style::tabWidgetCornerRect(SubElement element, const QStyleOption *option, const QWidget *widget) const 2245 { 2246 // cast option and check 2247 const QStyleOptionTabWidgetFrame *tabOption = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option); 2248 if (!tabOption) 2249 return QRect(); 2250 2251 // copy rect 2252 const QRect paneRect(subElementRect(SE_TabWidgetTabPane, option, widget)); 2253 QRect rect; 2254 2255 switch (element) { 2256 case SE_TabWidgetLeftCorner: 2257 rect = QRect(QPoint(0, 0), tabOption->leftCornerWidgetSize); 2258 break; 2259 2260 case SE_TabWidgetRightCorner: 2261 rect = QRect(QPoint(0, 0), tabOption->rightCornerWidgetSize); 2262 break; 2263 2264 default: 2265 break; 2266 } 2267 2268 if (element == SE_TabWidgetRightCorner) 2269 rect.moveRight(paneRect.right()); 2270 else 2271 rect.moveLeft(paneRect.left()); 2272 2273 switch (tabOption->shape) { 2274 case QTabBar::RoundedNorth: 2275 case QTabBar::TriangularNorth: 2276 rect.moveBottom(paneRect.top() - 1); 2277 rect.translate(0, 3); 2278 break; 2279 2280 case QTabBar::RoundedSouth: 2281 case QTabBar::TriangularSouth: 2282 rect.moveTop(paneRect.bottom() + 1); 2283 rect.translate(0, -3); 2284 break; 2285 2286 default: 2287 return QRect(); 2288 } 2289 2290 rect = visualRect(tabOption, rect); 2291 return rect; 2292 } 2293 2294 //____________________________________________________________________ 2295 QRect Style::toolBoxTabContentsRect(const QStyleOption *option, const QWidget *widget) const 2296 { 2297 // cast option and check 2298 const QStyleOptionToolBox *toolBoxOption(qstyleoption_cast<const QStyleOptionToolBox *>(option)); 2299 if (!toolBoxOption) 2300 return option->rect; 2301 2302 // copy rect 2303 const QRect &rect(option->rect); 2304 2305 int contentsWidth(0); 2306 if (!toolBoxOption->icon.isNull()) { 2307 const int iconSize(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); 2308 contentsWidth += iconSize; 2309 2310 if (!toolBoxOption->text.isEmpty()) 2311 contentsWidth += Metrics::ToolBox_TabItemSpacing; 2312 } 2313 2314 if (!toolBoxOption->text.isEmpty()) { 2315 const int textWidth = toolBoxOption->fontMetrics.size(_mnemonics->textFlags(), toolBoxOption->text).width(); 2316 contentsWidth += textWidth; 2317 } 2318 2319 contentsWidth = qMin(contentsWidth, rect.width()); 2320 contentsWidth = qMax(contentsWidth, int(Metrics::ToolBox_TabMinWidth)); 2321 return centerRect(rect, contentsWidth, rect.height()); 2322 } 2323 2324 //______________________________________________________________ 2325 QRect Style::groupBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2326 { 2327 QRect rect = option->rect; 2328 switch (subControl) { 2329 case SC_GroupBoxFrame: 2330 return rect; 2331 2332 case SC_GroupBoxContents: { 2333 // cast option and check 2334 const QStyleOptionGroupBox *groupBoxOption = qstyleoption_cast<const QStyleOptionGroupBox *>(option); 2335 if (!groupBoxOption) 2336 break; 2337 2338 // take out frame width 2339 rect = insideMargin(rect, Metrics::Frame_FrameWidth); 2340 2341 // get state 2342 const bool checkable(groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox); 2343 const bool emptyText(groupBoxOption->text.isEmpty()); 2344 2345 // calculate title height 2346 int titleHeight(0); 2347 if (!emptyText) 2348 titleHeight = groupBoxOption->fontMetrics.height(); 2349 if (checkable) 2350 titleHeight = qMax(titleHeight, int(Metrics::CheckBox_Size)); 2351 2352 // add margin 2353 if (titleHeight > 0) 2354 titleHeight += 2 * Metrics::GroupBox_TitleMarginWidth; 2355 2356 rect.adjust(0, titleHeight, 0, 0); 2357 return rect; 2358 } 2359 2360 case SC_GroupBoxCheckBox: 2361 case SC_GroupBoxLabel: { 2362 // cast option and check 2363 const QStyleOptionGroupBox *groupBoxOption = qstyleoption_cast<const QStyleOptionGroupBox *>(option); 2364 if (!groupBoxOption) 2365 break; 2366 2367 // take out frame width 2368 rect = insideMargin(rect, Metrics::Frame_FrameWidth); 2369 2370 const bool emptyText(groupBoxOption->text.isEmpty()); 2371 const bool checkable(groupBoxOption->subControls & QStyle::SC_GroupBoxCheckBox); 2372 2373 // calculate title height 2374 int titleHeight(0); 2375 int titleWidth(0); 2376 if (!emptyText) { 2377 const QFontMetrics fontMetrics = option->fontMetrics; 2378 titleHeight = qMax(titleHeight, fontMetrics.height()); 2379 titleWidth += fontMetrics.size(_mnemonics->textFlags(), groupBoxOption->text).width(); 2380 } 2381 2382 if (checkable) { 2383 titleHeight = qMax(titleHeight, int(Metrics::CheckBox_Size)); 2384 titleWidth += Metrics::CheckBox_Size; 2385 if (!emptyText) 2386 titleWidth += Metrics::CheckBox_ItemSpacing; 2387 } 2388 2389 // adjust height 2390 QRect titleRect(rect); 2391 titleRect.setHeight(titleHeight); 2392 titleRect.translate(0, Metrics::GroupBox_TitleMarginWidth); 2393 2394 // center 2395 titleRect = centerRect(titleRect, titleWidth, titleHeight); 2396 2397 if (subControl == SC_GroupBoxCheckBox) { 2398 // vertical centering 2399 titleRect = centerRect(titleRect, titleWidth, Metrics::CheckBox_Size); 2400 2401 // horizontal positioning 2402 const QRect subRect(titleRect.topLeft(), QSize(Metrics::CheckBox_Size, titleRect.height())); 2403 return visualRect(option->direction, titleRect, subRect); 2404 2405 } else { 2406 // vertical centering 2407 QFontMetrics fontMetrics = option->fontMetrics; 2408 titleRect = centerRect(titleRect, titleWidth, fontMetrics.height()); 2409 2410 // horizontal positioning 2411 QRect subRect(titleRect); 2412 if (checkable) 2413 subRect.adjust(Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing, 0, 0, 0); 2414 return visualRect(option->direction, titleRect, subRect); 2415 } 2416 } 2417 2418 default: 2419 break; 2420 } 2421 2422 return KStyle::subControlRect(CC_GroupBox, option, subControl, widget); 2423 } 2424 2425 //___________________________________________________________________________________________________________________ 2426 QRect Style::toolButtonSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2427 { 2428 // cast option and check 2429 const QStyleOptionToolButton *toolButtonOption = qstyleoption_cast<const QStyleOptionToolButton *>(option); 2430 if (!toolButtonOption) 2431 return KStyle::subControlRect(CC_ToolButton, option, subControl, widget); 2432 2433 const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); 2434 const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu 2435 && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); 2436 2437 // store rect 2438 const QRect &rect(option->rect); 2439 const int menuButtonWidth(Metrics::MenuButton_IndicatorWidth); 2440 switch (subControl) { 2441 case SC_ToolButtonMenu: { 2442 // check fratures 2443 if (!(hasPopupMenu || hasInlineIndicator)) 2444 return QRect(); 2445 2446 // check features 2447 QRect menuRect(rect); 2448 menuRect.setLeft(rect.right() - menuButtonWidth + 1); 2449 if (hasInlineIndicator) { 2450 menuRect.setTop(menuRect.bottom() - menuButtonWidth + 1); 2451 } 2452 2453 return visualRect(option, menuRect); 2454 } 2455 2456 case SC_ToolButton: { 2457 if (hasPopupMenu) { 2458 QRect contentsRect(rect); 2459 contentsRect.setRight(rect.right() - menuButtonWidth); 2460 return visualRect(option, contentsRect); 2461 2462 } else 2463 return rect; 2464 } 2465 2466 default: 2467 return QRect(); 2468 } 2469 } 2470 2471 //___________________________________________________________________________________________________________________ 2472 QRect Style::comboBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2473 { 2474 // cast option and check 2475 const QStyleOptionComboBox *comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); 2476 if (!comboBoxOption) 2477 return KStyle::subControlRect(CC_ComboBox, option, subControl, widget); 2478 2479 const bool editable(comboBoxOption->editable); 2480 const bool flat(editable && !comboBoxOption->frame); 2481 2482 // copy rect 2483 QRect rect(option->rect); 2484 2485 switch (subControl) { 2486 case SC_ComboBoxFrame: 2487 return flat ? rect : QRect(); 2488 case SC_ComboBoxListBoxPopup: 2489 return rect; 2490 2491 case SC_ComboBoxArrow: { 2492 // take out frame width 2493 if (!flat) 2494 rect = insideMargin(rect, Metrics::Frame_FrameWidth); 2495 2496 QRect arrowRect(rect.right() - Metrics::MenuButton_IndicatorWidth + 1, rect.top(), Metrics::MenuButton_IndicatorWidth, rect.height()); 2497 2498 arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); 2499 return visualRect(option, arrowRect); 2500 } 2501 2502 case SC_ComboBoxEditField: { 2503 QRect labelRect; 2504 const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); 2505 labelRect = QRect(rect.left(), rect.top(), rect.width() - Metrics::MenuButton_IndicatorWidth, rect.height()); 2506 2507 // remove margins 2508 if (!flat && rect.height() > option->fontMetrics.height() + 2 * frameWidth) { 2509 labelRect.adjust(frameWidth, frameWidth, 0, -frameWidth); 2510 } 2511 2512 return visualRect(option, labelRect); 2513 } 2514 2515 default: 2516 break; 2517 } 2518 2519 return KStyle::subControlRect(CC_ComboBox, option, subControl, widget); 2520 } 2521 2522 //___________________________________________________________________________________________________________________ 2523 QRect Style::spinBoxSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2524 { 2525 // cast option and check 2526 const QStyleOptionSpinBox *spinBoxOption(qstyleoption_cast<const QStyleOptionSpinBox *>(option)); 2527 if (!spinBoxOption) 2528 return KStyle::subControlRect(CC_SpinBox, option, subControl, widget); 2529 const bool flat(!spinBoxOption->frame); 2530 2531 // copy rect 2532 QRect rect(option->rect); 2533 2534 switch (subControl) { 2535 case SC_SpinBoxFrame: 2536 return flat ? QRect() : rect; 2537 2538 case SC_SpinBoxUp: 2539 case SC_SpinBoxDown: { 2540 // take out frame width 2541 if (!flat && rect.height() >= 2 * Metrics::Frame_FrameWidth + Metrics::SpinBox_ArrowButtonWidth) 2542 rect = insideMargin(rect, Metrics::Frame_FrameWidth); 2543 2544 QRect arrowRect; 2545 arrowRect = QRect(rect.right() - Metrics::SpinBox_ArrowButtonWidth + 1, rect.top(), Metrics::SpinBox_ArrowButtonWidth, rect.height()); 2546 2547 const int arrowHeight(qMin(rect.height(), int(Metrics::SpinBox_ArrowButtonWidth))); 2548 arrowRect = centerRect(arrowRect, Metrics::SpinBox_ArrowButtonWidth, arrowHeight); 2549 arrowRect.setHeight(arrowHeight / 2); 2550 if (subControl == SC_SpinBoxDown) 2551 arrowRect.translate(0, arrowHeight / 2); 2552 2553 return visualRect(option, arrowRect); 2554 } 2555 2556 case SC_SpinBoxEditField: { 2557 QRect labelRect; 2558 labelRect = QRect(rect.left(), rect.top(), rect.width() - Metrics::SpinBox_ArrowButtonWidth, rect.height()); 2559 2560 // remove right side line editor margins 2561 const int frameWidth(pixelMetric(PM_SpinBoxFrameWidth, option, widget)); 2562 if (!flat && labelRect.height() > option->fontMetrics.height() + 2 * frameWidth) { 2563 labelRect.adjust(frameWidth, frameWidth, 0, -frameWidth); 2564 } 2565 2566 return visualRect(option, labelRect); 2567 } 2568 2569 default: 2570 break; 2571 } 2572 2573 return KStyle::subControlRect(CC_SpinBox, option, subControl, widget); 2574 } 2575 2576 //___________________________________________________________________________________________________________________ 2577 QRect Style::scrollBarInternalSubControlRect(const QStyleOptionComplex *option, SubControl subControl) const 2578 { 2579 const QRect &rect = option->rect; 2580 const State &state(option->state); 2581 const bool horizontal(state & State_Horizontal); 2582 2583 switch (subControl) { 2584 case SC_ScrollBarSubLine: { 2585 int majorSize(scrollBarButtonHeight(_subLineButtons)); 2586 if (horizontal) 2587 return visualRect(option, QRect(rect.left(), rect.top(), majorSize, rect.height())); 2588 else 2589 return visualRect(option, QRect(rect.left(), rect.top(), rect.width(), majorSize)); 2590 } 2591 2592 case SC_ScrollBarAddLine: { 2593 int majorSize(scrollBarButtonHeight(_addLineButtons)); 2594 if (horizontal) 2595 return visualRect(option, QRect(rect.right() - majorSize + 1, rect.top(), majorSize, rect.height())); 2596 else 2597 return visualRect(option, QRect(rect.left(), rect.bottom() - majorSize + 1, rect.width(), majorSize)); 2598 } 2599 2600 default: 2601 return QRect(); 2602 } 2603 } 2604 2605 //___________________________________________________________________________________________________________________ 2606 QRect Style::scrollBarSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2607 { 2608 // cast option and check 2609 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 2610 if (!sliderOption) 2611 return KStyle::subControlRect(CC_ScrollBar, option, subControl, widget); 2612 2613 // get relevant state 2614 const State &state(option->state); 2615 const bool horizontal(state & State_Horizontal); 2616 2617 switch (subControl) { 2618 case SC_ScrollBarSubLine: 2619 case SC_ScrollBarAddLine: 2620 return scrollBarInternalSubControlRect(option, subControl); 2621 2622 case SC_ScrollBarGroove: { 2623 QRect topRect = visualRect(option, scrollBarInternalSubControlRect(option, SC_ScrollBarSubLine)); 2624 QRect bottomRect = visualRect(option, scrollBarInternalSubControlRect(option, SC_ScrollBarAddLine)); 2625 2626 QPoint topLeftCorner; 2627 QPoint botRightCorner; 2628 2629 if (horizontal) { 2630 topLeftCorner = QPoint(topRect.right() + 1, topRect.top()); 2631 botRightCorner = QPoint(bottomRect.left() - 1, topRect.bottom()); 2632 2633 } else { 2634 topLeftCorner = QPoint(topRect.left(), topRect.bottom() + 1); 2635 botRightCorner = QPoint(topRect.right(), bottomRect.top() - 1); 2636 } 2637 2638 // define rect 2639 return visualRect(option, QRect(topLeftCorner, botRightCorner)); 2640 } 2641 2642 case SC_ScrollBarSlider: { 2643 // We handle RTL here to unreflect things if need be 2644 QRect groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); 2645 2646 if (sliderOption->minimum == sliderOption->maximum) 2647 return groove; 2648 2649 // Figure out how much room we have.. 2650 int space(horizontal ? groove.width() : groove.height()); 2651 2652 // Calculate the portion of this space that the slider should take up. 2653 int sliderSize = space * qreal(sliderOption->pageStep) / (sliderOption->maximum - sliderOption->minimum + sliderOption->pageStep); 2654 sliderSize = qMax(sliderSize, static_cast<int>(Metrics::ScrollBar_MinSliderHeight)); 2655 sliderSize = qMin(sliderSize, space); 2656 2657 space -= sliderSize; 2658 if (space <= 0) 2659 return groove; 2660 2661 int pos = qRound(qreal(sliderOption->sliderPosition - sliderOption->minimum) / (sliderOption->maximum - sliderOption->minimum) * space); 2662 if (sliderOption->upsideDown) 2663 pos = space - pos; 2664 if (horizontal) 2665 return visualRect(option, QRect(groove.left() + pos, groove.top(), sliderSize, groove.height())); 2666 else 2667 return visualRect(option, QRect(groove.left(), groove.top() + pos, groove.width(), sliderSize)); 2668 } 2669 2670 case SC_ScrollBarSubPage: { 2671 // We do visualRect here to unreflect things if need be 2672 QRect slider = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget)); 2673 QRect groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); 2674 2675 if (horizontal) 2676 return visualRect(option, QRect(groove.left(), groove.top(), slider.left() - groove.left(), groove.height())); 2677 else 2678 return visualRect(option, QRect(groove.left(), groove.top(), groove.width(), slider.top() - groove.top())); 2679 } 2680 2681 case SC_ScrollBarAddPage: { 2682 // We do visualRect here to unreflect things if need be 2683 QRect slider = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget)); 2684 QRect groove = visualRect(option, subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); 2685 2686 if (horizontal) 2687 return visualRect(option, QRect(slider.right() + 1, groove.top(), groove.right() - slider.right(), groove.height())); 2688 else 2689 return visualRect(option, QRect(groove.left(), slider.bottom() + 1, groove.width(), groove.bottom() - slider.bottom())); 2690 } 2691 2692 default: 2693 return KStyle::subControlRect(CC_ScrollBar, option, subControl, widget); 2694 ; 2695 } 2696 } 2697 2698 //___________________________________________________________________________________________________________________ 2699 QRect Style::sliderSubControlRect(const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const 2700 { 2701 // cast option and check 2702 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 2703 if (!sliderOption) 2704 return KStyle::subControlRect(CC_Slider, option, subControl, widget); 2705 2706 switch (subControl) { 2707 case SC_SliderGroove: { 2708 // direction 2709 const bool horizontal(sliderOption->orientation == Qt::Horizontal); 2710 2711 // get base class rect 2712 QRect grooveRect(KStyle::subControlRect(CC_Slider, option, subControl, widget)); 2713 grooveRect = insideMargin(grooveRect, pixelMetric(PM_DefaultFrameWidth, option, widget)); 2714 2715 // centering 2716 if (horizontal) { 2717 grooveRect = centerRect(grooveRect, grooveRect.width(), Metrics::Slider_GrooveThickness); 2718 grooveRect = insideMargin(grooveRect, 3, 0); 2719 2720 } else { 2721 grooveRect = centerRect(grooveRect, Metrics::Slider_GrooveThickness, grooveRect.height()); 2722 grooveRect = insideMargin(grooveRect, 0, 3); 2723 } 2724 2725 return grooveRect; 2726 } 2727 2728 case SC_SliderHandle: { 2729 QRect handleRect(KStyle::subControlRect(CC_Slider, option, subControl, widget)); 2730 handleRect = centerRect(handleRect, Metrics::Slider_ControlThickness, Metrics::Slider_ControlThickness); 2731 return handleRect; 2732 } 2733 2734 default: 2735 return KStyle::subControlRect(CC_Slider, option, subControl, widget); 2736 } 2737 } 2738 2739 //______________________________________________________________ 2740 QSize Style::checkBoxSizeFromContents(const QStyleOption *, const QSize &contentsSize, const QWidget *) const 2741 { 2742 // get contents size 2743 QSize size(contentsSize); 2744 2745 // add focus height 2746 size = expandSize(size, 0, Metrics::CheckBox_FocusMarginWidth); 2747 2748 // make sure there is enough height for indicator 2749 size.setHeight(qMax(size.height(), int(Metrics::CheckBox_Size))); 2750 2751 // Add space for the indicator and the icon 2752 size.rwidth() += Metrics::CheckBox_Size + Metrics::CheckBox_ItemSpacing; 2753 2754 // also add extra space, to leave room to the right of the label 2755 size.rwidth() += Metrics::CheckBox_ItemSpacing; 2756 2757 return size; 2758 } 2759 2760 //______________________________________________________________ 2761 QSize Style::lineEditSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 2762 { 2763 // cast option and check 2764 const QStyleOptionFrame *frameOption(qstyleoption_cast<const QStyleOptionFrame *>(option)); 2765 if (!frameOption) 2766 return contentsSize; 2767 2768 const bool flat(frameOption->lineWidth == 0); 2769 const int frameWidth(pixelMetric(PM_DefaultFrameWidth, option, widget)); 2770 return flat ? contentsSize : expandSize(contentsSize, frameWidth); 2771 } 2772 2773 //______________________________________________________________ 2774 QSize Style::comboBoxSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 2775 { 2776 // cast option and check 2777 const QStyleOptionComboBox *comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); 2778 if (!comboBoxOption) 2779 return contentsSize; 2780 2781 // copy size 2782 QSize size(contentsSize); 2783 2784 // add relevant margin 2785 const bool flat(!comboBoxOption->frame); 2786 const int frameWidth(pixelMetric(PM_ComboBoxFrameWidth, option, widget)); 2787 if (!flat) 2788 size = expandSize(size, frameWidth); 2789 2790 // make sure there is enough height for the button 2791 size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); 2792 2793 // add button width and spacing 2794 size.rwidth() += Metrics::MenuButton_IndicatorWidth; 2795 2796 return size; 2797 } 2798 2799 //______________________________________________________________ 2800 QSize Style::spinBoxSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 2801 { 2802 // cast option and check 2803 const QStyleOptionSpinBox *spinBoxOption(qstyleoption_cast<const QStyleOptionSpinBox *>(option)); 2804 if (!spinBoxOption) 2805 return contentsSize; 2806 2807 const bool flat(!spinBoxOption->frame); 2808 2809 // copy size 2810 QSize size(contentsSize); 2811 2812 // add editor margins 2813 const int frameWidth(pixelMetric(PM_SpinBoxFrameWidth, option, widget)); 2814 if (!flat) 2815 size = expandSize(size, frameWidth); 2816 2817 // make sure there is enough height for the button 2818 size.setHeight(qMax(size.height(), int(Metrics::SpinBox_ArrowButtonWidth))); 2819 2820 // add button width and spacing 2821 size.rwidth() += Metrics::SpinBox_ArrowButtonWidth; 2822 2823 return size; 2824 } 2825 2826 //______________________________________________________________ 2827 QSize Style::sliderSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const 2828 { 2829 // cast option and check 2830 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 2831 if (!sliderOption) 2832 return contentsSize; 2833 2834 // store tick position and orientation 2835 const QSlider::TickPosition &tickPosition(sliderOption->tickPosition); 2836 const bool horizontal(sliderOption->orientation == Qt::Horizontal); 2837 const bool disableTicks(!StyleConfigData::sliderDrawTickMarks()); 2838 2839 /* 2840 Qt adds its own tick length directly inside QSlider. 2841 Take it out and replace by ours, if needed 2842 */ 2843 const int tickLength(disableTicks ? 0 2844 : (Metrics::Slider_TickLength + Metrics::Slider_TickMarginWidth 2845 + (Metrics::Slider_GrooveThickness - Metrics::Slider_ControlThickness) / 2)); 2846 2847 const int builtInTickLength(5); 2848 if (tickPosition == QSlider::NoTicks) 2849 return contentsSize; 2850 2851 QSize size(contentsSize); 2852 if (horizontal) { 2853 if (tickPosition & QSlider::TicksAbove) 2854 size.rheight() += tickLength - builtInTickLength; 2855 if (tickPosition & QSlider::TicksBelow) 2856 size.rheight() += tickLength - builtInTickLength; 2857 2858 } else { 2859 if (tickPosition & QSlider::TicksAbove) 2860 size.rwidth() += tickLength - builtInTickLength; 2861 if (tickPosition & QSlider::TicksBelow) 2862 size.rwidth() += tickLength - builtInTickLength; 2863 } 2864 2865 return size; 2866 } 2867 2868 //______________________________________________________________ 2869 QSize Style::pushButtonSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 2870 { 2871 // cast option and check 2872 const QStyleOptionButton *buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); 2873 if (!buttonOption) 2874 return contentsSize; 2875 2876 QSize size(contentsSize); 2877 2878 // add space for arrow 2879 if (buttonOption->features & QStyleOptionButton::HasMenu) { 2880 size.rheight() += 2 * Metrics::Button_MarginWidth; 2881 size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); 2882 size.rwidth() += Metrics::Button_MarginWidth; 2883 2884 if (!(buttonOption->icon.isNull() && buttonOption->text.isEmpty())) { 2885 size.rwidth() += Metrics::Button_ItemSpacing; 2886 } 2887 2888 } else 2889 size = expandSize(size, Metrics::Button_MarginWidth); 2890 2891 // add space for icon 2892 if (!buttonOption->icon.isNull()) { 2893 QSize iconSize = buttonOption->iconSize; 2894 if (!iconSize.isValid()) 2895 iconSize = QSize(pixelMetric(PM_SmallIconSize, option, widget), pixelMetric(PM_SmallIconSize, option, widget)); 2896 2897 size.setHeight(qMax(size.height(), iconSize.height())); 2898 2899 if (!buttonOption->text.isEmpty()) { 2900 size.rwidth() += Metrics::Button_ItemSpacing; 2901 } 2902 } 2903 2904 // make sure buttons have a minimum width 2905 if (!buttonOption->text.isEmpty()) { 2906 size.rwidth() = qMax(size.rwidth(), int(Metrics::Button_MinWidth)); 2907 } 2908 2909 // finally add margins 2910 return expandSize(size, Metrics::Frame_FrameWidth); 2911 } 2912 2913 //______________________________________________________________ 2914 QSize Style::toolButtonSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const 2915 { 2916 // cast option and check 2917 const QStyleOptionToolButton *toolButtonOption = qstyleoption_cast<const QStyleOptionToolButton *>(option); 2918 if (!toolButtonOption) 2919 return contentsSize; 2920 2921 // copy size 2922 QSize size = contentsSize; 2923 2924 // get relevant state flags 2925 const State &state(option->state); 2926 const bool autoRaise(state & State_AutoRaise); 2927 const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); 2928 const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu 2929 && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); 2930 2931 const int marginWidth(autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); 2932 2933 if (hasInlineIndicator) 2934 size.rwidth() += Metrics::ToolButton_InlineIndicatorWidth; 2935 size = expandSize(size, marginWidth); 2936 2937 return size; 2938 } 2939 2940 //______________________________________________________________ 2941 QSize Style::menuBarItemSizeFromContents(const QStyleOption *, const QSize &contentsSize, const QWidget *) const 2942 { 2943 return expandSize(contentsSize, Metrics::MenuBarItem_MarginWidth, Metrics::MenuBarItem_MarginHeight); 2944 } 2945 2946 //______________________________________________________________ 2947 QSize Style::menuItemSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 2948 { 2949 // cast option and check 2950 const QStyleOptionMenuItem *menuItemOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option); 2951 if (!menuItemOption) 2952 return contentsSize; 2953 2954 // First, we calculate the intrinsic size of the item. 2955 // this must be kept consistent with what's in drawMenuItemControl 2956 QSize size(contentsSize); 2957 switch (menuItemOption->menuItemType) { 2958 case QStyleOptionMenuItem::Normal: 2959 case QStyleOptionMenuItem::DefaultItem: 2960 case QStyleOptionMenuItem::SubMenu: { 2961 const int iconWidth(isQtQuickControl(option, widget) ? qMax(pixelMetric(PM_SmallIconSize, option, widget), menuItemOption->maxIconWidth) 2962 : menuItemOption->maxIconWidth); 2963 2964 int leftColumnWidth(iconWidth); 2965 2966 // add space with respect to text 2967 leftColumnWidth += Metrics::MenuItem_ItemSpacing; 2968 2969 // add checkbox indicator width 2970 if (menuItemOption->menuHasCheckableItems) { 2971 leftColumnWidth += Metrics::CheckBox_Size + Metrics::MenuItem_ItemSpacing; 2972 } 2973 2974 // add spacing for accelerator 2975 /* 2976 Note: 2977 The width of the accelerator itself is not included here since 2978 Qt will add that on separately after obtaining the 2979 sizeFromContents() for each menu item in the menu to be shown 2980 ( see QMenuPrivate::calcActionRects() ) 2981 */ 2982 const bool hasAccelerator(menuItemOption->text.indexOf(QLatin1Char('\t')) >= 0); 2983 if (hasAccelerator) 2984 size.rwidth() += Metrics::MenuItem_AcceleratorSpace; 2985 2986 // right column 2987 const int rightColumnWidth = Metrics::MenuButton_IndicatorWidth + Metrics::MenuItem_ItemSpacing; 2988 size.rwidth() += leftColumnWidth + rightColumnWidth; 2989 2990 // make sure height is large enough for icon and arrow 2991 size.setHeight(qMax(size.height(), int(Metrics::MenuButton_IndicatorWidth))); 2992 size.setHeight(qMax(size.height(), int(Metrics::CheckBox_Size))); 2993 size.setHeight(qMax(size.height(), iconWidth)); 2994 return expandSize(size, Metrics::MenuItem_MarginWidth); 2995 } 2996 2997 case QStyleOptionMenuItem::Separator: { 2998 if (menuItemOption->text.isEmpty() && menuItemOption->icon.isNull()) { 2999 return expandSize(QSize(0, 1), Metrics::MenuItem_MarginWidth); 3000 3001 } else { 3002 // build toolbutton option 3003 const QStyleOptionToolButton toolButtonOption(separatorMenuItemOption(menuItemOption, widget)); 3004 3005 // make sure height is large enough for icon and text 3006 const int iconWidth(qMax(pixelMetric(PM_SmallIconSize, option, widget), menuItemOption->maxIconWidth)); 3007 const int textHeight(menuItemOption->fontMetrics.height()); 3008 if (!menuItemOption->icon.isNull()) 3009 size.setHeight(qMax(size.height(), iconWidth)); 3010 if (!menuItemOption->text.isEmpty()) { 3011 size.setHeight(qMax(size.height(), textHeight)); 3012 size.setWidth(qMax(size.width(), menuItemOption->fontMetrics.horizontalAdvance(menuItemOption->text))); 3013 } 3014 3015 return sizeFromContents(CT_ToolButton, &toolButtonOption, size, widget); 3016 } 3017 } 3018 3019 // for all other cases, return input 3020 default: 3021 return contentsSize; 3022 } 3023 } 3024 3025 //______________________________________________________________ 3026 QSize Style::tabWidgetSizeFromContents(const QStyleOption *, const QSize &contentsSize, const QWidget *) const 3027 { 3028 return expandSize(contentsSize, Metrics::TabWidget_MarginWidth); 3029 } 3030 3031 //______________________________________________________________ 3032 QSize Style::tabBarTabSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const 3033 { 3034 const auto tabOption(qstyleoption_cast<const QStyleOptionTab *>(option)); 3035 const auto tabOptionV3(qstyleoption_cast<const QStyleOptionTab *>(option)); 3036 const bool hasText(tabOption && !tabOption->text.isEmpty()); 3037 const bool hasIcon(tabOption && !tabOption->icon.isNull()); 3038 const bool hasLeftButton(tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty()); 3039 const bool hasRightButton(tabOptionV3 && !tabOptionV3->leftButtonSize.isEmpty()); 3040 3041 // calculate width increment for horizontal tabs 3042 int widthIncrement = 0; 3043 if (hasIcon && !(hasText || hasLeftButton || hasRightButton)) 3044 widthIncrement -= 4; 3045 if (hasText && hasIcon) 3046 widthIncrement += Metrics::TabBar_TabItemSpacing; 3047 if (hasLeftButton && (hasText || hasIcon)) 3048 widthIncrement += Metrics::TabBar_TabItemSpacing; 3049 if (hasRightButton && (hasText || hasIcon || hasLeftButton)) 3050 widthIncrement += Metrics::TabBar_TabItemSpacing; 3051 3052 // add margins 3053 QSize size(contentsSize); 3054 3055 // compare to minimum size 3056 const bool verticalTabs(tabOption && isVerticalTab(tabOption)); 3057 if (verticalTabs) { 3058 size.rwidth() += 2 * Metrics::TabBar_TabOffset; 3059 size.rheight() += widthIncrement; 3060 if (hasIcon && !hasText) 3061 size = size.expandedTo(QSize(Metrics::TabBar_TabMinHeight, 0)); 3062 else 3063 size = size.expandedTo(QSize(Metrics::TabBar_TabMinHeight, Metrics::TabBar_TabMinWidth)); 3064 3065 } else { 3066 size.rheight() += 2 * Metrics::TabBar_TabOffset; 3067 size.rwidth() += widthIncrement; 3068 if (hasIcon && !hasText) 3069 size = size.expandedTo(QSize(0, Metrics::TabBar_TabMinHeight)); 3070 else 3071 size = size.expandedTo(QSize(Metrics::TabBar_TabMinWidth, Metrics::TabBar_TabMinHeight)); 3072 } 3073 3074 return size; 3075 } 3076 3077 //______________________________________________________________ 3078 QSize Style::headerSectionSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *) const 3079 { 3080 // cast option and check 3081 const QStyleOptionHeader *headerOption(qstyleoption_cast<const QStyleOptionHeader *>(option)); 3082 if (!headerOption) 3083 return contentsSize; 3084 3085 // get text size 3086 const bool horizontal(headerOption->orientation == Qt::Horizontal); 3087 const bool hasText(!headerOption->text.isEmpty()); 3088 const bool hasIcon(!headerOption->icon.isNull()); 3089 3090 const QSize textSize(hasText ? headerOption->fontMetrics.size(0, headerOption->text) : QSize()); 3091 const QSize iconSize(hasIcon ? QSize(22, 22) : QSize()); 3092 3093 // contents width 3094 int contentsWidth(0); 3095 if (hasText) 3096 contentsWidth += textSize.width(); 3097 if (hasIcon) { 3098 contentsWidth += iconSize.width(); 3099 if (hasText) 3100 contentsWidth += Metrics::Header_ItemSpacing; 3101 } 3102 3103 // contents height 3104 int contentsHeight(headerOption->fontMetrics.height()); 3105 if (hasIcon) 3106 contentsHeight = qMax(contentsHeight, iconSize.height()); 3107 3108 if (horizontal && headerOption->sortIndicator != QStyleOptionHeader::None) { 3109 // also add space for sort indicator 3110 contentsWidth += Metrics::Header_ArrowSize + Metrics::Header_ItemSpacing; 3111 contentsHeight = qMax(contentsHeight, int(Metrics::Header_ArrowSize)); 3112 } 3113 3114 // update contents size, add margins and return 3115 const QSize size(contentsSize.expandedTo(QSize(contentsWidth, contentsHeight))); 3116 return expandSize(size, Metrics::Header_MarginWidth); 3117 } 3118 3119 //______________________________________________________________ 3120 QSize Style::itemViewItemSizeFromContents(const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const 3121 { 3122 // call base class 3123 QSize size(KStyle::sizeFromContents(CT_ItemViewItem, option, contentsSize, widget)); 3124 3125 // add margins 3126 return expandSize(size, Metrics::ItemView_ItemMarginWidth); 3127 } 3128 3129 //___________________________________________________________________________________ 3130 bool Style::drawFramePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3131 { 3132 // copy rect and palette 3133 const QRect &rect(option->rect); 3134 const QPalette &palette(option->palette); 3135 3136 // store state 3137 const State &state(option->state); 3138 const bool enabled(state & State_Enabled); 3139 3140 const bool isInputWidget((widget && widget->testAttribute(Qt::WA_Hover)) 3141 || (isQtQuickControl(option, widget) && option->styleObject->property("elementType").toString() == QStringLiteral("edit"))); 3142 3143 const bool mouseOver(enabled && isInputWidget && (state & State_MouseOver)); 3144 const bool hasFocus(enabled && isInputWidget && (state & State_HasFocus)); 3145 3146 // assume focus takes precedence over hover 3147 _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus); 3148 _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver && !hasFocus); 3149 3150 if (state & State_Sunken) { 3151 // retrieve animation mode and opacity 3152 const AnimationMode mode(_animations->inputWidgetEngine().frameAnimationMode(widget)); 3153 const qreal opacity(_animations->inputWidgetEngine().frameOpacity(widget)); 3154 3155 if (_frameShadowFactory->isRegistered(widget)) { 3156 _frameShadowFactory->updateShadowsGeometry(widget, rect); 3157 _frameShadowFactory->updateState(widget, hasFocus, mouseOver, opacity, mode); 3158 3159 } else { 3160 StyleOptions options; 3161 if (hasFocus) 3162 options |= Focus; 3163 if (mouseOver) 3164 options |= Hover; 3165 3166 _helper->renderHole(painter, palette.color(QPalette::Window), rect, options, opacity, mode, TileSet::Ring); 3167 } 3168 3169 } else if (state & State_Raised) { 3170 const QRect local(rect); 3171 renderSlab(painter, rect, palette.color(QPalette::Window), NoFill); 3172 } 3173 3174 return true; 3175 } 3176 3177 //___________________________________________________________________________________ 3178 bool Style::drawFrameLineEditPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3179 { 3180 // copy rect and palette 3181 const QRect &rect(option->rect); 3182 const QPalette &palette(option->palette); 3183 3184 // make sure there is enough room to render frame 3185 if (rect.height() < 2 * Metrics::LineEdit_FrameWidth + option->fontMetrics.height()) { 3186 const QColor background(palette.color(QPalette::Base)); 3187 3188 painter->setPen(Qt::NoPen); 3189 painter->setBrush(background); 3190 painter->drawRect(rect); 3191 return true; 3192 3193 } else { 3194 // store state 3195 const State &state(option->state); 3196 const bool enabled(state & State_Enabled); 3197 const bool mouseOver(enabled && (state & State_MouseOver)); 3198 const bool hasFocus(enabled && (state & State_HasFocus)); 3199 3200 // assume focus takes precedence over hover 3201 _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus); 3202 _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver && !hasFocus); 3203 3204 // retrieve animation mode and opacity 3205 const AnimationMode mode(_animations->inputWidgetEngine().frameAnimationMode(widget)); 3206 const qreal opacity(_animations->inputWidgetEngine().frameOpacity(widget)); 3207 3208 // fill 3209 painter->setPen(Qt::NoPen); 3210 painter->setBrush(palette.color(QPalette::Base)); 3211 _helper->fillHole(*painter, rect); 3212 3213 // render hole 3214 StyleOptions options; 3215 if (hasFocus) 3216 options |= Focus; 3217 if (mouseOver) 3218 options |= Hover; 3219 _helper->renderHole(painter, palette.color(QPalette::Window), rect, options, opacity, mode, TileSet::Ring); 3220 } 3221 3222 return true; 3223 } 3224 3225 //___________________________________________________________________________________ 3226 bool Style::drawFrameFocusRectPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3227 { 3228 if (!widget) 3229 return true; 3230 3231 // no focus indicator on buttons, since it is rendered elsewhere 3232 if (qobject_cast<const QAbstractButton *>(widget)) { 3233 return true; 3234 } 3235 3236 const State &state(option->state); 3237 const QRect rect(option->rect.adjusted(0, 0, 0, 1)); 3238 const QPalette &palette(option->palette); 3239 3240 if (rect.width() < 10) 3241 return true; 3242 3243 const QColor outlineColor(state & State_Selected ? palette.color(QPalette::HighlightedText) : palette.color(QPalette::Highlight)); 3244 painter->setRenderHint(QPainter::Antialiasing, false); 3245 painter->setPen(outlineColor); 3246 painter->drawLine(rect.bottomLeft(), rect.bottomRight()); 3247 3248 return true; 3249 } 3250 3251 //___________________________________________________________________________________ 3252 bool Style::drawFrameMenuPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3253 { 3254 // only draw frame for ( expanded ) toolbars 3255 // do nothing for other cases 3256 if (qobject_cast<const QToolBar *>(widget)) { 3257 _helper->renderWindowBackground(painter, option->rect, widget, option->palette); 3258 _helper->drawFloatFrame(painter, option->rect, option->palette.window().color(), true); 3259 3260 } else if (isQtQuickControl(option, widget)) { 3261 // QtQuick Control case 3262 painter->fillRect(option->rect, option->palette.window()); 3263 _helper->drawFloatFrame(painter, option->rect, option->palette.window().color(), true); 3264 } 3265 3266 return true; 3267 } 3268 3269 //______________________________________________________________ 3270 bool Style::drawFrameGroupBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3271 { 3272 // cast option and check 3273 const auto frameOption(qstyleoption_cast<const QStyleOptionFrame *>(option)); 3274 if (!frameOption) 3275 return true; 3276 3277 // no frame for flat groupboxes 3278 if (frameOption->features & QStyleOptionFrame::Flat) 3279 return true; 3280 // normal frame 3281 const QPalette &palette(option->palette); 3282 const QRect &rect(option->rect); 3283 const QColor base(_helper->backgroundColor(palette.color(QPalette::Window), widget, rect.center())); 3284 3285 painter->save(); 3286 painter->setRenderHint(QPainter::Antialiasing); 3287 painter->setPen(Qt::NoPen); 3288 3289 QLinearGradient innerGradient(0, rect.top() - rect.height() + 12, 0, rect.bottom() + rect.height() - 19); 3290 QColor light(_helper->calcLightColor(base)); 3291 light.setAlphaF(0.4); 3292 innerGradient.setColorAt(0, light); 3293 light.setAlphaF(0); 3294 innerGradient.setColorAt(1, light); 3295 painter->setBrush(innerGradient); 3296 painter->setClipRect(rect.adjusted(0, 0, 0, -19)); 3297 _helper->fillSlab(*painter, rect); 3298 3299 painter->setClipping(false); 3300 _helper->slope(base, 0).render(rect, painter); 3301 3302 painter->restore(); 3303 return true; 3304 } 3305 3306 //___________________________________________________________________________________ 3307 bool Style::drawFrameTabWidgetPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 3308 { 3309 // cast option and check 3310 const QStyleOptionTabWidgetFrame *tabOption(qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)); 3311 if (!tabOption) 3312 return true; 3313 3314 // copy rect and palette 3315 const QRect &rect(option->rect); 3316 const QPalette &palette(option->palette); 3317 3318 const bool reverseLayout(option->direction == Qt::RightToLeft); 3319 3320 /* 3321 no frame is drawn when tabbar is empty. 3322 this is consistent with the tabWidgetTabContents subelementRect 3323 */ 3324 if (tabOption->tabBarSize.isEmpty()) 3325 return true; 3326 3327 // get tabbar dimensions 3328 const int width(tabOption->tabBarSize.width()); 3329 const int height(tabOption->tabBarSize.height()); 3330 3331 // left corner widget 3332 const int leftWidth(tabOption->leftCornerWidgetSize.width()); 3333 const int rightWidth(tabOption->rightCornerWidgetSize.width()); 3334 3335 // list of slabs to be drawn 3336 SlabRect::List slabs; 3337 3338 QRect baseSlabRect(rect); 3339 3340 // render the three free sides 3341 switch (tabOption->shape) { 3342 case QTabBar::RoundedNorth: 3343 case QTabBar::TriangularNorth: { 3344 // main slab 3345 slabs << SlabRect(baseSlabRect, (TileSet::Ring & ~TileSet::Top)); 3346 3347 // top 3348 if (reverseLayout) { 3349 // left side 3350 QRect slabRect(baseSlabRect); 3351 slabRect.setRight(qMax(slabRect.right() - width - leftWidth, slabRect.left() + rightWidth)); 3352 slabRect.setHeight(1); 3353 slabs << SlabRect(slabRect, TileSet::TopLeft).adjusted(TileSet::DefaultSize); 3354 3355 // right side 3356 if (rightWidth > 0) { 3357 QRect slabRect(baseSlabRect); 3358 slabRect.setLeft(slabRect.right() - rightWidth); 3359 slabRect.setHeight(1); 3360 slabs << SlabRect(slabRect, TileSet::TopRight).adjusted(TileSet::DefaultSize); 3361 } 3362 3363 } else { 3364 // left side 3365 if (leftWidth > 0) { 3366 QRect slabRect(baseSlabRect); 3367 slabRect.setRight(baseSlabRect.left() + leftWidth); 3368 slabRect.setHeight(1); 3369 slabs << SlabRect(slabRect, TileSet::TopLeft).adjusted(TileSet::DefaultSize); 3370 } 3371 3372 // right side 3373 QRect slabRect(baseSlabRect); 3374 slabRect.setLeft(qMin(slabRect.left() + width + leftWidth + 1, slabRect.right() - rightWidth)); 3375 slabRect.setHeight(1); 3376 slabs << SlabRect(slabRect, TileSet::TopRight).adjusted(TileSet::DefaultSize); 3377 } 3378 break; 3379 } 3380 3381 case QTabBar::RoundedSouth: 3382 case QTabBar::TriangularSouth: { 3383 slabs << SlabRect(baseSlabRect, TileSet::Ring & ~TileSet::Bottom); 3384 3385 if (reverseLayout) { 3386 // left side 3387 QRect slabRect(baseSlabRect); 3388 slabRect.setRight(qMax(slabRect.right() - width - leftWidth, slabRect.left() + rightWidth)); 3389 slabRect.setTop(slabRect.bottom()); 3390 slabs << SlabRect(slabRect, TileSet::BottomLeft).adjusted(TileSet::DefaultSize); 3391 3392 // right side 3393 if (rightWidth > 0) { 3394 QRect slabRect(baseSlabRect); 3395 slabRect.setLeft(slabRect.right() - rightWidth - TileSet::DefaultSize); 3396 slabRect.setTop(slabRect.bottom()); 3397 slabs << SlabRect(slabRect, TileSet::BottomRight).adjusted(TileSet::DefaultSize); 3398 } 3399 3400 } else { 3401 // left side 3402 if (leftWidth > 0) { 3403 QRect slabRect(baseSlabRect); 3404 slabRect.setRight(baseSlabRect.left() + leftWidth); 3405 slabRect.setTop(slabRect.bottom()); 3406 slabs << SlabRect(slabRect, TileSet::BottomLeft).adjusted(TileSet::DefaultSize); 3407 } 3408 3409 // right side 3410 QRect slabRect(baseSlabRect); 3411 slabRect.setLeft(qMin(slabRect.left() + width + leftWidth + 1, slabRect.right() - rightWidth)); 3412 slabRect.setTop(slabRect.bottom()); 3413 slabs << SlabRect(slabRect, TileSet::BottomRight).adjusted(TileSet::DefaultSize); 3414 } 3415 3416 break; 3417 } 3418 3419 case QTabBar::RoundedWest: 3420 case QTabBar::TriangularWest: { 3421 slabs << SlabRect(baseSlabRect, TileSet::Ring & ~TileSet::Left); 3422 3423 // bottom side 3424 QRect slabRect(baseSlabRect); 3425 slabRect.setTop(qMin(slabRect.top() + height, slabRect.bottom())); 3426 slabRect.setWidth(1); 3427 slabs << SlabRect(slabRect, TileSet::BottomLeft).adjusted(TileSet::DefaultSize); 3428 3429 break; 3430 } 3431 3432 case QTabBar::RoundedEast: 3433 case QTabBar::TriangularEast: { 3434 slabs << SlabRect(baseSlabRect, TileSet::Ring & ~TileSet::Right); 3435 3436 // bottom side 3437 QRect slabRect(baseSlabRect); 3438 slabRect.setTop(qMin(slabRect.top() + height, slabRect.bottom())); 3439 slabRect.setLeft(slabRect.right()); 3440 slabs << SlabRect(slabRect, TileSet::BottomRight).adjusted(TileSet::DefaultSize); 3441 break; 3442 } 3443 3444 break; 3445 3446 default: 3447 break; 3448 } 3449 3450 // render registered slabs 3451 for (const SlabRect &slab : std::as_const(slabs)) { 3452 renderSlab(painter, slab, palette.color(QPalette::Window), NoFill); 3453 } 3454 3455 return true; 3456 } 3457 3458 //___________________________________________________________________________________ 3459 bool Style::drawFrameTabBarBasePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 3460 { 3461 // tabbar frame used either for 'separate' tabbar, or in 'document mode' 3462 3463 // cast option and check 3464 const QStyleOptionTabBarBase *tabOption(qstyleoption_cast<const QStyleOptionTabBarBase *>(option)); 3465 if (!tabOption) 3466 return true; 3467 3468 if (tabOption->tabBarRect.isValid()) { 3469 // if tabBar rect is valid, all the frame is handled in tabBarTabShapeControl 3470 // nothing to be done here. 3471 // on the other hand, invalid tabBarRect corresponds to buttons in tabbars ( e.g. corner buttons ), 3472 // and the appropriate piece of frame needs to be drawn 3473 return true; 3474 } 3475 3476 // store palette and rect 3477 const QPalette &palette(option->palette); 3478 const QRect &rect(option->rect); 3479 3480 if (!rect.isValid()) 3481 return true; 3482 3483 QRect frameRect(rect); 3484 SlabRect slab; 3485 switch (tabOption->shape) { 3486 case QTabBar::RoundedNorth: 3487 case QTabBar::TriangularNorth: { 3488 frameRect = insideMargin(frameRect, -8, 0); 3489 frameRect.translate(0, 4); 3490 slab = SlabRect(frameRect, TileSet::Top); 3491 break; 3492 } 3493 3494 case QTabBar::RoundedSouth: 3495 case QTabBar::TriangularSouth: { 3496 frameRect = insideMargin(frameRect, -8, 0); 3497 frameRect.translate(0, -4); 3498 slab = SlabRect(frameRect, TileSet::Bottom); 3499 break; 3500 } 3501 3502 default: 3503 return true; 3504 } 3505 3506 // render registered slabs 3507 renderSlab(painter, slab, palette.color(QPalette::Window), NoFill); 3508 3509 return true; 3510 } 3511 3512 //___________________________________________________________________________________ 3513 bool Style::drawFrameWindowPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 3514 { 3515 // copy rect and palette 3516 const QRect &rect(option->rect); 3517 const QPalette &palette(option->palette); 3518 3519 // render 3520 _helper->drawFloatFrame(painter, rect, palette.window().color(), false); 3521 3522 return true; 3523 } 3524 3525 //___________________________________________________________________________________ 3526 bool Style::drawIndicatorArrowPrimitive(ArrowOrientation orientation, const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3527 { 3528 // store rect and palette 3529 const QRect &rect(option->rect); 3530 const QPalette &palette(option->palette); 3531 3532 // store state 3533 const State &state(option->state); 3534 const bool enabled(state & State_Enabled); 3535 bool mouseOver(enabled && (state & State_MouseOver)); 3536 bool hasFocus(enabled && (state & State_HasFocus)); 3537 3538 // detect special buttons 3539 const bool inTabBar(widget && qobject_cast<const QTabBar *>(widget->parentWidget())); 3540 const bool inToolButton(qstyleoption_cast<const QStyleOptionToolButton *>(option)); 3541 3542 // color 3543 QColor color; 3544 if (inTabBar) { 3545 // for tabbar arrows one uses animations to get the arrow color 3546 // get animation state 3547 /* there is no need to update the engine since this was already done when rendering the frame */ 3548 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 3549 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 3550 3551 StyleOptions styleOptions; 3552 if (mouseOver) 3553 styleOptions |= Hover; 3554 if (hasFocus) 3555 styleOptions |= Focus; 3556 3557 color = _helper->arrowColor(palette, styleOptions, opacity, mode); 3558 3559 } else if (mouseOver && !inToolButton) { 3560 color = _helper->hoverColor(palette); 3561 3562 } else if (inToolButton) { 3563 const bool flat(state & State_AutoRaise); 3564 3565 // cast option 3566 const QStyleOptionToolButton *toolButtonOption(static_cast<const QStyleOptionToolButton *>(option)); 3567 const bool hasPopupMenu(toolButtonOption->subControls & SC_ToolButtonMenu); 3568 if (flat && hasPopupMenu) { 3569 // for menu arrows in flat toolbutton one uses animations to get the arrow color 3570 // handle arrow over animation 3571 const bool arrowHover(mouseOver && (toolButtonOption->activeSubControls & SC_ToolButtonMenu)); 3572 _animations->toolButtonEngine().updateState(widget, AnimationHover, arrowHover); 3573 3574 const bool animated(_animations->toolButtonEngine().isAnimated(widget, AnimationHover)); 3575 const qreal opacity(_animations->toolButtonEngine().opacity(widget, AnimationHover)); 3576 3577 StyleOptions styleOptions; 3578 if (arrowHover) 3579 styleOptions |= Hover; 3580 3581 color = _helper->arrowColor(palette, styleOptions, opacity, animated ? AnimationHover : AnimationNone); 3582 3583 } else { 3584 color = palette.color(flat ? QPalette::WindowText : QPalette::ButtonText); 3585 } 3586 3587 } else 3588 color = palette.color(QPalette::WindowText); 3589 3590 // get arrow polygon 3591 const QPolygonF arrow = genericArrow(orientation, ArrowNormal); 3592 3593 const qreal penThickness = 1.6; 3594 const qreal offset(qMin(penThickness, qreal(1))); 3595 3596 painter->translate(QRectF(rect).center()); 3597 painter->setRenderHint(QPainter::Antialiasing); 3598 3599 painter->translate(0, offset); 3600 const QColor background = palette.color(QPalette::Window); 3601 painter->setPen(QPen(_helper->calcLightColor(background), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 3602 painter->drawPolyline(arrow); 3603 painter->translate(0, -offset); 3604 3605 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 3606 painter->drawPolyline(arrow); 3607 3608 return true; 3609 } 3610 3611 //___________________________________________________________________________________ 3612 bool Style::drawIndicatorHeaderArrowPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3613 { 3614 const QStyleOptionHeader *headerOption = qstyleoption_cast<const QStyleOptionHeader *>(option); 3615 const State &state(option->state); 3616 3617 // arrow orientation 3618 ArrowOrientation orientation(ArrowNone); 3619 if (state & State_UpArrow || (headerOption && headerOption->sortIndicator == QStyleOptionHeader::SortUp)) 3620 orientation = ArrowUp; 3621 else if (state & State_DownArrow || (headerOption && headerOption->sortIndicator == QStyleOptionHeader::SortDown)) 3622 orientation = ArrowDown; 3623 if (orientation == ArrowNone) 3624 return true; 3625 3626 // invert arrows if requested by (hidden) options 3627 if (StyleConfigData::viewInvertSortIndicator()) 3628 orientation = (orientation == ArrowUp) ? ArrowDown : ArrowUp; 3629 3630 // flags, rect and palette 3631 const QRect &rect(option->rect); 3632 const QPalette &palette(option->palette); 3633 const bool enabled(state & State_Enabled); 3634 const bool mouseOver(enabled && (state & State_MouseOver)); 3635 3636 _animations->headerViewEngine().updateState(widget, rect.topLeft(), mouseOver); 3637 const bool animated(enabled && _animations->headerViewEngine().isAnimated(widget, rect.topLeft())); 3638 3639 // define gradient and polygon for drawing arrow 3640 const QPolygonF arrow = genericArrow(orientation, ArrowNormal); 3641 QColor color = palette.color(QPalette::WindowText); 3642 const QColor background = palette.color(QPalette::Window); 3643 const QColor highlight(_helper->hoverColor(palette)); 3644 const qreal penThickness = 1.6; 3645 const qreal offset(qMin(penThickness, qreal(1))); 3646 3647 if (animated) { 3648 const qreal opacity(_animations->headerViewEngine().opacity(widget, rect.topLeft())); 3649 color = KColorUtils::mix(color, highlight, opacity); 3650 3651 } else if (mouseOver) 3652 color = highlight; 3653 3654 painter->translate(QRectF(rect).center()); 3655 painter->translate(0, 1); 3656 painter->setRenderHint(QPainter::Antialiasing); 3657 3658 painter->translate(0, offset); 3659 painter->setPen(QPen(_helper->calcLightColor(background), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 3660 painter->drawPolyline(arrow); 3661 painter->translate(0, -offset); 3662 3663 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 3664 painter->drawPolyline(arrow); 3665 3666 return true; 3667 } 3668 3669 //______________________________________________________________ 3670 bool Style::drawPanelButtonCommandPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3671 { 3672 // copy rect and palette 3673 const QRect &rect(option->rect); 3674 const QPalette &palette(option->palette); 3675 3676 // store state 3677 const State &state(option->state); 3678 const bool enabled(state & State_Enabled); 3679 const bool mouseOver(enabled && (state & State_MouseOver)); 3680 const bool hasFocus(enabled && (state & State_HasFocus) && !(widget && widget->focusProxy())); 3681 const bool sunken(state & (State_On | State_Sunken)); 3682 3683 StyleOptions styleOptions; 3684 if (sunken) 3685 styleOptions |= Sunken; 3686 if (hasFocus) 3687 styleOptions |= Focus; 3688 if (mouseOver) 3689 styleOptions |= Hover; 3690 3691 // update animation state 3692 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 3693 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 3694 3695 // store animation state 3696 AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 3697 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 3698 3699 // decide if widget must be rendered flat. 3700 /* 3701 The decision is made depending on 3702 - whether the "flat" flag is set in the option 3703 - whether the widget is hight enough to render both icons and normal margins 3704 Note: in principle one should also check for the button text height 3705 */ 3706 3707 const QStyleOptionButton *buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); 3708 bool flat = (buttonOption 3709 && (buttonOption->features.testFlag(QStyleOptionButton::Flat) 3710 || ((!buttonOption->icon.isNull()) && sizeFromContents(CT_PushButton, option, buttonOption->iconSize, widget).height() > rect.height()))); 3711 3712 if (flat) { 3713 if (!sunken) { 3714 const QColor glow(_helper->buttonGlowColor(palette, styleOptions, opacity, mode)); 3715 if (glow.isValid()) 3716 _helper->slitFocused(glow).render(rect, painter); 3717 3718 } else { 3719 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions, opacity, mode, TileSet::Ring); 3720 } 3721 3722 } else { 3723 // match color to the window background 3724 QColor buttonColor(_helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 3725 3726 // merge button color with highlight in case of default button 3727 if (enabled && buttonOption && (buttonOption->features & QStyleOptionButton::DefaultButton)) { 3728 const QColor tintColor(_helper->calcLightColor(buttonColor)); 3729 buttonColor = KColorUtils::mix(buttonColor, tintColor, 0.5); 3730 } 3731 3732 // disable animation for sunken buttons 3733 if (sunken) 3734 mode = AnimationNone; 3735 renderButtonSlab(painter, rect, buttonColor, styleOptions, opacity, mode, TileSet::Ring); 3736 } 3737 3738 return true; 3739 } 3740 3741 //______________________________________________________________ 3742 bool Style::drawPanelButtonToolPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3743 { 3744 // copy rect and palette 3745 const QRect &rect(option->rect); 3746 const QPalette &palette(option->palette); 3747 3748 // store state 3749 const State &state(option->state); 3750 const bool enabled(state & State_Enabled); 3751 const bool mouseOver(enabled && (state & State_MouseOver)); 3752 const bool hasFocus(enabled && (state & State_HasFocus)); 3753 const bool autoRaised(state & State_AutoRaise); 3754 const bool sunken(state & (State_On | State_Sunken)); 3755 3756 const bool reverseLayout(option->direction == Qt::RightToLeft); 3757 3758 // toolbar animation 3759 const bool isInToolBar(widget && qobject_cast<const QToolBar *>(widget->parent())); 3760 const bool toolBarAnimated( 3761 isInToolBar && widget 3762 && (_animations->toolBarEngine().isAnimated(widget->parentWidget()) || _animations->toolBarEngine().isFollowMouseAnimated(widget->parentWidget()))); 3763 const QRect animatedRect((isInToolBar && widget) ? _animations->toolBarEngine().animatedRect(widget->parentWidget()) : QRect()); 3764 const QRect childRect((widget && widget->parentWidget()) ? rect.translated(widget->mapToParent(QPoint(0, 0))) : QRect()); 3765 const QRect currentRect(widget ? _animations->toolBarEngine().currentRect(widget->parentWidget()) : QRect()); 3766 const bool current(isInToolBar && widget && widget->parentWidget() && currentRect.intersects(rect.translated(widget->mapToParent(QPoint(0, 0))))); 3767 3768 const bool toolBarTimerActive(isInToolBar && widget && _animations->toolBarEngine().isTimerActive(widget->parentWidget())); 3769 const qreal toolBarOpacity((isInToolBar && widget) ? _animations->toolBarEngine().opacity(widget->parentWidget()) : 0); 3770 3771 // normal animation state 3772 // no need to update, this was already done in drawToolButtonComplexControl 3773 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 3774 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 3775 3776 // style options 3777 StyleOptions styleOptions; 3778 if (sunken) 3779 styleOptions |= Sunken; 3780 if (hasFocus) 3781 styleOptions |= Focus; 3782 if (mouseOver) 3783 styleOptions |= Hover; 3784 3785 // non autoraised tool buttons get same slab as regular buttons 3786 if (!autoRaised) { 3787 TileSet::Tiles tiles(TileSet::Ring); 3788 3789 // adjust tiles and rect in case of menubutton 3790 const QToolButton *toolButton = qobject_cast<const QToolButton *>(widget); 3791 const bool hasPopupMenu(toolButton && toolButton->popupMode() == QToolButton::MenuButtonPopup); 3792 3793 if (hasPopupMenu) { 3794 if (reverseLayout) 3795 tiles &= ~TileSet::Left; 3796 else 3797 tiles &= ~TileSet::Right; 3798 } 3799 3800 // match button color to window background 3801 const QColor buttonColor(_helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 3802 3803 // render slab 3804 renderButtonSlab(painter, rect, buttonColor, styleOptions, opacity, mode, tiles); 3805 3806 return true; 3807 } 3808 3809 // normal ( auto-raised ) toolbuttons 3810 if (sunken) { 3811 // fill hole 3812 qreal holeOpacity = 1; 3813 const qreal bias = 0.75; 3814 if (mode == AnimationHover) 3815 holeOpacity = 1 - bias * opacity; 3816 else if (toolBarAnimated && enabled && animatedRect.isNull() && current) 3817 holeOpacity = 1 - bias * toolBarOpacity; 3818 else if (enabled && ((toolBarTimerActive && current) || mouseOver)) 3819 holeOpacity = 1 - bias; 3820 3821 if (holeOpacity > 0) { 3822 QColor color(_helper->backgroundColor(_helper->calcMidColor(palette.color(QPalette::Window)), widget, rect.center())); 3823 color = _helper->alphaColor(color, holeOpacity); 3824 painter->setRenderHint(QPainter::Antialiasing); 3825 painter->setPen(Qt::NoPen); 3826 painter->setBrush(color); 3827 painter->drawRoundedRect(insideMargin(rect, 1), 3.5, 3.5); 3828 } 3829 3830 styleOptions |= HoleContrast; 3831 if (mode != AnimationNone) { 3832 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions, opacity, mode, TileSet::Ring); 3833 3834 } else if (toolBarAnimated) { 3835 if (enabled && animatedRect.isNull() && current) { 3836 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions, toolBarOpacity, AnimationHover, TileSet::Ring); 3837 3838 } else { 3839 _helper->renderHole(painter, palette.color(QPalette::Window), rect, HoleContrast); 3840 } 3841 3842 } else if (toolBarTimerActive && current) { 3843 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions | Hover); 3844 3845 } else { 3846 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions); 3847 } 3848 3849 } else { 3850 const QColor glow(_helper->buttonGlowColor(palette, styleOptions, opacity, mode)); 3851 if (mode != AnimationNone) 3852 _helper->slitFocused(glow).render(rect, painter); 3853 else if (toolBarAnimated) { 3854 if (enabled && animatedRect.isNull() && current) { 3855 QColor glow(_helper->alphaColor(_helper->hoverColor(palette), toolBarOpacity)); 3856 _helper->slitFocused(glow).render(rect, painter); 3857 } 3858 3859 } else if (hasFocus || mouseOver) { 3860 _helper->slitFocused(glow).render(rect, painter); 3861 3862 } else if (toolBarTimerActive && current) { 3863 _helper->slitFocused(_helper->hoverColor(palette)).render(rect, painter); 3864 } 3865 } 3866 3867 return true; 3868 } 3869 3870 //______________________________________________________________ 3871 bool Style::drawTabBarPanelButtonToolPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3872 { 3873 const QPalette &palette(option->palette); 3874 QRect rect(option->rect); 3875 3876 // adjust rect depending on shape 3877 const QTabBar *tabBar(static_cast<const QTabBar *>(widget->parent())); 3878 switch (tabBar->shape()) { 3879 case QTabBar::RoundedNorth: 3880 case QTabBar::TriangularNorth: 3881 rect.adjust(0, 0, 0, -6); 3882 break; 3883 3884 case QTabBar::RoundedSouth: 3885 case QTabBar::TriangularSouth: 3886 rect.adjust(0, 6, 0, 0); 3887 break; 3888 3889 case QTabBar::RoundedWest: 3890 case QTabBar::TriangularWest: 3891 rect.adjust(0, 0, -6, 0); 3892 break; 3893 3894 case QTabBar::RoundedEast: 3895 case QTabBar::TriangularEast: 3896 rect.adjust(6, 0, 0, 0); 3897 break; 3898 3899 default: 3900 break; 3901 } 3902 3903 const QPalette local(widget->parentWidget() ? widget->parentWidget()->palette() : palette); 3904 3905 // check whether parent has autofill background flag 3906 const QWidget *parent = _helper->checkAutoFillBackground(widget); 3907 if (parent && !qobject_cast<const QDockWidget *>(parent)) 3908 painter->fillRect(rect, parent->palette().color(parent->backgroundRole())); 3909 else 3910 _helper->renderWindowBackground(painter, rect, widget, local); 3911 3912 return true; 3913 } 3914 3915 //___________________________________________________________________________________ 3916 bool Style::drawPanelScrollAreaCornerPrimitive(const QStyleOption *, QPainter *, const QWidget *widget) const 3917 { 3918 // disable painting of PE_PanelScrollAreaCorner 3919 // the default implementation fills the rect with the window background color 3920 // which does not work for windows that have gradients. 3921 // unfortunately, this does not work when scrollbars are children of QWebView, 3922 // in which case, false is returned, in order to fall back to the parent style implementation 3923 return !(widget && widget->inherits("QWebView")); 3924 } 3925 3926 //___________________________________________________________________________________ 3927 bool Style::drawPanelMenuPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3928 { 3929 // do nothing if menu is embedded in another widget 3930 // this corresponds to having a transparent background 3931 if (widget && !widget->isWindow()) 3932 return true; 3933 3934 // cast option and check 3935 const QStyleOptionMenuItem *menuItemOption(qstyleoption_cast<const QStyleOptionMenuItem *>(option)); 3936 if (!(menuItemOption && widget)) 3937 return true; 3938 3939 // copy rect and get color 3940 const QRect &rect = menuItemOption->rect; 3941 const QColor color = menuItemOption->palette.color(widget->window()->backgroundRole()); 3942 const bool hasAlpha(_helper->hasAlphaChannel(widget)); 3943 if (hasAlpha) { 3944 painter->setCompositionMode(QPainter::CompositionMode_Source); 3945 _helper->roundCorner(color).render(rect, painter); 3946 3947 painter->setCompositionMode(QPainter::CompositionMode_SourceOver); 3948 painter->setClipPath(_helper->roundedPath(insideMargin(rect, 1)), Qt::IntersectClip); 3949 } 3950 3951 _helper->renderMenuBackground(painter, rect, widget, menuItemOption->palette); 3952 3953 if (hasAlpha) 3954 painter->setClipping(false); 3955 _helper->drawFloatFrame(painter, rect, color, !hasAlpha); 3956 3957 return true; 3958 } 3959 3960 //___________________________________________________________________________________ 3961 bool Style::drawPanelTipLabelPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 3962 { 3963 // force registration of widget 3964 if (widget && widget->window()) { 3965 _shadowHelper->registerWidget(widget->window(), true); 3966 } 3967 3968 const QRect &rect(option->rect); 3969 const QColor color(option->palette.brush(QPalette::ToolTipBase).color()); 3970 QColor topColor(_helper->backgroundTopColor(color)); 3971 QColor bottomColor(_helper->backgroundBottomColor(color)); 3972 3973 // make tooltip semi transparents when possible 3974 // alpha is copied from "kdebase/apps/dolphin/tooltips/filemetadatatooltip.cpp" 3975 const bool hasAlpha(_helper->hasAlphaChannel(widget)); 3976 if (hasAlpha && StyleConfigData::toolTipTransparent()) { 3977 if (widget && widget->window()) { 3978 _blurHelper->registerWidget(widget->window()); 3979 } 3980 topColor.setAlpha(220); 3981 bottomColor.setAlpha(220); 3982 } 3983 3984 QLinearGradient gradient(0, rect.top(), 0, rect.bottom()); 3985 gradient.setColorAt(0, topColor); 3986 gradient.setColorAt(1, bottomColor); 3987 3988 // contrast pixmap 3989 QLinearGradient gradient2(0, rect.top(), 0, rect.bottom()); 3990 gradient2.setColorAt(0.5, _helper->calcLightColor(bottomColor)); 3991 gradient2.setColorAt(0.9, bottomColor); 3992 3993 painter->save(); 3994 3995 if (hasAlpha) { 3996 painter->setRenderHint(QPainter::Antialiasing); 3997 3998 QRectF local(rect); 3999 local.adjust(0.5, 0.5, -0.5, -0.5); 4000 4001 painter->setPen(Qt::NoPen); 4002 painter->setBrush(gradient); 4003 painter->drawRoundedRect(local, 4, 4); 4004 4005 painter->setBrush(Qt::NoBrush); 4006 painter->setPen(QPen(gradient2, 1.1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 4007 painter->drawRoundedRect(local, 3.5, 3.5); 4008 4009 } else { 4010 painter->setPen(Qt::NoPen); 4011 painter->setBrush(gradient); 4012 painter->drawRect(rect); 4013 4014 painter->setBrush(Qt::NoBrush); 4015 painter->setPen(QPen(gradient2, 1.1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 4016 painter->drawRect(rect); 4017 } 4018 4019 painter->restore(); 4020 4021 return true; 4022 } 4023 4024 //___________________________________________________________________________________ 4025 bool Style::drawPanelItemViewItemPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4026 { 4027 // cast option and check 4028 const auto viewItemOption = qstyleoption_cast<const QStyleOptionViewItem *>(option); 4029 4030 if (!viewItemOption) 4031 return false; 4032 4033 // try cast widget 4034 const auto view = qobject_cast<const QAbstractItemView *>(widget); 4035 4036 // store palette and rect 4037 const auto &palette(option->palette); 4038 QRect rect(option->rect); 4039 4040 // store flags 4041 const State &state(option->state); 4042 const bool mouseOver((state & State_MouseOver) && (!view || view->selectionMode() != QAbstractItemView::NoSelection)); 4043 const bool selected(state & State_Selected); 4044 const bool enabled(state & State_Enabled); 4045 const bool active(state & State_Active); 4046 const bool hasCustomBackground(viewItemOption->backgroundBrush.style() != Qt::NoBrush && !selected); 4047 const bool hasSolidBackground(!hasCustomBackground || viewItemOption->backgroundBrush.style() == Qt::SolidPattern); 4048 4049 if (!mouseOver && !selected && !hasCustomBackground && !(viewItemOption->features & QStyleOptionViewItem::Alternate)) { 4050 return true; 4051 } 4052 4053 QPalette::ColorGroup colorGroup; 4054 if (enabled) 4055 colorGroup = active ? QPalette::Normal : QPalette::Inactive; 4056 else 4057 colorGroup = QPalette::Disabled; 4058 4059 QColor color; 4060 if (hasCustomBackground && hasSolidBackground) 4061 color = viewItemOption->backgroundBrush.color(); 4062 else 4063 color = palette.color(colorGroup, QPalette::Highlight); 4064 4065 if (mouseOver && !hasCustomBackground) { 4066 if (!selected) 4067 color.setAlphaF(0.2); 4068 else 4069 color = color.lighter(110); 4070 } 4071 4072 if (viewItemOption && (viewItemOption->features & QStyleOptionViewItem::Alternate)) { 4073 painter->fillRect(option->rect, palette.brush(colorGroup, QPalette::AlternateBase)); 4074 } 4075 4076 if (!mouseOver && !selected && !hasCustomBackground) { 4077 return true; 4078 } 4079 4080 if (hasCustomBackground && !hasSolidBackground) { 4081 const QPointF oldBrushOrigin = painter->brushOrigin(); 4082 painter->setBrushOrigin(viewItemOption->rect.topLeft()); 4083 painter->setBrush(viewItemOption->backgroundBrush); 4084 painter->setPen(Qt::NoPen); 4085 painter->drawRect(viewItemOption->rect); 4086 painter->setBrushOrigin(oldBrushOrigin); 4087 4088 } else { 4089 // get selection tileset 4090 TileSet tileSet(_helper->selection(color, rect.height(), hasCustomBackground)); 4091 4092 bool roundedLeft = false; 4093 bool roundedRight = false; 4094 if (viewItemOption) { 4095 roundedLeft = (viewItemOption->viewItemPosition == QStyleOptionViewItem::Beginning); 4096 roundedRight = (viewItemOption->viewItemPosition == QStyleOptionViewItem::End); 4097 4098 if (viewItemOption->viewItemPosition == QStyleOptionViewItem::OnlyOne || viewItemOption->viewItemPosition == QStyleOptionViewItem::Invalid 4099 || (view && view->selectionBehavior() != QAbstractItemView::SelectRows)) { 4100 roundedLeft = true; 4101 roundedRight = true; 4102 } 4103 } 4104 4105 const bool reverseLayout(option->direction == Qt::RightToLeft); 4106 4107 // define tiles 4108 TileSet::Tiles tiles(TileSet::Center); 4109 if (!reverseLayout ? roundedLeft : roundedRight) 4110 tiles |= TileSet::Left; 4111 if (!reverseLayout ? roundedRight : roundedLeft) 4112 tiles |= TileSet::Right; 4113 4114 // adjust rect and render 4115 rect = tileSet.adjust(rect, tiles); 4116 if (rect.isValid()) 4117 tileSet.render(rect, painter, tiles); 4118 } 4119 4120 return true; 4121 } 4122 4123 //___________________________________________________________________________________ 4124 bool Style::drawIndicatorMenuCheckMarkPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 4125 { 4126 const QRect &rect(option->rect); 4127 const State &state(option->state); 4128 const QPalette &palette(option->palette); 4129 const bool enabled(state & State_Enabled); 4130 4131 StyleOptions styleOptions(NoFill); 4132 if (!enabled) 4133 styleOptions |= Disabled; 4134 4135 renderCheckBox(painter, rect, palette, styleOptions, CheckOn); 4136 return true; 4137 } 4138 4139 //___________________________________________________________________________________ 4140 bool Style::drawIndicatorCheckBoxPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4141 { 4142 // get rect 4143 const QRect &rect(option->rect); 4144 const State &state(option->state); 4145 const bool enabled(state & State_Enabled); 4146 const bool mouseOver(enabled && (state & State_MouseOver)); 4147 const bool hasFocus(enabled && (state & State_HasFocus)); 4148 4149 StyleOptions styleOptions; 4150 if (!enabled) 4151 styleOptions |= Disabled; 4152 if (mouseOver) 4153 styleOptions |= Hover; 4154 if (hasFocus) 4155 styleOptions |= Focus; 4156 4157 // get checkbox state 4158 CheckBoxState checkBoxState; 4159 if (state & State_NoChange) 4160 checkBoxState = CheckTriState; 4161 else if (state & State_Sunken) 4162 checkBoxState = CheckSunken; 4163 else if (state & State_On) 4164 checkBoxState = CheckOn; 4165 else 4166 checkBoxState = CheckOff; 4167 4168 // match button color to window background 4169 QPalette palette(option->palette); 4170 palette.setColor(QPalette::Button, _helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 4171 4172 // animation state: mouseOver has precedence over focus 4173 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 4174 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 4175 4176 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 4177 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 4178 renderCheckBox(painter, rect, palette, styleOptions, checkBoxState, opacity, mode); 4179 4180 return true; 4181 } 4182 4183 //___________________________________________________________________________________ 4184 bool Style::drawIndicatorRadioButtonPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4185 { 4186 // copy rect 4187 const QRect &rect(option->rect); 4188 4189 // store state 4190 const State &state(option->state); 4191 const bool enabled(state & State_Enabled); 4192 const bool mouseOver(enabled && (state & State_MouseOver)); 4193 const bool hasFocus(state & State_HasFocus); 4194 4195 StyleOptions styleOptions; 4196 if (!enabled) 4197 styleOptions |= Disabled; 4198 if (mouseOver) 4199 styleOptions |= Hover; 4200 if (hasFocus) 4201 styleOptions |= Focus; 4202 4203 CheckBoxState checkBoxState; 4204 if (state & State_Sunken) 4205 checkBoxState = CheckSunken; 4206 else if (state & State_On) 4207 checkBoxState = CheckOn; 4208 else 4209 checkBoxState = CheckOff; 4210 4211 // match button color to window background 4212 QPalette palette(option->palette); 4213 palette.setColor(QPalette::Button, _helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 4214 4215 // animation state: mouseOver has precedence over focus 4216 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 4217 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 4218 4219 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 4220 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 4221 renderRadioButton(painter, rect, palette, styleOptions, checkBoxState, opacity, mode); 4222 4223 return true; 4224 } 4225 4226 //___________________________________________________________________________________ 4227 bool Style::drawIndicatorButtonDropDownPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4228 { 4229 // cast option and check 4230 const QStyleOptionToolButton *toolButtonOption(qstyleoption_cast<const QStyleOptionToolButton *>(option)); 4231 if (!toolButtonOption) 4232 return true; 4233 4234 // copy palette and rect 4235 const QPalette &palette(option->palette); 4236 const QRect &rect(option->rect); 4237 4238 // store state 4239 const State &state(option->state); 4240 const bool autoRaise(state & State_AutoRaise); 4241 4242 // do nothing for autoraise buttons 4243 if (autoRaise || !(toolButtonOption->subControls & SC_ToolButtonMenu)) 4244 return true; 4245 4246 // store state 4247 const bool enabled(state & State_Enabled); 4248 const bool hasFocus(enabled && (state & State_HasFocus)); 4249 const bool mouseOver(enabled && (state & State_MouseOver)); 4250 const bool sunken(enabled && (state & State_Sunken)); 4251 const bool reverseLayout(option->direction == Qt::RightToLeft); 4252 4253 // match button color to window background 4254 const QColor highlight(_helper->hoverColor(palette)); 4255 const QColor background(_helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 4256 StyleOptions styleOptions; 4257 if (hasFocus) 4258 styleOptions |= Focus; 4259 if (mouseOver) 4260 styleOptions |= Hover; 4261 4262 // update animation state 4263 // mouse over takes precedence over focus 4264 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 4265 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 4266 4267 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 4268 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 4269 4270 // paint frame 4271 TileSet::Tiles tiles(TileSet::Ring); 4272 if (state & (State_On | State_Sunken)) 4273 styleOptions |= Sunken; 4274 if (reverseLayout) 4275 tiles &= ~TileSet::Right; 4276 else 4277 tiles &= ~TileSet::Left; 4278 4279 painter->setClipRect(rect, Qt::IntersectClip); 4280 renderButtonSlab(painter, rect, background, styleOptions, opacity, mode, tiles); 4281 4282 // draw separating vertical line 4283 const QColor color(palette.color(QPalette::Button)); 4284 const QColor light = _helper->alphaColor(_helper->calcLightColor(color), 0.6); 4285 QColor dark = _helper->calcDarkColor(color); 4286 dark.setAlpha(200); 4287 4288 const int top(rect.top() + (sunken ? 3 : 2)); 4289 const int bottom(rect.bottom() - 4); 4290 4291 painter->setPen(QPen(light, 1)); 4292 4293 if (reverseLayout) { 4294 painter->drawLine(rect.right() + 1, top + 1, rect.right() + 1, bottom); 4295 painter->drawLine(rect.right() - 1, top + 2, rect.right() - 1, bottom); 4296 painter->setPen(dark); 4297 painter->drawLine(rect.right(), top, rect.right(), bottom); 4298 4299 } else { 4300 painter->drawLine(rect.left() - 1, top + 1, rect.left() - 1, bottom - 1); 4301 painter->drawLine(rect.left() + 1, top + 1, rect.left() + 1, bottom - 1); 4302 painter->setPen(dark); 4303 painter->drawLine(rect.left(), top, rect.left(), bottom); 4304 } 4305 4306 return true; 4307 } 4308 4309 //___________________________________________________________________________________ 4310 bool Style::drawIndicatorTabClosePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 4311 { 4312 if (_tabCloseIcon.isNull()) { 4313 // load the icon on-demand: in the constructor, KDE is not yet ready to find it! 4314 _tabCloseIcon = QIcon::fromTheme(QStringLiteral("dialog-close")); 4315 if (_tabCloseIcon.isNull()) 4316 return false; 4317 } 4318 4319 const int size(pixelMetric(QStyle::PM_SmallIconSize)); 4320 QIcon::Mode mode; 4321 if (option->state & State_Enabled) { 4322 if (option->state & State_Raised) 4323 mode = QIcon::Active; 4324 else 4325 mode = QIcon::Normal; 4326 } else 4327 mode = QIcon::Disabled; 4328 4329 if (!(option->state & State_Raised) && !(option->state & State_Sunken) && !(option->state & QStyle::State_Selected)) 4330 mode = QIcon::Disabled; 4331 4332 QIcon::State state = option->state & State_Sunken ? QIcon::On : QIcon::Off; 4333 QPixmap pixmap(_tabCloseIcon.pixmap(size, mode, state)); 4334 drawItemPixmap(painter, option->rect, Qt::AlignCenter, pixmap); 4335 return true; 4336 } 4337 4338 //___________________________________________________________________________________ 4339 bool Style::drawIndicatorTabTearPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4340 { 4341 const QStyleOptionTab *tabOption(qstyleoption_cast<const QStyleOptionTab *>(option)); 4342 if (!tabOption) 4343 return true; 4344 4345 const QRect &rect(option->rect); 4346 const QPalette &palette(option->palette); 4347 const bool reverseLayout(option->direction == Qt::RightToLeft); 4348 4349 // in fact with current version of Qt ( 4.6.0 ) the cast fails and document mode is always false 4350 // this will hopefully be fixed in later versions 4351 const auto tabOptionV3(qstyleoption_cast<const QStyleOptionTab *>(option)); 4352 bool documentMode(tabOptionV3 ? tabOptionV3->documentMode : false); 4353 4354 const QTabWidget *tabWidget = (widget && widget->parentWidget()) ? qobject_cast<const QTabWidget *>(widget->parentWidget()) : nullptr; 4355 documentMode |= (tabWidget ? tabWidget->documentMode() : true); 4356 4357 QRect gradientRect(rect); 4358 switch (tabOption->shape) { 4359 case QTabBar::TriangularNorth: 4360 case QTabBar::RoundedNorth: 4361 gradientRect.adjust(0, 0, 0, -5); 4362 break; 4363 4364 case QTabBar::TriangularSouth: 4365 case QTabBar::RoundedSouth: 4366 gradientRect.adjust(0, 5, 0, 0); 4367 break; 4368 4369 case QTabBar::TriangularWest: 4370 case QTabBar::RoundedWest: 4371 gradientRect.adjust(0, 0, -5, 0); 4372 break; 4373 4374 case QTabBar::TriangularEast: 4375 case QTabBar::RoundedEast: 4376 gradientRect.adjust(5, 0, 0, 0); 4377 break; 4378 4379 default: 4380 return true; 4381 } 4382 4383 // fade tabbar 4384 QPixmap pixmap(gradientRect.size()); 4385 { 4386 pixmap.fill(Qt::transparent); 4387 QPainter painter(&pixmap); 4388 4389 const bool verticalTabs(isVerticalTab(tabOption)); 4390 4391 int width = 0; 4392 int height = 0; 4393 if (verticalTabs) 4394 height = gradientRect.height(); 4395 else 4396 width = gradientRect.width(); 4397 4398 QLinearGradient grad; 4399 if (reverseLayout && !verticalTabs) 4400 grad = QLinearGradient(0, 0, width, height); 4401 else 4402 grad = QLinearGradient(width, height, 0, 0); 4403 4404 grad.setColorAt(0, Qt::transparent); 4405 grad.setColorAt(0.6, Qt::black); 4406 4407 if (widget) { 4408 _helper->renderWindowBackground(&painter, pixmap.rect(), widget, palette); 4409 } 4410 painter.setCompositionMode(QPainter::CompositionMode_DestinationAtop); 4411 painter.fillRect(pixmap.rect(), QBrush(grad)); 4412 painter.end(); 4413 } 4414 4415 // draw pixmap 4416 painter->drawPixmap(gradientRect.topLeft() + QPoint(0, -1), pixmap); 4417 4418 return true; 4419 } 4420 4421 //___________________________________________________________________________________ 4422 bool Style::drawIndicatorToolBarHandlePrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 4423 { 4424 // do nothing if disabled from options 4425 if (!StyleConfigData::toolBarDrawItemSeparator()) { 4426 return true; 4427 } 4428 4429 // copy rect and palette 4430 const QRect &rect(option->rect); 4431 const QPalette &palette(option->palette); 4432 4433 // store state 4434 const State &state(option->state); 4435 const bool horizontal(state & State_Horizontal); 4436 int counter(1); 4437 4438 if (horizontal) { 4439 const int center(rect.left() + rect.width() / 2); 4440 for (int j = rect.top() + 2; j <= rect.bottom() - 3; j += 3, ++counter) { 4441 if (counter % 2 == 0) 4442 _helper->renderDot(painter, QPoint(center + 1, j), palette.color(QPalette::Window)); 4443 else 4444 _helper->renderDot(painter, QPoint(center - 2, j), palette.color(QPalette::Window)); 4445 } 4446 4447 } else { 4448 const int center(rect.top() + rect.height() / 2); 4449 for (int j = rect.left() + 2; j <= rect.right() - 3; j += 3, ++counter) { 4450 if (counter % 2 == 0) 4451 _helper->renderDot(painter, QPoint(j, center + 1), palette.color(QPalette::Window)); 4452 else 4453 _helper->renderDot(painter, QPoint(j, center - 2), palette.color(QPalette::Window)); 4454 } 4455 } 4456 4457 return true; 4458 } 4459 4460 //___________________________________________________________________________________ 4461 bool Style::drawIndicatorToolBarSeparatorPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4462 { 4463 /* 4464 do nothing if disabled from options 4465 also need to check if widget is a combobox, because of Qt hack using 'toolbar' separator primitive 4466 for rendering separators in comboboxes 4467 */ 4468 if (!(StyleConfigData::toolBarDrawItemSeparator() || qobject_cast<const QComboBox *>(widget))) { 4469 return true; 4470 } 4471 4472 // store rect and palette 4473 const QRect &rect(option->rect); 4474 const QPalette &palette(option->palette); 4475 4476 // store state 4477 const State &state(option->state); 4478 const bool separatorIsVertical(state & State_Horizontal); 4479 4480 // define color and render 4481 const QColor color(palette.color(QPalette::Window)); 4482 if (separatorIsVertical) 4483 _helper->drawSeparator(painter, rect, color, Qt::Vertical); 4484 else 4485 _helper->drawSeparator(painter, rect, color, Qt::Horizontal); 4486 4487 return true; 4488 } 4489 4490 //___________________________________________________________________________________ 4491 bool Style::drawIndicatorBranchPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *) const 4492 { 4493 // copy rect and palette 4494 const QRect &rect(option->rect); 4495 const QPalette &palette(option->palette); 4496 4497 // state 4498 const State &state(option->state); 4499 const bool reverseLayout(option->direction == Qt::RightToLeft); 4500 4501 // draw expander 4502 int expanderAdjust = 0; 4503 if (state & State_Children) { 4504 int sizeLimit = qMin(rect.width(), rect.height()); 4505 const bool expanderOpen(state & State_Open); 4506 4507 // make sure size limit is odd 4508 expanderAdjust = sizeLimit / 2 + 1; 4509 4510 // flags 4511 const bool enabled(state & State_Enabled); 4512 const bool mouseOver(enabled && (state & State_MouseOver)); 4513 4514 // color 4515 const QColor expanderColor(mouseOver ? _helper->hoverColor(palette) : palette.color(QPalette::Text)); 4516 4517 // get arrow size from option 4518 ArrowSize size = ArrowSmall; 4519 qreal penThickness(1.2); 4520 switch (StyleConfigData::viewTriangularExpanderSize()) { 4521 case StyleConfigData::TE_TINY: 4522 size = ArrowTiny; 4523 break; 4524 4525 default: 4526 case StyleConfigData::TE_SMALL: 4527 size = ArrowSmall; 4528 break; 4529 4530 case StyleConfigData::TE_NORMAL: 4531 penThickness = 1.6; 4532 size = ArrowNormal; 4533 break; 4534 } 4535 4536 // get arrows polygon 4537 QPolygonF arrow; 4538 if (expanderOpen) 4539 arrow = genericArrow(ArrowDown, size); 4540 else 4541 arrow = genericArrow(reverseLayout ? ArrowLeft : ArrowRight, size); 4542 4543 // render 4544 painter->save(); 4545 painter->translate(QRectF(rect).center()); 4546 painter->setPen(QPen(expanderColor, penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 4547 painter->setRenderHint(QPainter::Antialiasing); 4548 painter->drawPolyline(arrow); 4549 painter->restore(); 4550 } 4551 4552 // tree branches 4553 if (!StyleConfigData::viewDrawTreeBranchLines()) 4554 return true; 4555 4556 const QPoint center(rect.center()); 4557 const QColor lineColor(KColorUtils::mix(palette.color(QPalette::Text), palette.color(QPalette::Window), 0.8)); 4558 painter->setRenderHint(QPainter::Antialiasing, false); 4559 painter->setPen(lineColor); 4560 if (state & (State_Item | State_Children | State_Sibling)) { 4561 const QLine line(QPoint(center.x(), rect.top()), QPoint(center.x(), center.y() - expanderAdjust)); 4562 painter->drawLine(line); 4563 } 4564 4565 // The right/left ( depending on dir ) line gets drawn if we have an item 4566 if (state & State_Item) { 4567 const QLine line = reverseLayout ? QLine(QPoint(rect.left(), center.y()), QPoint(center.x() - expanderAdjust, center.y())) 4568 : QLine(QPoint(center.x() + expanderAdjust, center.y()), QPoint(rect.right(), center.y())); 4569 painter->drawLine(line); 4570 } 4571 4572 // The bottom if we have a sibling 4573 if (state & State_Sibling) { 4574 const QLine line(QPoint(center.x(), center.y() + expanderAdjust), QPoint(center.x(), rect.bottom())); 4575 painter->drawLine(line); 4576 } 4577 4578 return true; 4579 } 4580 4581 //___________________________________________________________________________________ 4582 bool Style::drawWidgetPrimitive(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4583 { 4584 // check widget and attributes 4585 if (!widget || !widget->testAttribute(Qt::WA_StyledBackground) || widget->testAttribute(Qt::WA_NoSystemBackground)) 4586 return false; 4587 if (!((widget->windowFlags() & Qt::WindowType_Mask) & (Qt::Window | Qt::Dialog))) 4588 return false; 4589 if (!widget->isWindow()) 4590 return false; 4591 4592 // normal "window" background 4593 const QPalette &palette(option->palette); 4594 4595 // do not render background if palette brush has a texture (pixmap or image) 4596 const QBrush brush(palette.brush(widget->backgroundRole())); 4597 if (!(brush.texture().isNull() && brush.textureImage().isNull())) { 4598 return false; 4599 } 4600 4601 _helper->renderWindowBackground(painter, option->rect, widget, palette); 4602 return true; 4603 } 4604 4605 //___________________________________________________________________________________ 4606 bool Style::drawPushButtonLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4607 { 4608 // cast option and check 4609 const QStyleOptionButton *buttonOption(qstyleoption_cast<const QStyleOptionButton *>(option)); 4610 if (!buttonOption) 4611 return true; 4612 4613 // copy rect and palette 4614 const QRect &rect(option->rect); 4615 const QPalette &palette(option->palette); 4616 4617 // state 4618 const State &state(option->state); 4619 const bool enabled(state & State_Enabled); 4620 const bool sunken((state & State_On) || (state & State_Sunken)); 4621 const bool mouseOver(enabled && (option->state & State_MouseOver)); 4622 const bool flat(buttonOption->features & QStyleOptionButton::Flat); 4623 4624 // content 4625 const bool hasIcon(!buttonOption->icon.isNull()); 4626 const bool hasText(!buttonOption->text.isEmpty()); 4627 4628 // contents 4629 QRect contentsRect(rect); 4630 4631 // color role 4632 const QPalette::ColorRole textRole(flat ? QPalette::WindowText : QPalette::ButtonText); 4633 4634 // menu arrow 4635 if (buttonOption->features & QStyleOptionButton::HasMenu) { 4636 // define rect 4637 QRect arrowRect(contentsRect); 4638 arrowRect.setLeft(contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1); 4639 arrowRect = centerRect(arrowRect, Metrics::MenuButton_IndicatorWidth, Metrics::MenuButton_IndicatorWidth); 4640 4641 contentsRect.setRight(arrowRect.left() - Metrics::Button_ItemSpacing - 1); 4642 contentsRect.adjust(Metrics::Button_MarginWidth, 0, 0, 0); 4643 4644 arrowRect = visualRect(option, arrowRect); 4645 4646 // arrow 4647 const qreal penThickness = 1.6; 4648 QPolygonF arrow = genericArrow(ArrowDown, ArrowNormal); 4649 4650 const QColor color = palette.color(flat ? QPalette::WindowText : QPalette::ButtonText); 4651 const QColor background = palette.color(flat ? QPalette::Window : QPalette::Button); 4652 4653 painter->save(); 4654 painter->translate(QRectF(arrowRect).center()); 4655 painter->setRenderHint(QPainter::Antialiasing); 4656 4657 const qreal offset(qMin(penThickness, qreal(1))); 4658 painter->translate(0, offset); 4659 painter->setPen(QPen(_helper->calcLightColor(background), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 4660 painter->drawPolyline(arrow); 4661 painter->translate(0, -offset); 4662 4663 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 4664 painter->drawPolyline(arrow); 4665 painter->restore(); 4666 4667 } else 4668 contentsRect = insideMargin(contentsRect, Metrics::Button_MarginWidth, 0); 4669 4670 // icon size 4671 QSize iconSize(buttonOption->iconSize); 4672 if (!iconSize.isValid()) { 4673 const int metric(pixelMetric(PM_SmallIconSize, option, widget)); 4674 iconSize = QSize(metric, metric); 4675 } 4676 4677 // text size 4678 const int textFlags(_mnemonics->textFlags() | Qt::AlignCenter); 4679 const QSize textSize(option->fontMetrics.size(textFlags, buttonOption->text)); 4680 4681 // adjust text and icon rect based on options 4682 QRect iconRect; 4683 QRect textRect; 4684 4685 if (hasText && !hasIcon) 4686 textRect = contentsRect; 4687 else if (hasIcon && !hasText) 4688 iconRect = contentsRect; 4689 else { 4690 const int contentsWidth(iconSize.width() + textSize.width() + Metrics::Button_ItemSpacing); 4691 iconRect = QRect( 4692 QPoint(contentsRect.left() + (contentsRect.width() - contentsWidth) / 2, contentsRect.top() + (contentsRect.height() - iconSize.height()) / 2), 4693 iconSize); 4694 textRect = QRect(QPoint(iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, contentsRect.top() + (contentsRect.height() - textSize.height()) / 2), 4695 textSize); 4696 } 4697 4698 // handle right to left 4699 if (iconRect.isValid()) 4700 iconRect = visualRect(option, iconRect); 4701 if (textRect.isValid()) 4702 textRect = visualRect(option, textRect); 4703 4704 // make sure there is enough room for icon 4705 if (iconRect.isValid()) 4706 iconRect = centerRect(iconRect, iconSize); 4707 4708 // render icon 4709 if (hasIcon && iconRect.isValid()) { 4710 // icon state and mode 4711 const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); 4712 QIcon::Mode iconMode; 4713 if (!enabled) 4714 iconMode = QIcon::Disabled; 4715 else if (mouseOver && flat) 4716 iconMode = QIcon::Active; 4717 else 4718 iconMode = QIcon::Normal; 4719 4720 const QPixmap pixmap = buttonOption->icon.pixmap(iconSize, iconMode, iconState); 4721 drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); 4722 } 4723 4724 // render text 4725 if (hasText && textRect.isValid()) { 4726 drawItemText(painter, textRect, textFlags, palette, enabled, buttonOption->text, textRole); 4727 } 4728 4729 return true; 4730 } 4731 4732 //___________________________________________________________________________________ 4733 bool Style::drawToolButtonLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4734 { 4735 // cast option and check 4736 const QStyleOptionToolButton *toolButtonOption(qstyleoption_cast<const QStyleOptionToolButton *>(option)); 4737 4738 // copy rect and palette 4739 const QRect &rect = option->rect; 4740 const QPalette &palette = option->palette; 4741 4742 // state 4743 const State &state(option->state); 4744 const bool enabled(state & State_Enabled); 4745 const bool sunken((state & State_On) || (state & State_Sunken)); 4746 const bool mouseOver(enabled && (option->state & State_MouseOver)); 4747 const bool flat(state & State_AutoRaise); 4748 4749 const bool hasArrow(toolButtonOption->features & QStyleOptionToolButton::Arrow); 4750 const bool hasIcon(!(hasArrow || toolButtonOption->icon.isNull())); 4751 const bool hasText(!toolButtonOption->text.isEmpty()); 4752 4753 // icon size 4754 const QSize iconSize(toolButtonOption->iconSize); 4755 4756 // text size 4757 int textFlags(_mnemonics->textFlags()); 4758 const QSize textSize(option->fontMetrics.size(textFlags, toolButtonOption->text)); 4759 4760 // adjust text and icon rect based on options 4761 QRect iconRect; 4762 QRect textRect; 4763 4764 if (hasText && (!(hasArrow || hasIcon) || toolButtonOption->toolButtonStyle == Qt::ToolButtonTextOnly)) { 4765 // text only 4766 textRect = rect; 4767 textFlags |= Qt::AlignCenter; 4768 4769 } else if ((hasArrow || hasIcon) && (!hasText || toolButtonOption->toolButtonStyle == Qt::ToolButtonIconOnly)) { 4770 // icon only 4771 iconRect = rect; 4772 4773 } else if (toolButtonOption->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { 4774 const int contentsHeight(iconSize.height() + textSize.height() + Metrics::ToolButton_ItemSpacing); 4775 iconRect = QRect(QPoint(rect.left() + (rect.width() - iconSize.width()) / 2, rect.top() + (rect.height() - contentsHeight) / 2), iconSize); 4776 textRect = QRect(QPoint(rect.left() + (rect.width() - textSize.width()) / 2, iconRect.bottom() + Metrics::ToolButton_ItemSpacing + 1), textSize); 4777 textFlags |= Qt::AlignCenter; 4778 4779 } else { 4780 const bool leftAlign(widget && widget->property(PropertyNames::toolButtonAlignment).toInt() == Qt::AlignLeft); 4781 4782 if (leftAlign) { 4783 const int marginWidth(Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth + 1); 4784 iconRect = QRect(QPoint(rect.left() + marginWidth, rect.top() + (rect.height() - iconSize.height()) / 2), iconSize); 4785 } else { 4786 const int contentsWidth(iconSize.width() + textSize.width() + Metrics::ToolButton_ItemSpacing); 4787 iconRect = QRect(QPoint(rect.left() + (rect.width() - contentsWidth) / 2, rect.top() + (rect.height() - iconSize.height()) / 2), iconSize); 4788 } 4789 4790 textRect = QRect(QPoint(iconRect.right() + Metrics::ToolButton_ItemSpacing + 1, rect.top() + (rect.height() - textSize.height()) / 2), textSize); 4791 4792 // handle right to left layouts 4793 iconRect = visualRect(option, iconRect); 4794 textRect = visualRect(option, textRect); 4795 4796 textFlags |= Qt::AlignLeft | Qt::AlignVCenter; 4797 } 4798 4799 // make sure there is enough room for icon 4800 if (iconRect.isValid()) 4801 iconRect = centerRect(iconRect, iconSize); 4802 4803 // render arrow or icon 4804 if (hasArrow && iconRect.isValid()) { 4805 QStyleOptionToolButton copy(*toolButtonOption); 4806 copy.rect = iconRect; 4807 switch (toolButtonOption->arrowType) { 4808 case Qt::LeftArrow: 4809 drawPrimitive(PE_IndicatorArrowLeft, ©, painter, widget); 4810 break; 4811 case Qt::RightArrow: 4812 drawPrimitive(PE_IndicatorArrowRight, ©, painter, widget); 4813 break; 4814 case Qt::UpArrow: 4815 drawPrimitive(PE_IndicatorArrowUp, ©, painter, widget); 4816 break; 4817 case Qt::DownArrow: 4818 drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); 4819 break; 4820 default: 4821 break; 4822 } 4823 4824 } else if (hasIcon && iconRect.isValid()) { 4825 // icon state and mode 4826 const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); 4827 QIcon::Mode iconMode; 4828 if (!enabled) 4829 iconMode = QIcon::Disabled; 4830 else if (mouseOver && flat) 4831 iconMode = QIcon::Active; 4832 else 4833 iconMode = QIcon::Normal; 4834 4835 const QPixmap pixmap = toolButtonOption->icon.pixmap(iconSize, iconMode, iconState); 4836 drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); 4837 } 4838 4839 // render text 4840 if (hasText && textRect.isValid()) { 4841 const QPalette::ColorRole textRole(flat ? QPalette::WindowText : QPalette::ButtonText); 4842 4843 painter->setFont(toolButtonOption->font); 4844 drawItemText(painter, textRect, textFlags, palette, enabled, toolButtonOption->text, textRole); 4845 } 4846 4847 return true; 4848 } 4849 4850 //___________________________________________________________________________________ 4851 bool Style::drawMenuBarItemControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4852 { 4853 // cast option and check 4854 const QStyleOptionMenuItem *menuItemOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option); 4855 if (!menuItemOption) 4856 return true; 4857 4858 // copy rect and palette 4859 const QRect &rect(option->rect); 4860 const QPalette &palette(option->palette); 4861 4862 // store state 4863 const State &state(option->state); 4864 const bool enabled(state & State_Enabled); 4865 const bool selected(enabled && (state & State_Selected)); 4866 const bool sunken(state & State_Sunken); 4867 const bool useStrongFocus = StyleConfigData::menuHighlightMode() == StyleConfigData::MM_STRONG; 4868 4869 if (enabled) { 4870 const bool active(state & State_Selected); 4871 const bool animated(_animations->menuBarEngine().isAnimated(widget, rect.topLeft())); 4872 const qreal opacity(_animations->menuBarEngine().opacity(widget, rect.topLeft())); 4873 const QRect currentRect(_animations->menuBarEngine().currentRect(widget, rect.topLeft())); 4874 const QRect animatedRect(_animations->menuBarEngine().animatedRect(widget)); 4875 4876 const bool intersected(animatedRect.intersects(rect)); 4877 const bool current(currentRect.contains(rect.topLeft())); 4878 const bool timerIsActive(_animations->menuBarEngine().isTimerActive(widget)); 4879 4880 // do nothing in case of empty intersection between animated rect and current 4881 if ((intersected || !animated || animatedRect.isNull()) && (active || animated || timerIsActive)) { 4882 QColor color(_helper->calcMidColor(palette.color(QPalette::Window))); 4883 if (StyleConfigData::menuHighlightMode() != StyleConfigData::MM_DARK) { 4884 if (state & State_Sunken) { 4885 if (StyleConfigData::menuHighlightMode() == StyleConfigData::MM_STRONG) 4886 color = palette.color(QPalette::Highlight); 4887 else 4888 color = KColorUtils::mix(color, KColorUtils::tint(color, palette.color(QPalette::Highlight), 0.6)); 4889 4890 } else { 4891 if (StyleConfigData::menuHighlightMode() == StyleConfigData::MM_STRONG) 4892 color = KColorUtils::tint(color, _helper->hoverColor(palette)); 4893 else 4894 color = KColorUtils::mix(color, KColorUtils::tint(color, _helper->hoverColor(palette))); 4895 } 4896 4897 } else 4898 color = _helper->backgroundColor(color, widget, rect.center()); 4899 4900 // drawing 4901 if (animated && intersected) { 4902 _helper->holeFlat(color, 0).render(insideMargin(animatedRect, 1), painter, TileSet::Full); 4903 4904 } else if (timerIsActive && current) { 4905 _helper->holeFlat(color, 0).render(insideMargin(rect, 1), painter, TileSet::Full); 4906 4907 } else if (animated && current) { 4908 color.setAlphaF(opacity); 4909 _helper->holeFlat(color, 0).render(insideMargin(rect, 1), painter, TileSet::Full); 4910 4911 } else if (active) { 4912 _helper->holeFlat(color, 0).render(insideMargin(rect, 1), painter, TileSet::Full); 4913 } 4914 } 4915 } 4916 /* 4917 check if item as an icon, in which case only the icon should be rendered 4918 consistently with comment in QMenuBarPrivate::calcActionRects 4919 */ 4920 if (!menuItemOption->icon.isNull()) { 4921 // icon size is forced to SmallIconSize 4922 const auto iconSize = pixelMetric(QStyle::PM_SmallIconSize, nullptr, widget); 4923 const auto iconRect = centerRect(rect, iconSize, iconSize); 4924 4925 // decide icon mode and state 4926 QIcon::Mode iconMode; 4927 QIcon::State iconState; 4928 if (!enabled) { 4929 iconMode = QIcon::Disabled; 4930 iconState = QIcon::Off; 4931 4932 } else { 4933 if (useStrongFocus && sunken) 4934 iconMode = QIcon::Selected; 4935 else if (selected) 4936 iconMode = QIcon::Active; 4937 else 4938 iconMode = QIcon::Normal; 4939 4940 iconState = sunken ? QIcon::On : QIcon::Off; 4941 } 4942 4943 const auto pixmap = menuItemOption->icon.pixmap(iconSize, iconMode, iconState); 4944 drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); 4945 4946 } else { 4947 // text role 4948 QPalette::ColorRole role(QPalette::WindowText); 4949 if (useStrongFocus && sunken && enabled) { 4950 role = QPalette::HighlightedText; 4951 } 4952 4953 // text flags 4954 const int textFlags(Qt::AlignCenter | _mnemonics->textFlags()); 4955 drawItemText(painter, rect, textFlags, palette, enabled, menuItemOption->text, role); 4956 } 4957 4958 return true; 4959 } 4960 4961 //___________________________________________________________________________________ 4962 bool Style::drawMenuItemControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 4963 { 4964 // cast option and check 4965 const QStyleOptionMenuItem *menuItemOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option); 4966 if (!menuItemOption) 4967 return true; 4968 if (menuItemOption->menuItemType == QStyleOptionMenuItem::EmptyArea) 4969 return true; 4970 4971 // copy rect and palette 4972 const QRect &rect(option->rect); 4973 const QPalette &palette(option->palette); 4974 4975 // render background 4976 renderMenuItemBackground(option, painter, widget); 4977 4978 // store state 4979 const State &state(option->state); 4980 const bool enabled(state & State_Enabled); 4981 const bool selected(enabled && (state & State_Selected)); 4982 const bool sunken(enabled && (state & (State_On | State_Sunken))); 4983 const bool hasFocus(enabled && (state & State_HasFocus)); 4984 const bool mouseOver(enabled && (state & State_MouseOver)); 4985 const bool reverseLayout(option->direction == Qt::RightToLeft); 4986 4987 // Active indicator 4988 if (selected) { 4989 // check if there is a 'sliding' animation in progress, in which case, do nothing 4990 const QRect animatedRect(_animations->menuEngine().animatedRect(widget)); 4991 if (animatedRect.isNull()) { 4992 const bool animated(_animations->menuEngine().isAnimated(widget, Current)); 4993 const QRect currentRect(_animations->menuEngine().currentRect(widget, Current)); 4994 const bool intersected(currentRect.contains(rect.topLeft())); 4995 4996 const QColor color(_helper->menuBackgroundColor(_helper->calcMidColor(palette.color(QPalette::Window)), widget, rect.center())); 4997 4998 if (animated && intersected) 4999 renderMenuItemRect(option, rect, color, palette, painter, _animations->menuEngine().opacity(widget, Current)); 5000 else 5001 renderMenuItemRect(option, rect, color, palette, painter); 5002 } 5003 } 5004 5005 // get rect available for contents 5006 QRect contentsRect(insideMargin(rect, Metrics::MenuItem_MarginWidth)); 5007 5008 // deal with separators 5009 if (menuItemOption->menuItemType == QStyleOptionMenuItem::Separator) { 5010 // normal separator 5011 if (menuItemOption->text.isEmpty() && menuItemOption->icon.isNull()) { 5012 // in all other cases draw regular separator 5013 const QColor color(_helper->menuBackgroundColor(palette.color(QPalette::Window), widget, rect.center())); 5014 _helper->drawSeparator(painter, rect, color, Qt::Horizontal); 5015 return true; 5016 5017 } else { 5018 // separator can have a title and an icon 5019 // in that case they are rendered as sunken flat toolbuttons 5020 QStyleOptionToolButton toolButtonOption(separatorMenuItemOption(menuItemOption, widget)); 5021 toolButtonOption.state = State_On | State_Sunken | State_Enabled; 5022 drawComplexControl(CC_ToolButton, &toolButtonOption, painter, widget); 5023 return true; 5024 } 5025 } 5026 5027 // define relevant rectangles 5028 // checkbox 5029 QRect checkBoxRect; 5030 if (menuItemOption->menuHasCheckableItems) { 5031 checkBoxRect = QRect(contentsRect.left(), 5032 contentsRect.top() + (contentsRect.height() - Metrics::CheckBox_Size) / 2 - 1, 5033 Metrics::CheckBox_Size, 5034 Metrics::CheckBox_Size); 5035 contentsRect.setLeft(checkBoxRect.right() + Metrics::MenuItem_ItemSpacing + 1); 5036 } 5037 5038 // render checkbox indicator 5039 const CheckBoxState checkBoxState(menuItemOption->checked ? CheckOn : CheckOff); 5040 if (menuItemOption->checkType == QStyleOptionMenuItem::NonExclusive) { 5041 checkBoxRect = visualRect(option, checkBoxRect); 5042 5043 StyleOptions styleOptions; 5044 styleOptions |= Sunken; 5045 if (!enabled) 5046 styleOptions |= Disabled; 5047 if (mouseOver) 5048 styleOptions |= Hover; 5049 if (hasFocus) 5050 styleOptions |= Focus; 5051 5052 QPalette localPalette(palette); 5053 localPalette.setColor(QPalette::Window, _helper->menuBackgroundColor(palette.color(QPalette::Window), widget, rect.topLeft())); 5054 renderCheckBox(painter, checkBoxRect, localPalette, styleOptions, checkBoxState); 5055 5056 } else if (menuItemOption->checkType == QStyleOptionMenuItem::Exclusive) { 5057 checkBoxRect = visualRect(option, checkBoxRect); 5058 5059 StyleOptions styleOptions; 5060 if (!enabled) 5061 styleOptions |= Disabled; 5062 if (mouseOver) 5063 styleOptions |= Hover; 5064 if (hasFocus) 5065 styleOptions |= Focus; 5066 5067 QPalette localPalette(palette); 5068 localPalette.setColor(QPalette::Window, _helper->menuBackgroundColor(palette.color(QPalette::Window), widget, rect.topLeft())); 5069 renderRadioButton(painter, checkBoxRect, localPalette, styleOptions, checkBoxState); 5070 } 5071 5072 // icon 5073 const int iconWidth(isQtQuickControl(option, widget) ? qMax(pixelMetric(PM_SmallIconSize, option, widget), menuItemOption->maxIconWidth) 5074 : menuItemOption->maxIconWidth); 5075 5076 QRect iconRect(contentsRect.left(), contentsRect.top() + (contentsRect.height() - iconWidth) / 2, iconWidth, iconWidth); 5077 contentsRect.setLeft(iconRect.right() + Metrics::MenuItem_ItemSpacing + 1); 5078 5079 if (!menuItemOption->icon.isNull()) { 5080 const QSize iconSize(pixelMetric(PM_SmallIconSize, option, widget), pixelMetric(PM_SmallIconSize, option, widget)); 5081 iconRect = centerRect(iconRect, iconSize); 5082 iconRect = visualRect(option, iconRect); 5083 5084 // icon mode 5085 QIcon::Mode mode; 5086 if ((StyleConfigData::menuHighlightMode() != StyleConfigData::MM_DARK) && selected) 5087 mode = QIcon::Selected; 5088 else if (selected) 5089 mode = QIcon::Active; 5090 else if (enabled) 5091 mode = QIcon::Normal; 5092 else 5093 mode = QIcon::Disabled; 5094 5095 // icon state 5096 const QIcon::State iconState(sunken ? QIcon::On : QIcon::Off); 5097 const QPixmap icon = menuItemOption->icon.pixmap(iconRect.size(), mode, iconState); 5098 painter->drawPixmap(iconRect, icon); 5099 } 5100 5101 // text role 5102 const QPalette::ColorRole textRole((selected && StyleConfigData::menuHighlightMode() == StyleConfigData::MM_STRONG) ? QPalette::HighlightedText 5103 : QPalette::WindowText); 5104 5105 QRect arrowRect(contentsRect.right() - Metrics::MenuButton_IndicatorWidth + 1, 5106 contentsRect.top() + (contentsRect.height() - Metrics::MenuButton_IndicatorWidth) / 2, 5107 Metrics::MenuButton_IndicatorWidth, 5108 Metrics::MenuButton_IndicatorWidth); 5109 contentsRect.setRight(arrowRect.left() - Metrics::MenuItem_ItemSpacing - 1); 5110 5111 // arrow 5112 if (menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu) { 5113 const qreal penThickness = 1.6; 5114 const QColor color = palette.color(textRole); 5115 const QColor background = palette.color(QPalette::Window); 5116 5117 // get arrow shape 5118 QPolygonF arrow = genericArrow(option->direction == Qt::LeftToRight ? ArrowRight : ArrowLeft, ArrowNormal); 5119 5120 painter->save(); 5121 painter->translate(QRectF(arrowRect).center()); 5122 painter->setRenderHint(QPainter::Antialiasing); 5123 5124 // white outline 5125 const qreal offset(qMin(penThickness, qreal(1))); 5126 painter->translate(0, offset); 5127 painter->setPen(QPen(_helper->calcLightColor(background), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 5128 painter->drawPolyline(arrow); 5129 painter->translate(0, -offset); 5130 5131 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 5132 painter->drawPolyline(arrow); 5133 painter->restore(); 5134 } 5135 5136 // text 5137 QRect textRect = contentsRect; 5138 if (!menuItemOption->text.isEmpty()) { 5139 // adjust textRect 5140 QString text = menuItemOption->text; 5141 textRect = centerRect(textRect, textRect.width(), option->fontMetrics.size(_mnemonics->textFlags(), text).height()); 5142 textRect = visualRect(option, textRect); 5143 5144 // set font 5145 painter->setFont(menuItemOption->font); 5146 5147 // locate accelerator and render 5148 const int tabPosition(text.indexOf(QLatin1Char('\t'))); 5149 if (tabPosition >= 0) { 5150 QString accelerator(text.mid(tabPosition + 1)); 5151 text = text.left(tabPosition); 5152 drawItemText(painter, textRect, Qt::AlignRight | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, accelerator, textRole); 5153 } 5154 5155 // render text 5156 const int textFlags(Qt::AlignVCenter | (reverseLayout ? Qt::AlignRight : Qt::AlignLeft) | _mnemonics->textFlags()); 5157 drawItemText(painter, textRect, textFlags, palette, enabled, text, textRole); 5158 } 5159 5160 return true; 5161 } 5162 5163 //___________________________________________________________________________________ 5164 bool Style::drawProgressBarControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5165 { 5166 const QStyleOptionProgressBar *progressBarOption(qstyleoption_cast<const QStyleOptionProgressBar *>(option)); 5167 if (!progressBarOption) 5168 return true; 5169 5170 QStyleOptionProgressBar progressBarOption2 = *progressBarOption; 5171 5172 progressBarOption2.rect = subElementRect(SE_ProgressBarGroove, progressBarOption, widget); 5173 drawControl(CE_ProgressBarGroove, &progressBarOption2, painter, widget); 5174 5175 // enable busy animations 5176 const QObject *styleObject(widget ? widget : progressBarOption->styleObject); 5177 5178 if (styleObject && _animations->busyIndicatorEngine().enabled()) { 5179 // register QML object if defined 5180 if (!widget && progressBarOption->styleObject) { 5181 _animations->busyIndicatorEngine().registerWidget(progressBarOption->styleObject); 5182 } 5183 5184 _animations->busyIndicatorEngine().setAnimated(styleObject, progressBarOption->maximum == 0 && progressBarOption->minimum == 0); 5185 } 5186 5187 if (_animations->busyIndicatorEngine().isAnimated(styleObject)) { 5188 progressBarOption2.progress = _animations->busyIndicatorEngine().value(); 5189 } 5190 5191 // render contents 5192 progressBarOption2.rect = subElementRect(SE_ProgressBarContents, progressBarOption, widget); 5193 drawControl(CE_ProgressBarContents, &progressBarOption2, painter, widget); 5194 5195 // render text 5196 const bool textVisible(progressBarOption->textVisible); 5197 const bool busy(progressBarOption->minimum == 0 && progressBarOption->maximum == 0); 5198 if (textVisible && !busy) { 5199 progressBarOption2.rect = subElementRect(SE_ProgressBarLabel, progressBarOption, widget); 5200 drawControl(CE_ProgressBarLabel, &progressBarOption2, painter, widget); 5201 } 5202 5203 return true; 5204 } 5205 5206 //___________________________________________________________________________________ 5207 bool Style::drawProgressBarContentsControl(const QStyleOption *option, QPainter *painter, const QWidget *) const 5208 { 5209 // cast option and check 5210 const QStyleOptionProgressBar *progressBarOption = qstyleoption_cast<const QStyleOptionProgressBar *>(option); 5211 if (!progressBarOption) 5212 return true; 5213 5214 // get orientation 5215 const auto progressBarOption2 = qstyleoption_cast<const QStyleOptionProgressBar *>(option); 5216 const bool horizontal(!progressBarOption2 || progressBarOption2->state & QStyle::State_Horizontal); 5217 5218 // copy rect and palette 5219 const QRect &rect(option->rect); 5220 const QPalette &palette(option->palette); 5221 5222 // make sure rect is large enough 5223 if (rect.isValid()) { 5224 // calculate dimension 5225 int dimension(20); 5226 if (progressBarOption2) 5227 dimension = qMax(5, horizontal ? rect.height() : rect.width()); 5228 _helper->progressBarIndicator(palette, dimension).render(rect, painter, TileSet::Full); 5229 } 5230 5231 return true; 5232 } 5233 5234 //___________________________________________________________________________________ 5235 bool Style::drawProgressBarGrooveControl(const QStyleOption *option, QPainter *painter, const QWidget *) const 5236 { 5237 const auto progressBarOption = qstyleoption_cast<const QStyleOptionProgressBar *>(option); 5238 const Qt::Orientation orientation(!progressBarOption || progressBarOption->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical); 5239 renderScrollBarHole(painter, option->rect, option->palette.color(QPalette::Window), orientation); 5240 5241 return true; 5242 } 5243 5244 //___________________________________________________________________________________ 5245 bool Style::drawProgressBarLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5246 { 5247 // cast option and check 5248 const QStyleOptionProgressBar *progressBarOption = qstyleoption_cast<const QStyleOptionProgressBar *>(option); 5249 if (!progressBarOption) 5250 return true; 5251 5252 // copy rect and palette 5253 const QRect &rect(option->rect); 5254 const QPalette &palette(option->palette); 5255 5256 // store state 5257 const State &state(option->state); 5258 const bool enabled(state & State_Enabled); 5259 const bool reverseLayout = (option->direction == Qt::RightToLeft); 5260 5261 // get orientation 5262 const auto progressBarOption2 = qstyleoption_cast<const QStyleOptionProgressBar *>(option); 5263 const bool horizontal = !progressBarOption2 || progressBarOption2->state & QStyle::State_Horizontal; 5264 5265 // check inverted appearance 5266 const bool inverted(progressBarOption2 ? progressBarOption2->invertedAppearance : false); 5267 5268 // rotate label for vertical layout 5269 QTransform transform; 5270 if (!horizontal) { 5271 if (reverseLayout) 5272 transform.rotate(-90); 5273 else 5274 transform.rotate(90); 5275 } 5276 5277 painter->setTransform(transform); 5278 const QRect progressRect(transform.inverted().mapRect(subElementRect(SE_ProgressBarContents, progressBarOption, widget))); 5279 QRect textRect(transform.inverted().mapRect(rect)); 5280 5281 Qt::Alignment hAlign((progressBarOption->textAlignment == Qt::AlignLeft) ? Qt::AlignHCenter : progressBarOption->textAlignment); 5282 5283 /* 5284 Figure out the geometry of the indicator. 5285 This is copied from drawProgressBarContentsControl 5286 */ 5287 if (progressRect.isValid()) { 5288 // first pass ( normal ) 5289 QRect textClipRect(textRect); 5290 5291 if (horizontal) { 5292 if ((reverseLayout && !inverted) || (inverted && !reverseLayout)) 5293 textClipRect.setRight(progressRect.left()); 5294 else 5295 textClipRect.setLeft(progressRect.right() + 1); 5296 5297 } else if ((reverseLayout && !inverted) || (inverted && !reverseLayout)) 5298 textClipRect.setLeft(progressRect.right() + 1); 5299 else 5300 textClipRect.setRight(progressRect.left()); 5301 5302 painter->setClipRect(textClipRect); 5303 drawItemText(painter, textRect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText); 5304 5305 // second pass ( highlighted ) 5306 painter->setClipRect(progressRect); 5307 drawItemText(painter, textRect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::HighlightedText); 5308 5309 } else { 5310 drawItemText(painter, textRect, Qt::AlignVCenter | hAlign, palette, enabled, progressBarOption->text, QPalette::WindowText); 5311 } 5312 5313 return true; 5314 } 5315 5316 //___________________________________________________________________________________ 5317 bool Style::drawScrollBarSliderControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5318 { 5319 // cast option and check 5320 const QStyleOptionSlider *sliderOption = qstyleoption_cast<const QStyleOptionSlider *>(option); 5321 if (!sliderOption) 5322 return true; 5323 5324 // store rect and palette 5325 QRect rect(option->rect); 5326 const QPalette &palette(option->palette); 5327 5328 // store state 5329 const State &state(option->state); 5330 const Qt::Orientation orientation((state & State_Horizontal) ? Qt::Horizontal : Qt::Vertical); 5331 const bool enabled(state & State_Enabled); 5332 const bool mouseOver(enabled && (state & State_MouseOver)); 5333 5334 // update animations 5335 _animations->scrollBarEngine().updateState(widget, enabled && (sliderOption->activeSubControls & SC_ScrollBarSlider)); 5336 const bool animated(enabled && _animations->scrollBarEngine().isAnimated(widget, SC_ScrollBarSlider)); 5337 5338 if (orientation == Qt::Horizontal) 5339 rect = insideMargin(rect, 0, 1); 5340 else 5341 rect = insideMargin(rect, 1, 0); 5342 5343 // render 5344 if (animated) 5345 renderScrollBarHandle(painter, rect, palette, orientation, mouseOver, _animations->scrollBarEngine().opacity(widget, SC_ScrollBarSlider)); 5346 else 5347 renderScrollBarHandle(painter, rect, palette, orientation, mouseOver); 5348 5349 return true; 5350 } 5351 5352 //___________________________________________________________________________________ 5353 bool Style::drawScrollBarAddLineControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5354 { 5355 // do nothing if no buttons are defined 5356 if (_addLineButtons == NoButton) 5357 return true; 5358 5359 // cast option and check 5360 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 5361 if (!sliderOption) 5362 return true; 5363 5364 const State &state(option->state); 5365 const bool horizontal(state & State_Horizontal); 5366 const bool reverseLayout(option->direction == Qt::RightToLeft); 5367 5368 // colors 5369 const QPalette &palette(option->palette); 5370 const QColor background(palette.color(QPalette::Window)); 5371 5372 // adjust rect, based on number of buttons to be drawn 5373 const QRect rect(scrollBarInternalSubControlRect(sliderOption, SC_ScrollBarAddLine)); 5374 5375 QColor color; 5376 QStyleOptionSlider copy(*sliderOption); 5377 if (_addLineButtons == DoubleButton) { 5378 if (horizontal) { 5379 // Draw the arrows 5380 const QSize halfSize(rect.width() / 2, rect.height()); 5381 const QRect leftSubButton(rect.topLeft(), halfSize); 5382 const QRect rightSubButton(leftSubButton.topRight() + QPoint(1, 0), halfSize); 5383 5384 copy.rect = leftSubButton; 5385 color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); 5386 renderScrollBarArrow(painter, leftSubButton, color, background, ArrowLeft); 5387 5388 copy.rect = rightSubButton; 5389 color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarSubLine : SC_ScrollBarAddLine, widget); 5390 renderScrollBarArrow(painter, rightSubButton, color, background, ArrowRight); 5391 5392 } else { 5393 const QSize halfSize(rect.width(), rect.height() / 2); 5394 const QRect topSubButton(rect.topLeft(), halfSize); 5395 const QRect botSubButton(topSubButton.bottomLeft() + QPoint(0, 1), halfSize); 5396 5397 copy.rect = topSubButton; 5398 color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); 5399 renderScrollBarArrow(painter, topSubButton, color, background, ArrowUp); 5400 5401 copy.rect = botSubButton; 5402 color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); 5403 renderScrollBarArrow(painter, botSubButton, color, background, ArrowDown); 5404 } 5405 5406 } else if (_addLineButtons == SingleButton) { 5407 copy.rect = rect; 5408 color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); 5409 if (horizontal) 5410 renderScrollBarArrow(painter, rect, color, background, reverseLayout ? ArrowLeft : ArrowRight); 5411 else 5412 renderScrollBarArrow(painter, rect, color, background, ArrowDown); 5413 } 5414 5415 return true; 5416 } 5417 5418 //___________________________________________________________________________________ 5419 bool Style::drawScrollBarSubLineControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5420 { 5421 // do nothing if no buttons are set 5422 if (_subLineButtons == NoButton) 5423 return true; 5424 5425 // cast option and check 5426 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 5427 if (!sliderOption) 5428 return true; 5429 5430 const State &state(option->state); 5431 const bool horizontal(state & State_Horizontal); 5432 const bool reverseLayout(option->direction == Qt::RightToLeft); 5433 5434 // colors 5435 const QPalette &palette(option->palette); 5436 const QColor background(palette.color(QPalette::Window)); 5437 5438 // adjust rect, based on number of buttons to be drawn 5439 QRect rect(scrollBarInternalSubControlRect(sliderOption, SC_ScrollBarSubLine)); 5440 5441 QColor color; 5442 QStyleOptionSlider copy(*sliderOption); 5443 if (_subLineButtons == DoubleButton) { 5444 if (horizontal) { 5445 // Draw the arrows 5446 const QSize halfSize(rect.width() / 2, rect.height()); 5447 const QRect leftSubButton(rect.topLeft(), halfSize); 5448 const QRect rightSubButton(leftSubButton.topRight() + QPoint(1, 0), halfSize); 5449 5450 copy.rect = leftSubButton; 5451 color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); 5452 renderScrollBarArrow(painter, leftSubButton, color, background, ArrowLeft); 5453 5454 copy.rect = rightSubButton; 5455 color = scrollBarArrowColor(©, reverseLayout ? SC_ScrollBarSubLine : SC_ScrollBarAddLine, widget); 5456 renderScrollBarArrow(painter, rightSubButton, color, background, ArrowRight); 5457 5458 } else { 5459 const QSize halfSize(rect.width(), rect.height() / 2); 5460 const QRect topSubButton(rect.topLeft(), halfSize); 5461 const QRect botSubButton(topSubButton.bottomLeft() + QPoint(0, 1), halfSize); 5462 5463 copy.rect = topSubButton; 5464 color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); 5465 renderScrollBarArrow(painter, topSubButton, color, background, ArrowUp); 5466 5467 copy.rect = botSubButton; 5468 color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); 5469 renderScrollBarArrow(painter, botSubButton, color, background, ArrowDown); 5470 } 5471 5472 } else if (_subLineButtons == SingleButton) { 5473 copy.rect = rect; 5474 color = scrollBarArrowColor(©, SC_ScrollBarSubLine, widget); 5475 if (horizontal) 5476 renderScrollBarArrow(painter, rect, color, background, reverseLayout ? ArrowRight : ArrowLeft); 5477 else 5478 renderScrollBarArrow(painter, rect, color, background, ArrowUp); 5479 } 5480 5481 return true; 5482 } 5483 5484 //___________________________________________________________________________________ 5485 bool Style::drawShapedFrameControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5486 { 5487 // cast option and check 5488 const auto frameOption = qstyleoption_cast<const QStyleOptionFrame *>(option); 5489 if (!frameOption) 5490 return false; 5491 5492 switch (frameOption->frameShape) { 5493 case QFrame::Box: { 5494 if (option->state & State_Sunken) 5495 return true; 5496 else 5497 break; 5498 } 5499 5500 case QFrame::HLine: { 5501 const QColor color(_helper->backgroundColor(option->palette.color(QPalette::Window), widget, option->rect.center())); 5502 _helper->drawSeparator(painter, option->rect, color, Qt::Horizontal); 5503 return true; 5504 } 5505 5506 case QFrame::VLine: { 5507 const QColor color(_helper->backgroundColor(option->palette.color(QPalette::Window), widget, option->rect.center())); 5508 _helper->drawSeparator(painter, option->rect, color, Qt::Vertical); 5509 return true; 5510 } 5511 5512 case QFrame::StyledPanel: { 5513 if (isQtQuickControl(option, widget)) { 5514 // ComboBox popup frame 5515 drawFrameMenuPrimitive(option, painter, widget); 5516 return true; 5517 5518 } else 5519 break; 5520 } 5521 5522 default: 5523 break; 5524 } 5525 5526 return false; 5527 } 5528 5529 //___________________________________________________________________________________ 5530 bool Style::drawRubberBandControl(const QStyleOption *option, QPainter *painter, const QWidget *) const 5531 { 5532 const QPalette &palette(option->palette); 5533 const QRect rect(option->rect); 5534 5535 QColor color = palette.color(QPalette::Highlight); 5536 painter->setPen(KColorUtils::mix(color, palette.color(QPalette::Active, QPalette::WindowText))); 5537 color.setAlpha(50); 5538 painter->setBrush(color); 5539 painter->setClipRegion(rect); 5540 painter->drawRect(rect.adjusted(0, 0, -1, -1)); 5541 return true; 5542 } 5543 5544 //___________________________________________________________________________________ 5545 bool Style::drawHeaderSectionControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5546 { 5547 // cast option and check 5548 const QStyleOptionHeader *headerOption(qstyleoption_cast<const QStyleOptionHeader *>(option)); 5549 if (!headerOption) 5550 return true; 5551 5552 // copy rect and palette 5553 const QRect &rect(option->rect); 5554 const QPalette &palette(option->palette); 5555 5556 // store state 5557 const bool horizontal(headerOption->orientation == Qt::Horizontal); 5558 const bool reverseLayout(option->direction == Qt::RightToLeft); 5559 const bool isFirst(horizontal && (headerOption->position == QStyleOptionHeader::Beginning)); 5560 const bool isCorner(widget && widget->inherits("QTableCornerButton")); 5561 5562 // corner header lines 5563 if (isCorner) { 5564 if (widget) 5565 _helper->renderWindowBackground(painter, rect, widget, palette); 5566 else 5567 painter->fillRect(rect, palette.color(QPalette::Window)); 5568 if (reverseLayout) 5569 renderHeaderLines(rect, palette, painter, TileSet::BottomLeft); 5570 else 5571 renderHeaderLines(rect, palette, painter, TileSet::BottomRight); 5572 5573 } else 5574 renderHeaderBackground(rect, palette, painter, widget, horizontal, reverseLayout); 5575 5576 // dots 5577 const QColor color(palette.color(QPalette::Window)); 5578 if (horizontal) { 5579 if (headerOption->section != 0 || isFirst) { 5580 const int center(rect.center().y()); 5581 const int pos(reverseLayout ? rect.left() + 1 : rect.right() - 1); 5582 _helper->renderDot(painter, QPoint(pos, center - 3), color); 5583 _helper->renderDot(painter, QPoint(pos, center), color); 5584 _helper->renderDot(painter, QPoint(pos, center + 3), color); 5585 } 5586 5587 } else { 5588 const int center(rect.center().x()); 5589 const int pos(rect.bottom() - 1); 5590 _helper->renderDot(painter, QPoint(center - 3, pos), color); 5591 _helper->renderDot(painter, QPoint(center, pos), color); 5592 _helper->renderDot(painter, QPoint(center + 3, pos), color); 5593 } 5594 5595 return true; 5596 } 5597 5598 //___________________________________________________________________________________ 5599 bool Style::drawHeaderEmptyAreaControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5600 { 5601 // use the same background as in drawHeaderPrimitive 5602 QPalette palette(option->palette); 5603 5604 if (widget && _animations->widgetEnableStateEngine().isAnimated(widget, AnimationEnable)) { 5605 palette = _helper->disabledPalette(palette, _animations->widgetEnableStateEngine().opacity(widget, AnimationEnable)); 5606 } 5607 5608 const bool horizontal(option->state & QStyle::State_Horizontal); 5609 const bool reverseLayout(option->direction == Qt::RightToLeft); 5610 renderHeaderBackground(option->rect, palette, painter, widget, horizontal, reverseLayout); 5611 5612 return true; 5613 } 5614 5615 //___________________________________________________________________________________ 5616 bool Style::drawTabBarTabLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5617 { 5618 // call parent style method 5619 KStyle::drawControl(CE_TabBarTabLabel, option, painter, widget); 5620 5621 // store rect and palette 5622 const QRect &rect(option->rect); 5623 const QPalette &palette(option->palette); 5624 5625 // check focus 5626 const State &state(option->state); 5627 const bool enabled(state & State_Enabled); 5628 const bool selected(state & State_Selected); 5629 const bool hasFocus(enabled && selected && (state & State_HasFocus)); 5630 5631 // update mouse over animation state 5632 _animations->tabBarEngine().updateState(widget, rect.topLeft(), AnimationFocus, hasFocus); 5633 const bool animated(enabled && selected && _animations->tabBarEngine().isAnimated(widget, rect.topLeft(), AnimationFocus)); 5634 const qreal opacity(_animations->tabBarEngine().opacity(widget, rect.topLeft(), AnimationFocus)); 5635 5636 if (!(hasFocus || animated)) 5637 return true; 5638 5639 // code is copied from QCommonStyle, but adds focus 5640 // cast option and check 5641 const QStyleOptionTab *tabOption(qstyleoption_cast<const QStyleOptionTab *>(option)); 5642 if (!tabOption || tabOption->text.isEmpty()) 5643 return true; 5644 5645 // tab option rect 5646 const bool verticalTabs(isVerticalTab(tabOption)); 5647 const int textFlags(Qt::AlignCenter | _mnemonics->textFlags()); 5648 5649 // text rect 5650 QRect textRect(subElementRect(SE_TabBarTabText, option, widget)); 5651 5652 if (verticalTabs) { 5653 // properly rotate painter 5654 painter->save(); 5655 int newX, newY, newRot; 5656 if (tabOption->shape == QTabBar::RoundedEast || tabOption->shape == QTabBar::TriangularEast) { 5657 newX = rect.width() + rect.x(); 5658 newY = rect.y(); 5659 newRot = 90; 5660 5661 } else { 5662 newX = rect.x(); 5663 newY = rect.y() + rect.height(); 5664 newRot = -90; 5665 } 5666 5667 QTransform transform; 5668 transform.translate(newX, newY); 5669 transform.rotate(newRot); 5670 painter->setTransform(transform, true); 5671 } 5672 5673 // adjust text rect based on font metrics 5674 textRect = option->fontMetrics.boundingRect(textRect, textFlags, tabOption->text); 5675 5676 // focus color 5677 QColor focusColor; 5678 if (animated) 5679 focusColor = _helper->alphaColor(_helper->focusColor(palette), opacity); 5680 else if (hasFocus) 5681 focusColor = _helper->focusColor(palette); 5682 5683 // render focus line 5684 if (focusColor.isValid()) { 5685 painter->save(); 5686 painter->setRenderHint(QPainter::Antialiasing, false); 5687 painter->setBrush(Qt::NoBrush); 5688 painter->setPen(focusColor); 5689 5690 painter->translate(0, 2); 5691 painter->drawLine(textRect.bottomLeft(), textRect.bottomRight()); 5692 painter->restore(); 5693 } 5694 5695 if (verticalTabs) 5696 painter->restore(); 5697 5698 return true; 5699 } 5700 5701 //___________________________________________________________________________________ 5702 bool Style::drawTabBarTabShapeControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5703 { 5704 // check if tabwidget is selected and redirect 5705 const State &state(option->state); 5706 const bool selected(state & State_Selected); 5707 if (selected) 5708 return drawTabBarTabShapeControl_selected(option, painter, widget); 5709 else 5710 return drawTabBarTabShapeControl_unselected(option, painter, widget); 5711 } 5712 5713 //___________________________________________________________________________________ 5714 bool Style::drawTabBarTabShapeControl_selected(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 5715 { 5716 // cast option and check 5717 const QStyleOptionTab *tabOption(qstyleoption_cast<const QStyleOptionTab *>(option)); 5718 if (!tabOption) 5719 return true; 5720 5721 // copy rect and palette 5722 const QRect &rect(option->rect); 5723 const QPalette &palette(option->palette); 5724 5725 // store state 5726 const State &state(option->state); 5727 const bool enabled(state & State_Enabled); 5728 const bool reverseLayout(option->direction == Qt::RightToLeft); 5729 5730 // tab position and state 5731 const QStyleOptionTab::TabPosition &position = tabOption->position; 5732 bool isFirst(position == QStyleOptionTab::OnlyOneTab || position == QStyleOptionTab::Beginning); 5733 bool isLast(position == QStyleOptionTab::OnlyOneTab || position == QStyleOptionTab::End); 5734 5735 // document mode 5736 const auto tabOptionV3 = qstyleoption_cast<const QStyleOptionTab *>(option); 5737 bool documentMode = tabOptionV3 ? tabOptionV3->documentMode : false; 5738 const QTabWidget *tabWidget = (widget && widget->parentWidget()) ? qobject_cast<const QTabWidget *>(widget->parentWidget()) : nullptr; 5739 documentMode |= (tabWidget ? tabWidget->documentMode() : true); 5740 5741 // this is needed to complete the base frame when there are widgets in tabbar 5742 const QTabBar *tabBar(qobject_cast<const QTabBar *>(widget)); 5743 const QRect tabBarRect(tabBar ? tabBar->rect() : QRect()); 5744 5745 // check if tab is being dragged 5746 const bool isDragged(painter->device() != tabBar); 5747 5748 // hover and animation state 5749 /* all are disabled when tabBar is locked ( drag in progress ) */ 5750 const bool tabBarLocked(_tabBarData->locks(tabBar)); 5751 const bool mouseOver(enabled && !tabBarLocked && (state & State_MouseOver)); 5752 5753 // animation state 5754 _animations->tabBarEngine().updateState(widget, rect.topLeft(), AnimationHover, mouseOver); 5755 5756 // handle base frame painting, for tabbars in which tab is being dragged 5757 _tabBarData->drawTabBarBaseControl(tabOption, painter, widget); 5758 if (tabBar && isDragged) 5759 _tabBarData->lock(tabBar); 5760 else if (_tabBarData->locks(tabBar)) 5761 _tabBarData->release(); 5762 5763 // corner widgets 5764 const bool verticalTabs(isVerticalTab(tabOption)); 5765 const bool hasLeftCornerWidget((tabOption->cornerWidgets & QStyleOptionTab::LeftCornerWidget) && !verticalTabs); 5766 5767 // true if widget is aligned to the frame 5768 const bool isFrameAligned(!documentMode && isFirst && !hasLeftCornerWidget && !isDragged); 5769 5770 // swap state based on reverse layout, so that they become layout independent 5771 if (reverseLayout && !verticalTabs) 5772 qSwap(isFirst, isLast); 5773 5774 // part of the tab in which the text is drawn 5775 QRect tabRect(insideMargin(rect, -1)); 5776 SlabRect tabSlab(insideMargin(rect, -1), TileSet::Ring); 5777 5778 // connection to the frame 5779 SlabRect::List slabs; 5780 5781 switch (tabOption->shape) { 5782 case QTabBar::RoundedNorth: 5783 case QTabBar::TriangularNorth: { 5784 tabSlab.tiles &= ~TileSet::Bottom; 5785 tabSlab.rect.adjust(0, 0, 0, 2); 5786 if (isDragged) 5787 break; 5788 5789 // left side 5790 if (isFrameAligned && !reverseLayout) { 5791 QRect frameRect(rect); 5792 frameRect.setLeft(frameRect.left() - 1); 5793 frameRect.setRight(tabRect.left()); 5794 frameRect.setTop(tabRect.bottom() - 4); 5795 slabs << SlabRect(frameRect, TileSet::Left).adjusted(TileSet::DefaultSize); 5796 5797 } else { 5798 QRect frameRect(rect); 5799 frameRect.setRight(tabRect.left() + 3); 5800 frameRect.setTop(rect.bottom() - TileSet::DefaultSize + 1); 5801 slabs << SlabRect(frameRect, TileSet::Top).adjusted(TileSet::DefaultSize); 5802 } 5803 5804 // right side 5805 if (isFrameAligned && reverseLayout) { 5806 QRect frameRect(rect); 5807 frameRect.setLeft(tabRect.right()); 5808 frameRect.setRight(frameRect.right() + 1); 5809 frameRect.setTop(tabRect.bottom() - 4); 5810 slabs << SlabRect(frameRect, TileSet::Right).adjusted(TileSet::DefaultSize); 5811 5812 } else { 5813 QRect frameRect(rect); 5814 frameRect.setLeft(tabRect.right() - 3); 5815 frameRect.setTop(rect.bottom() - TileSet::DefaultSize + 1); 5816 slabs << SlabRect(frameRect, TileSet::Top).adjusted(TileSet::DefaultSize); 5817 } 5818 5819 // extra base, to extend below inactive tabs and buttons 5820 if (tabBar) { 5821 QRect frameRect(rect); 5822 frameRect.setTop(rect.bottom() - Metrics::TabBar_BaseOverlap + 1); 5823 5824 if (rect.left() > tabBarRect.left()) { 5825 frameRect.setLeft(tabBarRect.left() - Metrics::TabBar_BaseOverlap); 5826 frameRect.setRight(rect.left() + Metrics::TabBar_BaseOverlap - 1); 5827 if (documentMode || reverseLayout) 5828 slabs << SlabRect(frameRect, TileSet::Top); 5829 else 5830 slabs << SlabRect(frameRect, TileSet::TopLeft); 5831 } 5832 5833 if (rect.right() < tabBarRect.right()) { 5834 frameRect.setLeft(rect.right() - Metrics::TabBar_BaseOverlap + 1); 5835 frameRect.setRight(tabBarRect.right() + Metrics::TabBar_BaseOverlap); 5836 if (documentMode || !reverseLayout) 5837 slabs << SlabRect(frameRect, TileSet::Top); 5838 else 5839 slabs << SlabRect(frameRect, TileSet::TopRight); 5840 } 5841 } 5842 5843 break; 5844 } 5845 5846 case QTabBar::RoundedSouth: 5847 case QTabBar::TriangularSouth: { 5848 tabSlab.tiles &= ~TileSet::Top; 5849 tabSlab.rect.adjust(0, -2, 0, 0); 5850 if (isDragged) 5851 break; 5852 5853 // left side 5854 if (isFrameAligned && !reverseLayout) { 5855 QRect frameRect(rect); 5856 frameRect.setLeft(frameRect.left() - 1); 5857 frameRect.setRight(tabRect.left()); 5858 frameRect.setBottom(tabRect.top() + 4); 5859 slabs << SlabRect(frameRect, TileSet::Left).adjusted(TileSet::DefaultSize); 5860 5861 } else { 5862 QRect frameRect(rect); 5863 frameRect.setRight(tabRect.left() + 3); 5864 frameRect.setBottom(rect.top() + TileSet::DefaultSize - 1); 5865 slabs << SlabRect(frameRect, TileSet::Bottom).adjusted(TileSet::DefaultSize); 5866 } 5867 5868 // right side 5869 if (isFrameAligned && reverseLayout) { 5870 QRect frameRect(rect); 5871 frameRect.setLeft(tabRect.right()); 5872 frameRect.setRight(frameRect.right() + 1); 5873 frameRect.setBottom(tabRect.top() + 4); 5874 slabs << SlabRect(frameRect, TileSet::Right).adjusted(TileSet::DefaultSize); 5875 5876 } else { 5877 QRect frameRect(rect); 5878 frameRect.setLeft(tabRect.right() - 3); 5879 frameRect.setBottom(rect.top() + TileSet::DefaultSize - 1); 5880 slabs << SlabRect(frameRect, TileSet::Bottom).adjusted(TileSet::DefaultSize); 5881 } 5882 5883 // extra base, to extend below tabbar buttons 5884 if (tabBar) { 5885 QRect frameRect(rect); 5886 frameRect.setBottom(rect.top() + Metrics::TabBar_BaseOverlap - 1); 5887 5888 if (rect.left() > tabBarRect.left()) { 5889 frameRect.setLeft(tabBarRect.left() - Metrics::TabBar_BaseOverlap); 5890 frameRect.setRight(rect.left() + Metrics::TabBar_BaseOverlap - 1); 5891 if (documentMode || reverseLayout) 5892 slabs << SlabRect(frameRect, TileSet::Bottom); 5893 else 5894 slabs << SlabRect(frameRect, TileSet::BottomLeft); 5895 } 5896 5897 if (rect.right() < tabBarRect.right()) { 5898 frameRect.setLeft(rect.right() - Metrics::TabBar_BaseOverlap + 1); 5899 frameRect.setRight(tabBarRect.right() + Metrics::TabBar_BaseOverlap); 5900 if (documentMode || !reverseLayout) 5901 slabs << SlabRect(frameRect, TileSet::Bottom); 5902 else 5903 slabs << SlabRect(frameRect, TileSet::BottomRight); 5904 } 5905 } 5906 5907 break; 5908 } 5909 5910 case QTabBar::RoundedWest: 5911 case QTabBar::TriangularWest: { 5912 tabSlab.tiles &= ~TileSet::Right; 5913 tabSlab.rect.adjust(0, 0, 2, 0); 5914 if (isDragged) 5915 break; 5916 5917 // top side 5918 if (isFrameAligned) { 5919 QRect frameRect(rect); 5920 frameRect.setLeft(tabRect.right() - 4); 5921 frameRect.setTop(frameRect.top() - 1); 5922 frameRect.setBottom(tabRect.top()); 5923 slabs << SlabRect(frameRect, TileSet::Top).adjusted(TileSet::DefaultSize); 5924 5925 } else { 5926 QRect frameRect(rect); 5927 frameRect.setLeft(rect.right() - TileSet::DefaultSize + 1); 5928 frameRect.setBottom(tabRect.top() + 3); 5929 slabs << SlabRect(frameRect, TileSet::Left).adjusted(TileSet::DefaultSize); 5930 } 5931 5932 // bottom side 5933 QRect frameRect(rect); 5934 frameRect.setLeft(rect.right() - TileSet::DefaultSize + 1); 5935 frameRect.setTop(tabRect.bottom() - 3); 5936 slabs << SlabRect(frameRect, TileSet::Left).adjusted(TileSet::DefaultSize); 5937 5938 // extra base, to extend below tabbar buttons 5939 if (tabBar) { 5940 QRect frameRect(rect); 5941 frameRect.setLeft(rect.right() - Metrics::TabBar_BaseOverlap + 1); 5942 if (rect.top() > tabBarRect.top()) { 5943 frameRect.setTop(tabBarRect.top() - Metrics::TabBar_BaseOverlap); 5944 frameRect.setBottom(rect.top() + Metrics::TabBar_BaseOverlap - 1); 5945 if (documentMode) 5946 slabs << SlabRect(frameRect, TileSet::Left); 5947 else 5948 slabs << SlabRect(frameRect, TileSet::TopLeft); 5949 } 5950 5951 if (rect.bottom() < tabBarRect.bottom()) { 5952 frameRect.setTop(rect.bottom() - Metrics::TabBar_BaseOverlap + 1); 5953 frameRect.setBottom(tabBarRect.bottom() + Metrics::TabBar_BaseOverlap - 1); 5954 slabs << SlabRect(frameRect, TileSet::Left); 5955 } 5956 } 5957 5958 break; 5959 } 5960 5961 case QTabBar::RoundedEast: 5962 case QTabBar::TriangularEast: { 5963 tabSlab.tiles &= ~TileSet::Left; 5964 tabSlab.rect.adjust(-2, 0, 0, 0); 5965 if (isDragged) 5966 break; 5967 5968 // top side 5969 if (isFrameAligned) { 5970 QRect frameRect(rect); 5971 frameRect.setRight(tabRect.left() + 4); 5972 frameRect.setTop(frameRect.top() - 1); 5973 frameRect.setBottom(tabRect.top()); 5974 slabs << SlabRect(frameRect, TileSet::Top).adjusted(TileSet::DefaultSize); 5975 5976 } else { 5977 QRect frameRect(rect); 5978 frameRect.setRight(rect.left() + TileSet::DefaultSize - 1); 5979 frameRect.setBottom(tabRect.top() + 3); 5980 slabs << SlabRect(frameRect, TileSet::Right).adjusted(TileSet::DefaultSize); 5981 } 5982 5983 // bottom side 5984 QRect frameRect(rect); 5985 frameRect.setRight(rect.left() + TileSet::DefaultSize - 1); 5986 frameRect.setTop(tabRect.bottom() - 3); 5987 slabs << SlabRect(frameRect, TileSet::Right).adjusted(TileSet::DefaultSize); 5988 5989 // extra base, to extend below tabbar buttons 5990 if (tabBar) { 5991 QRect frameRect(rect); 5992 frameRect.setRight(rect.left() + Metrics::TabBar_BaseOverlap - 1); 5993 5994 if (rect.top() > tabBarRect.top()) { 5995 frameRect.setTop(tabBarRect.top() - Metrics::TabBar_BaseOverlap); 5996 frameRect.setBottom(rect.top() + Metrics::TabBar_BaseOverlap - 1); 5997 if (documentMode) 5998 slabs << SlabRect(frameRect, TileSet::Right); 5999 else 6000 slabs << SlabRect(frameRect, TileSet::TopRight); 6001 } 6002 6003 if (rect.bottom() < tabBarRect.bottom()) { 6004 frameRect.setTop(rect.bottom() - Metrics::TabBar_BaseOverlap + 1); 6005 frameRect.setBottom(tabBarRect.bottom() + Metrics::TabBar_BaseOverlap - 1); 6006 slabs << SlabRect(frameRect, TileSet::Right); 6007 } 6008 } 6009 6010 break; 6011 } 6012 6013 default: 6014 break; 6015 } 6016 6017 // store default color 6018 const QColor color(palette.color(QPalette::Window)); 6019 6020 // render connections to frame 6021 // extra care must be taken care of so that no slab 6022 // extends beyond tabWidget frame, if any 6023 const QRect tabWidgetRect(tabWidget ? tabWidget->rect().translated(-widget->geometry().topLeft()) : QRect()); 6024 6025 for (SlabRect slab : std::as_const(slabs)) { 6026 adjustSlabRect(slab, tabWidgetRect, documentMode, verticalTabs); 6027 renderSlab(painter, slab, color, NoFill); 6028 } 6029 6030 // adjust clip rect and render tab 6031 if (tabBar) { 6032 painter->save(); 6033 painter->setClipRegion(tabBarClipRegion(tabBar)); 6034 } 6035 6036 // fill tab 6037 if (isDragged) 6038 fillTabBackground(painter, tabRect, color, widget); 6039 6040 // slab options 6041 renderSlab(painter, tabSlab, color, NoFill); 6042 fillTab(painter, tabRect, color, tabOption->shape); 6043 6044 // restore clip region 6045 if (tabBar) 6046 painter->restore(); 6047 6048 return true; 6049 } 6050 6051 //___________________________________________________________________________________ 6052 bool Style::drawTabBarTabShapeControl_unselected(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 6053 { 6054 // cast option and check 6055 const QStyleOptionTab *tabOption(qstyleoption_cast<const QStyleOptionTab *>(option)); 6056 if (!tabOption) 6057 return true; 6058 6059 // copy rect and palette 6060 const QRect &rect(option->rect); 6061 const QPalette &palette(option->palette); 6062 6063 // store state 6064 const State &state(option->state); 6065 const bool enabled(state & State_Enabled); 6066 const bool reverseLayout(option->direction == Qt::RightToLeft); 6067 6068 // tab position and flags 6069 const QStyleOptionTab::TabPosition &position = tabOption->position; 6070 bool isFirst(position == QStyleOptionTab::OnlyOneTab || position == QStyleOptionTab::Beginning); 6071 bool isLast(position == QStyleOptionTab::OnlyOneTab || position == QStyleOptionTab::End); 6072 bool isLeftOfSelected(tabOption->selectedPosition == QStyleOptionTab::NextIsSelected); 6073 bool isRightOfSelected(tabOption->selectedPosition == QStyleOptionTab::PreviousIsSelected); 6074 6075 // document mode 6076 const auto tabOptV3 = qstyleoption_cast<const QStyleOptionTab *>(option); 6077 bool documentMode = tabOptV3 ? tabOptV3->documentMode : false; 6078 const QTabWidget *tabWidget = (widget && widget->parentWidget()) ? qobject_cast<const QTabWidget *>(widget->parentWidget()) : nullptr; 6079 documentMode |= (tabWidget ? tabWidget->documentMode() : true); 6080 6081 // this is needed to complete the base frame when there are widgets in tabbar 6082 const QTabBar *tabBar(qobject_cast<const QTabBar *>(widget)); 6083 const QRect tabBarRect(tabBar ? tabBar->rect() : QRect()); 6084 6085 // hover and animation flags 6086 /* all are disabled when tabBar is locked ( drag in progress ) */ 6087 const bool tabBarLocked(_tabBarData->locks(tabBar)); 6088 const bool mouseOver(enabled && !tabBarLocked && (state & State_MouseOver)); 6089 6090 // animation state 6091 _animations->tabBarEngine().updateState(widget, rect.topLeft(), AnimationHover, mouseOver); 6092 const bool animated(enabled && !tabBarLocked && _animations->tabBarEngine().isAnimated(widget, rect.topLeft(), AnimationHover)); 6093 6094 // corner widgets 6095 const bool verticalTabs(isVerticalTab(tabOption)); 6096 const bool hasLeftCornerWidget((tabOption->cornerWidgets & QStyleOptionTab::LeftCornerWidget) && !verticalTabs); 6097 6098 // true if widget is aligned to the frame 6099 /* need to check for 'isRightOfSelected' because for some reason the isFirst flag is set when active tab is being moved */ 6100 const bool isFrameAligned(!documentMode && isFirst && !hasLeftCornerWidget && !isRightOfSelected); 6101 isFirst &= !isRightOfSelected; 6102 isLast &= !isLeftOfSelected; 6103 6104 // swap flags based on reverse layout, so that they become layout independent 6105 if (reverseLayout && !verticalTabs) { 6106 qSwap(isFirst, isLast); 6107 qSwap(isLeftOfSelected, isRightOfSelected); 6108 } 6109 6110 const qreal radius = 4; 6111 6112 // part of the tab in which the text is drawn 6113 QRect tabRect(rect); 6114 QPainterPath path; 6115 6116 // highlighted slab (if any) 6117 SlabRect highlightSlab; 6118 6119 switch (tabOption->shape) { 6120 case QTabBar::RoundedNorth: 6121 case QTabBar::TriangularNorth: { 6122 tabRect.adjust(0, 3, 1, -4); 6123 6124 // adjust sides when slab is adjacent to selected slab 6125 if (isLeftOfSelected) 6126 tabRect.adjust(0, 0, 2, 0); 6127 else if (isRightOfSelected) 6128 tabRect.adjust(-2, 0, 0, 0); 6129 6130 if (isFirst) { 6131 tabRect.adjust(1, 0, 0, 0); 6132 if (isFrameAligned) 6133 path.moveTo(tabRect.bottomLeft() + QPoint(0, 2)); 6134 else 6135 path.moveTo(tabRect.bottomLeft()); 6136 path.lineTo(tabRect.topLeft() + QPointF(0, radius)); 6137 path.quadTo(tabRect.topLeft(), tabRect.topLeft() + QPoint(radius, 0)); 6138 path.lineTo(tabRect.topRight()); 6139 path.lineTo(tabRect.bottomRight()); 6140 6141 } else if (isLast) { 6142 tabRect.adjust(0, 0, -2, 0); 6143 path.moveTo(tabRect.bottomLeft()); 6144 path.lineTo(tabRect.topLeft()); 6145 path.lineTo(tabRect.topRight() - QPointF(radius, 0)); 6146 path.quadTo(tabRect.topRight(), tabRect.topRight() + QPointF(0, radius)); 6147 if (isFrameAligned) 6148 path.lineTo(tabRect.bottomRight() + QPointF(0, 2)); 6149 else 6150 path.lineTo(tabRect.bottomRight()); 6151 6152 } else { 6153 path.moveTo(tabRect.bottomLeft()); 6154 path.lineTo(tabRect.topLeft()); 6155 path.lineTo(tabRect.topRight()); 6156 path.lineTo(tabRect.bottomRight()); 6157 } 6158 6159 // highlight 6160 QRect highlightRect(tabRect.left(), tabRect.bottom() - Metrics::TabBar_BaseOverlap + Metrics::TabBar_TabOffset, tabRect.width(), 1); 6161 if (isFrameAligned && isFirst) 6162 highlightSlab = SlabRect(highlightRect.adjusted(-2, 0, 0, 0), TileSet::TopLeft); 6163 else if (isFrameAligned && isLast) 6164 highlightSlab = SlabRect(highlightRect.adjusted(0, 0, 2, 0), TileSet::TopRight); 6165 else 6166 highlightSlab = SlabRect(highlightRect, TileSet::Top); 6167 break; 6168 } 6169 6170 case QTabBar::RoundedSouth: 6171 case QTabBar::TriangularSouth: { 6172 tabRect.adjust(0, 4, 1, -3); 6173 6174 // adjust sides when slab is adjacent to selected slab 6175 if (isLeftOfSelected) 6176 tabRect.adjust(0, 0, 2, 0); 6177 else if (isRightOfSelected) 6178 tabRect.adjust(-2, 0, 0, 0); 6179 6180 if (isFirst) { 6181 tabRect.adjust(1, 0, 0, 0); 6182 if (isFrameAligned) 6183 path.moveTo(tabRect.topLeft() - QPoint(0, 2)); 6184 else 6185 path.moveTo(tabRect.topLeft()); 6186 path.lineTo(tabRect.bottomLeft() - QPointF(0, radius)); 6187 path.quadTo(tabRect.bottomLeft(), tabRect.bottomLeft() + QPoint(radius, 0)); 6188 path.lineTo(tabRect.bottomRight()); 6189 path.lineTo(tabRect.topRight()); 6190 6191 } else if (isLast) { 6192 tabRect.adjust(0, 0, -2, 0); 6193 path.moveTo(tabRect.topLeft()); 6194 path.lineTo(tabRect.bottomLeft()); 6195 path.lineTo(tabRect.bottomRight() - QPointF(radius, 0)); 6196 path.quadTo(tabRect.bottomRight(), tabRect.bottomRight() - QPointF(0, radius)); 6197 if (isFrameAligned) 6198 path.lineTo(tabRect.topRight() - QPointF(0, 2)); 6199 else 6200 path.lineTo(tabRect.topRight()); 6201 6202 } else { 6203 path.moveTo(tabRect.topLeft()); 6204 path.lineTo(tabRect.bottomLeft()); 6205 path.lineTo(tabRect.bottomRight()); 6206 path.lineTo(tabRect.topRight()); 6207 } 6208 6209 // highlight 6210 QRect highlightRect(tabRect.left(), tabRect.top() - Metrics::TabBar_BaseOverlap + Metrics::TabBar_TabOffset, tabRect.width(), TileSet::DefaultSize); 6211 if (isFrameAligned && isFirst) 6212 highlightSlab = SlabRect(highlightRect.adjusted(-2, 0, 0, 0), TileSet::BottomLeft); 6213 else if (isFrameAligned && isLast) 6214 highlightSlab = SlabRect(highlightRect.adjusted(0, 0, 2, 0), TileSet::BottomRight); 6215 else 6216 highlightSlab = SlabRect(highlightRect, TileSet::Bottom); 6217 6218 break; 6219 } 6220 6221 case QTabBar::RoundedWest: 6222 case QTabBar::TriangularWest: { 6223 tabRect.adjust(3, 0, -4, 1); 6224 6225 // adjust sides when slab is adjacent to selected slab 6226 if (isLeftOfSelected) 6227 tabRect.adjust(0, 0, 0, 2); 6228 else if (isRightOfSelected) 6229 tabRect.adjust(0, -2, 0, 0); 6230 6231 if (isFirst) { 6232 tabRect.adjust(0, 1, 0, 0); 6233 if (isFrameAligned) 6234 path.moveTo(tabRect.topRight() + QPoint(2, 0)); 6235 else 6236 path.moveTo(tabRect.topRight()); 6237 path.lineTo(tabRect.topLeft() + QPointF(radius, 0)); 6238 path.quadTo(tabRect.topLeft(), tabRect.topLeft() + QPoint(0, radius)); 6239 path.lineTo(tabRect.bottomLeft()); 6240 path.lineTo(tabRect.bottomRight()); 6241 6242 } else if (isLast) { 6243 tabRect.adjust(0, 0, 0, -1); 6244 path.moveTo(tabRect.topRight()); 6245 path.lineTo(tabRect.topLeft()); 6246 path.lineTo(tabRect.bottomLeft() - QPointF(0, radius)); 6247 path.quadTo(tabRect.bottomLeft(), tabRect.bottomLeft() + QPointF(radius, 0)); 6248 path.lineTo(tabRect.bottomRight()); 6249 6250 } else { 6251 path.moveTo(tabRect.topRight()); 6252 path.lineTo(tabRect.topLeft()); 6253 path.lineTo(tabRect.bottomLeft()); 6254 path.lineTo(tabRect.bottomRight()); 6255 } 6256 6257 // highlight 6258 QRect highlightRect(tabRect.right() - Metrics::TabBar_BaseOverlap + Metrics::TabBar_TabOffset, tabRect.top(), 1, tabRect.height()); 6259 if (isFrameAligned && isFirst) 6260 highlightSlab = SlabRect(highlightRect.adjusted(0, -2, 0, 0), TileSet::TopLeft); 6261 else if (isFrameAligned && isLast) 6262 highlightSlab = SlabRect(highlightRect.adjusted(0, 0, 0, 2), TileSet::BottomLeft); 6263 else 6264 highlightSlab = SlabRect(highlightRect, TileSet::Left); 6265 6266 break; 6267 } 6268 6269 case QTabBar::RoundedEast: 6270 case QTabBar::TriangularEast: { 6271 tabRect.adjust(4, 0, -3, 1); 6272 6273 // adjust sides when slab is adjacent to selected slab 6274 if (isLeftOfSelected) 6275 tabRect.adjust(0, 0, 0, 2); 6276 else if (isRightOfSelected) 6277 tabRect.adjust(0, -2, 0, 0); 6278 6279 if (isFirst) { 6280 tabRect.adjust(0, 1, 0, 0); 6281 if (isFrameAligned) 6282 path.moveTo(tabRect.topLeft() - QPoint(2, 0)); 6283 else 6284 path.moveTo(tabRect.topLeft()); 6285 path.lineTo(tabRect.topRight() - QPointF(radius, 0)); 6286 path.quadTo(tabRect.topRight(), tabRect.topRight() + QPoint(0, radius)); 6287 path.lineTo(tabRect.bottomRight()); 6288 path.lineTo(tabRect.bottomLeft()); 6289 6290 } else if (isLast) { 6291 tabRect.adjust(0, 0, 0, -1); 6292 path.moveTo(tabRect.topLeft()); 6293 path.lineTo(tabRect.topRight()); 6294 path.lineTo(tabRect.bottomRight() - QPointF(0, radius)); 6295 path.quadTo(tabRect.bottomRight(), tabRect.bottomRight() - QPointF(radius, 0)); 6296 path.lineTo(tabRect.bottomLeft()); 6297 6298 } else { 6299 path.moveTo(tabRect.topLeft()); 6300 path.lineTo(tabRect.topRight()); 6301 path.lineTo(tabRect.bottomRight()); 6302 path.lineTo(tabRect.bottomLeft()); 6303 } 6304 6305 // highlight 6306 QRect highlightRect(tabRect.left() - Metrics::TabBar_BaseOverlap + Metrics::TabBar_TabOffset, tabRect.top(), TileSet::DefaultSize, tabRect.height()); 6307 if (isFrameAligned && isFirst) 6308 highlightSlab = SlabRect(highlightRect.adjusted(0, -2, 0, 0), TileSet::TopRight); 6309 else if (isFrameAligned && isLast) 6310 highlightSlab = SlabRect(highlightRect.adjusted(0, 0, 0, 2), TileSet::BottomRight); 6311 else 6312 highlightSlab = SlabRect(highlightRect, TileSet::Right); 6313 6314 break; 6315 } 6316 6317 default: 6318 break; 6319 } 6320 6321 const QColor color(palette.color(QPalette::Window)); 6322 6323 // adjust clip rect and render tab 6324 if (tabBar) { 6325 painter->save(); 6326 painter->setClipRegion(tabBarClipRegion(tabBar)); 6327 } 6328 6329 // fill tab 6330 const QColor backgroundColor = _helper->backgroundColor(color, widget, rect.center()); 6331 const QColor midColor = _helper->alphaColor(_helper->calcDarkColor(backgroundColor), 0.4); 6332 const QColor darkColor = _helper->alphaColor(_helper->calcDarkColor(backgroundColor), 0.6); 6333 6334 painter->save(); 6335 painter->translate(0.5, 0.5); 6336 painter->setRenderHints(QPainter::Antialiasing); 6337 painter->setPen(darkColor); 6338 painter->setBrush(midColor); 6339 painter->drawPath(path); 6340 painter->restore(); 6341 6342 // restore clip region 6343 if (tabBar) 6344 painter->restore(); 6345 6346 // handle base frame painting, for tabbars in which tab is being dragged 6347 _tabBarData->drawTabBarBaseControl(tabOption, painter, widget); 6348 6349 // hovered highlight 6350 if ((animated || mouseOver) && highlightSlab.isValid()) { 6351 highlightSlab.adjust(TileSet::DefaultSize); 6352 const QRect tabWidgetRect(tabWidget ? tabWidget->rect().translated(-widget->geometry().topLeft()) : QRect()); 6353 adjustSlabRect(highlightSlab, tabWidgetRect, documentMode, verticalTabs); 6354 6355 const qreal opacity(_animations->tabBarEngine().opacity(widget, rect.topLeft(), AnimationHover)); 6356 const StyleOptions hoverTabOpts(NoFill | Hover); 6357 6358 // pass an invalid color to have only the glow painted 6359 if (animated) 6360 renderSlab(painter, highlightSlab, QColor(), hoverTabOpts, opacity, AnimationHover); 6361 else 6362 renderSlab(painter, highlightSlab, QColor(), hoverTabOpts); 6363 } 6364 6365 return true; 6366 } 6367 6368 //___________________________________________________________________________________ 6369 bool Style::drawToolBoxTabLabelControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 6370 { 6371 // cast option and check 6372 const QStyleOptionToolBox *toolBoxOption(qstyleoption_cast<const QStyleOptionToolBox *>(option)); 6373 if (!toolBoxOption) 6374 return true; 6375 6376 // copy palette 6377 const QPalette &palette(option->palette); 6378 6379 const State &state(option->state); 6380 const bool enabled(state & State_Enabled); 6381 6382 // text alignment 6383 const int textFlags(_mnemonics->textFlags() | Qt::AlignCenter); 6384 6385 // contents rect 6386 const QRect rect(subElementRect(SE_ToolBoxTabContents, option, widget)); 6387 6388 // store icon size 6389 const int iconSize(pixelMetric(QStyle::PM_SmallIconSize, option, widget)); 6390 6391 // find contents size and rect 6392 QRect contentsRect(rect); 6393 QSize contentsSize; 6394 if (!toolBoxOption->text.isEmpty()) { 6395 contentsSize = option->fontMetrics.size(_mnemonics->textFlags(), toolBoxOption->text); 6396 if (!toolBoxOption->icon.isNull()) 6397 contentsSize.rwidth() += Metrics::ToolBox_TabItemSpacing; 6398 } 6399 6400 // icon size 6401 if (!toolBoxOption->icon.isNull()) { 6402 contentsSize.setHeight(qMax(contentsSize.height(), iconSize)); 6403 contentsSize.rwidth() += iconSize; 6404 } 6405 6406 // adjust contents rect 6407 contentsRect = centerRect(contentsRect, contentsSize); 6408 6409 // render icon 6410 if (!toolBoxOption->icon.isNull()) { 6411 // icon rect 6412 QRect iconRect; 6413 if (toolBoxOption->text.isEmpty()) 6414 iconRect = centerRect(contentsRect, iconSize, iconSize); 6415 else { 6416 iconRect = contentsRect; 6417 iconRect.setWidth(iconSize); 6418 iconRect = centerRect(iconRect, iconSize, iconSize); 6419 contentsRect.setLeft(iconRect.right() + Metrics::ToolBox_TabItemSpacing + 1); 6420 } 6421 6422 iconRect = visualRect(option, iconRect); 6423 const QIcon::Mode mode(enabled ? QIcon::Normal : QIcon::Disabled); 6424 const QPixmap pixmap(toolBoxOption->icon.pixmap(iconSize, mode)); 6425 drawItemPixmap(painter, iconRect, textFlags, pixmap); 6426 } 6427 6428 // render text 6429 if (!toolBoxOption->text.isEmpty()) { 6430 contentsRect = visualRect(option, contentsRect); 6431 drawItemText(painter, contentsRect, textFlags, palette, enabled, toolBoxOption->text, QPalette::WindowText); 6432 } 6433 6434 return true; 6435 } 6436 6437 //___________________________________________________________________________________ 6438 bool Style::drawToolBoxTabShapeControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 6439 { 6440 // copy rect and palette 6441 const QRect &rect(option->rect); 6442 const QPalette &palette(option->palette); 6443 6444 // copy state 6445 const State &state(option->state); 6446 const bool enabled(state & State_Enabled); 6447 const bool selected(state & State_Selected); 6448 const bool mouseOver(enabled && !selected && (state & State_MouseOver)); 6449 const bool reverseLayout(option->direction == Qt::RightToLeft); 6450 6451 // cast option and check 6452 const auto v2 = qstyleoption_cast<const QStyleOptionToolBox *>(option); 6453 if (v2 && v2->position == QStyleOptionToolBox::Beginning && selected) 6454 return true; 6455 6456 /* 6457 the proper widget ( the toolbox tab ) is not passed as argument by Qt. 6458 What is passed is the toolbox directly. To implement animations properly, 6459 the painter->device() is used instead 6460 */ 6461 bool animated(false); 6462 qreal opacity(AnimationData::OpacityInvalid); 6463 if (enabled) { 6464 // try retrieve button from painter device. 6465 if (QPaintDevice *device = painter->device()) { 6466 _animations->toolBoxEngine().updateState(device, mouseOver); 6467 animated = _animations->toolBoxEngine().isAnimated(device); 6468 opacity = _animations->toolBoxEngine().opacity(device); 6469 } 6470 } 6471 6472 // save colors for shadow 6473 /* important: option returns a wrong color. We use the widget's palette when widget is set */ 6474 const QColor color(widget ? widget->palette().color(widget->backgroundRole()) : palette.color(QPalette::Window)); 6475 const QColor dark(_helper->calcDarkColor(color)); 6476 QList<QColor> colors; 6477 colors.append(_helper->calcLightColor(color)); 6478 6479 if (mouseOver || animated) { 6480 QColor highlight = _helper->hoverColor(palette); 6481 if (animated) { 6482 colors.append(KColorUtils::mix(dark, highlight, opacity)); 6483 colors.append(_helper->alphaColor(highlight, 0.2 * opacity)); 6484 6485 } else { 6486 colors.append(highlight); 6487 colors.append(_helper->alphaColor(highlight, 0.2)); 6488 } 6489 6490 } else 6491 colors.append(dark); 6492 6493 // create path 6494 const qreal radius(8); 6495 const qreal offset(radius * std::tan(M_PI / 8)); 6496 const QRectF rectf(rect); 6497 6498 QPainterPath path; 6499 if (reverseLayout) { 6500 path.moveTo(rectf.right() - 1, rectf.top()); 6501 path.lineTo(rectf.left() + 50 + radius + offset, rectf.top()); 6502 path.arcTo(QRectF(rectf.left() + 50 + radius + offset - 2 * radius, rectf.top(), radius * 2, radius * 2), 90, 45); 6503 path.lineTo(rectf.left() + 50 - rectf.height() + 3 + offset / std::sqrt(2), rectf.bottom() - 3 - offset / std::sqrt(2)); 6504 path.arcTo(QRectF(rectf.left() + 50 - rectf.height() + 3 + radius - offset - 2 * radius, rectf.bottom() - 3 - 2 * radius, 2 * radius, 2 * radius), 6505 315, 6506 -45); 6507 path.lineTo(rectf.left(), rectf.bottom() - 3); 6508 6509 } else { 6510 path.moveTo(rectf.left(), rectf.top()); 6511 path.lineTo(rectf.right() - 50 - radius - offset, rectf.top()); 6512 path.arcTo(QRectF(rectf.right() - 50 - radius - offset, rectf.top(), radius * 2, radius * 2), 90, -45); 6513 path.lineTo(rectf.right() - 50 + rectf.height() - 3 - offset / std::sqrt(2), rectf.bottom() - 3 - offset / std::sqrt(2)); 6514 path.arcTo(QRectF(rectf.right() - 50 + rectf.height() - 3 - radius + offset, rectf.bottom() - 3 - 2 * radius, 2 * radius, 2 * radius), 225, 45); 6515 path.lineTo(rectf.right() - 1, rectf.bottom() - 3); 6516 } 6517 6518 // paint 6519 painter->setRenderHint(QPainter::Antialiasing, true); 6520 painter->translate(0.5, 0.5); 6521 painter->translate(0, 2); 6522 for (const QColor &color : std::as_const(colors)) { 6523 painter->setPen(color); 6524 painter->drawPath(path); 6525 painter->translate(0, -1); 6526 } 6527 6528 return true; 6529 } 6530 6531 //___________________________________________________________________________________ 6532 bool Style::drawDockWidgetTitleControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 6533 { 6534 // cast option and check 6535 const QStyleOptionDockWidget *dockWidgetOption = qstyleoption_cast<const QStyleOptionDockWidget *>(option); 6536 if (!dockWidgetOption) 6537 return true; 6538 6539 // copy palette 6540 const QPalette &palette(option->palette); 6541 6542 // store state 6543 const State &state(option->state); 6544 const bool enabled(state & State_Enabled); 6545 const bool reverseLayout(option->direction == Qt::RightToLeft); 6546 6547 // cast to v2 to check vertical bar 6548 const auto v2 = qstyleoption_cast<const QStyleOptionDockWidget *>(option); 6549 const bool verticalTitleBar(v2 ? v2->verticalTitleBar : false); 6550 6551 const QRect buttonRect(subElementRect(dockWidgetOption->floatable ? SE_DockWidgetFloatButton : SE_DockWidgetCloseButton, option, widget)); 6552 6553 // get rectangle and adjust to properly accounts for buttons 6554 QRect rect(insideMargin(dockWidgetOption->rect, Metrics::Frame_FrameWidth)); 6555 if (verticalTitleBar) { 6556 if (buttonRect.isValid()) 6557 rect.setTop(buttonRect.bottom() + 1); 6558 6559 } else if (reverseLayout) { 6560 if (buttonRect.isValid()) 6561 rect.setLeft(buttonRect.right() + 1); 6562 rect.adjust(0, 0, -4, 0); 6563 6564 } else { 6565 if (buttonRect.isValid()) 6566 rect.setRight(buttonRect.left() - 1); 6567 rect.adjust(4, 0, 0, 0); 6568 } 6569 6570 QString title(dockWidgetOption->title); 6571 int titleWidth = dockWidgetOption->fontMetrics.size(_mnemonics->textFlags(), title).width(); 6572 int width = verticalTitleBar ? rect.height() : rect.width(); 6573 if (width < titleWidth) 6574 title = dockWidgetOption->fontMetrics.elidedText(title, Qt::ElideRight, width, Qt::TextShowMnemonic); 6575 6576 if (verticalTitleBar) { 6577 QSize s = rect.size(); 6578 s.transpose(); 6579 rect.setSize(s); 6580 6581 painter->save(); 6582 painter->translate(rect.left(), rect.top() + rect.width()); 6583 painter->rotate(-90); 6584 painter->translate(-rect.left(), -rect.top()); 6585 drawItemText(painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText); 6586 painter->restore(); 6587 6588 } else { 6589 drawItemText(painter, rect, Qt::AlignLeft | Qt::AlignVCenter | _mnemonics->textFlags(), palette, enabled, title, QPalette::WindowText); 6590 } 6591 6592 return true; 6593 } 6594 6595 //___________________________________________________________________________________ 6596 bool Style::drawToolBarControl(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 6597 { 6598 // copy rect and palette 6599 const QRect &rect(option->rect); 6600 const QPalette &palette(option->palette); 6601 6602 // when timeLine is running draw border event if not hovered 6603 const bool toolBarAnimated(_animations->toolBarEngine().isFollowMouseAnimated(widget)); 6604 const QRect animatedRect(_animations->toolBarEngine().animatedRect(widget)); 6605 const bool toolBarIntersected(toolBarAnimated && animatedRect.intersects(rect)); 6606 if (toolBarIntersected) { 6607 _helper->slitFocused(_helper->focusColor(palette)).render(animatedRect, painter); 6608 } 6609 6610 // draw nothing otherwise ( toolbars are transparent ) 6611 6612 return true; 6613 } 6614 6615 //______________________________________________________________ 6616 bool Style::drawToolButtonComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 6617 { 6618 // check autoRaise state 6619 const State &state(option->state); 6620 const bool isInToolBar(widget && qobject_cast<QToolBar *>(widget->parent())); 6621 6622 // get rect and palette 6623 const QRect &rect(option->rect); 6624 const QStyleOptionToolButton *toolButtonOption(qstyleoption_cast<const QStyleOptionToolButton *>(option)); 6625 if (!toolButtonOption) 6626 return true; 6627 6628 const bool enabled(state & State_Enabled); 6629 const bool mouseOver(enabled && (state & State_MouseOver)); 6630 const bool hasFocus(enabled && (state & State_HasFocus)); 6631 const bool sunken(state & (State_Sunken | State_On)); 6632 const bool autoRaise(state & State_AutoRaise); 6633 6634 if (isInToolBar) { 6635 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 6636 6637 } else { 6638 // mouseOver has precedence over focus 6639 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 6640 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 6641 } 6642 6643 // toolbar animation 6644 QWidget *parent(widget ? widget->parentWidget() : nullptr); 6645 const bool toolBarAnimated(isInToolBar && _animations->toolBarEngine().isAnimated(parent)); 6646 const QRect animatedRect(_animations->toolBarEngine().animatedRect(parent)); 6647 const QRect currentRect(_animations->toolBarEngine().currentRect(parent)); 6648 const bool current(isInToolBar && currentRect.intersects(rect.translated(widget->mapToParent(QPoint(0, 0))))); 6649 const bool toolBarTimerActive(isInToolBar && _animations->toolBarEngine().isTimerActive(widget->parentWidget())); 6650 6651 // normal toolbutton animation 6652 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 6653 6654 // detect buttons in tabbar, for which special rendering is needed 6655 const bool inTabBar(widget && qobject_cast<const QTabBar *>(widget->parentWidget())); 6656 6657 // local copy of option 6658 QStyleOptionToolButton copy(*toolButtonOption); 6659 6660 const bool hasPopupMenu(toolButtonOption->features & QStyleOptionToolButton::MenuButtonPopup); 6661 const bool hasInlineIndicator(toolButtonOption->features & QStyleOptionToolButton::HasMenu 6662 && toolButtonOption->features & QStyleOptionToolButton::PopupDelay && !hasPopupMenu); 6663 6664 const QRect buttonRect(subControlRect(CC_ToolButton, option, SC_ToolButton, widget)); 6665 const QRect menuRect(subControlRect(CC_ToolButton, option, SC_ToolButtonMenu, widget)); 6666 6667 // frame 6668 const bool drawFrame((enabled && !(mouseOver || hasFocus || sunken) 6669 && ((mode != AnimationNone) || (((toolBarAnimated && animatedRect.isNull()) || toolBarTimerActive) && current))) 6670 || (toolButtonOption->subControls & SC_ToolButton)); 6671 if (drawFrame) { 6672 copy.rect = buttonRect; 6673 if (inTabBar) 6674 drawTabBarPanelButtonToolPrimitive(©, painter, widget); 6675 else 6676 drawPrimitive(PE_PanelButtonTool, ©, painter, widget); 6677 } 6678 6679 if (hasPopupMenu) { 6680 copy.rect = menuRect; 6681 if (!autoRaise) { 6682 drawPrimitive(PE_IndicatorButtonDropDown, ©, painter, widget); 6683 copy.state &= ~(State_MouseOver | State_HasFocus); 6684 } 6685 6686 drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); 6687 6688 } else if (hasInlineIndicator) { 6689 copy.rect = menuRect; 6690 copy.state &= ~(State_MouseOver | State_HasFocus); 6691 drawPrimitive(PE_IndicatorArrowDown, ©, painter, widget); 6692 } 6693 6694 // contents 6695 { 6696 // restore state 6697 copy.state = state; 6698 6699 // define contents rect 6700 QRect contentsRect(buttonRect); 6701 6702 // detect dock widget title button 6703 /* for dockwidget title buttons, do not take out margins, so that icon do not get scaled down */ 6704 const bool isDockWidgetTitleButton(widget && widget->inherits("QDockWidgetTitleButton")); 6705 if (isDockWidgetTitleButton) { 6706 // cast to abstract button 6707 // adjust state to have correct icon rendered 6708 const QAbstractButton *button(qobject_cast<const QAbstractButton *>(widget)); 6709 if (button->isChecked() || button->isDown()) 6710 copy.state |= State_On; 6711 6712 } else if (!inTabBar && hasInlineIndicator) { 6713 const int marginWidth(autoRaise ? Metrics::ToolButton_MarginWidth : Metrics::Button_MarginWidth + Metrics::Frame_FrameWidth); 6714 contentsRect = insideMargin(contentsRect, marginWidth, 0); 6715 contentsRect.setRight(contentsRect.right() - Metrics::ToolButton_InlineIndicatorWidth); 6716 contentsRect = visualRect(option, contentsRect); 6717 } 6718 6719 copy.rect = contentsRect; 6720 6721 // render 6722 drawControl(CE_ToolButtonLabel, ©, painter, widget); 6723 } 6724 6725 return true; 6726 } 6727 6728 //______________________________________________________________ 6729 bool Style::drawComboBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 6730 { 6731 // cast option and check 6732 const QStyleOptionComboBox *comboBoxOption(qstyleoption_cast<const QStyleOptionComboBox *>(option)); 6733 if (!comboBoxOption) 6734 return true; 6735 6736 // rect and palette 6737 const QRect &rect(option->rect); 6738 const QPalette &palette(option->palette); 6739 6740 // state 6741 const State &state(option->state); 6742 const bool enabled(state & State_Enabled); 6743 const bool mouseOver(enabled && (state & State_MouseOver)); 6744 const bool hasFocus(enabled && (state & State_HasFocus)); 6745 const bool editable(comboBoxOption->editable); 6746 const bool sunken(state & (State_On | State_Sunken)); 6747 bool flat(!comboBoxOption->frame); 6748 6749 // style options 6750 StyleOptions styleOptions; 6751 if (mouseOver) 6752 styleOptions |= Hover; 6753 if (hasFocus) 6754 styleOptions |= Focus; 6755 if (sunken && !editable) 6756 styleOptions |= Sunken; 6757 6758 // frame 6759 if (comboBoxOption->subControls & SC_ComboBoxFrame) { 6760 if (editable) { 6761 // editable combobox. Make it look like a LineEdit 6762 // focus takes precedence over hover 6763 _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus); 6764 _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver && !hasFocus); 6765 6766 // input area 6767 painter->setRenderHint(QPainter::Antialiasing); 6768 flat |= (rect.height() <= 2 * Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth); 6769 if (flat) { 6770 const QColor background(palette.color(QPalette::Base)); 6771 6772 painter->setPen(Qt::NoPen); 6773 painter->setBrush(background); 6774 painter->drawRect(rect); 6775 6776 } else { 6777 drawPrimitive(PE_FrameLineEdit, option, painter, widget); 6778 } 6779 6780 } else { 6781 // non editable combobox. Make it look like a PushButton 6782 // hover takes precedence over focus 6783 _animations->inputWidgetEngine().updateState(widget, AnimationHover, mouseOver); 6784 _animations->inputWidgetEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 6785 6786 const AnimationMode mode(_animations->inputWidgetEngine().buttonAnimationMode(widget)); 6787 const qreal opacity(_animations->inputWidgetEngine().buttonOpacity(widget)); 6788 6789 // blend button color to the background 6790 const QColor buttonColor(_helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 6791 const QRect slabRect(rect); 6792 6793 if (flat) { 6794 if (!sunken) { 6795 // hover rect 6796 const QColor glow(_helper->buttonGlowColor(palette, styleOptions, opacity, mode)); 6797 if (glow.isValid()) 6798 _helper->slitFocused(glow).render(rect, painter); 6799 6800 } else { 6801 styleOptions |= HoleContrast; 6802 _helper->renderHole(painter, palette.color(QPalette::Window), rect, styleOptions, opacity, mode); 6803 } 6804 6805 } else { 6806 renderButtonSlab(painter, slabRect, buttonColor, styleOptions, opacity, mode, TileSet::Ring); 6807 } 6808 } 6809 } 6810 6811 if (comboBoxOption->subControls & SC_ComboBoxArrow) { 6812 const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget); 6813 const bool empty(comboBox && !comboBox->count()); 6814 6815 QColor color; 6816 QColor background; 6817 bool drawContrast(true); 6818 6819 if (comboBoxOption->editable) { 6820 if (enabled && empty) 6821 color = palette.color(QPalette::Disabled, QPalette::Text); 6822 else { 6823 // check animation state 6824 const bool subControlHover(enabled && mouseOver && comboBoxOption->activeSubControls & SC_ComboBoxArrow); 6825 _animations->comboBoxEngine().updateState(widget, AnimationHover, subControlHover); 6826 6827 const bool animated(enabled && _animations->comboBoxEngine().isAnimated(widget, AnimationHover)); 6828 const qreal opacity(_animations->comboBoxEngine().opacity(widget, AnimationHover)); 6829 6830 if (animated) { 6831 QColor highlight = _helper->hoverColor(palette); 6832 color = KColorUtils::mix(palette.color(QPalette::Text), highlight, opacity); 6833 6834 } else if (subControlHover) { 6835 color = _helper->hoverColor(palette); 6836 6837 } else { 6838 color = palette.color(QPalette::Text); 6839 } 6840 } 6841 6842 background = palette.color(QPalette::Window); 6843 6844 if (enabled) 6845 drawContrast = false; 6846 6847 } else { 6848 // foreground color 6849 const QPalette::ColorRole role(flat ? QPalette::WindowText : QPalette::ButtonText); 6850 if (enabled && empty) 6851 color = palette.color(QPalette::Disabled, role); 6852 else 6853 color = palette.color(role); 6854 6855 // background color 6856 background = palette.color(flat ? QPalette::Window : QPalette::Button); 6857 } 6858 6859 // draw the arrow 6860 QRect arrowRect = subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget); 6861 const QPolygonF arrow(genericArrow(ArrowDown, ArrowNormal)); 6862 const qreal penThickness = 1.6; 6863 6864 painter->save(); 6865 painter->translate(QRectF(arrowRect).center()); 6866 painter->setRenderHint(QPainter::Antialiasing); 6867 6868 if (drawContrast) { 6869 const qreal offset(qMin(penThickness, qreal(1))); 6870 painter->translate(0, offset); 6871 painter->setPen(QPen(_helper->calcLightColor(palette.color(QPalette::Window)), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 6872 painter->drawPolyline(arrow); 6873 painter->translate(0, -offset); 6874 } 6875 6876 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 6877 painter->drawPolyline(arrow); 6878 painter->restore(); 6879 } 6880 6881 return true; 6882 } 6883 6884 //______________________________________________________________ 6885 bool Style::drawSpinBoxComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 6886 { 6887 // cast option and check 6888 const QStyleOptionSpinBox *spinBoxOption = qstyleoption_cast<const QStyleOptionSpinBox *>(option); 6889 if (!spinBoxOption) 6890 return true; 6891 6892 // copy rect and palette 6893 const QRect &rect(option->rect); 6894 const QPalette &palette(option->palette); 6895 6896 if (spinBoxOption->subControls & SC_SpinBoxFrame) { 6897 // detect flat spinboxes 6898 bool flat(!spinBoxOption->frame); 6899 flat |= (rect.height() <= 2 * Metrics::Frame_FrameWidth + Metrics::MenuButton_IndicatorWidth); 6900 if (flat) { 6901 const QColor background(palette.color(QPalette::Base)); 6902 6903 painter->setRenderHint(QPainter::Antialiasing); 6904 painter->setPen(Qt::NoPen); 6905 painter->setBrush(background); 6906 painter->drawRect(rect); 6907 6908 } else { 6909 drawPrimitive(PE_FrameLineEdit, option, painter, widget); 6910 } 6911 } 6912 6913 if (spinBoxOption->subControls & SC_SpinBoxUp) 6914 renderSpinBoxArrow(painter, spinBoxOption, widget, SC_SpinBoxUp); 6915 if (spinBoxOption->subControls & SC_SpinBoxDown) 6916 renderSpinBoxArrow(painter, spinBoxOption, widget, SC_SpinBoxDown); 6917 6918 return true; 6919 } 6920 6921 //______________________________________________________________ 6922 bool Style::drawSliderComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 6923 { 6924 // cast option and check 6925 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 6926 if (!sliderOption) 6927 return true; 6928 6929 // copy rect and palette 6930 const QRect &rect(option->rect); 6931 const QPalette &palette(option->palette); 6932 6933 // copy state 6934 const State &state(option->state); 6935 const bool enabled(state & State_Enabled); 6936 const bool mouseOver(enabled && (state & State_MouseOver)); 6937 const bool hasFocus(state & State_HasFocus); 6938 6939 // direction 6940 const bool horizontal(sliderOption->orientation == Qt::Horizontal); 6941 6942 if (sliderOption->subControls & SC_SliderTickmarks) { 6943 const bool upsideDown(sliderOption->upsideDown); 6944 const int tickPosition(sliderOption->tickPosition); 6945 const int available(pixelMetric(PM_SliderSpaceAvailable, option, widget)); 6946 int interval = sliderOption->tickInterval; 6947 if (interval < 1) 6948 interval = sliderOption->pageStep; 6949 if (interval >= 1) { 6950 const int fudge(pixelMetric(PM_SliderLength, option, widget) / 2); 6951 int current(sliderOption->minimum); 6952 6953 // store tick lines 6954 const QRect grooveRect(subControlRect(CC_Slider, sliderOption, SC_SliderGroove, widget)); 6955 QList<QLine> tickLines; 6956 if (horizontal) { 6957 if (tickPosition & QSlider::TicksAbove) 6958 tickLines.append(QLine(rect.left(), 6959 grooveRect.top() - Metrics::Slider_TickMarginWidth, 6960 rect.left(), 6961 grooveRect.top() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength)); 6962 if (tickPosition & QSlider::TicksBelow) 6963 tickLines.append(QLine(rect.left(), 6964 grooveRect.bottom() + Metrics::Slider_TickMarginWidth, 6965 rect.left(), 6966 grooveRect.bottom() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength)); 6967 6968 } else { 6969 if (tickPosition & QSlider::TicksAbove) 6970 tickLines.append(QLine(grooveRect.left() - Metrics::Slider_TickMarginWidth, 6971 rect.top(), 6972 grooveRect.left() - Metrics::Slider_TickMarginWidth - Metrics::Slider_TickLength, 6973 rect.top())); 6974 if (tickPosition & QSlider::TicksBelow) 6975 tickLines.append(QLine(grooveRect.right() + Metrics::Slider_TickMarginWidth, 6976 rect.top(), 6977 grooveRect.right() + Metrics::Slider_TickMarginWidth + Metrics::Slider_TickLength, 6978 rect.top())); 6979 } 6980 6981 // colors 6982 QColor base(_helper->backgroundColor(palette.color(QPalette::Window), widget, rect.center())); 6983 base = _helper->calcDarkColor(base); 6984 painter->setPen(base); 6985 6986 while (current <= sliderOption->maximum) { 6987 // calculate positions and draw lines 6988 int position(sliderPositionFromValue(sliderOption->minimum, sliderOption->maximum, current, available) + fudge); 6989 for (const QLine &tickLine : std::as_const(tickLines)) { 6990 if (horizontal) 6991 painter->drawLine(tickLine.translated(upsideDown ? (rect.width() - position) : position, 0)); 6992 else 6993 painter->drawLine(tickLine.translated(0, upsideDown ? (rect.height() - position) : position)); 6994 } 6995 6996 // go to next position 6997 current += interval; 6998 } 6999 } 7000 } 7001 7002 // groove 7003 if (sliderOption->subControls & SC_SliderGroove) { 7004 // get rect 7005 QRect grooveRect(subControlRect(CC_Slider, sliderOption, SC_SliderGroove, widget)); 7006 7007 // render 7008 _helper->scrollHole(palette.color(QPalette::Window), sliderOption->orientation, true).render(grooveRect, painter, TileSet::Full); 7009 } 7010 7011 // handle 7012 if (sliderOption->subControls & SC_SliderHandle) { 7013 // get rect and center 7014 QRect handleRect(subControlRect(CC_Slider, sliderOption, SC_SliderHandle, widget)); 7015 7016 // handle state 7017 const bool handleActive(sliderOption->activeSubControls & SC_SliderHandle); 7018 const bool sunken(state & (State_On | State_Sunken)); 7019 StyleOptions styleOptions; 7020 if (hasFocus) 7021 styleOptions |= Focus; 7022 if (handleActive && mouseOver) 7023 styleOptions |= Hover; 7024 7025 // animation state 7026 _animations->widgetStateEngine().updateState(widget, AnimationHover, handleActive && mouseOver); 7027 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus); 7028 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 7029 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 7030 7031 // define colors 7032 const QColor color(_helper->backgroundColor(palette.color(QPalette::Button), widget, handleRect.center())); 7033 const QColor glow(_helper->buttonGlowColor(palette, styleOptions, opacity, mode)); 7034 7035 // render 7036 painter->drawPixmap(handleRect.topLeft(), _helper->sliderSlab(color, glow, sunken, 0)); 7037 } 7038 7039 return true; 7040 } 7041 7042 //______________________________________________________________ 7043 bool Style::drawDialComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 7044 { 7045 const State &state(option->state); 7046 const bool enabled = state & State_Enabled; 7047 const bool mouseOver(enabled && (state & State_MouseOver)); 7048 const bool hasFocus(enabled && (state & State_HasFocus)); 7049 const bool sunken(state & (State_On | State_Sunken)); 7050 7051 StyleOptions styleOptions; 7052 if (sunken) 7053 styleOptions |= Sunken; 7054 if (hasFocus) 7055 styleOptions |= Focus; 7056 if (mouseOver) 7057 styleOptions |= Hover; 7058 7059 // mouseOver has precedence over focus 7060 _animations->widgetStateEngine().updateState(widget, AnimationHover, mouseOver); 7061 _animations->widgetStateEngine().updateState(widget, AnimationFocus, hasFocus && !mouseOver); 7062 7063 const AnimationMode mode(_animations->widgetStateEngine().buttonAnimationMode(widget)); 7064 const qreal opacity(_animations->widgetStateEngine().buttonOpacity(widget)); 7065 7066 const QRect rect(option->rect); 7067 const QPalette &palette(option->palette); 7068 const QColor buttonColor(_helper->backgroundColor(palette.color(QPalette::Button), widget, rect.center())); 7069 renderDialSlab(painter, rect, buttonColor, option, styleOptions, opacity, mode); 7070 7071 return true; 7072 } 7073 7074 //______________________________________________________________ 7075 bool Style::drawScrollBarComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 7076 { 7077 // render full groove directly, rather than using the addPage and subPage control element methods 7078 if (option->subControls & SC_ScrollBarGroove) { 7079 // retrieve groove rectangle 7080 QRect grooveRect(subControlRect(CC_ScrollBar, option, SC_ScrollBarGroove, widget)); 7081 7082 const QPalette &palette(option->palette); 7083 const QColor color(palette.color(QPalette::Window)); 7084 const State &state(option->state); 7085 const bool horizontal(state & State_Horizontal); 7086 7087 if (horizontal) 7088 grooveRect = centerRect(grooveRect, grooveRect.width(), StyleConfigData::scrollBarWidth()); 7089 else 7090 grooveRect = centerRect(grooveRect, StyleConfigData::scrollBarWidth(), grooveRect.height()); 7091 7092 // render 7093 renderScrollBarHole(painter, grooveRect, color, Qt::Horizontal); 7094 } 7095 7096 // call base class primitive 7097 KStyle::drawComplexControl(CC_ScrollBar, option, painter, widget); 7098 return true; 7099 } 7100 7101 //______________________________________________________________ 7102 bool Style::drawTitleBarComplexControl(const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const 7103 { 7104 const QStyleOptionTitleBar *titleBarOption(qstyleoption_cast<const QStyleOptionTitleBar *>(option)); 7105 if (!titleBarOption) 7106 return true; 7107 7108 const State &state(option->state); 7109 const bool enabled(state & State_Enabled); 7110 const bool active(enabled && (titleBarOption->titleBarState & Qt::WindowActive)); 7111 7112 // draw title text 7113 { 7114 QRect textRect = subControlRect(CC_TitleBar, titleBarOption, SC_TitleBarLabel, widget); 7115 7116 // enable state transition 7117 _animations->widgetEnableStateEngine().updateState(widget, AnimationEnable, active); 7118 7119 // make sure palette has the correct color group 7120 QPalette palette(option->palette); 7121 7122 if (_animations->widgetEnableStateEngine().isAnimated(widget, AnimationEnable)) { 7123 palette = _helper->disabledPalette(palette, _animations->widgetEnableStateEngine().opacity(widget, AnimationEnable)); 7124 } 7125 7126 palette.setCurrentColorGroup(active ? QPalette::Active : QPalette::Disabled); 7127 KStyle::drawItemText(painter, textRect, Qt::AlignCenter, palette, active, titleBarOption->text, QPalette::WindowText); 7128 } 7129 7130 // menu button 7131 if ((titleBarOption->subControls & SC_TitleBarSysMenu) && (titleBarOption->titleBarFlags & Qt::WindowSystemMenuHint) && !titleBarOption->icon.isNull()) { 7132 QRect iconRect = subControlRect(CC_TitleBar, titleBarOption, SC_TitleBarSysMenu, widget); 7133 const int iconWidth(pixelMetric(PM_SmallIconSize, option, widget)); 7134 const QSize iconSize(iconWidth, iconWidth); 7135 iconRect = centerRect(iconRect, iconSize); 7136 const QPixmap pixmap = titleBarOption->icon.pixmap(iconSize, QIcon::Normal, QIcon::On); 7137 painter->drawPixmap(iconRect, pixmap); 7138 } 7139 7140 if ((titleBarOption->subControls & SC_TitleBarMinButton) && (titleBarOption->titleBarFlags & Qt::WindowMinimizeButtonHint)) { 7141 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarMinButton); 7142 } 7143 7144 if ((titleBarOption->subControls & SC_TitleBarMaxButton) && (titleBarOption->titleBarFlags & Qt::WindowMaximizeButtonHint)) { 7145 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarMaxButton); 7146 } 7147 7148 if ((titleBarOption->subControls & SC_TitleBarCloseButton)) { 7149 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarCloseButton); 7150 } 7151 7152 if ((titleBarOption->subControls & SC_TitleBarNormalButton) 7153 && (((titleBarOption->titleBarFlags & Qt::WindowMinimizeButtonHint) && (titleBarOption->titleBarState & Qt::WindowMinimized)) 7154 || ((titleBarOption->titleBarFlags & Qt::WindowMaximizeButtonHint) && (titleBarOption->titleBarState & Qt::WindowMaximized)))) { 7155 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarNormalButton); 7156 } 7157 7158 if (titleBarOption->subControls & SC_TitleBarShadeButton) { 7159 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarShadeButton); 7160 } 7161 7162 if (titleBarOption->subControls & SC_TitleBarUnshadeButton) { 7163 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarUnshadeButton); 7164 } 7165 7166 if ((titleBarOption->subControls & SC_TitleBarContextHelpButton) && (titleBarOption->titleBarFlags & Qt::WindowContextHelpButtonHint)) { 7167 renderTitleBarButton(painter, titleBarOption, widget, SC_TitleBarContextHelpButton); 7168 } 7169 7170 return true; 7171 } 7172 7173 //_________________________________________________________________________________ 7174 void Style::renderDialSlab(QPainter *painter, 7175 const QRect &constRect, 7176 const QColor &color, 7177 const QStyleOption *option, 7178 StyleOptions styleOptions, 7179 qreal opacity, 7180 AnimationMode mode) const 7181 { 7182 // cast option and check 7183 const QStyleOptionSlider *sliderOption(qstyleoption_cast<const QStyleOptionSlider *>(option)); 7184 if (!sliderOption) 7185 return; 7186 7187 // copy palette 7188 const QPalette &palette(option->palette); 7189 7190 // adjust rect to be square, and centered 7191 const int dimension(qMin(constRect.width(), constRect.height())); 7192 const QRect rect(centerRect(constRect, dimension, dimension)); 7193 7194 // calculate glow color 7195 const QColor glow(_helper->buttonGlowColor(palette, styleOptions, opacity, mode)); 7196 7197 // get main slab 7198 QPixmap pixmap(_helper->dialSlab(color, glow, 0, dimension)); 7199 { 7200 const QColor light(_helper->calcLightColor(color)); 7201 const QColor shadow(_helper->calcShadowColor(color)); 7202 7203 QPainter painter(&pixmap); 7204 painter.setPen(Qt::NoPen); 7205 painter.setRenderHints(QPainter::Antialiasing); 7206 7207 // indicator 7208 const qreal angle(dialAngle(sliderOption, sliderOption->sliderPosition)); 7209 QPointF center(pixmap.rect().center() / _helper->devicePixelRatio(pixmap)); 7210 const int sliderWidth(dimension / 6); 7211 const qreal radius(0.5 * (dimension - 2 * sliderWidth)); 7212 center += QPointF(radius * cos(angle), -radius * sin(angle)); 7213 7214 QRectF sliderRect(0, 0, sliderWidth, sliderWidth); 7215 sliderRect.moveCenter(center); 7216 7217 // outline circle 7218 const qreal offset(0.3); 7219 painter.setBrush(light); 7220 painter.setPen(Qt::NoPen); 7221 painter.drawEllipse(sliderRect.translated(0, offset)); 7222 7223 // mask 7224 painter.setPen(Qt::NoPen); 7225 painter.save(); 7226 painter.setCompositionMode(QPainter::CompositionMode_DestinationOut); 7227 painter.setBrush(QBrush(Qt::black)); 7228 painter.drawEllipse(sliderRect); 7229 painter.restore(); 7230 7231 // shadow 7232 painter.translate(sliderRect.topLeft()); 7233 _helper->drawInverseShadow(painter, shadow.darker(200), 0, sliderRect.width(), 0); 7234 7235 // glow 7236 if (glow.isValid()) 7237 _helper->drawInverseGlow(painter, glow, 0, sliderRect.width(), sliderRect.width()); 7238 7239 painter.end(); 7240 } 7241 7242 painter->drawPixmap(rect.topLeft(), pixmap); 7243 7244 return; 7245 } 7246 7247 //____________________________________________________________________________________ 7248 void Style::renderButtonSlab(QPainter *painter, QRect rect, const QColor &color, StyleOptions options, qreal opacity, AnimationMode mode, TileSet::Tiles tiles) 7249 const 7250 { 7251 // check rect 7252 if (!rect.isValid()) 7253 return; 7254 7255 // edges 7256 // for slabs, hover takes precedence over focus ( other way around for holes ) 7257 // but in any case if the button is sunken we don't show focus nor hover 7258 TileSet tileSet; 7259 if (options & Sunken) { 7260 tileSet = _helper->slabSunken(color); 7261 7262 } else { 7263 QColor glow = _helper->buttonGlowColor(QPalette::Active, options, opacity, mode); 7264 tileSet = _helper->slab(color, glow, 0); 7265 } 7266 7267 // adjust rect to account for missing tiles 7268 if (tileSet.isValid()) 7269 rect = tileSet.adjust(rect, tiles); 7270 7271 // fill 7272 if (!(options & NoFill)) 7273 _helper->fillButtonSlab(*painter, rect, color, options & Sunken); 7274 7275 // render slab 7276 if (tileSet.isValid()) 7277 tileSet.render(rect, painter, tiles); 7278 } 7279 7280 //____________________________________________________________________________________ 7281 void Style::renderSlab(QPainter *painter, QRect rect, const QColor &color, StyleOptions options, qreal opacity, AnimationMode mode, TileSet::Tiles tiles) const 7282 { 7283 // check rect 7284 if (!rect.isValid()) 7285 return; 7286 7287 // fill 7288 if (!(options & NoFill)) { 7289 painter->save(); 7290 painter->setRenderHint(QPainter::Antialiasing); 7291 painter->setPen(Qt::NoPen); 7292 7293 if (_helper->calcShadowColor(color).value() > color.value() && (options & Sunken)) { 7294 QLinearGradient innerGradient(0, rect.top(), 0, rect.bottom() + rect.height()); 7295 innerGradient.setColorAt(0, color); 7296 innerGradient.setColorAt(1, _helper->calcLightColor(color)); 7297 painter->setBrush(innerGradient); 7298 7299 } else { 7300 QLinearGradient innerGradient(0, rect.top() - rect.height(), 0, rect.bottom()); 7301 innerGradient.setColorAt(0, _helper->calcLightColor(color)); 7302 innerGradient.setColorAt(1, color); 7303 painter->setBrush(innerGradient); 7304 } 7305 7306 _helper->fillSlab(*painter, rect); 7307 7308 painter->restore(); 7309 } 7310 7311 // edges 7312 // for slabs, hover takes precedence over focus ( other way around for holes ) 7313 // but in any case if the button is sunken we don't show focus nor hover 7314 TileSet tileSet; 7315 if ((options & Sunken) && color.isValid()) { 7316 tileSet = _helper->slabSunken(color); 7317 7318 } else { 7319 // calculate proper glow color based on current settings and opacity 7320 const QColor glow(_helper->buttonGlowColor(QPalette::Active, options, opacity, mode)); 7321 if (color.isValid() || glow.isValid()) 7322 tileSet = _helper->slab(color, glow, 0); 7323 else 7324 return; 7325 } 7326 7327 // render tileset 7328 if (tileSet.isValid()) 7329 tileSet.render(rect, painter, tiles); 7330 } 7331 7332 //______________________________________________________________________________________________________________________________ 7333 void Style::fillTabBackground(QPainter *painter, const QRect &rect, const QColor &color, const QWidget *widget) const 7334 { 7335 // filling 7336 const QRect fillRect(insideMargin(rect, Metrics::TabBar_TabOffset)); 7337 if (widget) 7338 _helper->renderWindowBackground(painter, fillRect, widget, color); 7339 else 7340 painter->fillRect(fillRect, color); 7341 } 7342 7343 //______________________________________________________________________________________________________________________________ 7344 void Style::fillTab(QPainter *painter, const QRect &rect, const QColor &color, QTabBar::Shape shape) const 7345 { 7346 const QColor dark(_helper->calcDarkColor(color)); 7347 const QColor shadow(_helper->calcShadowColor(color)); 7348 const QColor light(_helper->calcLightColor(color)); 7349 const QRect fillRect(insideMargin(rect, Metrics::TabBar_TabOffset)); 7350 7351 QLinearGradient gradient; 7352 switch (shape) { 7353 case QTabBar::RoundedNorth: 7354 case QTabBar::TriangularNorth: 7355 gradient = QLinearGradient(fillRect.topLeft(), fillRect.bottomLeft()); 7356 break; 7357 7358 case QTabBar::RoundedSouth: 7359 case QTabBar::TriangularSouth: 7360 gradient = QLinearGradient(fillRect.bottomLeft(), fillRect.topLeft()); 7361 break; 7362 7363 case QTabBar::RoundedEast: 7364 case QTabBar::TriangularEast: 7365 gradient = QLinearGradient(fillRect.topRight(), fillRect.topLeft()); 7366 break; 7367 7368 case QTabBar::RoundedWest: 7369 case QTabBar::TriangularWest: 7370 gradient = QLinearGradient(fillRect.topLeft(), fillRect.topRight()); 7371 break; 7372 7373 default: 7374 return; 7375 } 7376 7377 gradient.setColorAt(0, _helper->alphaColor(light, 0.5)); 7378 gradient.setColorAt(0.1, _helper->alphaColor(light, 0.5)); 7379 gradient.setColorAt(0.25, _helper->alphaColor(light, 0.3)); 7380 gradient.setColorAt(0.5, _helper->alphaColor(light, 0.2)); 7381 gradient.setColorAt(0.75, _helper->alphaColor(light, 0.1)); 7382 gradient.setColorAt(0.9, Qt::transparent); 7383 7384 painter->setRenderHints(QPainter::Antialiasing); 7385 painter->setPen(Qt::NoPen); 7386 7387 painter->setBrush(gradient); 7388 painter->drawRoundedRect(fillRect, 2, 2); 7389 } 7390 7391 //____________________________________________________________________________________________________ 7392 void Style::renderSpinBoxArrow(QPainter *painter, const QStyleOptionSpinBox *option, const QWidget *widget, const SubControl &subControl) const 7393 { 7394 const QPalette &palette(option->palette); 7395 const State &state(option->state); 7396 7397 // enable state 7398 bool enabled(state & State_Enabled); 7399 7400 // check steps enable step 7401 const bool atLimit((subControl == SC_SpinBoxUp && !(option->stepEnabled & QAbstractSpinBox::StepUpEnabled)) 7402 || (subControl == SC_SpinBoxDown && !(option->stepEnabled & QAbstractSpinBox::StepDownEnabled))); 7403 7404 // update enabled state accordingly 7405 enabled &= !atLimit; 7406 7407 // update mouse-over effect 7408 const bool mouseOver(enabled && (state & State_MouseOver)); 7409 7410 // check animation state 7411 const bool subControlHover(enabled && mouseOver && (option->activeSubControls & subControl)); 7412 _animations->spinBoxEngine().updateState(widget, subControl, subControlHover); 7413 7414 const bool animated(enabled && _animations->spinBoxEngine().isAnimated(widget, subControl)); 7415 const qreal opacity(_animations->spinBoxEngine().opacity(widget, subControl)); 7416 7417 QColor color; 7418 if (animated) { 7419 QColor highlight = _helper->hoverColor(palette); 7420 color = KColorUtils::mix(palette.color(QPalette::Text), highlight, opacity); 7421 7422 } else if (subControlHover) { 7423 color = _helper->hoverColor(palette); 7424 7425 } else if (atLimit) { 7426 color = palette.color(QPalette::Disabled, QPalette::Text); 7427 7428 } else { 7429 color = palette.color(QPalette::Text); 7430 } 7431 7432 const qreal penThickness = 1.6; 7433 const QColor background = palette.color(QPalette::Window); 7434 7435 const QPolygonF arrow(genericArrow((subControl == SC_SpinBoxUp) ? ArrowUp : ArrowDown, ArrowNormal)); 7436 const QRect arrowRect(subControlRect(CC_SpinBox, option, subControl, widget)); 7437 7438 painter->save(); 7439 painter->translate(QRectF(arrowRect).center()); 7440 painter->setRenderHint(QPainter::Antialiasing); 7441 7442 painter->setPen(QPen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 7443 painter->drawPolyline(arrow); 7444 painter->restore(); 7445 7446 return; 7447 } 7448 7449 //___________________________________________________________________________________ 7450 void Style::renderSplitter(const QStyleOption *option, QPainter *painter, const QWidget *widget, bool horizontal) const 7451 { 7452 // copy rect and palette 7453 const QRect &rect(option->rect); 7454 const QPalette &palette(option->palette); 7455 7456 // store state 7457 const State &state(option->state); 7458 const bool enabled(state & State_Enabled); 7459 const bool mouseOver(enabled && (state & (State_MouseOver | State_Sunken))); 7460 7461 // get orientation 7462 const Qt::Orientation orientation(horizontal ? Qt::Horizontal : Qt::Vertical); 7463 7464 bool animated(false); 7465 qreal opacity(AnimationData::OpacityInvalid); 7466 7467 if (enabled) { 7468 if (qobject_cast<const QMainWindow *>(widget)) { 7469 _animations->dockSeparatorEngine().updateRect(widget, rect, orientation, mouseOver); 7470 animated = _animations->dockSeparatorEngine().isAnimated(widget, rect, orientation); 7471 opacity = animated ? _animations->dockSeparatorEngine().opacity(widget, orientation) : AnimationData::OpacityInvalid; 7472 7473 } else if (QPaintDevice *device = painter->device()) { 7474 /* 7475 try update QSplitterHandle using painter device, because Qt passes 7476 QSplitter as the widget to the QStyle primitive. 7477 */ 7478 _animations->splitterEngine().updateState(device, mouseOver); 7479 animated = _animations->splitterEngine().isAnimated(device); 7480 opacity = _animations->splitterEngine().opacity(device); 7481 } 7482 } 7483 7484 // get base color 7485 const QColor color = palette.color(QPalette::Window); 7486 7487 if (horizontal) { 7488 const int hCenter = rect.center().x(); 7489 const int h = rect.height(); 7490 7491 if (animated || mouseOver) { 7492 const QColor highlight = _helper->alphaColor(_helper->calcLightColor(color), 0.5 * (animated ? opacity : 1)); 7493 const qreal fraction(rect.height() > 30 ? 10 / rect.height() : 0.1); 7494 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); 7495 gradient.setColorAt(0, Qt::transparent); 7496 gradient.setColorAt(fraction, highlight); 7497 gradient.setColorAt(1 - fraction, highlight); 7498 gradient.setColorAt(1, Qt::transparent); 7499 painter->fillRect(rect, gradient); 7500 } 7501 7502 const int ngroups(qMax(1, h / 250)); 7503 int center((h - (ngroups - 1) * 250) / 2 + rect.top()); 7504 for (int k = 0; k < ngroups; k++, center += 250) { 7505 _helper->renderDot(painter, QPoint(hCenter, center - 3), color); 7506 _helper->renderDot(painter, QPoint(hCenter, center), color); 7507 _helper->renderDot(painter, QPoint(hCenter, center + 3), color); 7508 } 7509 7510 } else { 7511 const int vCenter(rect.center().y()); 7512 const int w(rect.width()); 7513 if (animated || mouseOver) { 7514 const QColor highlight(_helper->alphaColor(_helper->calcLightColor(color), 0.5 * (animated ? opacity : 1))); 7515 const qreal fraction(rect.width() > 30 ? 10 / rect.width() : 0.1); 7516 QLinearGradient gradient(rect.topLeft(), rect.topRight()); 7517 gradient.setColorAt(0, Qt::transparent); 7518 gradient.setColorAt(fraction, highlight); 7519 gradient.setColorAt(1 - fraction, highlight); 7520 gradient.setColorAt(1, Qt::transparent); 7521 painter->fillRect(rect, gradient); 7522 } 7523 7524 const int ngroups(qMax(1, w / 250)); 7525 int center = (w - (ngroups - 1) * 250) / 2 + rect.left(); 7526 for (int k = 0; k < ngroups; k++, center += 250) { 7527 _helper->renderDot(painter, QPoint(center - 3, vCenter), color); 7528 _helper->renderDot(painter, QPoint(center, vCenter), color); 7529 _helper->renderDot(painter, QPoint(center + 3, vCenter), color); 7530 } 7531 } 7532 } 7533 7534 //____________________________________________________________________________________________________ 7535 void Style::renderTitleBarButton(QPainter *painter, const QStyleOptionTitleBar *option, const QWidget *widget, const SubControl &subControl) const 7536 { 7537 // get relevant rect 7538 const QRect rect = subControlRect(CC_TitleBar, option, subControl, widget); 7539 if (!rect.isValid()) 7540 return; 7541 7542 // copy palette 7543 QPalette palette = option->palette; 7544 7545 // store state 7546 const State &state(option->state); 7547 const bool enabled(state & State_Enabled); 7548 const bool active(enabled && (option->titleBarState & Qt::WindowActive)); 7549 7550 // enable state transition 7551 _animations->widgetEnableStateEngine().updateState(widget, AnimationEnable, active); 7552 if (_animations->widgetEnableStateEngine().isAnimated(widget, AnimationEnable)) { 7553 palette = _helper->disabledPalette(palette, _animations->widgetEnableStateEngine().opacity(widget, AnimationEnable)); 7554 } 7555 7556 const bool sunken(state & State_Sunken); 7557 const bool mouseOver((!sunken) && widget && rect.translated(widget->mapToGlobal(QPoint(0, 0))).contains(QCursor::pos())); 7558 7559 _animations->mdiWindowEngine().updateState(widget, subControl, enabled && mouseOver); 7560 const bool animated(enabled && _animations->mdiWindowEngine().isAnimated(widget, subControl)); 7561 const qreal opacity(_animations->mdiWindowEngine().opacity(widget, subControl)); 7562 7563 // contrast color 7564 const QColor base = option->palette.color(QPalette::Active, QPalette::Window); 7565 7566 // icon color 7567 QColor color; 7568 if (animated) { 7569 const QColor base(palette.color(active ? QPalette::Active : QPalette::Disabled, QPalette::WindowText)); 7570 const QColor glow(subControl == SC_TitleBarCloseButton ? _helper->negativeTextColor(palette) : _helper->hoverColor(palette)); 7571 7572 color = KColorUtils::mix(base, glow, opacity); 7573 7574 } else if (mouseOver) { 7575 color = (subControl == SC_TitleBarCloseButton) ? _helper->negativeTextColor(palette) : _helper->hoverColor(palette); 7576 7577 } else { 7578 color = palette.color(active ? QPalette::Active : QPalette::Disabled, QPalette::WindowText); 7579 } 7580 7581 // rendering 7582 renderTitleBarButton(painter, rect, base, color, subControl); 7583 } 7584 7585 //____________________________________________________________________________________________________ 7586 void Style::renderTitleBarButton(QPainter *painter, const QRect &rect, const QColor &base, const QColor &color, const SubControl &subControl) const 7587 { 7588 painter->save(); 7589 painter->setRenderHints(QPainter::Antialiasing); 7590 painter->setBrush(Qt::NoBrush); 7591 7592 painter->drawPixmap(rect, _helper->dockWidgetButton(base, true, rect.width())); 7593 7594 const qreal width(1.1); 7595 7596 // contrast 7597 painter->translate(0, 0.5); 7598 painter->setPen(QPen(_helper->calcLightColor(base), width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 7599 renderTitleBarIcon(painter, rect, subControl); 7600 7601 // main icon painting 7602 painter->translate(0, -1); 7603 painter->setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 7604 renderTitleBarIcon(painter, rect, subControl); 7605 7606 painter->restore(); 7607 } 7608 7609 //____________________________________________________________________________________ 7610 void Style::renderTitleBarIcon(QPainter *painter, const QRect &rect, const SubControl &subControl) const 7611 { 7612 painter->save(); 7613 7614 painter->translate(rect.topLeft()); 7615 painter->scale(qreal(rect.width()) / 16, qreal(rect.height()) / 16); 7616 7617 switch (subControl) { 7618 case SC_TitleBarContextHelpButton: { 7619 painter->drawArc(6, 4, 3, 3, 135 * 16, -180 * 16); 7620 painter->drawArc(8, 7, 3, 3, 135 * 16, 45 * 16); 7621 painter->drawPoint(8, 11); 7622 break; 7623 } 7624 7625 case SC_TitleBarMinButton: { 7626 painter->drawPolyline(QPolygon() << QPoint(5, 7) << QPoint(8, 10) << QPoint(11, 7)); 7627 break; 7628 } 7629 7630 case SC_TitleBarNormalButton: { 7631 painter->drawPolygon(QPolygon() << QPoint(8, 5) << QPoint(11, 8) << QPoint(8, 11) << QPoint(5, 8)); 7632 break; 7633 } 7634 7635 case SC_TitleBarMaxButton: { 7636 painter->drawPolyline(QPolygon() << QPoint(5, 9) << QPoint(8, 6) << QPoint(11, 9)); 7637 break; 7638 } 7639 7640 case SC_TitleBarCloseButton: { 7641 painter->drawLine(QPointF(5.5, 5.5), QPointF(10.5, 10.5)); 7642 painter->drawLine(QPointF(10.5, 5.5), QPointF(5.5, 10.5)); 7643 break; 7644 } 7645 7646 case SC_TitleBarShadeButton: { 7647 painter->drawLine(QPoint(5, 11), QPoint(11, 11)); 7648 painter->drawPolyline(QPolygon() << QPoint(5, 5) << QPoint(8, 8) << QPoint(11, 5)); 7649 break; 7650 } 7651 7652 case SC_TitleBarUnshadeButton: { 7653 painter->drawPolyline(QPolygon() << QPoint(5, 8) << QPoint(8, 5) << QPoint(11, 8)); 7654 painter->drawLine(QPoint(5, 11), QPoint(11, 11)); 7655 break; 7656 } 7657 7658 default: 7659 break; 7660 } 7661 painter->restore(); 7662 } 7663 7664 //__________________________________________________________________________ 7665 void Style::renderHeaderBackground(const QRect &rect, const QPalette &palette, QPainter *painter, const QWidget *widget, bool horizontal, bool reverse) const 7666 { 7667 // use window background for the background 7668 if (widget) 7669 _helper->renderWindowBackground(painter, rect, widget, palette); 7670 else 7671 painter->fillRect(rect, palette.color(QPalette::Window)); 7672 7673 if (horizontal) 7674 renderHeaderLines(rect, palette, painter, TileSet::Bottom); 7675 else if (reverse) 7676 renderHeaderLines(rect, palette, painter, TileSet::Left); 7677 else 7678 renderHeaderLines(rect, palette, painter, TileSet::Right); 7679 } 7680 7681 //__________________________________________________________________________ 7682 void Style::renderHeaderLines(const QRect &constRect, const QPalette &palette, QPainter *painter, TileSet::Tiles tiles) const 7683 { 7684 // add horizontal lines 7685 const QColor color(palette.color(QPalette::Window)); 7686 const QColor dark(_helper->calcDarkColor(color)); 7687 const QColor light(_helper->calcLightColor(color)); 7688 7689 painter->save(); 7690 QRect rect(constRect); 7691 if (tiles & TileSet::Bottom) { 7692 painter->setPen(dark); 7693 if (tiles & TileSet::Left) 7694 painter->drawPoint(rect.bottomLeft()); 7695 else if (tiles & TileSet::Right) 7696 painter->drawPoint(rect.bottomRight()); 7697 else 7698 painter->drawLine(rect.bottomLeft(), rect.bottomRight()); 7699 7700 rect.adjust(0, 0, 0, -1); 7701 painter->setPen(light); 7702 if (tiles & TileSet::Left) { 7703 painter->drawLine(rect.bottomLeft(), rect.bottomLeft() + QPoint(1, 0)); 7704 painter->drawLine(rect.bottomLeft() + QPoint(1, 0), rect.bottomLeft() + QPoint(1, 1)); 7705 7706 } else if (tiles & TileSet::Right) { 7707 painter->drawLine(rect.bottomRight(), rect.bottomRight() - QPoint(1, 0)); 7708 painter->drawLine(rect.bottomRight() - QPoint(1, 0), rect.bottomRight() - QPoint(1, -1)); 7709 7710 } else { 7711 painter->drawLine(rect.bottomLeft(), rect.bottomRight()); 7712 } 7713 } else if (tiles & TileSet::Left) { 7714 painter->setPen(dark); 7715 painter->drawLine(rect.topLeft(), rect.bottomLeft()); 7716 7717 rect.adjust(1, 0, 0, 0); 7718 painter->setPen(light); 7719 painter->drawLine(rect.topLeft(), rect.bottomLeft()); 7720 7721 } else if (tiles & TileSet::Right) { 7722 painter->setPen(dark); 7723 painter->drawLine(rect.topRight(), rect.bottomRight()); 7724 7725 rect.adjust(0, 0, -1, 0); 7726 painter->setPen(light); 7727 painter->drawLine(rect.topRight(), rect.bottomRight()); 7728 } 7729 7730 painter->restore(); 7731 7732 return; 7733 } 7734 7735 //__________________________________________________________________________ 7736 void Style::renderMenuItemBackground(const QStyleOption *option, QPainter *painter, const QWidget *widget) const 7737 { 7738 const QRect &rect(option->rect); 7739 const QPalette &palette(option->palette); 7740 const QRect animatedRect(_animations->menuEngine().animatedRect(widget)); 7741 if (!animatedRect.isNull()) { 7742 if (animatedRect.intersects(rect)) { 7743 const QColor color(_helper->menuBackgroundColor(_helper->calcMidColor(palette.color(QPalette::Window)), widget, animatedRect.center())); 7744 renderMenuItemRect(option, animatedRect, color, palette, painter); 7745 } 7746 7747 } else if (_animations->menuEngine().isTimerActive(widget)) { 7748 const QRect previousRect(_animations->menuEngine().currentRect(widget, Previous)); 7749 if (previousRect.intersects(rect)) { 7750 const QColor color(_helper->menuBackgroundColor(_helper->calcMidColor(palette.color(QPalette::Window)), widget, previousRect.center())); 7751 renderMenuItemRect(option, previousRect, color, palette, painter); 7752 } 7753 7754 } else if (_animations->menuEngine().isAnimated(widget, Previous)) { 7755 QRect previousRect(_animations->menuEngine().currentRect(widget, Previous)); 7756 if (previousRect.intersects(rect)) { 7757 const qreal opacity(_animations->menuEngine().opacity(widget, Previous)); 7758 const QColor color(_helper->menuBackgroundColor(_helper->calcMidColor(palette.color(QPalette::Window)), widget, previousRect.center())); 7759 renderMenuItemRect(option, previousRect, color, palette, painter, opacity); 7760 } 7761 } 7762 7763 return; 7764 } 7765 7766 //__________________________________________________________________________ 7767 void Style::renderMenuItemRect(const QStyleOption *option, const QRect &rect, const QColor &base, const QPalette &palette, QPainter *painter, qreal opacity) 7768 const 7769 { 7770 if (opacity == 0) 7771 return; 7772 7773 // get relevant color 7774 // TODO: this is inconsistent with MenuBar color. 7775 // this should change to properly account for 'sunken' state 7776 QColor color(base); 7777 if (StyleConfigData::menuHighlightMode() == StyleConfigData::MM_STRONG) { 7778 color = palette.color(QPalette::Highlight); 7779 7780 } else if (StyleConfigData::menuHighlightMode() == StyleConfigData::MM_SUBTLE) { 7781 color = KColorUtils::mix(color, KColorUtils::tint(color, palette.color(QPalette::Highlight), 0.6)); 7782 } 7783 7784 // special painting for items with submenus 7785 const QStyleOptionMenuItem *menuItemOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option); 7786 if (menuItemOption && menuItemOption->menuItemType == QStyleOptionMenuItem::SubMenu) { 7787 QPixmap pixmap(rect.size()); 7788 { 7789 pixmap.fill(Qt::transparent); 7790 QPainter painter(&pixmap); 7791 const QRect pixmapRect(pixmap.rect()); 7792 7793 painter.setRenderHint(QPainter::Antialiasing); 7794 painter.setPen(Qt::NoPen); 7795 7796 painter.setBrush(color); 7797 _helper->fillHole(painter, pixmapRect); 7798 7799 _helper->holeFlat(color, 0).render(pixmapRect.adjusted(1, 2, -2, -1), &painter); 7800 7801 QRect maskRect(visualRect(option->direction, pixmapRect, QRect(pixmapRect.width() - 40, 0, 40, pixmapRect.height()))); 7802 QLinearGradient gradient(visualPos(option->direction, maskRect, QPoint(maskRect.left(), 0)), 7803 visualPos(option->direction, maskRect, QPoint(maskRect.right() - 4, 0))); 7804 gradient.setColorAt(0, Qt::black); 7805 gradient.setColorAt(1, Qt::transparent); 7806 painter.setBrush(gradient); 7807 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 7808 painter.drawRect(maskRect); 7809 7810 if (opacity >= 0 && opacity < 1) { 7811 painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); 7812 painter.fillRect(pixmapRect, _helper->alphaColor(Qt::black, opacity)); 7813 } 7814 7815 painter.end(); 7816 } 7817 7818 painter->drawPixmap(visualRect(option, rect), pixmap); 7819 7820 } else { 7821 if (opacity >= 0 && opacity < 1) { 7822 color.setAlphaF(opacity); 7823 } 7824 7825 _helper->holeFlat(color, 0).render(rect.adjusted(1, 2, -2, -1), painter, TileSet::Full); 7826 } 7827 } 7828 7829 //________________________________________________________________________ 7830 void Style::renderCheckBox(QPainter *painter, 7831 const QRect &constRect, 7832 const QPalette &palette, 7833 StyleOptions options, 7834 CheckBoxState state, 7835 qreal opacity, 7836 AnimationMode mode) const 7837 { 7838 const int size(qMin(constRect.width(), constRect.height())); 7839 const QRect rect(centerRect(constRect, size, size)); 7840 7841 if (!(options & NoFill)) { 7842 if (options & Sunken) 7843 _helper->holeFlat(palette.color(QPalette::Window), 0, false).render(insideMargin(rect, 1), painter, TileSet::Full); 7844 else 7845 renderSlab(painter, rect, palette.color(QPalette::Button), options, opacity, mode, TileSet::Ring); 7846 } 7847 7848 if (state == CheckOff) 7849 return; 7850 7851 // check mark 7852 qreal penThickness(2); 7853 const QColor color(palette.color((options & Sunken) ? QPalette::WindowText : QPalette::ButtonText)); 7854 const QColor background(palette.color((options & Sunken) ? QPalette::Window : QPalette::Button)); 7855 QPen pen(_helper->decoColor(background, color), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); 7856 QPen contrastPen(_helper->calcLightColor(background), penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); 7857 if (state == CheckTriState) { 7858 QVector<qreal> dashes; 7859 dashes << 1 << 2; 7860 penThickness = 1.3; 7861 pen.setWidthF(penThickness); 7862 contrastPen.setWidthF(penThickness); 7863 pen.setDashPattern(dashes); 7864 contrastPen.setDashPattern(dashes); 7865 7866 } else if (state == CheckSunken) { 7867 pen.setColor(_helper->alphaColor(pen.color(), 0.3)); 7868 contrastPen.setColor(_helper->alphaColor(contrastPen.color(), 0.3)); 7869 } 7870 7871 painter->save(); 7872 painter->translate(QRectF(rect).center()); 7873 7874 if (!(options & Sunken)) 7875 painter->translate(0, -1); 7876 painter->setRenderHint(QPainter::Antialiasing); 7877 7878 QPolygonF checkMark; 7879 checkMark << QPointF(5, -2) << QPointF(-1, 5) << QPointF(-4, 2); 7880 7881 const qreal offset(qMin(penThickness, qreal(1))); 7882 painter->setPen(contrastPen); 7883 painter->translate(0, offset); 7884 painter->drawPolyline(checkMark); 7885 7886 painter->setPen(pen); 7887 painter->translate(0, -offset); 7888 painter->drawPolyline(checkMark); 7889 7890 painter->restore(); 7891 7892 return; 7893 } 7894 7895 //___________________________________________________________________ 7896 void Style::renderRadioButton(QPainter *painter, 7897 const QRect &constRect, 7898 const QPalette &palette, 7899 StyleOptions options, 7900 CheckBoxState state, 7901 qreal opacity, 7902 AnimationMode mode) const 7903 { 7904 // get pixmap 7905 const QColor color(palette.color(QPalette::Button)); 7906 const QColor glow(_helper->buttonGlowColor(palette, options, opacity, mode)); 7907 QPixmap pixmap(_helper->roundSlab(color, glow, 0)); 7908 7909 // center rect 7910 const QRect rect(centerRect(constRect, pixmap.size() / _helper->devicePixelRatio(pixmap))); 7911 7912 // render 7913 painter->drawPixmap(rect.topLeft(), pixmap); 7914 7915 // draw the radio mark 7916 if (state != CheckOff) { 7917 const qreal radius(2.6); 7918 const qreal dx(0.5 * rect.width() - radius); 7919 const qreal dy(0.5 * rect.height() - radius); 7920 const QRectF symbolRect(QRectF(rect).adjusted(dx, dy, -dx, -dy)); 7921 7922 painter->save(); 7923 painter->setRenderHints(QPainter::Antialiasing); 7924 painter->setPen(Qt::NoPen); 7925 7926 const QColor background(palette.color(QPalette::Button)); 7927 const QColor color(palette.color(QPalette::ButtonText)); 7928 7929 // contrast 7930 if (state == CheckOn) 7931 painter->setBrush(_helper->calcLightColor(background)); 7932 else 7933 painter->setBrush(_helper->alphaColor(_helper->calcLightColor(background), 0.3)); 7934 painter->translate(0, radius / 2); 7935 painter->drawEllipse(symbolRect); 7936 7937 // symbol 7938 if (state == CheckOn) 7939 painter->setBrush(_helper->decoColor(background, color)); 7940 else 7941 painter->setBrush(_helper->alphaColor(_helper->decoColor(background, color), 0.3)); 7942 painter->translate(0, -radius / 2); 7943 painter->drawEllipse(symbolRect); 7944 painter->restore(); 7945 } 7946 7947 return; 7948 } 7949 7950 //______________________________________________________________________________ 7951 void Style::renderScrollBarHole(QPainter *painter, 7952 const QRect &rect, 7953 const QColor &color, 7954 const Qt::Orientation &orientation, 7955 const TileSet::Tiles &tiles) const 7956 { 7957 if (!rect.isValid()) 7958 return; 7959 7960 // one need to make smaller shadow 7961 // notably on the size when rect height is too high 7962 const bool smallShadow(orientation == Qt::Horizontal ? rect.height() < 10 : rect.width() < 10); 7963 _helper->scrollHole(color, orientation, smallShadow).render(rect, painter, tiles); 7964 } 7965 7966 //______________________________________________________________________________ 7967 void Style::renderScrollBarHandle(QPainter *painter, 7968 const QRect &constRect, 7969 const QPalette &palette, 7970 const Qt::Orientation &orientation, 7971 const bool &hover, 7972 const qreal &opacity) const 7973 { 7974 if (!constRect.isValid()) 7975 return; 7976 7977 // define rect and check 7978 QRect rect(insideMargin(constRect, 3)); 7979 7980 painter->save(); 7981 painter->setRenderHints(QPainter::Antialiasing); 7982 const QColor color(palette.color(QPalette::Button)); 7983 7984 // draw the slider 7985 const qreal radius = 3.5; 7986 7987 // glow / shadow 7988 QColor glow; 7989 const QColor shadow(_helper->alphaColor(_helper->calcShadowColor(color), 0.4)); 7990 const QColor hovered(_helper->hoverColor(palette)); 7991 7992 if (opacity >= 0) 7993 glow = KColorUtils::mix(shadow, hovered, opacity); 7994 else if (hover) 7995 glow = hovered; 7996 else 7997 glow = shadow; 7998 7999 _helper->scrollHandle(color, glow).render(constRect, painter, TileSet::Full); 8000 8001 // contents 8002 const QColor mid(_helper->calcMidColor(color)); 8003 QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); 8004 gradient.setColorAt(0, color); 8005 gradient.setColorAt(1, mid); 8006 painter->setPen(Qt::NoPen); 8007 painter->setBrush(gradient); 8008 painter->drawRoundedRect(insideMargin(rect, 1), radius - 2, radius - 2); 8009 8010 // bevel pattern 8011 const QColor light(_helper->calcLightColor(color)); 8012 8013 const bool horizontal(orientation == Qt::Horizontal); 8014 QLinearGradient patternGradient(0, 0, horizontal ? 30 : 0, horizontal ? 0 : 30); 8015 patternGradient.setSpread(QGradient::ReflectSpread); 8016 patternGradient.setColorAt(0, Qt::transparent); 8017 patternGradient.setColorAt(1, _helper->alphaColor(light, 0.1)); 8018 8019 QRect bevelRect(rect); 8020 if (horizontal) 8021 bevelRect = insideMargin(bevelRect, 0, 3); 8022 else 8023 bevelRect = insideMargin(bevelRect, 3, 0); 8024 8025 if (bevelRect.isValid()) { 8026 painter->setBrush(patternGradient); 8027 painter->drawRect(bevelRect); 8028 } 8029 8030 painter->restore(); 8031 return; 8032 } 8033 8034 //______________________________________________________________________________ 8035 void Style::renderScrollBarArrow(QPainter *painter, const QRect &rect, const QColor &color, const QColor &background, ArrowOrientation orientation) const 8036 { 8037 const qreal penThickness = 1.6; 8038 QPolygonF arrow(genericArrow(orientation, ArrowNormal)); 8039 8040 const QColor contrast(_helper->calcLightColor(background)); 8041 const QColor base(_helper->decoColor(background, color)); 8042 8043 painter->save(); 8044 painter->translate(QRectF(rect).center()); 8045 painter->setRenderHint(QPainter::Antialiasing); 8046 8047 const qreal offset(qMin(penThickness, qreal(1))); 8048 painter->translate(0, offset); 8049 painter->setPen(QPen(contrast, penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 8050 painter->drawPolyline(arrow); 8051 painter->translate(0, -offset); 8052 8053 painter->setPen(QPen(base, penThickness, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); 8054 painter->drawPolyline(arrow); 8055 painter->restore(); 8056 8057 return; 8058 } 8059 8060 //______________________________________________________________________________ 8061 QColor Style::scrollBarArrowColor(const QStyleOptionSlider *option, const SubControl &control, const QWidget *widget) const 8062 { 8063 // copy rect and palette 8064 const QRect &rect(option->rect); 8065 const QPalette &palette(option->palette); 8066 8067 // color 8068 QColor color(palette.color(QPalette::WindowText)); 8069 8070 // check enabled state 8071 const bool enabled(option->state & State_Enabled); 8072 if (!enabled) 8073 return color; 8074 8075 if ((control == SC_ScrollBarSubLine && option->sliderValue == option->minimum) 8076 || (control == SC_ScrollBarAddLine && option->sliderValue == option->maximum)) { 8077 // manually disable arrow, to indicate that scrollbar is at limit 8078 return palette.color(QPalette::Disabled, QPalette::WindowText); 8079 } 8080 8081 const bool mouseOver(_animations->scrollBarEngine().isHovered(widget, control)); 8082 const bool animated(_animations->scrollBarEngine().isAnimated(widget, control)); 8083 const qreal opacity(_animations->scrollBarEngine().opacity(widget, control)); 8084 8085 // retrieve mouse position from engine 8086 QPoint position(mouseOver ? _animations->scrollBarEngine().position(widget) : QPoint(-1, -1)); 8087 if (mouseOver && rect.contains(position)) { 8088 // need to update the arrow controlRect on fly because there is no 8089 // way to get it from the styles directly, outside of repaint events 8090 _animations->scrollBarEngine().setSubControlRect(widget, control, rect); 8091 } 8092 8093 if (rect.intersects(_animations->scrollBarEngine().subControlRect(widget, control))) { 8094 QColor highlight = _helper->hoverColor(palette); 8095 if (animated) { 8096 color = KColorUtils::mix(color, highlight, opacity); 8097 8098 } else if (mouseOver) { 8099 color = highlight; 8100 } 8101 } 8102 8103 return color; 8104 } 8105 8106 //______________________________________________________________________________ 8107 qreal Style::dialAngle(const QStyleOptionSlider *sliderOption, int value) const 8108 { 8109 // calculate angle at which handle needs to be drawn 8110 qreal angle(0); 8111 if (sliderOption->maximum == sliderOption->minimum) 8112 angle = M_PI / 2; 8113 else { 8114 qreal fraction(qreal(value - sliderOption->minimum) / qreal(sliderOption->maximum - sliderOption->minimum)); 8115 if (!sliderOption->upsideDown) 8116 fraction = 1 - fraction; 8117 8118 if (sliderOption->dialWrapping) 8119 angle = 1.5 * M_PI - fraction * 2 * M_PI; 8120 else 8121 angle = (M_PI * 8 - fraction * 10 * M_PI) / 6; 8122 } 8123 8124 return angle; 8125 } 8126 8127 //______________________________________________________________ 8128 void Style::polishScrollArea(QAbstractScrollArea *scrollArea) const 8129 { 8130 if (!scrollArea) 8131 return; 8132 8133 // HACK: add exception for KPIM transactionItemView, which is an overlay widget 8134 // and must have filled background. This is a temporary workaround until a more 8135 // robust solution is found. 8136 if (scrollArea->inherits("KPIM::TransactionItemView")) { 8137 // also need to make the scrollarea background plain ( using autofill background ) 8138 // so that optional vertical scrollbar background is not transparent either. 8139 // TODO: possibly add an event filter to use the "normal" window background 8140 // instead of something flat. 8141 scrollArea->setAutoFillBackground(true); 8142 return; 8143 } 8144 8145 // check frame style and background role 8146 if (!(scrollArea->frameShape() == QFrame::NoFrame || scrollArea->backgroundRole() == QPalette::Window)) { 8147 return; 8148 } 8149 8150 // get viewport and check background role 8151 QWidget *viewport(scrollArea->viewport()); 8152 if (!(viewport && viewport->backgroundRole() == QPalette::Window)) 8153 return; 8154 8155 // change viewport autoFill background. 8156 // do the same for children if the background role is QPalette::Window 8157 viewport->setAutoFillBackground(false); 8158 const QList<QWidget *> children = viewport->findChildren<QWidget *>(); 8159 for (QWidget *child : children) { 8160 if (child->parent() == viewport && child->backgroundRole() == QPalette::Window) { 8161 child->setAutoFillBackground(false); 8162 } 8163 } 8164 } 8165 8166 //_______________________________________________________________ 8167 QRegion Style::tabBarClipRegion(const QTabBar *tabBar) const 8168 { 8169 // need to mask-out arrow buttons, if visible. 8170 QRegion mask(tabBar->rect()); 8171 const auto children = tabBar->children(); 8172 for (const QObject *child : children) { 8173 const QToolButton *toolButton(qobject_cast<const QToolButton *>(child)); 8174 if (toolButton && toolButton->isVisible()) 8175 mask -= toolButton->geometry(); 8176 } 8177 8178 return mask; 8179 } 8180 8181 //____________________________________________________________________________________ 8182 QPolygonF Style::genericArrow(ArrowOrientation orientation, ArrowSize size) const 8183 { 8184 QPolygonF arrow; 8185 switch (orientation) { 8186 case ArrowUp: { 8187 if (size == ArrowTiny) 8188 arrow << QPointF(-2.25, 1.125) << QPointF(0, -1.125) << QPointF(2.25, 1.125); 8189 else if (size == ArrowSmall) 8190 arrow << QPointF(-2.5, 1.5) << QPointF(0, -1.5) << QPointF(2.5, 1.5); 8191 else 8192 arrow << QPointF(-3.5, 2) << QPointF(0, -2) << QPointF(3.5, 2); 8193 break; 8194 } 8195 8196 case ArrowDown: { 8197 if (size == ArrowTiny) 8198 arrow << QPointF(-2.25, -1.125) << QPointF(0, 1.125) << QPointF(2.25, -1.125); 8199 else if (size == ArrowSmall) 8200 arrow << QPointF(-2.5, -1.5) << QPointF(0, 1.5) << QPointF(2.5, -1.5); 8201 else 8202 arrow << QPointF(-3.5, -2) << QPointF(0, 2) << QPointF(3.5, -2); 8203 break; 8204 } 8205 8206 case ArrowLeft: { 8207 if (size == ArrowTiny) 8208 arrow << QPointF(1.125, -2.25) << QPointF(-1.125, 0) << QPointF(1.125, 2.25); 8209 else if (size == ArrowSmall) 8210 arrow << QPointF(1.5, -2.5) << QPointF(-1.5, 0) << QPointF(1.5, 2.5); 8211 else 8212 arrow << QPointF(2, -3.5) << QPointF(-2, 0) << QPointF(2, 3.5); 8213 8214 break; 8215 } 8216 8217 case ArrowRight: { 8218 if (size == ArrowTiny) 8219 arrow << QPointF(-1.125, -2.25) << QPointF(1.125, 0) << QPointF(-1.125, 2.25); 8220 else if (size == ArrowSmall) 8221 arrow << QPointF(-1.5, -2.5) << QPointF(1.5, 0) << QPointF(-1.5, 2.5); 8222 else 8223 arrow << QPointF(-2, -3.5) << QPointF(2, 0) << QPointF(-2, 3.5); 8224 break; 8225 } 8226 8227 default: 8228 break; 8229 } 8230 8231 return arrow; 8232 } 8233 8234 //____________________________________________________________________________________ 8235 QStyleOptionToolButton Style::separatorMenuItemOption(const QStyleOptionMenuItem *menuItemOption, const QWidget *widget) const 8236 { 8237 // separator can have a title and an icon 8238 // in that case they are rendered as sunken flat toolbuttons 8239 QStyleOptionToolButton toolButtonOption; 8240 toolButtonOption.initFrom(widget); 8241 toolButtonOption.rect = menuItemOption->rect; 8242 toolButtonOption.features = QStyleOptionToolButton::None; 8243 toolButtonOption.state = State_On | State_Sunken | State_Enabled; 8244 toolButtonOption.subControls = SC_ToolButton; 8245 toolButtonOption.icon = menuItemOption->icon; 8246 8247 const int iconWidth(pixelMetric(PM_SmallIconSize, menuItemOption, widget)); 8248 toolButtonOption.iconSize = QSize(iconWidth, iconWidth); 8249 toolButtonOption.text = menuItemOption->text; 8250 8251 toolButtonOption.toolButtonStyle = Qt::ToolButtonTextBesideIcon; 8252 8253 return toolButtonOption; 8254 } 8255 8256 //____________________________________________________________________ 8257 bool Style::isQtQuickControl(const QStyleOption *option, const QWidget *widget) const 8258 { 8259 const bool is = (widget == nullptr) && option && option->styleObject && option->styleObject->inherits("QQuickItem"); 8260 if (is) 8261 _windowManager->registerQuickItem(static_cast<QQuickItem *>(option->styleObject)); 8262 return is; 8263 } 8264 8265 //_____________________________________________________________ 8266 Style::SlabRect::SlabRect(void) 8267 : tiles(TileSet::Ring) 8268 { 8269 } 8270 8271 //_____________________________________________________________ 8272 Style::SlabRect::SlabRect(const QRect &rect, int tiles) 8273 : rect(rect) 8274 , tiles(TileSet::Tiles(tiles)) 8275 { 8276 } 8277 8278 //_____________________________________________________________ 8279 bool Style::SlabRect::isValid(void) const 8280 { 8281 return rect.isValid() && tiles; 8282 } 8283 8284 //_____________________________________________________________ 8285 void Style::SlabRect::adjust(int tileSize) 8286 { 8287 if (!(tiles & TileSet::Left)) 8288 rect.adjust(-tileSize, 0, 0, 0); 8289 if (!(tiles & TileSet::Right)) 8290 rect.adjust(0, 0, tileSize, 0); 8291 if (!(tiles & TileSet::Top)) 8292 rect.adjust(0, -tileSize, 0, 0); 8293 if (!(tiles & TileSet::Bottom)) 8294 rect.adjust(0, 0, 0, tileSize); 8295 } 8296 8297 //_____________________________________________________________ 8298 Style::SlabRect Style::SlabRect::adjusted(int tileSize) const 8299 { 8300 SlabRect copy(*this); 8301 copy.adjust(tileSize); 8302 return copy; 8303 } 8304 8305 } 8306 8307 namespace OxygenPrivate 8308 { 8309 8310 //_________________________________________________________________________________________________________ 8311 void TabBarData::drawTabBarBaseControl(const QStyleOptionTab *tabOption, QPainter *painter, const QWidget *widget) 8312 { 8313 // check parent 8314 if (!_style) 8315 return; 8316 8317 // make sure widget is locked 8318 if (!locks(widget)) 8319 return; 8320 8321 // make sure dirty flag is set 8322 if (!_dirty) 8323 return; 8324 8325 // cast to TabBar and check 8326 const QTabBar *tabBar(qobject_cast<const QTabBar *>(widget)); 8327 if (!tabBar) 8328 return; 8329 8330 // get reverseLayout flag 8331 const bool reverseLayout(tabOption->direction == Qt::RightToLeft); 8332 8333 // get documentMode flag 8334 const auto tabOptionV3 = qstyleoption_cast<const QStyleOptionTab *>(tabOption); 8335 8336 bool documentMode = tabOptionV3 ? tabOptionV3->documentMode : false; 8337 const QTabWidget *tabWidget = (widget && widget->parentWidget()) ? qobject_cast<const QTabWidget *>(widget->parentWidget()) : nullptr; 8338 documentMode |= (tabWidget ? tabWidget->documentMode() : true); 8339 8340 const QRect tabBarRect(tabBar->rect()); 8341 8342 // define slab 8343 Oxygen::Style::SlabRect slab; 8344 8345 // switch on tab shape 8346 switch (tabOption->shape) { 8347 case QTabBar::RoundedNorth: 8348 case QTabBar::TriangularNorth: { 8349 Oxygen::TileSet::Tiles tiles(Oxygen::TileSet::Top); 8350 QRect frameRect; 8351 frameRect.setLeft(tabBarRect.left() - Oxygen::TileSet::DefaultSize); 8352 frameRect.setRight(tabBarRect.right() + Oxygen::TileSet::DefaultSize); 8353 frameRect.setTop(tabBarRect.bottom() - Oxygen::TileSet::DefaultSize + 1); 8354 frameRect.setHeight(4); 8355 if (!(documentMode || reverseLayout)) 8356 tiles |= Oxygen::TileSet::Left; 8357 if (!documentMode && reverseLayout) 8358 tiles |= Oxygen::TileSet::Right; 8359 slab = Oxygen::Style::SlabRect(frameRect, tiles); 8360 break; 8361 } 8362 8363 case QTabBar::RoundedSouth: 8364 case QTabBar::TriangularSouth: { 8365 Oxygen::TileSet::Tiles tiles(Oxygen::TileSet::Bottom); 8366 QRect frameRect; 8367 frameRect.setLeft(tabBarRect.left() - Oxygen::TileSet::DefaultSize); 8368 frameRect.setRight(tabBarRect.right() + Oxygen::TileSet::DefaultSize); 8369 frameRect.setBottom(tabBarRect.top() + Oxygen::TileSet::DefaultSize - 1); 8370 frameRect.setTop(frameRect.bottom() - 4); 8371 if (!(documentMode || reverseLayout)) 8372 tiles |= Oxygen::TileSet::Left; 8373 if (!documentMode && reverseLayout) 8374 tiles |= Oxygen::TileSet::Right; 8375 slab = Oxygen::Style::SlabRect(frameRect, tiles); 8376 break; 8377 } 8378 8379 case QTabBar::RoundedWest: 8380 case QTabBar::TriangularWest: { 8381 Oxygen::TileSet::Tiles tiles(Oxygen::TileSet::Left); 8382 QRect frameRect; 8383 frameRect.setTop(tabBarRect.top() - Oxygen::TileSet::DefaultSize); 8384 frameRect.setBottom(tabBarRect.bottom() + Oxygen::TileSet::DefaultSize); 8385 frameRect.setLeft(tabBarRect.right() - Oxygen::TileSet::DefaultSize + 1); 8386 frameRect.setWidth(4); 8387 if (!(documentMode || reverseLayout)) 8388 tiles |= Oxygen::TileSet::Top; 8389 if (!documentMode && reverseLayout) 8390 tiles |= Oxygen::TileSet::Bottom; 8391 slab = Oxygen::Style::SlabRect(frameRect, tiles); 8392 break; 8393 } 8394 8395 case QTabBar::RoundedEast: 8396 case QTabBar::TriangularEast: { 8397 Oxygen::TileSet::Tiles tiles(Oxygen::TileSet::Right); 8398 QRect frameRect; 8399 frameRect.setTop(tabBarRect.top() - Oxygen::TileSet::DefaultSize); 8400 frameRect.setBottom(tabBarRect.bottom() + Oxygen::TileSet::DefaultSize); 8401 frameRect.setRight(tabBarRect.left() + Oxygen::TileSet::DefaultSize - 1); 8402 frameRect.setLeft(frameRect.right() - 4); 8403 if (!(documentMode || reverseLayout)) 8404 tiles |= Oxygen::TileSet::Top; 8405 if (!documentMode && reverseLayout) 8406 tiles |= Oxygen::TileSet::Bottom; 8407 slab = Oxygen::Style::SlabRect(frameRect, tiles); 8408 break; 8409 } 8410 8411 default: 8412 break; 8413 } 8414 8415 const bool verticalTabs(_style.data()->isVerticalTab(tabOption)); 8416 const QRect tabWidgetRect(tabWidget ? tabWidget->rect().translated(-widget->geometry().topLeft()) : QRect()); 8417 8418 const QPalette &palette(tabOption->palette); 8419 const QColor color(palette.color(QPalette::Window)); 8420 _style.data()->adjustSlabRect(slab, tabWidgetRect, documentMode, verticalTabs); 8421 _style.data()->renderSlab(painter, slab, color, Oxygen::NoFill); 8422 8423 setDirty(false); 8424 return; 8425 } 8426 8427 }