Skip to content

Commit 43e87d9

Browse files
committed
feat: Enhance ColoredToolButton with color management and custom painting
1 parent b864268 commit 43e87d9

2 files changed

Lines changed: 195 additions & 51 deletions

File tree

src/controls/coloredtoolbutton.cpp

Lines changed: 177 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
#include "coloredtoolbutton.h"
22

33
#include <QApplication>
4+
#include <QBrush>
5+
#include <QLinearGradient>
6+
#include <QPainter>
7+
#include <QPalette>
48
#include <QStyle>
9+
#include <QStyleOptionFocusRect>
10+
#include <QStyleOptionToolButton>
11+
#include <QStylePainter>
512

613
///
714
/// \brief ColoredToolButton::ColoredToolButton
@@ -10,7 +17,6 @@
1017
ColoredToolButton::ColoredToolButton(QWidget* parent)
1118
: QToolButton(parent)
1219
{
13-
clearColors();
1420
}
1521

1622
///
@@ -19,15 +25,40 @@ ColoredToolButton::ColoredToolButton(QWidget* parent)
1925
///
2026
void ColoredToolButton::setColors(const Colors& colors)
2127
{
22-
setStyleSheet(coloredStyleSheet(colors));
28+
_colors = colors;
29+
_hasColors = true;
30+
update();
2331
}
2432

2533
///
2634
/// \brief ColoredToolButton::clearColors
2735
///
2836
void ColoredToolButton::clearColors()
2937
{
30-
setStyleSheet(defaultStyleSheet());
38+
_hasColors = false;
39+
update();
40+
}
41+
42+
///
43+
/// \brief ColoredToolButton::paintEvent
44+
/// \param event
45+
///
46+
void ColoredToolButton::paintEvent(QPaintEvent* event)
47+
{
48+
Q_UNUSED(event)
49+
50+
QStyleOptionToolButton option;
51+
initStyleOption(&option);
52+
53+
if(!_hasColors) {
54+
QStylePainter painter(this);
55+
painter.drawComplexControl(QStyle::CC_ToolButton, option);
56+
return;
57+
}
58+
59+
QStylePainter painter(this);
60+
option.palette = coloredPalette(option);
61+
drawColoredToolButton(&painter, option);
3162
}
3263

3364
///
@@ -42,64 +73,162 @@ bool ColoredToolButton::isFusionStyle()
4273
}
4374

4475
///
45-
/// \brief ColoredToolButton::background
46-
/// \param top
47-
/// \param bottom
76+
/// \brief ColoredToolButton::buttonColor
77+
/// \param option
4878
/// \return
4979
///
50-
QString ColoredToolButton::background(const QString& top, const QString& bottom)
80+
QColor ColoredToolButton::buttonColor(const QStyleOptionToolButton& option) const
5181
{
52-
return QString("qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:1 %2)")
53-
.arg(top, bottom);
82+
if(option.state & (QStyle::State_Sunken | QStyle::State_On))
83+
return QColor(_colors.pressed);
84+
85+
if(option.state & QStyle::State_MouseOver)
86+
return QColor(_colors.hover);
87+
88+
return QColor(_colors.base);
5489
}
5590

5691
///
57-
/// \brief ColoredToolButton::defaultStyleSheet
92+
/// \brief ColoredToolButton::buttonBrush
93+
/// \param option
5894
/// \return
5995
///
60-
QString ColoredToolButton::defaultStyleSheet()
96+
QBrush ColoredToolButton::buttonBrush(const QStyleOptionToolButton& option) const
6197
{
62-
return "padding: 0px 12px;";
98+
QColor top;
99+
QColor bottom;
100+
101+
if(option.state & (QStyle::State_Sunken | QStyle::State_On)) {
102+
top = QColor(_colors.pressed);
103+
bottom = QColor(_colors.border);
104+
}
105+
else if(option.state & QStyle::State_MouseOver) {
106+
top = QColor(_colors.hover);
107+
bottom = QColor(_colors.pressed);
108+
}
109+
else {
110+
top = QColor(_colors.base);
111+
bottom = QColor(_colors.hover);
112+
}
113+
114+
if(!isFusionStyle())
115+
return top;
116+
117+
QLinearGradient gradient(option.rect.topLeft(), option.rect.bottomLeft());
118+
gradient.setColorAt(0.0, top);
119+
gradient.setColorAt(1.0, bottom);
120+
return gradient;
63121
}
64122

65123
///
66-
/// \brief ColoredToolButton::coloredStyleSheet
67-
/// \param colors
124+
/// \brief ColoredToolButton::coloredPalette
125+
/// \param option
68126
/// \return
69127
///
70-
QString ColoredToolButton::coloredStyleSheet(const Colors& colors)
128+
QPalette ColoredToolButton::coloredPalette(const QStyleOptionToolButton& option) const
71129
{
72-
const QString normalBackground = isFusionStyle()
73-
? background(colors.base, colors.hover)
74-
: colors.base;
75-
const QString hoverBackground = isFusionStyle()
76-
? background(colors.hover, colors.pressed)
77-
: colors.hover;
78-
const QString pressedBackground = isFusionStyle()
79-
? background(colors.pressed, colors.border)
80-
: colors.pressed;
81-
82-
return QString(R"(
83-
ColoredToolButton {
84-
color: white;
85-
padding: 0px 12px 0px 2px;
86-
background-color: %1;
87-
border: 1px solid %2;
88-
border-radius: 4px;
89-
}
90-
ColoredToolButton:hover {
91-
background-color: %3;
92-
}
93-
ColoredToolButton:pressed {
94-
background-color: %4;
95-
}
96-
ColoredToolButton::menu-button {
97-
width: 12px;
98-
border-left: 1px solid %2;
99-
}
100-
ColoredToolButton::menu-arrow {
101-
width: 10px;
102-
height: 10px;
103-
}
104-
)").arg(normalBackground, colors.border, hoverBackground, pressedBackground);
130+
const QColor button = buttonColor(option);
131+
const QColor border(_colors.border);
132+
const QColor text(Qt::white);
133+
134+
QPalette palette = option.palette;
135+
136+
for(const QPalette::ColorGroup group : { QPalette::Active, QPalette::Inactive, QPalette::Disabled }) {
137+
palette.setColor(group, QPalette::Button, button);
138+
palette.setColor(group, QPalette::ButtonText, text);
139+
palette.setColor(group, QPalette::WindowText, text);
140+
palette.setColor(group, QPalette::Light, QColor(_colors.hover).lighter(115));
141+
palette.setColor(group, QPalette::Midlight, QColor(_colors.hover));
142+
palette.setColor(group, QPalette::Mid, border);
143+
palette.setColor(group, QPalette::Dark, border);
144+
palette.setColor(group, QPalette::Shadow, border.darker(125));
145+
}
146+
147+
return palette;
148+
}
149+
150+
///
151+
/// \brief ColoredToolButton::drawColoredToolButton
152+
/// \param painter
153+
/// \param option
154+
///
155+
void ColoredToolButton::drawColoredToolButton(QPainter* painter, const QStyleOptionToolButton& option) const
156+
{
157+
const QRect buttonRect = style()->subControlRect(QStyle::CC_ToolButton, &option, QStyle::SC_ToolButton, this);
158+
const QRect menuRect = style()->subControlRect(QStyle::CC_ToolButton, &option, QStyle::SC_ToolButtonMenu, this);
159+
const QColor border(_colors.border);
160+
161+
QStyle::State buttonState = option.state & ~QStyle::State_Sunken;
162+
QStyle::State menuState = buttonState;
163+
const bool autoRaise = option.state & QStyle::State_AutoRaise;
164+
165+
if(autoRaise && (!(buttonState & QStyle::State_MouseOver) || !(buttonState & QStyle::State_Enabled)))
166+
buttonState &= ~QStyle::State_Raised;
167+
168+
if(option.state & QStyle::State_Sunken) {
169+
if(option.activeSubControls & QStyle::SC_ToolButton) {
170+
buttonState |= QStyle::State_Sunken;
171+
menuState |= QStyle::State_MouseOver | QStyle::State_Sunken;
172+
}
173+
else if(option.activeSubControls & QStyle::SC_ToolButtonMenu) {
174+
menuState |= QStyle::State_Sunken;
175+
buttonState |= QStyle::State_MouseOver;
176+
}
177+
}
178+
179+
painter->save();
180+
painter->setRenderHint(QPainter::Antialiasing, true);
181+
painter->setPen(border);
182+
painter->setBrush(buttonBrush(option));
183+
painter->drawRoundedRect(option.rect.adjusted(0, 0, -1, -1), 4.0, 4.0);
184+
painter->restore();
185+
186+
if(option.state & QStyle::State_HasFocus) {
187+
QStyleOptionFocusRect focus;
188+
focus.QStyleOption::operator=(option);
189+
focus.rect.adjust(3, 3, -3, -3);
190+
if(option.features & QStyleOptionToolButton::MenuButtonPopup)
191+
focus.rect.adjust(0, 0, -style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &option, this), 0);
192+
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &focus, painter, this);
193+
}
194+
195+
QStyleOptionToolButton label = option;
196+
label.state = buttonState;
197+
if(!autoRaise)
198+
label.state &= ~QStyle::State_Sunken;
199+
label.rect = buttonRect;
200+
if(option.subControls & QStyle::SC_ToolButtonMenu) {
201+
if(isRightToLeft())
202+
label.rect.setLeft(menuRect.right() + 1);
203+
else
204+
label.rect.setRight(menuRect.left() - 1);
205+
}
206+
label.rect.adjust(2, 2, -2, -2);
207+
style()->drawControl(QStyle::CE_ToolButtonLabel, &label, painter, this);
208+
209+
if(option.subControls & QStyle::SC_ToolButtonMenu) {
210+
QStyleOptionToolButton tool = option;
211+
tool.state = menuState;
212+
213+
painter->save();
214+
painter->setPen(option.palette.dark().color());
215+
painter->drawLine(menuRect.left(), menuRect.top() + 3,
216+
menuRect.left(), menuRect.bottom() - 3);
217+
painter->setPen(option.palette.light().color());
218+
painter->drawLine(menuRect.left() - 1, menuRect.top() + 3,
219+
menuRect.left() - 1, menuRect.bottom() - 3);
220+
221+
tool.rect = menuRect.adjusted(2, 3, -2, -1);
222+
style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &tool, painter, this);
223+
painter->restore();
224+
}
225+
else if(option.features & QStyleOptionToolButton::HasMenu) {
226+
const int indicator = style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &option, this);
227+
QStyleOptionToolButton arrow = option;
228+
arrow.rect = QRect(option.rect.right() + 4 - indicator,
229+
option.rect.height() - indicator + 4,
230+
indicator - 5,
231+
indicator - 5);
232+
style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrow, painter, this);
233+
}
105234
}

src/controls/coloredtoolbutton.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22
#define COLOREDTOOLBUTTON_H
33

44
#include <QToolButton>
5+
#include <QColor>
56
#include <QString>
67

8+
class QBrush;
9+
class QPaintEvent;
10+
class QPalette;
11+
class QPainter;
12+
class QStyleOptionToolButton;
13+
714
///
815
/// \brief The ColoredToolButton class
916
///
@@ -25,11 +32,19 @@ class ColoredToolButton : public QToolButton
2532
void setColors(const Colors& colors);
2633
void clearColors();
2734

35+
protected:
36+
void paintEvent(QPaintEvent* event) override;
37+
2838
private:
2939
static bool isFusionStyle();
30-
static QString background(const QString& top, const QString& bottom);
31-
static QString defaultStyleSheet();
32-
static QString coloredStyleSheet(const Colors& colors);
40+
41+
QColor buttonColor(const QStyleOptionToolButton& option) const;
42+
QBrush buttonBrush(const QStyleOptionToolButton& option) const;
43+
QPalette coloredPalette(const QStyleOptionToolButton& option) const;
44+
void drawColoredToolButton(QPainter* painter, const QStyleOptionToolButton& option) const;
45+
46+
Colors _colors;
47+
bool _hasColors = false;
3348
};
3449

3550
#endif // COLOREDTOOLBUTTON_H

0 commit comments

Comments
 (0)