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, ©); 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, ©, painter, widget); 4886 break; 4887 case Qt::RightArrow: 4888 drawPrimitive(PE_IndicatorArrowRight, ©, painter, widget); 4889 break; 4890 case Qt::UpArrow: 4891 drawPrimitive(PE_IndicatorArrowUp, ©, painter, widget); 4892 break; 4893 case Qt::DownArrow: 4894 drawPrimitive(PE_IndicatorArrowDown, ©, 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(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); 5689 _helper->renderArrow(painter, leftSubButton, color, ArrowLeft); 5690 5691 copy.rect = rightSubButton; 5692 color = scrollBarArrowColor(©, 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(©, SC_ScrollBarSubLine, widget); 5702 _helper->renderArrow(painter, topSubButton, color, ArrowUp); 5703 5704 copy.rect = botSubButton; 5705 color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); 5706 _helper->renderArrow(painter, botSubButton, color, ArrowDown); 5707 } 5708 5709 } else if (_addLineButtons == SingleButton) { 5710 copy.rect = rect; 5711 color = scrollBarArrowColor(©, 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(©, reverseLayout ? SC_ScrollBarAddLine : SC_ScrollBarSubLine, widget); 5768 _helper->renderArrow(painter, leftSubButton, color, ArrowLeft); 5769 5770 copy.rect = rightSubButton; 5771 color = scrollBarArrowColor(©, 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(©, SC_ScrollBarSubLine, widget); 5781 _helper->renderArrow(painter, topSubButton, color, ArrowUp); 5782 5783 copy.rect = botSubButton; 5784 color = scrollBarArrowColor(©, SC_ScrollBarAddLine, widget); 5785 _helper->renderArrow(painter, botSubButton, color, ArrowDown); 5786 } 5787 5788 } else if (_subLineButtons == SingleButton) { 5789 copy.rect = rect; 5790 color = scrollBarArrowColor(©, 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(©, painter, widget); 6780 } else { 6781 drawPrimitive(PE_PanelButtonTool, ©, painter, widget); 6782 } 6783 } 6784 6785 // arrow 6786 if (menuStyle == BreezePrivate::ToolButtonMenuArrowStyle::SubControl) { 6787 copy.rect = menuRect; 6788 drawPrimitive(PE_IndicatorButtonDropDown, ©, painter, widget); 6789 6790 copy.state &= ~State_MouseOver; 6791 copy.state &= ~State_Sunken; 6792 copy.state &= ~State_On; 6793 drawPrimitive(PE_IndicatorArrowDown, ©, 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, ©, 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, ©, 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, ©, 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 }