File indexing completed on 2024-05-12 13:30:25

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