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

Plasma

meter.cpp
Go to the documentation of this file.
00001 /*
00002  *   Copyright (C) 2007 Petri Damsten <damu@iki.fi>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "meter.h"
00021 #include "private/meter_p.h"
00022 
00023 #include <cmath>
00024 
00025 #include <QPainter>
00026 #include <QTimeLine>
00027 #include <QPropertyAnimation>
00028 
00029 #include <kdebug.h>
00030 #include <kglobalsettings.h>
00031 
00032 #include "plasma/animator.h"
00033 #include "plasma/framesvg.h"
00034 #include "plasma/theme.h"
00035 
00036 namespace Plasma {
00037 
00038 MeterPrivate::MeterPrivate(Meter *m)
00039         : QObject(m),
00040           minimum(0),
00041           maximum(100),
00042           value(0),
00043           targetValue(0),
00044           meterType(Meter::AnalogMeter),
00045           image(0),
00046           minrotate(0),
00047           maxrotate(360),
00048           meter(m)
00049 {
00050 }
00051 
00052 void MeterPrivate::progressChanged(int progress)
00053     {
00054         value = progress;
00055         meter->update();
00056     }
00057 
00058 void MeterPrivate::paint(QPainter *p, const QString &elementID)
00059     {
00060         if (image->hasElement(elementID)) {
00061             QRectF elementRect = image->elementRect(elementID);
00062             image->paint(p, elementRect, elementID);
00063         }
00064     }
00065 
00066 void MeterPrivate::text(QPainter *p, int index)
00067     {
00068         QString elementID = QString("label%1").arg(index);
00069         QString text = labels[index];
00070 
00071         if (image->hasElement(elementID)) {
00072             QRectF elementRect = image->elementRect(elementID);
00073             Qt::Alignment align = Qt::AlignCenter;
00074 
00075 
00076             if (colors.count() > index) {
00077                 p->setPen(QPen(colors[index]));
00078             } else {
00079                 p->setPen(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
00080             }
00081             if (fonts.count() > index) {
00082                 p->setFont(fonts[index]);
00083             }
00084 
00085             QFontMetricsF fm(p->font());
00086             // If the height is too small increase the Height of the button to shall the whole text #192988
00087             if (elementRect.height() < fm.height()) {
00088                 QPointF oldCenter = elementRect.center();
00089                 elementRect.setHeight(fm.height());
00090                 elementRect.moveCenter(oldCenter);
00091             }
00092 
00093             if (alignments.count() > index) {
00094                 align = alignments[index];
00095             }
00096             if (elementRect.width() > elementRect.height()) {
00097                 if (align&Qt::AlignLeft) {
00098                     p->drawText(elementRect.bottomLeft(), text);
00099                 } else {
00100                     p->drawText(elementRect, align, text);
00101                 }
00102             } else {
00103                 p->save();
00104                 QPointF rotateCenter(
00105                         elementRect.left() + elementRect.width() / 2,
00106                         elementRect.top() + elementRect.height() / 2);
00107                 p->translate(rotateCenter);
00108                 p->rotate(-90);
00109                 p->translate(elementRect.height() / -2,
00110                              elementRect.width() / -2);
00111                 QRectF r(0, 0, elementRect.height(), elementRect.width());
00112                 p->drawText(r, align, text);
00113                 p->restore();
00114             }
00115         }
00116     }
00117 
00118 QRectF MeterPrivate::barRect()
00119     {
00120         QRectF elementRect;
00121 
00122         if (labels.count() > 0) {
00123             elementRect = image->elementRect("background");
00124         } else {
00125             elementRect = QRectF(QPoint(0,0), meter->size());
00126         }
00127 
00128         if (image->hasElement("hint-bar-stretch") || !image->hasElement("bar-active-center")) {
00129             return elementRect;
00130         }
00131 
00132         QSize imageSize = image->size();
00133         image->resize();
00134         QSize tileSize = image->elementSize("bar-active-center");
00135         image->resize(imageSize);
00136 
00137         if (elementRect.width() > elementRect.height()) {
00138             qreal ratio = qMax(1, tileSize.height() / tileSize.width());
00139             int numTiles = qMax(qreal(1.0), qreal(elementRect.width())/(qreal(elementRect.height())/ratio));
00140             tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
00141 
00142             QPoint center = elementRect.center().toPoint();
00143             elementRect.setWidth(tileSize.width()*numTiles);
00144             elementRect.moveCenter(center);
00145         } else {
00146             qreal ratio = qMax(1, tileSize.width() / tileSize.height());
00147             int numTiles = qMax(qreal(1.0), qreal(elementRect.height())/(qreal(elementRect.width())/ratio));
00148             tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
00149 
00150             QPoint center = elementRect.center().toPoint();
00151             elementRect.setHeight(tileSize.height()*numTiles);
00152             elementRect.moveCenter(center);
00153         }
00154 
00155         return elementRect;
00156     }
00157 
00158 void MeterPrivate::paintBackground(QPainter *p)
00159     {
00160         //be retrocompatible with themes for kde <= 4.1
00161         if (image->hasElement("background-center")) {
00162             QRectF elementRect = barRect();
00163             if (elementRect.isEmpty()) {
00164                 return; // nothing to be done
00165             }
00166 
00167             QSize imageSize = image->size();
00168             image->resize();
00169 
00170             image->setElementPrefix("background");
00171             image->resizeFrame(elementRect.size());
00172             image->paintFrame(p, elementRect.topLeft());
00173             image->resize(imageSize);
00174 
00175             paintBar(p, "bar-inactive");
00176         } else {
00177             paint(p, "background");
00178         }
00179     }
00180 
00181 void MeterPrivate::paintBar(QPainter *p, const QString &prefix)
00182     {
00183         QRectF elementRect = barRect();
00184 
00185         image->setUsingRenderingCache(false);
00186         if (image->hasElement("hint-bar-stretch")) {
00187             const QSize imageSize = image->size();
00188             image->resize();
00189             image->setElementPrefix(prefix);
00190             image->resizeFrame(elementRect.size());
00191             image->paintFrame(p, elementRect.topLeft());
00192             image->resize(imageSize);
00193         } else {
00194             const QSize imageSize = image->size();
00195             image->resize();
00196             QSize tileSize = image->elementSize("bar-active-center");
00197 
00198             if (elementRect.width() > elementRect.height()) {
00199                 qreal ratio = tileSize.height() / tileSize.width();
00200                 int numTiles = elementRect.width()/(elementRect.height()/ratio);
00201                 tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
00202             } else {
00203                 qreal ratio = tileSize.width() / tileSize.height();
00204                 int numTiles = elementRect.height()/(elementRect.width()/ratio);
00205                 tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
00206             }
00207 
00208             image->setElementPrefix(prefix);
00209             image->resizeFrame(tileSize);
00210             p->drawTiledPixmap(elementRect, image->framePixmap());
00211             image->resize(imageSize);
00212         }
00213         image->setUsingRenderingCache(true);
00214     }
00215 
00216 void MeterPrivate::paintForeground(QPainter *p)
00217     {
00218         for (int i = 0; i < labels.count(); ++i) {
00219             text(p, i);
00220         }
00221 
00222         paint(p, "foreground");
00223     }
00224 
00225 void MeterPrivate::setSizePolicyAndPreferredSize()
00226     {
00227         switch (meterType) {
00228             case Meter::BarMeterHorizontal:
00229                 meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
00230                 break;
00231             case Meter::BarMeterVertical:
00232                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
00233                 break;
00234             case Meter::AnalogMeter:
00235             default:
00236                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00237                 break;
00238         }
00239 
00240         if (image) {
00241             //set a sane preferredSize. We can't just use the svg's native size, since that way
00242             //letters get cut off if the user uses a font larger then usual. Check how many rows of
00243             //labels we have, add 1 (the progress bar), and multiply by the font height to get a
00244             //somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
00245             //we look into alternatives for 4.3.
00246             uint i = 0;
00247             uint rows = 0;
00248             qreal prevY = -1;
00249             QString labelName = "label0";
00250             while (image->hasElement(labelName)) {
00251                 if (image->elementRect(labelName).y() > prevY) {
00252                     prevY = image->elementRect(labelName).y();
00253                     rows++;
00254                 }
00255                 i++;
00256                 labelName = QString("label%0").arg(i);
00257             }
00258 
00259             Plasma::Theme *theme = Plasma::Theme::defaultTheme();
00260             QFont font = theme->font(Plasma::Theme::DefaultFont);
00261             QFontMetrics fm(font);
00262 
00263             meter->setPreferredHeight((rows + 1) * fm.height());
00264         } else {
00265             meter->setPreferredSize(QSizeF(30, 30));
00266         }
00267     }
00268 
00269 Meter::Meter(QGraphicsItem *parent) :
00270         QGraphicsWidget(parent),
00271         d(new MeterPrivate(this))
00272 {
00273     d->setSizePolicyAndPreferredSize();
00274 
00275     d->animation = new QPropertyAnimation(d, "meterValue");
00276 }
00277 
00278 Meter::~Meter()
00279 {
00280     delete d->animation;
00281     delete d;
00282 }
00283 
00284 void Meter::setMaximum(int maximum)
00285 {
00286     d->maximum = maximum;
00287 }
00288 
00289 int Meter::maximum() const
00290 {
00291     return d->maximum;
00292 }
00293 
00294 void Meter::setMinimum(int minimum)
00295 {
00296     d->minimum = minimum;
00297 }
00298 
00299 int Meter::minimum() const
00300 {
00301     return d->minimum;
00302 }
00303 
00304 int Meter::value() const
00305 {
00306     return d->value;
00307 }
00308 
00309 void Meter::setValue(int value)
00310 {
00311     if (value == d->targetValue) {
00312         return;
00313     }
00314 
00315     d->targetValue = qBound(d->minimum, value, d->maximum);
00316     int delta = abs(d->value - d->targetValue);
00317 
00318     if (d->animation->state() != QAbstractAnimation::Running) {
00319         d->animation->stop();
00320     }
00321 
00322     //kDebug() << d->targetValue << d->value << delta;
00323     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
00324         delta / qreal(d->maximum) < 0.1) {
00325         d->value = value;
00326         update();
00327     } else  {
00328         d->animation->setStartValue(d->value);
00329         d->animation->setEndValue(value);
00330         d->animation->start();
00331     }
00332     emit valueChanged(value);
00333 }
00334 
00335 int MeterPrivate::meterValue() const
00336 {
00337     return value;
00338 }
00339 
00340 void MeterPrivate::setMeterValue(int value)
00341 {
00342     progressChanged(value);
00343 }
00344 
00345 void Meter::setLabel(int index, const QString &text)
00346 {
00347     while (d->labels.count() <= index) {
00348         d->labels << QString();
00349     }
00350     d->labels[index] = text;
00351 }
00352 
00353 QString Meter::label(int index) const
00354 {
00355     return d->labels[index];
00356 }
00357 
00358 void Meter::setLabelColor(int index, const QColor &color)
00359 {
00360     while (d->colors.count() <= index) {
00361         d->colors << color;
00362     }
00363     d->colors[index] = color;
00364 }
00365 
00366 QColor Meter::labelColor(int index) const
00367 {
00368     return d->colors[index];
00369 }
00370 
00371 void Meter::setLabelFont(int index, const QFont &font)
00372 {
00373     while (d->fonts.count() <= index) {
00374         d->fonts << font;
00375     }
00376     d->fonts[index] = font;
00377 }
00378 
00379 QFont Meter::labelFont(int index) const
00380 {
00381     return d->fonts[index];
00382 }
00383 
00384 void Meter::setLabelAlignment(int index, const Qt::Alignment alignment)
00385 {
00386     while (d->alignments.count() <= index) {
00387         d->alignments << alignment;
00388     }
00389     d->alignments[index] = alignment;
00390 }
00391 
00392 Qt::Alignment Meter::labelAlignment(int index) const
00393 {
00394     return d->alignments[index];
00395 }
00396 
00397 QRectF Meter::labelRect(int index) const
00398 {
00399     QString elementID = QString("label%1").arg(index);
00400     return d->image->elementRect(elementID);
00401 }
00402 
00403 void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
00404 {
00405     Q_UNUSED(sourceName)
00406 
00407     foreach (const QVariant &v, data) {
00408         if (v.type() == QVariant::Int ||
00409             v.type() == QVariant::UInt ||
00410             v.type() == QVariant::LongLong ||
00411             v.type() == QVariant::ULongLong) {
00412             setValue(v.toInt());
00413             return;
00414         }
00415     }
00416 }
00417 
00418 void Meter::setSvg(const QString &svg)
00419 {
00420     if (d->svg == svg) {
00421         return;
00422     }
00423 
00424     d->svg = svg;
00425     delete d->image;
00426     d->image = new Plasma::FrameSvg(this);
00427     d->image->setImagePath(svg);
00428     // To create renderer and get default size
00429     d->image->resize();
00430     d->setSizePolicyAndPreferredSize();
00431     if (d->image->hasElement("rotateminmax")) {
00432         QRectF r = d->image->elementRect("rotateminmax");
00433         d->minrotate = (int)r.height();
00434         d->maxrotate = (int)r.width();
00435     }
00436 }
00437 
00438 QString Meter::svg() const
00439 {
00440     return d->svg;
00441 }
00442 
00443 void Meter::setMeterType(MeterType meterType)
00444 {
00445     d->meterType = meterType;
00446     if (d->svg.isEmpty()) {
00447         if (meterType == BarMeterHorizontal) {
00448             setSvg("widgets/bar_meter_horizontal");
00449         } else if (meterType == BarMeterVertical) {
00450             setSvg("widgets/bar_meter_vertical");
00451         } else if (meterType == AnalogMeter) {
00452             setSvg("widgets/analog_meter");
00453         }
00454     }
00455     d->setSizePolicyAndPreferredSize();
00456 }
00457 
00458 Meter::MeterType Meter::meterType() const
00459 {
00460     return d->meterType;
00461 }
00462 
00463 void Meter::paint(QPainter *p,
00464                   const QStyleOptionGraphicsItem *option,
00465                   QWidget *widget)
00466 {
00467     Q_UNUSED(option)
00468     Q_UNUSED(widget)
00469 
00470     if (d->svg.isEmpty()) {
00471         setMeterType(d->meterType);
00472     }
00473 
00474     if (!d->image) {
00475         return;
00476     }
00477 
00478     QRectF rect(QPointF(0, 0), size());
00479     QRectF clipRect;
00480     qreal percentage = 0.0;
00481     qreal angle = 0.0;
00482     QPointF rotateCenter;
00483     QSize intSize = QSize((int)size().width(), (int)size().height());
00484 
00485     if (intSize != d->image->size()) {
00486         d->image->resize(intSize);
00487     }
00488 
00489     if (d->maximum != d->minimum) {
00490         percentage = (qreal)(d->value - d->minimum) / (d->maximum - d->minimum);
00491     }
00492 
00493     p->setRenderHint(QPainter::SmoothPixmapTransform);
00494     switch (d->meterType) {
00495     case BarMeterHorizontal:
00496     case BarMeterVertical:
00497         d->paintBackground(p);
00498 
00499         p->save();
00500         clipRect = d->barRect();
00501         if (clipRect.width() > clipRect.height()) {
00502             clipRect.setWidth(clipRect.width() * percentage);
00503         } else {
00504             qreal bottom = clipRect.bottom();
00505             clipRect.setHeight(clipRect.height() * percentage);
00506             clipRect.moveBottom(bottom);
00507         }
00508         p->setClipRect(clipRect, Qt::IntersectClip);
00509 
00510         //be retrocompatible
00511         if (d->image->hasElement("bar-active-center")) {
00512             d->paintBar(p, "bar-active");
00513         } else {
00514             d->paint(p, "bar");
00515         }
00516         p->restore();
00517 
00518         d->paintForeground(p);
00519         break;
00520     case AnalogMeter:
00521         d->paintBackground(p);
00522 
00523         p->save();
00524         if (d->image->hasElement("rotatecenter")) {
00525             QRectF r = d->image->elementRect("rotatecenter");
00526             rotateCenter = QPointF(r.left() + r.width() / 2,
00527                                    r.top() + r.height() / 2);
00528         } else {
00529             rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
00530         }
00531         angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
00532 
00533         if (d->image->hasElement("pointer-shadow")) {
00534             p->save();
00535             p->translate(rotateCenter+QPoint(2,3));
00536             p->rotate(angle);
00537             p->translate(-1 * rotateCenter);
00538             d->paint(p, "pointer-shadow");
00539             p->restore();
00540         }
00541 
00542         p->translate(rotateCenter);
00543         p->rotate(angle);
00544         p->translate(-1 * rotateCenter);
00545         d->paint(p, "pointer");
00546         p->restore();
00547 
00548         d->paintForeground(p);
00549         break;
00550     }
00551 }
00552 
00553 QSizeF Meter::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
00554 {
00555     return QGraphicsWidget::sizeHint(which, constraint);
00556 }
00557 
00558 } // End of namepace
00559 
00560 #include "meter.moc"
00561 #include "../private/meter_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:30:44 by doxygen 1.7.5.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.9.5 API Reference

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