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

Plasma

  • sources
  • kde-4.12
  • kdelibs
  • 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 
36 namespace Plasma {
37 
38 MeterPrivate::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 
52 void MeterPrivate::progressChanged(int progress)
53  {
54  value = progress;
55  meter->update();
56  }
57 
58 void 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 
66 void 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 
118 QRectF 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 
158 void 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 
181 void 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 
216 void 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 
225 void 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 
269 Meter::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 
278 Meter::~Meter()
279 {
280  delete d->animation;
281  delete d;
282 }
283 
284 void Meter::setMaximum(int maximum)
285 {
286  d->maximum = maximum;
287 }
288 
289 int Meter::maximum() const
290 {
291  return d->maximum;
292 }
293 
294 void Meter::setMinimum(int minimum)
295 {
296  d->minimum = minimum;
297 }
298 
299 int Meter::minimum() const
300 {
301  return d->minimum;
302 }
303 
304 int Meter::value() const
305 {
306  return d->value;
307 }
308 
309 void 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 
335 int MeterPrivate::meterValue() const
336 {
337  return value;
338 }
339 
340 void MeterPrivate::setMeterValue(int value)
341 {
342  progressChanged(value);
343 }
344 
345 void 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 
353 QString Meter::label(int index) const
354 {
355  return d->labels[index];
356 }
357 
358 void 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 
366 QColor Meter::labelColor(int index) const
367 {
368  return d->colors[index];
369 }
370 
371 void 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 
379 QFont Meter::labelFont(int index) const
380 {
381  return d->fonts[index];
382 }
383 
384 void 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 
392 Qt::Alignment Meter::labelAlignment(int index) const
393 {
394  return d->alignments[index];
395 }
396 
397 QRectF Meter::labelRect(int index) const
398 {
399  QString elementID = QString("label%1").arg(index);
400  return d->image->elementRect(elementID);
401 }
402 
403 void 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 
418 void 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 
438 QString Meter::svg() const
439 {
440  return d->svg;
441 }
442 
443 void 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 
458 Meter::MeterType Meter::meterType() const
459 {
460  return d->meterType;
461 }
462 
463 void 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 
553 QSizeF 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"
Plasma::Meter::meterType
MeterType meterType() const
Plasma::Meter::sizeHint
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint=QSizeF()) const
Definition: meter.cpp:553
Plasma::Meter::paint
virtual void paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *widget=0)
Reimplemented from Plasma::Widget.
Definition: meter.cpp:463
Plasma::Meter::Meter
Meter(QGraphicsItem *parent=0)
Constructor.
Definition: meter.cpp:269
Plasma::Meter::setLabelAlignment
void setLabelAlignment(int index, const Qt::Alignment alignment)
Set text label alignment for the meter.
Definition: meter.cpp:384
Plasma::Meter::setMaximum
void setMaximum(int maximum)
Set maximum value for the meter.
Definition: meter.cpp:284
Plasma::Meter::setSvg
void setSvg(const QString &svg)
Set svg file name.
Definition: meter.cpp:418
Plasma::Meter::labelRect
QRectF labelRect(int index) const
Definition: meter.cpp:397
Plasma::Theme::DefaultFont
The standard text font.
Definition: theme.h:80
QWidget
Plasma::Meter::setMinimum
void setMinimum(int minimum)
Set minimum value for the meter.
Definition: meter.cpp:294
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::TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
meter.h
theme.h
Plasma::FrameSvg
Provides an SVG with borders.
Definition: framesvg.h:76
Plasma::DataEngine::Data
QHash< QString, QVariant > Data
Definition: dataengine.h:68
QObject
Plasma::Meter::setMeterType
void setMeterType(MeterType type)
Set meter type.
Definition: meter.cpp:443
Plasma::Meter::label
QString label(int index) const
Definition: meter.cpp:353
Plasma::Meter::setValue
void setValue(int value)
Set value for the meter.
Definition: meter.cpp:309
Plasma::Meter::~Meter
~Meter()
Destructor.
Definition: meter.cpp:278
Plasma::Meter::labelAlignment
Qt::Alignment labelAlignment(int index) const
Definition: meter.cpp:392
Plasma::Meter::maximum
int maximum() const
Plasma::Meter::labelFont
QFont labelFont(int index) const
Definition: meter.cpp:379
Plasma::Meter::setLabel
void setLabel(int index, const QString &text)
Set text label for the meter.
Definition: meter.cpp:345
Plasma::Meter::setLabelColor
void setLabelColor(int index, const QColor &color)
Set text label color for the meter.
Definition: meter.cpp:358
Plasma::Meter::BarMeterVertical
Vertical bar meter (like thermometer).
Definition: meter.h:72
Plasma::Theme
Interface to the Plasma theme.
Definition: theme.h:56
Plasma::Meter::labelColor
QColor labelColor(int index) const
Definition: meter.cpp:366
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
framesvg.h
Plasma::Meter::valueChanged
void valueChanged(const int &value)
This signal is sent when the value of the meter changes programmatically.
Plasma::Meter::BarMeterHorizontal
Horizontal bar meter (like thermometer).
Definition: meter.h:70
Plasma::Meter::AnalogMeter
Analog meter (like tachometer).
Definition: meter.h:74
Plasma::Meter::value
int value() const
Plasma::Meter::setLabelFont
void setLabelFont(int index, const QFont &font)
Set text label font for the meter.
Definition: meter.cpp:371
animator.h
Plasma::Meter::dataUpdated
void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
Used when connecting to a DataEngine.
Definition: meter.cpp:403
Plasma::Meter::svg
QString svg() const
QStyleOptionGraphicsItem
Plasma::Meter::minimum
int minimum() const
QGraphicsWidget
Plasma::Meter::MeterType
MeterType
Meter types enum.
Definition: meter.h:68
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:33 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



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