• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.4 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 
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  image->resizeFrame(elementRect.size());
188  image->paintFrame(p);
189  } else {
190  QSize imageSize = image->size();
191  image->resize();
192  QSize tileSize = image->elementSize("bar-active-center");
193 
194  if (elementRect.width() > elementRect.height()) {
195  qreal ratio = tileSize.height() / tileSize.width();
196  int numTiles = elementRect.width()/(elementRect.height()/ratio);
197  tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
198  } else {
199  qreal ratio = tileSize.width() / tileSize.height();
200  int numTiles = elementRect.height()/(elementRect.width()/ratio);
201  tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
202  }
203 
204  image->setElementPrefix(prefix);
205  image->resizeFrame(tileSize);
206  p->drawTiledPixmap(elementRect, image->framePixmap());
207  image->resize(imageSize);
208  }
209  image->setUsingRenderingCache(true);
210  }
211 
212 void MeterPrivate::paintForeground(QPainter *p)
213  {
214  for (int i = 0; i < labels.count(); ++i) {
215  text(p, i);
216  }
217 
218  paint(p, "foreground");
219  }
220 
221 void MeterPrivate::setSizePolicyAndPreferredSize()
222  {
223  switch (meterType) {
224  case Meter::BarMeterHorizontal:
225  meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
226  break;
227  case Meter::BarMeterVertical:
228  meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
229  break;
230  case Meter::AnalogMeter:
231  default:
232  meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
233  break;
234  }
235 
236  if (image) {
237  //set a sane preferredSize. We can't just use the svg's native size, since that way
238  //letters get cut off if the user uses a font larger then usual. Check how many rows of
239  //labels we have, add 1 (the progress bar), and multiply by the font height to get a
240  //somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
241  //we look into alternatives for 4.3.
242  uint i = 0;
243  uint rows = 0;
244  qreal prevY = -1;
245  QString labelName = "label0";
246  while (image->hasElement(labelName)) {
247  if (image->elementRect(labelName).y() > prevY) {
248  prevY = image->elementRect(labelName).y();
249  rows++;
250  }
251  i++;
252  labelName = QString("label%0").arg(i);
253  }
254 
255  Plasma::Theme *theme = Plasma::Theme::defaultTheme();
256  QFont font = theme->font(Plasma::Theme::DefaultFont);
257  QFontMetrics fm(font);
258 
259  meter->setPreferredHeight((rows + 1) * fm.height());
260  } else {
261  meter->setPreferredSize(QSizeF(30, 30));
262  }
263  }
264 
265 Meter::Meter(QGraphicsItem *parent) :
266  QGraphicsWidget(parent),
267  d(new MeterPrivate(this))
268 {
269  d->setSizePolicyAndPreferredSize();
270 
271  d->animation = new QPropertyAnimation(d, "meterValue");
272 }
273 
274 Meter::~Meter()
275 {
276  delete d->animation;
277  delete d;
278 }
279 
280 void Meter::setMaximum(int maximum)
281 {
282  d->maximum = maximum;
283 }
284 
285 int Meter::maximum() const
286 {
287  return d->maximum;
288 }
289 
290 void Meter::setMinimum(int minimum)
291 {
292  d->minimum = minimum;
293 }
294 
295 int Meter::minimum() const
296 {
297  return d->minimum;
298 }
299 
300 int Meter::value() const
301 {
302  return d->value;
303 }
304 
305 void Meter::setValue(int value)
306 {
307  if (value == d->targetValue) {
308  return;
309  }
310 
311  d->targetValue = qBound(d->minimum, value, d->maximum);
312  int delta = abs(d->value - d->targetValue);
313 
314  if (d->animation->state() != QAbstractAnimation::Running) {
315  d->animation->stop();
316  }
317 
318  //kDebug() << d->targetValue << d->value << delta;
319  if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
320  delta / qreal(d->maximum) < 0.1) {
321  d->value = value;
322  update();
323  } else {
324  d->animation->setStartValue(d->value);
325  d->animation->setEndValue(value);
326  d->animation->start();
327  }
328  emit valueChanged(value);
329 }
330 
331 int MeterPrivate::meterValue() const
332 {
333  return value;
334 }
335 
336 void MeterPrivate::setMeterValue(int value)
337 {
338  progressChanged(value);
339 }
340 
341 void Meter::setLabel(int index, const QString &text)
342 {
343  while (d->labels.count() <= index) {
344  d->labels << QString();
345  }
346  d->labels[index] = text;
347 }
348 
349 QString Meter::label(int index) const
350 {
351  return d->labels[index];
352 }
353 
354 void Meter::setLabelColor(int index, const QColor &color)
355 {
356  while (d->colors.count() <= index) {
357  d->colors << color;
358  }
359  d->colors[index] = color;
360 }
361 
362 QColor Meter::labelColor(int index) const
363 {
364  return d->colors[index];
365 }
366 
367 void Meter::setLabelFont(int index, const QFont &font)
368 {
369  while (d->fonts.count() <= index) {
370  d->fonts << font;
371  }
372  d->fonts[index] = font;
373 }
374 
375 QFont Meter::labelFont(int index) const
376 {
377  return d->fonts[index];
378 }
379 
380 void Meter::setLabelAlignment(int index, const Qt::Alignment alignment)
381 {
382  while (d->alignments.count() <= index) {
383  d->alignments << alignment;
384  }
385  d->alignments[index] = alignment;
386 }
387 
388 Qt::Alignment Meter::labelAlignment(int index) const
389 {
390  return d->alignments[index];
391 }
392 
393 QRectF Meter::labelRect(int index) const
394 {
395  QString elementID = QString("label%1").arg(index);
396  return d->image->elementRect(elementID);
397 }
398 
399 void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
400 {
401  Q_UNUSED(sourceName)
402 
403  foreach (const QVariant &v, data) {
404  if (v.type() == QVariant::Int ||
405  v.type() == QVariant::UInt ||
406  v.type() == QVariant::LongLong ||
407  v.type() == QVariant::ULongLong) {
408  setValue(v.toInt());
409  return;
410  }
411  }
412 }
413 
414 void Meter::setSvg(const QString &svg)
415 {
416  if (d->svg == svg) {
417  return;
418  }
419 
420  d->svg = svg;
421  delete d->image;
422  d->image = new Plasma::FrameSvg(this);
423  d->image->setImagePath(svg);
424  // To create renderer and get default size
425  d->image->resize();
426  d->setSizePolicyAndPreferredSize();
427  if (d->image->hasElement("rotateminmax")) {
428  QRectF r = d->image->elementRect("rotateminmax");
429  d->minrotate = (int)r.height();
430  d->maxrotate = (int)r.width();
431  }
432 }
433 
434 QString Meter::svg() const
435 {
436  return d->svg;
437 }
438 
439 void Meter::setMeterType(MeterType meterType)
440 {
441  d->meterType = meterType;
442  if (d->svg.isEmpty()) {
443  if (meterType == BarMeterHorizontal) {
444  setSvg("widgets/bar_meter_horizontal");
445  } else if (meterType == BarMeterVertical) {
446  setSvg("widgets/bar_meter_vertical");
447  } else if (meterType == AnalogMeter) {
448  setSvg("widgets/analog_meter");
449  }
450  }
451  d->setSizePolicyAndPreferredSize();
452 }
453 
454 Meter::MeterType Meter::meterType() const
455 {
456  return d->meterType;
457 }
458 
459 void Meter::paint(QPainter *p,
460  const QStyleOptionGraphicsItem *option,
461  QWidget *widget)
462 {
463  Q_UNUSED(option)
464  Q_UNUSED(widget)
465 
466  if (d->svg.isEmpty()) {
467  setMeterType(d->meterType);
468  }
469 
470  if (!d->image) {
471  return;
472  }
473 
474  QRectF rect(QPointF(0, 0), size());
475  QRectF clipRect;
476  qreal percentage = 0.0;
477  qreal angle = 0.0;
478  QPointF rotateCenter;
479  QSize intSize = QSize((int)size().width(), (int)size().height());
480 
481  if (intSize != d->image->size()) {
482  d->image->resize(intSize);
483  }
484 
485  if (d->maximum != d->minimum) {
486  percentage = (qreal)(d->value - d->minimum) / (d->maximum - d->minimum);
487  }
488 
489  p->setRenderHint(QPainter::SmoothPixmapTransform);
490  switch (d->meterType) {
491  case BarMeterHorizontal:
492  case BarMeterVertical:
493  d->paintBackground(p);
494 
495  p->save();
496  clipRect = d->barRect();
497  if (clipRect.width() > clipRect.height()) {
498  clipRect.setWidth(clipRect.width() * percentage);
499  } else {
500  qreal bottom = clipRect.bottom();
501  clipRect.setHeight(clipRect.height() * percentage);
502  clipRect.moveBottom(bottom);
503  }
504  p->setClipRect(clipRect, Qt::IntersectClip);
505 
506  //be retrocompatible
507  if (d->image->hasElement("bar-active-center")) {
508  d->paintBar(p, "bar-active");
509  } else {
510  d->paint(p, "bar");
511  }
512  p->restore();
513 
514  d->paintForeground(p);
515  break;
516  case AnalogMeter:
517  d->paintBackground(p);
518 
519  p->save();
520  if (d->image->hasElement("rotatecenter")) {
521  QRectF r = d->image->elementRect("rotatecenter");
522  rotateCenter = QPointF(r.left() + r.width() / 2,
523  r.top() + r.height() / 2);
524  } else {
525  rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
526  }
527  angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
528 
529  if (d->image->hasElement("pointer-shadow")) {
530  p->save();
531  p->translate(rotateCenter+QPoint(2,3));
532  p->rotate(angle);
533  p->translate(-1 * rotateCenter);
534  d->paint(p, "pointer-shadow");
535  p->restore();
536  }
537 
538  p->translate(rotateCenter);
539  p->rotate(angle);
540  p->translate(-1 * rotateCenter);
541  d->paint(p, "pointer");
542  p->restore();
543 
544  d->paintForeground(p);
545  break;
546  }
547 }
548 
549 QSizeF Meter::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
550 {
551  return QGraphicsWidget::sizeHint(which, constraint);
552 }
553 
554 } // End of namepace
555 
556 #include "meter.moc"
557 #include "../private/meter_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Tue Jul 17 2012 07:28:49 by doxygen 1.8.1 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.8.4 API Reference

Skip menu "kdelibs-4.8.4 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