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, &copy, painter, widget);
4808             break;
4809         case Qt::RightArrow:
4810             drawPrimitive(PE_IndicatorArrowRight, &copy, painter, widget);
4811             break;
4812         case Qt::UpArrow:
4813             drawPrimitive(PE_IndicatorArrowUp, &copy, painter, widget);
4814             break;
4815         case Qt::DownArrow:
4816             drawPrimitive(PE_IndicatorArrowDown, &copy, 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(&copy, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget);
5384             renderScrollBarArrow(painter, leftSubButton, color, background, ArrowLeft);
5385 
5386             copy.rect = rightSubButton;
5387             color = scrollBarArrowColor(&copy, 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(&copy, SC_ScrollBarSubLine, widget);
5397             renderScrollBarArrow(painter, topSubButton, color, background, ArrowUp);
5398 
5399             copy.rect = botSubButton;
5400             color = scrollBarArrowColor(&copy, SC_ScrollBarAddLine, widget);
5401             renderScrollBarArrow(painter, botSubButton, color, background, ArrowDown);
5402         }
5403 
5404     } else if (_addLineButtons == SingleButton) {
5405         copy.rect = rect;
5406         color = scrollBarArrowColor(&copy, 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(&copy, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget);
5450             renderScrollBarArrow(painter, leftSubButton, color, background, ArrowLeft);
5451 
5452             copy.rect = rightSubButton;
5453             color = scrollBarArrowColor(&copy, 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(&copy, SC_ScrollBarSubLine, widget);
5463             renderScrollBarArrow(painter, topSubButton, color, background, ArrowUp);
5464 
5465             copy.rect = botSubButton;
5466             color = scrollBarArrowColor(&copy, SC_ScrollBarAddLine, widget);
5467             renderScrollBarArrow(painter, botSubButton, color, background, ArrowDown);
5468         }
5469 
5470     } else if (_subLineButtons == SingleButton) {
5471         copy.rect = rect;
5472         color = scrollBarArrowColor(&copy, 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(&copy, painter, widget);
6673         else
6674             drawPrimitive(PE_PanelButtonTool, &copy, painter, widget);
6675     }
6676 
6677     if (hasPopupMenu) {
6678         copy.rect = menuRect;
6679         if (!autoRaise) {
6680             drawPrimitive(PE_IndicatorButtonDropDown, &copy, painter, widget);
6681             copy.state &= ~(State_MouseOver | State_HasFocus);
6682         }
6683 
6684         drawPrimitive(PE_IndicatorArrowDown, &copy, painter, widget);
6685 
6686     } else if (hasInlineIndicator) {
6687         copy.rect = menuRect;
6688         copy.state &= ~(State_MouseOver | State_HasFocus);
6689         drawPrimitive(PE_IndicatorArrowDown, &copy, 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, &copy, 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 }