]> git.sur5r.net Git - minitube/blob - src/segmentedcontrol.cpp
Upload 3.9.3-2 to unstable
[minitube] / src / segmentedcontrol.cpp
1 /* $BEGIN_LICENSE
2
3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
5
6 Minitube is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Minitube is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
18
19 $END_LICENSE */
20
21 #include "segmentedcontrol.h"
22 #include "fontutils.h"
23 #include "iconutils.h"
24 #include "mainwindow.h"
25 #include "painterutils.h"
26
27 SegmentedControl::SegmentedControl(QWidget *parent) : QWidget(parent) {
28     setAttribute(Qt::WA_OpaquePaintEvent);
29
30     setMouseTracking(true);
31
32     hoveredAction = nullptr;
33     checkedAction = nullptr;
34     pressedAction = nullptr;
35
36     setupColors();
37     connect(qApp, &QGuiApplication::paletteChanged, this, [this] {
38         setupColors();
39         update();
40     });
41 }
42
43 QAction *SegmentedControl::addAction(QAction *action) {
44     QWidget::addAction(action);
45     action->setCheckable(true);
46     actionList.append(action);
47     return action;
48 }
49
50 bool SegmentedControl::setCheckedAction(int index) {
51     if (index < 0) {
52         checkedAction = nullptr;
53         return true;
54     }
55     QAction *newCheckedAction = actionList.at(index);
56     return setCheckedAction(newCheckedAction);
57 }
58
59 bool SegmentedControl::setCheckedAction(QAction *action) {
60     if (checkedAction == action) {
61         return false;
62     }
63     if (checkedAction) checkedAction->setChecked(false);
64     checkedAction = action;
65     checkedAction->setChecked(true);
66     update();
67     return true;
68 }
69
70 QSize SegmentedControl::minimumSizeHint() const {
71     int itemsWidth = calculateButtonWidth() * actionList.size() * 1.2;
72     return (QSize(itemsWidth, QFontMetrics(font()).height() * 1.8));
73 }
74
75 void SegmentedControl::paintEvent(QPaintEvent * /*event*/) {
76     const int height = rect().height();
77     const int width = rect().width();
78
79     QPainter p(this);
80
81     // Calculate Buttons Size & Location
82     const int buttonWidth = width / actionList.size();
83
84     const qreal pixelRatio = devicePixelRatioF();
85     QPen pen(borderColor);
86     const qreal penWidth = 1. / pixelRatio;
87     pen.setWidthF(penWidth);
88     p.setPen(pen);
89
90     // Draw Buttons
91     QRect rect(0, 0, buttonWidth, height);
92     const int actionCount = actionList.size();
93     for (int i = 0; i < actionCount; i++) {
94         QAction *action = actionList.at(i);
95         if (i + 1 == actionCount) {
96             // last button
97             rect.setWidth(width - buttonWidth * (actionCount - 1));
98             paintButton(&p, rect, action);
99         } else {
100             paintButton(&p, rect, action);
101             rect.moveLeft(rect.x() + rect.width());
102         }
103     }
104 }
105
106 void SegmentedControl::mouseMoveEvent(QMouseEvent *event) {
107     QAction *action = findHoveredAction(event->pos());
108
109     if (!action && hoveredAction) {
110         hoveredAction = nullptr;
111         update();
112     } else if (action && action != hoveredAction) {
113         hoveredAction = action;
114         action->hover();
115         update();
116
117         // status tip
118         MainWindow::instance()->statusBar()->showMessage(action->statusTip());
119     }
120 }
121
122 void SegmentedControl::mousePressEvent(QMouseEvent *event) {
123     QWidget::mousePressEvent(event);
124     if (hoveredAction) {
125         pressedAction = hoveredAction;
126         update();
127     }
128 }
129
130 void SegmentedControl::mouseReleaseEvent(QMouseEvent *event) {
131     QWidget::mouseReleaseEvent(event);
132     pressedAction = nullptr;
133     if (hoveredAction) {
134         bool changed = setCheckedAction(hoveredAction);
135         if (changed) hoveredAction->trigger();
136     }
137 }
138
139 void SegmentedControl::leaveEvent(QEvent *event) {
140     QWidget::leaveEvent(event);
141     // status tip
142     MainWindow::instance()->statusBar()->clearMessage();
143     hoveredAction = nullptr;
144     pressedAction = nullptr;
145     update();
146 }
147
148 void SegmentedControl::setupColors() {
149     selectedColor = palette().color(QPalette::Base);
150     if (selectedColor.value() > 128) {
151         int factor = 105;
152         backgroundColor = selectedColor.darker(factor);
153         borderColor = backgroundColor;
154         hoveredColor = backgroundColor.darker(factor);
155         pressedColor = hoveredColor.darker(factor);
156     } else {
157         int factor = 130;
158         backgroundColor = selectedColor.lighter(factor);
159         borderColor = backgroundColor;
160         hoveredColor = backgroundColor.lighter(factor);
161         pressedColor = hoveredColor.lighter(factor);
162     }
163 }
164
165 QAction *SegmentedControl::findHoveredAction(const QPoint &pos) const {
166     const int w = width();
167     if (pos.y() <= 0 || pos.x() >= w || pos.y() >= height()) return nullptr;
168
169     int buttonWidth = w / actionList.size();
170
171     int buttonIndex = pos.x() / buttonWidth;
172
173     if (buttonIndex >= actionList.size()) return nullptr;
174     return actionList[buttonIndex];
175 }
176
177 int SegmentedControl::calculateButtonWidth() const {
178     QFontMetrics fontMetrics(font());
179     int tmpItemWidth, itemWidth = 0;
180     for (QAction *action : actionList) {
181         tmpItemWidth = fontMetrics.width(action->text());
182         if (itemWidth < tmpItemWidth) itemWidth = tmpItemWidth;
183     }
184     return itemWidth;
185 }
186
187 void SegmentedControl::paintButton(QPainter *painter, const QRect &rect, const QAction *action) {
188     painter->save();
189     painter->translate(rect.topLeft());
190
191     const int height = rect.height();
192     const int width = rect.width();
193
194     QColor c;
195     if (action == checkedAction) {
196         c = selectedColor;
197     } else if (action == pressedAction) {
198         c = pressedColor;
199     } else if (action == hoveredAction) {
200         c = hoveredColor;
201     } else {
202         c = backgroundColor;
203     }
204     painter->fillRect(0, 0, width, height, c);
205
206     const QString text = action->text();
207
208     painter->setPen(palette().windowText().color());
209     painter->drawText(0, 0, width, height, Qt::AlignCenter, text);
210
211     if (action->property("notifyCount").isValid()) {
212         QRect textBox = painter->boundingRect(rect, Qt::AlignCenter, text);
213         painter->translate((width + textBox.width()) / 2 + 10, (height - textBox.height()) / 2);
214         PainterUtils::paintBadge(painter, action->property("notifyCount").toString(), false, c);
215     }
216
217     painter->restore();
218 }