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 
16 
17 */
18 
19 #include "QRoundProgressBar.h"
20 
21 #include <QPainter>
22 #include <QPainterPath>
23 
24 QRoundProgressBar::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 
31 void 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 
123 void QRoundProgressBar::setDataColors(const QGradientStops &stopPoints)
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 
160 void 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 
221 void QRoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
222 {
223  p.fillRect(baseRect, palette().window());
224 }
225 
226 void 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());
233  p.drawEllipse(baseRect);
234  break;
235 
236  case StylePie:
237  p.setPen(QPen(palette().base().color(), m_outlinePenWidth));
238  p.setBrush(palette().base());
239  p.drawEllipse(baseRect);
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 
253 void 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
271  QPainterPath dataPath;
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));
281  p.drawPath(dataPath);
282 }
283 
284 void 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 
301 void 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 
310 void 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 
325 QString 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 
344 void 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 
360 void QRoundProgressBar::rebuildDataBrushIfNeeded()
361 {
362  if (m_rebuildBrush)
363  {
364  m_rebuildBrush = false;
365 
366  QConicalGradient dataBrush;
367  dataBrush.setCenter(0.5, 0.5);
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());
380  p.setBrush(QPalette::Highlight, dataBrush);
381  setPalette(p);
382  }
383 }
void setCenter(const QPointF &center)
void setColorAt(qreal position, const QColor &color)
void setRange(double min, double max)
Defines minimum und maximum of the allowed value range.
AlignCenter
QWidget * window() const const
void resetFormat()
Sets format string to empty string.
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
void setPen(const QColor &color)
Format_ARGB32_Premultiplied
QString number(int n, int base)
void drawEllipse(const QRectF &rectangle)
@ StyleLine
Line style (thin round line around the text)
void update()
void setMaximum(double max)
Defines maximum of the allowed value range.
void clear()
QRectF adjusted(qreal dx1, qreal dy1, qreal dx2, qreal dy2) const const
void setFillRule(Qt::FillRule fillRule)
QString format() const
Returns the string used to generate the current text.
void drawText(const QPointF &position, const QString &text)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setBarStyle(BarStyle style)
Sets visual style of the widget.
void setValue(double val)
Sets a value which will be shown on the widget.
void setAngle(qreal angle)
void setCoordinateMode(QGradient::CoordinateMode mode)
WindingFill
void setNullPosition(double position)
Defines position of minimum value.
void setFormat(const QString &format)
Defines the string used to generate the current text.
QStyle * style() const const
@ StylePie
Pie style (filled pie segment with the text in center)
bool isEmpty() const const
void drawPath(const QPainterPath &path)
BarStyle
The BarStyle enum defines general look of the progress bar.
double value() const
Returns current value shown on the widget.
void setDataPenWidth(double penWidth)
Sets width of the data circle pen.
void setDecimals(int count)
Sets number of decimals to show after the comma (default is 1).
void setBrush(const QBrush &brush)
QPointF center() const const
void moveTo(const QPointF &point)
void setDataColors(const QGradientStops &stopPoints)
Sets colors of the visible data and makes gradient brush from them.
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
void setFont(const QFont &font)
void setOutlinePenWidth(double penWidth)
Sets width of the outline circle pen.
void drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
@ StyleDonut
Donut style (filled torus around the text)
void setMinimum(double min)
Defines minimum of the allowed value range.
void lineTo(const QPointF &endPoint)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 19 2022 03:57:54 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.