File indexing completed on 2024-05-19 09:28:03

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