1 #include "roundprogressbar.h"
2
3 #include <QtGui/QPainter>
4 #include <QtGui/QPainterPath>
5
6
7 namespace QSint
8 {
9
10
RoundProgressBar(QWidget * parent)11 RoundProgressBar::RoundProgressBar(QWidget *parent) :
12 QWidget(parent),
13 m_min(0), m_max(100),
14 m_value(25),
15 m_nullPosition(PositionTop),
16 m_barStyle(StyleDonut),
17 m_outlinePenWidth(1),
18 m_dataPenWidth(1),
19 m_rebuildBrush(false),
20 m_format("%p%"),
21 m_decimals(1),
22 m_updateFlags(UF_PERCENT)
23 {
24 QPalette p(palette());
25 p.setBrush(QPalette::Window, Qt::transparent);
26 setPalette(p);
27 }
28
setRange(double min,double max)29 void RoundProgressBar::setRange(double min, double max)
30 {
31 m_min = min;
32 m_max = max;
33
34 if (m_max < m_min)
35 qSwap(m_max, m_min);
36
37 if (m_value < m_min)
38 m_value = m_min;
39 else if (m_value > m_max)
40 m_value = m_max;
41
42 m_rebuildBrush = true;
43
44 update();
45 }
46
setMinimum(double min)47 void RoundProgressBar::setMinimum(double min)
48 {
49 setRange(min, m_max);
50 }
51
setMaximum(double max)52 void RoundProgressBar::setMaximum(double max)
53 {
54 setRange(m_min, max);
55 }
56
setValue(double val)57 void RoundProgressBar::setValue(double val)
58 {
59 if (m_value != val)
60 {
61 if (val < m_min)
62 m_value = m_min;
63 else if (val > m_max)
64 m_value = m_max;
65 else
66 m_value = val;
67
68 update();
69 }
70 }
71
setValue(int val)72 void RoundProgressBar::setValue(int val)
73 {
74 setValue(double(val));
75 }
76
setNullPosition(double position)77 void RoundProgressBar::setNullPosition(double position)
78 {
79 if (position != m_nullPosition)
80 {
81 m_nullPosition = position;
82
83 m_rebuildBrush = true;
84
85 update();
86 }
87 }
88
setBarStyle(RoundProgressBar::BarStyle style)89 void RoundProgressBar::setBarStyle(RoundProgressBar::BarStyle style)
90 {
91 if (style != m_barStyle)
92 {
93 m_barStyle = style;
94
95 m_rebuildBrush = true;
96
97 update();
98 }
99 }
100
setOutlinePenWidth(double penWidth)101 void RoundProgressBar::setOutlinePenWidth(double penWidth)
102 {
103 if (penWidth != m_outlinePenWidth)
104 {
105 m_outlinePenWidth = penWidth;
106
107 update();
108 }
109 }
110
setDataPenWidth(double penWidth)111 void RoundProgressBar::setDataPenWidth(double penWidth)
112 {
113 if (penWidth != m_dataPenWidth)
114 {
115 m_dataPenWidth = penWidth;
116
117 update();
118 }
119 }
120
setDataColors(const QGradientStops & stopPoints)121 void RoundProgressBar::setDataColors(const QGradientStops &stopPoints)
122 {
123 if (stopPoints != m_gradientData)
124 {
125 m_gradientData = stopPoints;
126 m_rebuildBrush = true;
127
128 update();
129 }
130 }
131
setFormat(const QString & format)132 void RoundProgressBar::setFormat(const QString &format)
133 {
134 if (format != m_format)
135 {
136 m_format = format;
137
138 valueFormatChanged();
139 }
140 }
141
resetFormat()142 void RoundProgressBar::resetFormat()
143 {
144 m_format = QString::null;
145
146 valueFormatChanged();
147 }
148
setDecimals(int count)149 void RoundProgressBar::setDecimals(int count)
150 {
151 if (count >= 0 && count != m_decimals)
152 {
153 m_decimals = count;
154
155 valueFormatChanged();
156 }
157 }
158
paintEvent(QPaintEvent *)159 void RoundProgressBar::paintEvent(QPaintEvent* /*event*/)
160 {
161 double outerRadius = qMin(width(), height());
162 QRectF baseRect(1, 1, outerRadius-2, outerRadius-2);
163
164 QImage buffer(outerRadius, outerRadius, QImage::Format_ARGB32_Premultiplied);
165 buffer.fill(Qt::transparent);
166
167 QPainter p(&buffer);
168 p.setRenderHint(QPainter::Antialiasing);
169
170 // data brush
171 rebuildDataBrushIfNeeded();
172
173 // background
174 drawBackground(p, buffer.rect());
175
176 // base circle
177 drawBase(p, baseRect);
178
179 // data circle
180 double delta = (m_max - m_min) / (m_value - m_min);
181 drawValue(p, baseRect, m_value, delta);
182
183 // center circle
184 double innerRadius(0);
185 QRectF innerRect;
186 calculateInnerRect(baseRect, outerRadius, innerRect, innerRadius);
187 drawInnerBackground(p, innerRect);
188
189 // text
190 drawText(p, innerRect, innerRadius, m_value);
191
192 // finally draw the bar
193 p.end();
194
195 QPainter painter(this);
196 painter.fillRect(baseRect, Qt::transparent);
197 painter.drawImage((width() - outerRadius) / 2, (height() - outerRadius) / 2, buffer);
198 }
199
drawBackground(QPainter & p,const QRectF & baseRect)200 void RoundProgressBar::drawBackground(QPainter &p, const QRectF &baseRect)
201 {
202 p.fillRect(baseRect, palette().background());
203 }
204
drawBase(QPainter & p,const QRectF & baseRect)205 void RoundProgressBar::drawBase(QPainter &p, const QRectF &baseRect)
206 {
207 switch (m_barStyle)
208 {
209 case StyleDonut:
210 p.setPen(QPen(palette().shadow().color(), m_outlinePenWidth));
211 p.setBrush(palette().base());
212 p.drawEllipse(baseRect);
213 break;
214
215 case StylePie:
216 case StyleExpand:
217 p.setPen(QPen(palette().base().color(), m_outlinePenWidth));
218 p.setBrush(palette().base());
219 p.drawEllipse(baseRect);
220 break;
221
222 case StyleLine:
223 p.setPen(QPen(palette().base().color(), m_outlinePenWidth));
224 p.setBrush(Qt::NoBrush);
225 p.drawEllipse(baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));
226 break;
227
228 default:;
229 }
230
231 }
232
drawValue(QPainter & p,const QRectF & baseRect,double value,double delta)233 void RoundProgressBar::drawValue(QPainter &p, const QRectF &baseRect, double value, double delta)
234 {
235 // nothing to draw
236 if (value == m_min)
237 return;
238
239 // for Expand style
240 if (m_barStyle == StyleExpand)
241 {
242 p.setBrush(palette().highlight());
243 p.setPen(QPen(palette().shadow().color(), m_dataPenWidth));
244
245 double radius = (baseRect.height() / 2) / delta;
246 p.drawEllipse(baseRect.center(), radius, radius);
247
248 return;
249 }
250
251
252 // for Line style
253 if (m_barStyle == StyleLine)
254 {
255 p.setPen(QPen(palette().highlight().color(), m_dataPenWidth));
256 p.setBrush(Qt::NoBrush);
257
258 if (value == m_max)
259 {
260 p.drawEllipse(
261 baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2));
262 }
263 else
264 {
265 double arcLength = 360.0 / delta;
266
267 p.drawArc(
268 baseRect.adjusted(m_outlinePenWidth/2, m_outlinePenWidth/2, -m_outlinePenWidth/2, -m_outlinePenWidth/2),
269 m_nullPosition * 16,
270 -arcLength * 16);
271 }
272
273 return;
274 }
275
276
277 // for Pie and Donut styles
278 QPainterPath dataPath;
279 dataPath.setFillRule(Qt::WindingFill);
280
281 // pie segment outer
282 if (value == m_max)
283 {
284 dataPath.addEllipse(baseRect);
285 }
286 else
287 {
288 double arcLength = 360.0 / delta;
289
290 dataPath.moveTo(baseRect.center());
291 dataPath.arcTo(baseRect, m_nullPosition, -arcLength);
292 dataPath.lineTo(baseRect.center());
293 }
294
295 p.setBrush(palette().highlight());
296 p.setPen(QPen(palette().shadow().color(), m_dataPenWidth));
297 p.drawPath(dataPath);
298 }
299
calculateInnerRect(const QRectF &,double outerRadius,QRectF & innerRect,double & innerRadius)300 void RoundProgressBar::calculateInnerRect(const QRectF &/*baseRect*/, double outerRadius, QRectF &innerRect, double &innerRadius)
301 {
302 // for Line and Expand styles
303 if (m_barStyle == StyleLine || m_barStyle == StyleExpand)
304 {
305 innerRadius = outerRadius - m_outlinePenWidth;
306 }
307 else // for Pie and Donut styles
308 {
309 innerRadius = outerRadius * 0.75;
310 }
311
312 double delta = (outerRadius - innerRadius) / 2;
313 innerRect = QRectF(delta, delta, innerRadius, innerRadius);
314 }
315
drawInnerBackground(QPainter & p,const QRectF & innerRect)316 void RoundProgressBar::drawInnerBackground(QPainter &p, const QRectF &innerRect)
317 {
318 if (m_barStyle == StyleDonut)
319 {
320 p.setBrush(palette().alternateBase());
321 p.drawEllipse(innerRect);
322 }
323 }
324
drawText(QPainter & p,const QRectF & innerRect,double innerRadius,double value)325 void RoundProgressBar::drawText(QPainter &p, const QRectF &innerRect, double innerRadius, double value)
326 {
327 if (m_format.isEmpty())
328 return;
329
330 // !!! to revise
331 QFont f(font());
332 f.setPixelSize(10);
333 QFontMetricsF fm(f);
334 double maxWidth = fm.width(valueToText(m_max));
335 double delta = innerRadius / maxWidth;
336 double fontSize = f.pixelSize() * delta * 0.75;
337 f.setPixelSize(fontSize);
338 //f.setPixelSize(innerRadius * qMax(0.05, (0.5 - (double)m_decimals * 0.2)));
339 p.setFont(f);
340
341 QRectF textRect(innerRect);
342 p.setPen(palette().text().color());
343 p.drawText(textRect, Qt::AlignCenter, valueToText(value));
344 }
345
valueToText(double value) const346 QString RoundProgressBar::valueToText(double value) const
347 {
348 QString textToDraw(m_format);
349
350 if (m_updateFlags & UF_VALUE)
351 textToDraw.replace("%v", QString::number(value, 'f', m_decimals));
352
353 if (m_updateFlags & UF_PERCENT)
354 {
355 double procent = (value - m_min) / (m_max - m_min) * 100.0;
356 textToDraw.replace("%p", QString::number(procent, 'f', m_decimals));
357 }
358
359 if (m_updateFlags & UF_MAX)
360 textToDraw.replace("%m", QString::number(m_max - m_min + 1, 'f', m_decimals));
361
362 return textToDraw;
363 }
364
valueFormatChanged()365 void RoundProgressBar::valueFormatChanged()
366 {
367 m_updateFlags = 0;
368
369 if (m_format.contains("%v"))
370 m_updateFlags |= UF_VALUE;
371
372 if (m_format.contains("%p"))
373 m_updateFlags |= UF_PERCENT;
374
375 if (m_format.contains("%m"))
376 m_updateFlags |= UF_MAX;
377
378 update();
379 }
380
rebuildDataBrushIfNeeded()381 void RoundProgressBar::rebuildDataBrushIfNeeded()
382 {
383 if (!m_rebuildBrush)
384 return;
385
386 if (m_gradientData.isEmpty())
387 return;
388
389 if (m_barStyle == StyleLine)
390 return;
391
392 m_rebuildBrush = false;
393
394 QPalette p(palette());
395
396 if (m_barStyle == StyleExpand)
397 {
398 QRadialGradient dataBrush(0.5,0.5, 0.5, 0.5,0.5);
399 dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
400
401 // set colors
402 for (int i = 0; i < m_gradientData.count(); i++)
403 dataBrush.setColorAt(m_gradientData.at(i).first, m_gradientData.at(i).second);
404
405 p.setBrush(QPalette::Highlight, dataBrush);
406 }
407 else
408 {
409 QConicalGradient dataBrush(QPointF(0.5,0.5), m_nullPosition);
410 dataBrush.setCoordinateMode(QGradient::StretchToDeviceMode);
411
412 // invert colors
413 for (int i = 0; i < m_gradientData.count(); i++)
414 dataBrush.setColorAt(1.0 - m_gradientData.at(i).first, m_gradientData.at(i).second);
415
416 p.setBrush(QPalette::Highlight, dataBrush);
417 }
418
419 setPalette(p);
420 }
421
422
423 } // namespace QSint
424
425