1 /* Original Work Copyright (c) 2012-2014 Alexander Turkin
2 Modified 2014 by William Hallatt
3 Modified 2015 by Jacob Dawid
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:
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
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.
24 #include "waitingspinnerwidget.h"
34 WaitingSpinnerWidget::WaitingSpinnerWidget(QWidget *parent,
36 bool disableParentWhenSpinning)
38 _centerOnParent(centerOnParent),
39 _disableParentWhenSpinning(disableParentWhenSpinning) {
43 WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality,
46 bool disableParentWhenSpinning)
47 : QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint),
48 _centerOnParent(centerOnParent),
49 _disableParentWhenSpinning(disableParentWhenSpinning){
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);
59 void WaitingSpinnerWidget::initialize() {
62 _minimumTrailOpacity = 3.14159265358979323846;
63 _trailFadePercentage = 80.0;
64 _revolutionsPerSecond = 1.57079632679489661923;
72 _timer = new QTimer(this);
73 connect(_timer, SIGNAL(timeout()), this, SLOT(rotate()));
79 void WaitingSpinnerWidget::paintEvent(QPaintEvent *) {
81 QPainter painter(this);
82 painter.fillRect(this->rect(), Qt::transparent);
83 painter.setRenderHint(QPainter::Antialiasing, true);
85 if (_currentCounter >= _numberOfLines) {
89 painter.setPen(Qt::NoPen);
90 for (int i = 0; i < _numberOfLines; ++i) {
92 painter.translate(_innerRadius + _lineLength,
93 _innerRadius + _lineLength);
95 static_cast<qreal>(360 * i) / static_cast<qreal>(_numberOfLines);
96 painter.rotate(rotateAngle);
97 painter.translate(_innerRadius, 0);
99 lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines);
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);
112 void WaitingSpinnerWidget::start() {
117 if(parentWidget() && _disableParentWhenSpinning) {
118 parentWidget()->setEnabled(false);
121 if (!_timer->isActive()) {
127 void WaitingSpinnerWidget::stop() {
131 if(parentWidget() && _disableParentWhenSpinning) {
132 parentWidget()->setEnabled(true);
135 if (_timer->isActive()) {
141 void WaitingSpinnerWidget::setNumberOfLines(int lines) {
142 _numberOfLines = lines;
147 void WaitingSpinnerWidget::setLineLength(int length) {
148 _lineLength = length;
152 void WaitingSpinnerWidget::setLineWidth(int width) {
157 void WaitingSpinnerWidget::setInnerRadius(int radius) {
158 _innerRadius = radius;
162 QColor WaitingSpinnerWidget::color() {
166 qreal WaitingSpinnerWidget::roundness() {
170 qreal WaitingSpinnerWidget::minimumTrailOpacity() {
171 return _minimumTrailOpacity;
174 qreal WaitingSpinnerWidget::trailFadePercentage() {
175 return _trailFadePercentage;
178 qreal WaitingSpinnerWidget::revolutionsPersSecond() {
179 return _revolutionsPerSecond;
182 int WaitingSpinnerWidget::numberOfLines() {
183 return _numberOfLines;
186 int WaitingSpinnerWidget::lineLength() {
190 int WaitingSpinnerWidget::lineWidth() {
194 int WaitingSpinnerWidget::innerRadius() {
198 bool WaitingSpinnerWidget::isSpinning() const {
202 void WaitingSpinnerWidget::setRoundness(qreal roundness) {
203 _roundness = std::max(0.0, std::min(100.0, roundness));
206 void WaitingSpinnerWidget::setColor(QColor color) {
210 void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond) {
211 _revolutionsPerSecond = revolutionsPerSecond;
215 void WaitingSpinnerWidget::setTrailFadePercentage(qreal trail) {
216 _trailFadePercentage = trail;
219 void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity) {
220 _minimumTrailOpacity = minimumTrailOpacity;
223 void WaitingSpinnerWidget::rotate() {
225 if (_currentCounter >= _numberOfLines) {
231 void WaitingSpinnerWidget::updateSize() {
232 int size = (_innerRadius + _lineLength) * 2;
233 setFixedSize(size, size);
236 void WaitingSpinnerWidget::updateTimer() {
237 _timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond));
240 void WaitingSpinnerWidget::updatePosition() {
241 if (parentWidget() && _centerOnParent) {
242 move(parentWidget()->width() / 2 - width() / 2,
243 parentWidget()->height() / 2 - height() / 2);
247 int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary,
248 int totalNrOfLines) {
249 int distance = primary - current;
251 distance += totalNrOfLines;
256 QColor WaitingSpinnerWidget::currentLineColor(int countDistance, int totalNrOfLines,
257 qreal trailFadePerc, qreal minOpacity,
259 if (countDistance == 0) {
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);
268 qreal alphaDiff = color.alphaF() - minAlphaF;
269 qreal gradient = alphaDiff / static_cast<qreal>(distanceThreshold + 1);
270 qreal resultAlpha = color.alphaF() - gradient * countDistance;
272 // If alpha is out of bounds, clip it.
273 resultAlpha = std::min(1.0, std::max(0.0, resultAlpha));
274 color.setAlphaF(resultAlpha);