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