ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
WaitingSpinnerWidget.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "WaitingSpinnerWidget.h"
9 
10 // Standard includes
11 #include <algorithm>
12 #include <cmath>
13 
14 // Qt includes
15 #include <QPainter>
16 #include <QTimer>
17 
19  bool centerOnParent,
20  bool disableParentWhenSpinning)
21  : QWidget(parent),
22  _centerOnParent(centerOnParent),
23  _disableParentWhenSpinning(disableParentWhenSpinning)
24 {
25  initialize();
26 }
27 
28 WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality,
29  QWidget *parent,
30  bool centerOnParent,
31  bool disableParentWhenSpinning)
32  : QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint),
33  _centerOnParent(centerOnParent),
34  _disableParentWhenSpinning(disableParentWhenSpinning)
35 {
36  initialize();
37 
38  // We need to set the window modality AFTER we've hidden the
39  // widget for the first time since changing this property while
40  // the widget is visible has no effect.
41  setWindowModality(modality);
42  setAttribute(Qt::WA_TranslucentBackground);
43 }
44 
45 void WaitingSpinnerWidget::initialize()
46 {
47  _color = Qt::black;
48  _roundness = 100.0;
49  _minimumTrailOpacity = 3.14159265358979323846;
50  _trailFadePercentage = 80.0;
51  _revolutionsPerSecond = 1.57079632679489661923;
52  _numberOfLines = 20;
53  _lineLength = 10;
54  _lineWidth = 2;
55  _innerRadius = 10;
56  _currentCounter = 0;
57  _isSpinning = false;
58 
59  _timer = new QTimer(this);
60  connect(_timer, SIGNAL(timeout()), this, SLOT(rotate()));
61  updateSize();
62  updateTimer();
63  hide();
64 }
65 
67 {
68  updatePosition();
69  QPainter painter(this);
70  painter.fillRect(this->rect(), Qt::transparent);
71  painter.setRenderHint(QPainter::Antialiasing, true);
72 
73  if (_currentCounter >= _numberOfLines)
74  {
75  _currentCounter = 0;
76  }
77 
78  painter.setPen(Qt::NoPen);
79  for (int i = 0; i < _numberOfLines; ++i)
80  {
81  painter.save();
82  painter.translate(_innerRadius + _lineLength, _innerRadius + _lineLength);
83  qreal rotateAngle = static_cast<qreal>(360 * i) / static_cast<qreal>(_numberOfLines);
84  painter.rotate(rotateAngle);
85  painter.translate(_innerRadius, 0);
86  int distance = lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines);
87  QColor color = currentLineColor(
88  distance, _numberOfLines, _trailFadePercentage, _minimumTrailOpacity, _color);
89  painter.setBrush(color);
90  // TODO improve the way rounded rect is painted
91  painter.drawRoundedRect(QRect(0, -_lineWidth / 2, _lineLength, _lineWidth),
92  _roundness,
93  _roundness,
94  Qt::RelativeSize);
95  painter.restore();
96  }
97 }
98 
100 {
101  updatePosition();
102  _isSpinning = true;
103  show();
104 
105  if (parentWidget() && _disableParentWhenSpinning)
106  {
107  parentWidget()->setEnabled(false);
108  }
109 
110  if (!_timer->isActive())
111  {
112  _timer->start();
113  _currentCounter = 0;
114  }
115 }
116 
118 {
119  _isSpinning = false;
120  hide();
121 
122  if (parentWidget() && _disableParentWhenSpinning)
123  {
124  parentWidget()->setEnabled(true);
125  }
126 
127  if (_timer->isActive())
128  {
129  _timer->stop();
130  _currentCounter = 0;
131  }
132 }
133 
135 {
136  _numberOfLines = lines;
137  _currentCounter = 0;
138  updateTimer();
139 }
140 
142 {
143  _lineLength = length;
144  updateSize();
145 }
146 
148 {
149  _lineWidth = width;
150  updateSize();
151 }
152 
154 {
155  _innerRadius = radius;
156  updateSize();
157 }
158 
160 {
161  return _color;
162 }
163 
165 {
166  return _roundness;
167 }
168 
170 {
171  return _minimumTrailOpacity;
172 }
173 
175 {
176  return _trailFadePercentage;
177 }
178 
180 {
181  return _revolutionsPerSecond;
182 }
183 
185 {
186  return _numberOfLines;
187 }
188 
190 {
191  return _lineLength;
192 }
193 
195 {
196  return _lineWidth;
197 }
198 
200 {
201  return _innerRadius;
202 }
203 
205 {
206  return _isSpinning;
207 }
208 
210 {
211  _roundness = std::max(0.0, std::min(100.0, roundness));
212 }
213 
215 {
216  _color = color;
217 }
218 
219 void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond)
220 {
221  _revolutionsPerSecond = revolutionsPerSecond;
222  updateTimer();
223 }
224 
226 {
227  _trailFadePercentage = trail;
228 }
229 
230 void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity)
231 {
232  _minimumTrailOpacity = minimumTrailOpacity;
233 }
234 
235 void WaitingSpinnerWidget::rotate()
236 {
237  ++_currentCounter;
238  if (_currentCounter >= _numberOfLines)
239  {
240  _currentCounter = 0;
241  }
242  update();
243 }
244 
245 void WaitingSpinnerWidget::updateSize()
246 {
247  int size = (_innerRadius + _lineLength) * 2;
248  setFixedSize(size, size);
249 }
250 
251 void WaitingSpinnerWidget::updateTimer()
252 {
253  _timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond));
254 }
255 
256 void WaitingSpinnerWidget::updatePosition()
257 {
258  if (parentWidget() && _centerOnParent)
259  {
260  move(parentWidget()->width() / 2 - width() / 2,
261  parentWidget()->height() / 2 - height() / 2);
262  }
263 }
264 
265 int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary, int totalNrOfLines)
266 {
267  int distance = primary - current;
268  if (distance < 0)
269  {
270  distance += totalNrOfLines;
271  }
272  return distance;
273 }
274 
275 QColor WaitingSpinnerWidget::currentLineColor(
276  int countDistance, int totalNrOfLines, qreal trailFadePerc, qreal minOpacity, QColor color)
277 {
278  if (countDistance == 0)
279  {
280  return color;
281  }
282  const qreal minAlphaF = minOpacity / 100.0;
283  int distanceThreshold = static_cast<int>(ceil((totalNrOfLines - 1) * trailFadePerc / 100.0));
284  if (countDistance > distanceThreshold)
285  {
286  color.setAlphaF(minAlphaF);
287  }
288  else
289  {
290  qreal alphaDiff = color.alphaF() - minAlphaF;
291  qreal gradient = alphaDiff / static_cast<qreal>(distanceThreshold + 1);
292  qreal resultAlpha = color.alphaF() - gradient * countDistance;
293 
294  // If alpha is out of bounds, clip it.
295  resultAlpha = std::min(1.0, std::max(0.0, resultAlpha));
296  color.setAlphaF(resultAlpha);
297  }
298  return color;
299 }
int width
int size
int height
math::float4 color
void paintEvent(QPaintEvent *paintEvent) override
void setNumberOfLines(int lines)
void setInnerRadius(int radius)
void setColor(QColor color)
void setLineLength(int length)
void setRoundness(qreal roundness)
void setMinimumTrailOpacity(qreal minimumTrailOpacity)
WaitingSpinnerWidget(QWidget *parent=nullptr, bool centerOnParent=true, bool disableParentWhenSpinning=true)
void setRevolutionsPerSecond(qreal revolutionsPerSecond)
void setTrailFadePercentage(qreal trail)
__host__ __device__ float length(float2 v)
Definition: cutil_math.h:1162
int min(int a, int b)
Definition: cutil_math.h:53
int max(int a, int b)
Definition: cutil_math.h:48
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
constexpr Rgb black(0, 0, 0)
Definition: lsd.c:1170