]> git.sur5r.net Git - minitube/blob - src/waitingspinnerwidget.cpp
Upload 3.9.3-2 to unstable
[minitube] / src / waitingspinnerwidget.cpp
1 /* Original Work Copyright (c) 2012-2014 Alexander Turkin
2    Modified 2014 by William Hallatt
3    Modified 2015 by Jacob Dawid
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy of
6 this software and associated documentation files (the "Software"), to deal in
7 the Software without restriction, including without limitation the rights to
8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 the Software, and to permit persons to whom the Software is furnished to do so,
10 subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 // Own includes
24 #include "waitingspinnerwidget.h"
25
26 // Standard includes
27 #include <cmath>
28 #include <algorithm>
29
30 // Qt includes
31 #include <QPainter>
32 #include <QTimer>
33
34 WaitingSpinnerWidget::WaitingSpinnerWidget(QWidget *parent,
35                                            bool centerOnParent,
36                                            bool disableParentWhenSpinning)
37     : QWidget(parent),
38       _centerOnParent(centerOnParent),
39       _disableParentWhenSpinning(disableParentWhenSpinning) {
40     initialize();
41 }
42
43 WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality,
44                                            QWidget *parent,
45                                            bool centerOnParent,
46                                            bool disableParentWhenSpinning)
47     : QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint),
48       _centerOnParent(centerOnParent),
49       _disableParentWhenSpinning(disableParentWhenSpinning){
50     initialize();
51
52     // We need to set the window modality AFTER we've hidden the
53     // widget for the first time since changing this property while
54     // the widget is visible has no effect.
55     setWindowModality(modality);
56     setAttribute(Qt::WA_TranslucentBackground);
57 }
58
59 void WaitingSpinnerWidget::initialize() {
60     _color = Qt::black;
61     _roundness = 100.0;
62     _minimumTrailOpacity = 3.14159265358979323846;
63     _trailFadePercentage = 80.0;
64     _revolutionsPerSecond = 1.57079632679489661923;
65     _numberOfLines = 20;
66     _lineLength = 10;
67     _lineWidth = 2;
68     _innerRadius = 10;
69     _currentCounter = 0;
70     _isSpinning = false;
71
72     _timer = new QTimer(this);
73     connect(_timer, SIGNAL(timeout()), this, SLOT(rotate()));
74     updateSize();
75     updateTimer();
76     hide();
77 }
78
79 void WaitingSpinnerWidget::paintEvent(QPaintEvent *) {
80     updatePosition();
81     QPainter painter(this);
82     painter.fillRect(this->rect(), Qt::transparent);
83     painter.setRenderHint(QPainter::Antialiasing, true);
84
85     if (_currentCounter >= _numberOfLines) {
86         _currentCounter = 0;
87     }
88
89     painter.setPen(Qt::NoPen);
90     for (int i = 0; i < _numberOfLines; ++i) {
91         painter.save();
92         painter.translate(_innerRadius + _lineLength,
93                           _innerRadius + _lineLength);
94         qreal rotateAngle =
95                 static_cast<qreal>(360 * i) / static_cast<qreal>(_numberOfLines);
96         painter.rotate(rotateAngle);
97         painter.translate(_innerRadius, 0);
98         int distance =
99                 lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines);
100         QColor color =
101                 currentLineColor(distance, _numberOfLines, _trailFadePercentage,
102                                  _minimumTrailOpacity, _color);
103         painter.setBrush(color);
104         // TODO improve the way rounded rect is painted
105         painter.drawRoundedRect(
106                     QRect(0, -_lineWidth / 2, _lineLength, _lineWidth), _roundness,
107                     _roundness, Qt::RelativeSize);
108         painter.restore();
109     }
110 }
111
112 void WaitingSpinnerWidget::start() {
113     updatePosition();
114     _isSpinning = true;
115     show();
116
117     if(parentWidget() && _disableParentWhenSpinning) {
118         parentWidget()->setEnabled(false);
119     }
120
121     if (!_timer->isActive()) {
122         _timer->start();
123         _currentCounter = 0;
124     }
125 }
126
127 void WaitingSpinnerWidget::stop() {
128     _isSpinning = false;
129     hide();
130
131     if(parentWidget() && _disableParentWhenSpinning) {
132         parentWidget()->setEnabled(true);
133     }
134
135     if (_timer->isActive()) {
136         _timer->stop();
137         _currentCounter = 0;
138     }
139 }
140
141 void WaitingSpinnerWidget::setNumberOfLines(int lines) {
142     _numberOfLines = lines;
143     _currentCounter = 0;
144     updateTimer();
145 }
146
147 void WaitingSpinnerWidget::setLineLength(int length) {
148     _lineLength = length;
149     updateSize();
150 }
151
152 void WaitingSpinnerWidget::setLineWidth(int width) {
153     _lineWidth = width;
154     updateSize();
155 }
156
157 void WaitingSpinnerWidget::setInnerRadius(int radius) {
158     _innerRadius = radius;
159     updateSize();
160 }
161
162 QColor WaitingSpinnerWidget::color() {
163     return _color;
164 }
165
166 qreal WaitingSpinnerWidget::roundness() {
167     return _roundness;
168 }
169
170 qreal WaitingSpinnerWidget::minimumTrailOpacity() {
171     return _minimumTrailOpacity;
172 }
173
174 qreal WaitingSpinnerWidget::trailFadePercentage() {
175     return _trailFadePercentage;
176 }
177
178 qreal WaitingSpinnerWidget::revolutionsPersSecond() {
179     return _revolutionsPerSecond;
180 }
181
182 int WaitingSpinnerWidget::numberOfLines() {
183     return _numberOfLines;
184 }
185
186 int WaitingSpinnerWidget::lineLength() {
187     return _lineLength;
188 }
189
190 int WaitingSpinnerWidget::lineWidth() {
191     return _lineWidth;
192 }
193
194 int WaitingSpinnerWidget::innerRadius() {
195     return _innerRadius;
196 }
197
198 bool WaitingSpinnerWidget::isSpinning() const {
199     return _isSpinning;
200 }
201
202 void WaitingSpinnerWidget::setRoundness(qreal roundness) {
203     _roundness = std::max(0.0, std::min(100.0, roundness));
204 }
205
206 void WaitingSpinnerWidget::setColor(QColor color) {
207     _color = color;
208 }
209
210 void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond) {
211     _revolutionsPerSecond = revolutionsPerSecond;
212     updateTimer();
213 }
214
215 void WaitingSpinnerWidget::setTrailFadePercentage(qreal trail) {
216     _trailFadePercentage = trail;
217 }
218
219 void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity) {
220     _minimumTrailOpacity = minimumTrailOpacity;
221 }
222
223 void WaitingSpinnerWidget::rotate() {
224     ++_currentCounter;
225     if (_currentCounter >= _numberOfLines) {
226         _currentCounter = 0;
227     }
228     update();
229 }
230
231 void WaitingSpinnerWidget::updateSize() {
232     int size = (_innerRadius + _lineLength) * 2;
233     setFixedSize(size, size);
234 }
235
236 void WaitingSpinnerWidget::updateTimer() {
237     _timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond));
238 }
239
240 void WaitingSpinnerWidget::updatePosition() {
241     if (parentWidget() && _centerOnParent) {
242         move(parentWidget()->width() / 2 - width() / 2,
243              parentWidget()->height() / 2 - height() / 2);
244     }
245 }
246
247 int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary,
248                                                        int totalNrOfLines) {
249     int distance = primary - current;
250     if (distance < 0) {
251         distance += totalNrOfLines;
252     }
253     return distance;
254 }
255
256 QColor WaitingSpinnerWidget::currentLineColor(int countDistance, int totalNrOfLines,
257                                               qreal trailFadePerc, qreal minOpacity,
258                                               QColor color) {
259     if (countDistance == 0) {
260         return color;
261     }
262     const qreal minAlphaF = minOpacity / 100.0;
263     int distanceThreshold =
264             static_cast<int>(ceil((totalNrOfLines - 1) * trailFadePerc / 100.0));
265     if (countDistance > distanceThreshold) {
266         color.setAlphaF(minAlphaF);
267     } else {
268         qreal alphaDiff = color.alphaF() - minAlphaF;
269         qreal gradient = alphaDiff / static_cast<qreal>(distanceThreshold + 1);
270         qreal resultAlpha = color.alphaF() - gradient * countDistance;
271
272         // If alpha is out of bounds, clip it.
273         resultAlpha = std::min(1.0, std::max(0.0, resultAlpha));
274         color.setAlphaF(resultAlpha);
275     }
276     return color;
277 }