Kstars

QRoundProgressBar.cpp
1/*
2 QRoundProgressBar - a circular progress bar Qt widget.
3
4 Sintegrial Technologies (c) 2015-now
5
6 The software is freeware and is distributed "as is" with the complete source codes.
7 Anybody is free to use it in any software projects, either commercial or non-commercial.
8 Please do not remove this copyright message and remain the name of the author unchanged.
9
10 It is very appreciated if you produce some feedback to us case you are going to use
11 the software.
12
13 Please send your questions, suggestions, and information about found issues to the
14
15 sintegrial@gmail.com
16
17*/
18
19#include "QRoundProgressBar.h"
20
21#include <QPainter>
22#include <QPainterPath>
23
24QRoundProgressBar::QRoundProgressBar(QWidget *parent)
25 : QWidget(parent), m_min(0), m_max(100), m_value(25), m_nullPosition(PositionTop), m_barStyle(StyleDonut),
26 m_outlinePenWidth(1), m_dataPenWidth(1), m_rebuildBrush(false), m_format("%p%"), m_decimals(1),
27 m_updateFlags(UF_PERCENT)
28{
29}
30
31void QRoundProgressBar::setRange(double min, double max)
32{
33 m_min = min;
34 m_max = max;
35
36 if (m_max < m_min)
37 qSwap(m_max, m_min);
38
39 if (m_value < m_min)
40 m_value = m_min;
41 else if (m_value > m_max)
42 m_value = m_max;
43
44 if (!m_gradientData.isEmpty())
45 m_rebuildBrush = true;
46
47 update();
48}
49
51{
52 setRange(min, m_max);
53}
54
56{
57 setRange(m_min, max);
58}
59
61{
62 if (m_value != val)
63 {
64 if (val < m_min)
65 m_value = m_min;
66 else if (val > m_max)
67 m_value = m_max;
68 else
69 m_value = val;
70
71 update();
72 }
73}
74
76{
77 setValue(double(val));
78}
79
81{
82 if (position != m_nullPosition)
83 {
84 m_nullPosition = position;
85
86 if (!m_gradientData.isEmpty())
87 m_rebuildBrush = true;
88
89 update();
90 }
91}
92
94{
95 if (style != m_barStyle)
96 {
97 m_barStyle = style;
98
99 update();
100 }
101}
102
104{
105 if (penWidth != m_outlinePenWidth)
106 {
107 m_outlinePenWidth = penWidth;
108
109 update();
110 }
111}
112
114{
115 if (penWidth != m_dataPenWidth)
116 {
117 m_dataPenWidth = penWidth;
118
119 update();
120 }
121}
122
124{
125 if (stopPoints != m_gradientData)
126 {
127 m_gradientData = stopPoints;
128 m_rebuildBrush = true;
129
130 update();
131 }
132}
133
135{
136 if (format != m_format)
137 {
138 m_format = format;
139
140 valueFormatChanged();
141 }
142}
143
145{
146 m_format.clear();
147 valueFormatChanged();
148}
149
151{
152 if (count >= 0 && count != m_decimals)
153 {
154 m_decimals = count;
155
156 valueFormatChanged();
157 }
158}
159
160void QRoundProgressBar::paintEvent(QPaintEvent * /*event*/)
161{
162#if 0
163 double outerRadius = qMin(width(), height());
164 QRectF baseRect(1, 1, outerRadius-2, outerRadius-2);
165
166 QImage buffer(outerRadius, outerRadius, QImage::Format_ARGB32_Premultiplied);
167
168 QPainter p(&buffer);
169 p.setRenderHint(QPainter::Antialiasing);
170
171 // data brush
172 rebuildDataBrushIfNeeded();
173
174 // background
175 drawBackground(p, buffer.rect());
176
177 // base circle
178 drawBase(p, baseRect);
179
180 // data circle
181 double arcStep = 360.0 / (m_max - m_min) * m_value;
182 drawValue(p, baseRect, m_value, arcStep);
183
184 // center circle
185 double innerRadius(0);
186 QRectF innerRect;
187 calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
188 drawInnerBackground(p, innerRect);
189
190 // text
191 drawText(p, innerRect, innerRadius, m_value);
192
193 // finally draw the bar
194 p.end();
195
196 QPainter painter(this);
197 painter.fillRect(baseRect, palette().background());
198 painter.drawImage(0,0, buffer);
199#endif
200 double outerRadius = qMin(width(), height());
201 QRectF baseRect(1, 1, outerRadius - 2, outerRadius - 2);
202 QPainter p(this);
203 //painter.fillRect(baseRect, palette().window());
204 p.setRenderHint(QPainter::Antialiasing);
205 p.fillRect(baseRect, Qt::NoBrush);
206 drawBase(p, baseRect);
207 // data circle
208 double arcStep = 360.0 / (m_max - m_min) * m_value;
209 drawValue(p, baseRect, m_value, arcStep);
210
211 // center circle
212 double innerRadius(0);
213 QRectF innerRect;
214 calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
215 drawInnerBackground(p, innerRect);
216
217 // text
218 drawText(p, innerRect, innerRadius, m_value);
219}
220
221void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
222{
224}
225
226void QRoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect)
227{
228 switch (m_barStyle)
229 {
230 case StyleDonut:
231 p.setPen(QPen(palette().shadow().color(), m_outlinePenWidth));
232 p.setBrush(palette().base());
234 break;
235
236 case StylePie:
237 p.setPen(QPen(palette().base().color(), m_outlinePenWidth));
238 p.setBrush(palette().base());
240 break;
241
242 case StyleLine:
243 p.setPen(QPen(palette().base().color(), m_outlinePenWidth));
245 p.drawEllipse(baseRect.adjusted(m_outlinePenWidth / 2, m_outlinePenWidth / 2, -m_outlinePenWidth / 2,
246 -m_outlinePenWidth / 2));
247 break;
248
249 default:;
250 }
251}
252
253void QRoundProgressBar::drawValue(QPainter &p, const QRectF &baseRect, double value, double arcLength)
254{
255 // nothing to draw
256 if (value == m_min)
257 return;
258
259 // for Line style
260 if (m_barStyle == StyleLine)
261 {
262 p.setPen(QPen(palette().highlight().color(), m_dataPenWidth));
264 p.drawArc(baseRect.adjusted(m_outlinePenWidth / 2, m_outlinePenWidth / 2, -m_outlinePenWidth / 2,
265 -m_outlinePenWidth / 2),
266 m_nullPosition * 16, -arcLength * 16);
267 return;
268 }
269
270 // for Pie and Donut styles
272 dataPath.setFillRule(Qt::WindingFill);
273
274 // pie segment outer
275 dataPath.moveTo(baseRect.center());
276 dataPath.arcTo(baseRect, m_nullPosition, -arcLength);
277 dataPath.lineTo(baseRect.center());
278
279 p.setBrush(palette().highlight());
280 p.setPen(QPen(palette().shadow().color(), m_dataPenWidth));
282}
283
284void QRoundProgressBar::calculateInnerRect(const QRectF & /*baseRect*/, double outerRadius, QRectF &innerRect,
285 double &innerRadius)
286{
287 // for Line style
288 if (m_barStyle == StyleLine)
289 {
290 innerRadius = outerRadius - m_outlinePenWidth;
291 }
292 else // for Pie and Donut styles
293 {
294 innerRadius = outerRadius * 0.75;
295 }
296
297 double delta = (outerRadius - innerRadius) / 2;
298 innerRect = QRectF(delta, delta, innerRadius, innerRadius);
299}
300
301void QRoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect)
302{
303 if (m_barStyle == StyleDonut)
304 {
305 p.setBrush(palette().alternateBase());
306 p.drawEllipse(innerRect);
307 }
308}
309
310void QRoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value)
311{
312 if (m_format.isEmpty())
313 return;
314
315 // !!! to revise
316 QFont f(font());
317 f.setPixelSize(innerRadius * qMax(0.05, (0.35 - (double)m_decimals * 0.08)));
318 p.setFont(f);
319
320 QRectF textRect(innerRect);
321 p.setPen(palette().text().color());
322 p.drawText(textRect, Qt::AlignCenter, valueToText(value));
323}
324
325QString QRoundProgressBar::valueToText(double value) const
326{
327 QString textToDraw(m_format);
328
329 if (m_updateFlags & UF_VALUE)
330 textToDraw.replace("%v", QString::number(value, 'f', m_decimals));
331
332 if (m_updateFlags & UF_PERCENT)
333 {
334 double procent = (value - m_min) / (m_max - m_min) * 100.0;
335 textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));
336 }
337
338 if (m_updateFlags & UF_MAX)
339 textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));
340
341 return textToDraw;
342}
343
344void QRoundProgressBar::valueFormatChanged()
345{
346 m_updateFlags = 0;
347
348 if (m_format.contains("%v"))
349 m_updateFlags |= UF_VALUE;
350
351 if (m_format.contains("%p"))
352 m_updateFlags |= UF_PERCENT;
353
354 if (m_format.contains("%m"))
355 m_updateFlags |= UF_MAX;
356
357 update();
358}
359
360void QRoundProgressBar::rebuildDataBrushIfNeeded()
361{
362 if (m_rebuildBrush)
363 {
364 m_rebuildBrush = false;
365
367 dataBrush.setCenter(0.5, 0.5);
368 dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
369
370 // invert colors
371 for (int i = 0; i < m_gradientData.count(); i++)
372 {
373 dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);
374 }
375
376 // angle
377 dataBrush.setAngle(m_nullPosition);
378
379 QPalette p(palette());
381 setPalette(p);
382 }
383}
void setDataPenWidth(double penWidth)
Sets width of the data circle pen.
void setValue(double val)
Sets a value which will be shown on the widget.
void setMinimum(double min)
Defines minimum of the allowed value range.
void setOutlinePenWidth(double penWidth)
Sets width of the outline circle pen.
void setDecimals(int count)
Sets number of decimals to show after the comma (default is 1).
double value() const
Returns current value shown on the widget.
void setMaximum(double max)
Defines maximum of the allowed value range.
void setBarStyle(BarStyle style)
Sets visual style of the widget.
void setFormat(const QString &format)
Defines the string used to generate the current text.
void setNullPosition(double position)
Defines position of minimum value.
QString format() const
Returns the string used to generate the current text.
void setRange(double min, double max)
Defines minimum und maximum of the allowed value range.
BarStyle
The BarStyle enum defines general look of the progress bar.
@ StylePie
Pie style (filled pie segment with the text in center)
@ StyleLine
Line style (thin round line around the text)
@ StyleDonut
Donut style (filled torus around the text)
void resetFormat()
Sets format string to empty string.
void setDataColors(const QGradientStops &stopPoints)
Sets colors of the visible data and makes gradient brush from them.
Format_ARGB32_Premultiplied
void drawArc(const QRect &rectangle, int startAngle, int spanAngle)
void drawEllipse(const QPoint &center, int rx, int ry)
void drawPath(const QPainterPath &path)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void clear()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
AlignCenter
WindingFill
QStyle * style() const const
void update()
QWidget * window() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.