• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • plasma
  • widgets
meter.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007 Petri Damsten <damu@iki.fi>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "meter.h"
21#include "private/meter_p.h"
22
23#include <cmath>
24
25#include <QPainter>
26#include <QTimeLine>
27#include <QPropertyAnimation>
28
29#include <kdebug.h>
30#include <kglobalsettings.h>
31
32#include "plasma/animator.h"
33#include "plasma/framesvg.h"
34#include "plasma/theme.h"
35
36namespace Plasma {
37
38MeterPrivate::MeterPrivate(Meter *m)
39 : QObject(m),
40 minimum(0),
41 maximum(100),
42 value(0),
43 targetValue(0),
44 meterType(Meter::AnalogMeter),
45 image(0),
46 minrotate(0),
47 maxrotate(360),
48 meter(m)
49{
50}
51
52void MeterPrivate::progressChanged(int progress)
53 {
54 value = progress;
55 meter->update();
56 }
57
58void MeterPrivate::paint(QPainter *p, const QString &elementID)
59 {
60 if (image->hasElement(elementID)) {
61 QRectF elementRect = image->elementRect(elementID);
62 image->paint(p, elementRect, elementID);
63 }
64 }
65
66void MeterPrivate::text(QPainter *p, int index)
67 {
68 QString elementID = QString("label%1").arg(index);
69 QString text = labels[index];
70
71 if (image->hasElement(elementID)) {
72 QRectF elementRect = image->elementRect(elementID);
73 Qt::Alignment align = Qt::AlignCenter;
74
75
76 if (colors.count() > index) {
77 p->setPen(QPen(colors[index]));
78 } else {
79 p->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
80 }
81 if (fonts.count() > index) {
82 p->setFont(fonts[index]);
83 }
84
85 QFontMetricsF fm(p->font());
86 // If the height is too small increase the Height of the button to shall the whole text #192988
87 if (elementRect.height() < fm.height()) {
88 QPointF oldCenter = elementRect.center();
89 elementRect.setHeight(fm.height());
90 elementRect.moveCenter(oldCenter);
91 }
92
93 if (alignments.count() > index) {
94 align = alignments[index];
95 }
96 if (elementRect.width() > elementRect.height()) {
97 if (align&Qt::AlignLeft) {
98 p->drawText(elementRect.bottomLeft(), text);
99 } else {
100 p->drawText(elementRect, align, text);
101 }
102 } else {
103 p->save();
104 QPointF rotateCenter(
105 elementRect.left() + elementRect.width() / 2,
106 elementRect.top() + elementRect.height() / 2);
107 p->translate(rotateCenter);
108 p->rotate(-90);
109 p->translate(elementRect.height() / -2,
110 elementRect.width() / -2);
111 QRectF r(0, 0, elementRect.height(), elementRect.width());
112 p->drawText(r, align, text);
113 p->restore();
114 }
115 }
116 }
117
118QRectF MeterPrivate::barRect()
119 {
120 QRectF elementRect;
121
122 if (labels.count() > 0) {
123 elementRect = image->elementRect("background");
124 } else {
125 elementRect = QRectF(QPoint(0,0), meter->size());
126 }
127
128 if (image->hasElement("hint-bar-stretch") || !image->hasElement("bar-active-center")) {
129 return elementRect;
130 }
131
132 QSize imageSize = image->size();
133 image->resize();
134 QSize tileSize = image->elementSize("bar-active-center");
135 image->resize(imageSize);
136
137 if (elementRect.width() > elementRect.height()) {
138 qreal ratio = qMax(1, tileSize.height() / tileSize.width());
139 int numTiles = qMax(qreal(1.0), qreal(elementRect.width())/(qreal(elementRect.height())/ratio));
140 tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
141
142 QPoint center = elementRect.center().toPoint();
143 elementRect.setWidth(tileSize.width()*numTiles);
144 elementRect.moveCenter(center);
145 } else {
146 qreal ratio = qMax(1, tileSize.width() / tileSize.height());
147 int numTiles = qMax(qreal(1.0), qreal(elementRect.height())/(qreal(elementRect.width())/ratio));
148 tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
149
150 QPoint center = elementRect.center().toPoint();
151 elementRect.setHeight(tileSize.height()*numTiles);
152 elementRect.moveCenter(center);
153 }
154
155 return elementRect;
156 }
157
158void MeterPrivate::paintBackground(QPainter *p)
159 {
160 //be retrocompatible with themes for kde <= 4.1
161 if (image->hasElement("background-center")) {
162 QRectF elementRect = barRect();
163 if (elementRect.isEmpty()) {
164 return; // nothing to be done
165 }
166
167 QSize imageSize = image->size();
168 image->resize();
169
170 image->setElementPrefix("background");
171 image->resizeFrame(elementRect.size());
172 image->paintFrame(p, elementRect.topLeft());
173 image->resize(imageSize);
174
175 paintBar(p, "bar-inactive");
176 } else {
177 paint(p, "background");
178 }
179 }
180
181void MeterPrivate::paintBar(QPainter *p, const QString &prefix)
182 {
183 QRectF elementRect = barRect();
184
185 image->setUsingRenderingCache(false);
186 if (image->hasElement("hint-bar-stretch")) {
187 const QSize imageSize = image->size();
188 image->resize();
189 image->setElementPrefix(prefix);
190 image->resizeFrame(elementRect.size());
191 image->paintFrame(p, elementRect.topLeft());
192 image->resize(imageSize);
193 } else {
194 const QSize imageSize = image->size();
195 image->resize();
196 QSize tileSize = image->elementSize("bar-active-center");
197
198 if (elementRect.width() > elementRect.height()) {
199 qreal ratio = tileSize.height() / tileSize.width();
200 int numTiles = elementRect.width()/(elementRect.height()/ratio);
201 tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
202 } else {
203 qreal ratio = tileSize.width() / tileSize.height();
204 int numTiles = elementRect.height()/(elementRect.width()/ratio);
205 tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
206 }
207
208 image->setElementPrefix(prefix);
209 image->resizeFrame(tileSize);
210 p->drawTiledPixmap(elementRect, image->framePixmap());
211 image->resize(imageSize);
212 }
213 image->setUsingRenderingCache(true);
214 }
215
216void MeterPrivate::paintForeground(QPainter *p)
217 {
218 for (int i = 0; i < labels.count(); ++i) {
219 text(p, i);
220 }
221
222 paint(p, "foreground");
223 }
224
225void MeterPrivate::setSizePolicyAndPreferredSize()
226 {
227 switch (meterType) {
228 case Meter::BarMeterHorizontal:
229 meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
230 break;
231 case Meter::BarMeterVertical:
232 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
233 break;
234 case Meter::AnalogMeter:
235 default:
236 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
237 break;
238 }
239
240 if (image) {
241 //set a sane preferredSize. We can't just use the svg's native size, since that way
242 //letters get cut off if the user uses a font larger then usual. Check how many rows of
243 //labels we have, add 1 (the progress bar), and multiply by the font height to get a
244 //somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
245 //we look into alternatives for 4.3.
246 uint i = 0;
247 uint rows = 0;
248 qreal prevY = -1;
249 QString labelName = "label0";
250 while (image->hasElement(labelName)) {
251 if (image->elementRect(labelName).y() > prevY) {
252 prevY = image->elementRect(labelName).y();
253 rows++;
254 }
255 i++;
256 labelName = QString("label%0").arg(i);
257 }
258
259 Plasma::Theme *theme = Plasma::Theme::defaultTheme();
260 QFont font = theme->font(Plasma::Theme::DefaultFont);
261 QFontMetrics fm(font);
262
263 meter->setPreferredHeight((rows + 1) * fm.height());
264 } else {
265 meter->setPreferredSize(QSizeF(30, 30));
266 }
267 }
268
269Meter::Meter(QGraphicsItem *parent) :
270 QGraphicsWidget(parent),
271 d(new MeterPrivate(this))
272{
273 d->setSizePolicyAndPreferredSize();
274
275 d->animation = new QPropertyAnimation(d, "meterValue");
276}
277
278Meter::~Meter()
279{
280 delete d->animation;
281 delete d;
282}
283
284void Meter::setMaximum(int maximum)
285{
286 d->maximum = maximum;
287}
288
289int Meter::maximum() const
290{
291 return d->maximum;
292}
293
294void Meter::setMinimum(int minimum)
295{
296 d->minimum = minimum;
297}
298
299int Meter::minimum() const
300{
301 return d->minimum;
302}
303
304int Meter::value() const
305{
306 return d->value;
307}
308
309void Meter::setValue(int value)
310{
311 if (value == d->targetValue) {
312 return;
313 }
314
315 d->targetValue = qBound(d->minimum, value, d->maximum);
316 int delta = abs(d->value - d->targetValue);
317
318 if (d->animation->state() != QAbstractAnimation::Running) {
319 d->animation->stop();
320 }
321
322 //kDebug() << d->targetValue << d->value << delta;
323 if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
324 delta / qreal(d->maximum) < 0.1) {
325 d->value = value;
326 update();
327 } else {
328 d->animation->setStartValue(d->value);
329 d->animation->setEndValue(value);
330 d->animation->start();
331 }
332 emit valueChanged(value);
333}
334
335int MeterPrivate::meterValue() const
336{
337 return value;
338}
339
340void MeterPrivate::setMeterValue(int value)
341{
342 progressChanged(value);
343}
344
345void Meter::setLabel(int index, const QString &text)
346{
347 while (d->labels.count() <= index) {
348 d->labels << QString();
349 }
350 d->labels[index] = text;
351}
352
353QString Meter::label(int index) const
354{
355 return d->labels[index];
356}
357
358void Meter::setLabelColor(int index, const QColor &color)
359{
360 while (d->colors.count() <= index) {
361 d->colors << color;
362 }
363 d->colors[index] = color;
364}
365
366QColor Meter::labelColor(int index) const
367{
368 return d->colors[index];
369}
370
371void Meter::setLabelFont(int index, const QFont &font)
372{
373 while (d->fonts.count() <= index) {
374 d->fonts << font;
375 }
376 d->fonts[index] = font;
377}
378
379QFont Meter::labelFont(int index) const
380{
381 return d->fonts[index];
382}
383
384void Meter::setLabelAlignment(int index, const Qt::Alignment alignment)
385{
386 while (d->alignments.count() <= index) {
387 d->alignments << alignment;
388 }
389 d->alignments[index] = alignment;
390}
391
392Qt::Alignment Meter::labelAlignment(int index) const
393{
394 return d->alignments[index];
395}
396
397QRectF Meter::labelRect(int index) const
398{
399 QString elementID = QString("label%1").arg(index);
400 return d->image->elementRect(elementID);
401}
402
403void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
404{
405 Q_UNUSED(sourceName)
406
407 foreach (const QVariant &v, data) {
408 if (v.type() == QVariant::Int ||
409 v.type() == QVariant::UInt ||
410 v.type() == QVariant::LongLong ||
411 v.type() == QVariant::ULongLong) {
412 setValue(v.toInt());
413 return;
414 }
415 }
416}
417
418void Meter::setSvg(const QString &svg)
419{
420 if (d->svg == svg) {
421 return;
422 }
423
424 d->svg = svg;
425 delete d->image;
426 d->image = new Plasma::FrameSvg(this);
427 d->image->setImagePath(svg);
428 // To create renderer and get default size
429 d->image->resize();
430 d->setSizePolicyAndPreferredSize();
431 if (d->image->hasElement("rotateminmax")) {
432 QRectF r = d->image->elementRect("rotateminmax");
433 d->minrotate = (int)r.height();
434 d->maxrotate = (int)r.width();
435 }
436}
437
438QString Meter::svg() const
439{
440 return d->svg;
441}
442
443void Meter::setMeterType(MeterType meterType)
444{
445 d->meterType = meterType;
446 if (d->svg.isEmpty()) {
447 if (meterType == BarMeterHorizontal) {
448 setSvg("widgets/bar_meter_horizontal");
449 } else if (meterType == BarMeterVertical) {
450 setSvg("widgets/bar_meter_vertical");
451 } else if (meterType == AnalogMeter) {
452 setSvg("widgets/analog_meter");
453 }
454 }
455 d->setSizePolicyAndPreferredSize();
456}
457
458Meter::MeterType Meter::meterType() const
459{
460 return d->meterType;
461}
462
463void Meter::paint(QPainter *p,
464 const QStyleOptionGraphicsItem *option,
465 QWidget *widget)
466{
467 Q_UNUSED(option)
468 Q_UNUSED(widget)
469
470 if (d->svg.isEmpty()) {
471 setMeterType(d->meterType);
472 }
473
474 if (!d->image) {
475 return;
476 }
477
478 QRectF rect(QPointF(0, 0), size());
479 QRectF clipRect;
480 qreal percentage = 0.0;
481 qreal angle = 0.0;
482 QPointF rotateCenter;
483 QSize intSize = QSize((int)size().width(), (int)size().height());
484
485 if (intSize != d->image->size()) {
486 d->image->resize(intSize);
487 }
488
489 if (d->maximum != d->minimum) {
490 percentage = (qreal)(d->value - d->minimum) / (d->maximum - d->minimum);
491 }
492
493 p->setRenderHint(QPainter::SmoothPixmapTransform);
494 switch (d->meterType) {
495 case BarMeterHorizontal:
496 case BarMeterVertical:
497 d->paintBackground(p);
498
499 p->save();
500 clipRect = d->barRect();
501 if (clipRect.width() > clipRect.height()) {
502 clipRect.setWidth(clipRect.width() * percentage);
503 } else {
504 qreal bottom = clipRect.bottom();
505 clipRect.setHeight(clipRect.height() * percentage);
506 clipRect.moveBottom(bottom);
507 }
508 p->setClipRect(clipRect, Qt::IntersectClip);
509
510 //be retrocompatible
511 if (d->image->hasElement("bar-active-center")) {
512 d->paintBar(p, "bar-active");
513 } else {
514 d->paint(p, "bar");
515 }
516 p->restore();
517
518 d->paintForeground(p);
519 break;
520 case AnalogMeter:
521 d->paintBackground(p);
522
523 p->save();
524 if (d->image->hasElement("rotatecenter")) {
525 QRectF r = d->image->elementRect("rotatecenter");
526 rotateCenter = QPointF(r.left() + r.width() / 2,
527 r.top() + r.height() / 2);
528 } else {
529 rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
530 }
531 angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
532
533 if (d->image->hasElement("pointer-shadow")) {
534 p->save();
535 p->translate(rotateCenter+QPoint(2,3));
536 p->rotate(angle);
537 p->translate(-1 * rotateCenter);
538 d->paint(p, "pointer-shadow");
539 p->restore();
540 }
541
542 p->translate(rotateCenter);
543 p->rotate(angle);
544 p->translate(-1 * rotateCenter);
545 d->paint(p, "pointer");
546 p->restore();
547
548 d->paintForeground(p);
549 break;
550 }
551}
552
553QSizeF Meter::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
554{
555 return QGraphicsWidget::sizeHint(which, constraint);
556}
557
558} // End of namepace
559
560#include "meter.moc"
561#include "../private/meter_p.moc"
animator.h
Plasma::DataEngine::Data
QHash< QString, QVariant > Data
Definition: dataengine.h:68
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:77
Plasma::Meter::setValue
void setValue(int value)
Set value for the meter.
Definition: meter.cpp:309
Plasma::Meter::value
int value
Definition: meter.h:60
Plasma::Meter::svg
QString svg
Definition: meter.h:61
Plasma::Meter::meterType
MeterType meterType
Definition: meter.h:62
Plasma::Meter::setSvg
void setSvg(const QString &svg)
Set svg file name.
Definition: meter.cpp:418
Plasma::Meter::valueChanged
void valueChanged(const int &value)
This signal is sent when the value of the meter changes programmatically.
Plasma::Meter::MeterType
MeterType
Meter types enum.
Definition: meter.h:68
Plasma::Meter::BarMeterHorizontal
@ BarMeterHorizontal
Horizontal bar meter (like thermometer).
Definition: meter.h:70
Plasma::Meter::BarMeterVertical
@ BarMeterVertical
Vertical bar meter (like thermometer).
Definition: meter.h:72
Plasma::Meter::AnalogMeter
@ AnalogMeter
Analog meter (like tachometer).
Definition: meter.h:74
Plasma::Meter::maximum
int maximum
Definition: meter.h:59
Plasma::Meter::minimum
int minimum
Definition: meter.h:58
Plasma::Meter::setMeterType
void setMeterType(MeterType type)
Set meter type.
Definition: meter.cpp:443
Plasma::Theme
Interface to the Plasma theme.
Definition: theme.h:57
Plasma::Theme::font
Q_INVOKABLE QFont font(FontRole role) const
Returns the font to be used by themed items.
Definition: theme.cpp:970
Plasma::Theme::DefaultFont
@ DefaultFont
The standard text font.
Definition: theme.h:80
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::Theme::TextColor
@ TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
QGraphicsWidget
QObject
QStyleOptionGraphicsItem
QWidget
framesvg.h
meter.h
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:25
theme.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal