• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • 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             image->resizeFrame(elementRect.size());
00188             image->paintFrame(p);
00189         } else {
00190             QSize imageSize = image->size();
00191             image->resize();
00192             QSize tileSize = image->elementSize("bar-active-center");
00193 
00194             if (elementRect.width() > elementRect.height()) {
00195                 qreal ratio = tileSize.height() / tileSize.width();
00196                 int numTiles = elementRect.width()/(elementRect.height()/ratio);
00197                 tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
00198             } else {
00199                 qreal ratio = tileSize.width() / tileSize.height();
00200                 int numTiles = elementRect.height()/(elementRect.width()/ratio);
00201                 tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
00202             }
00203 
00204             image->setElementPrefix(prefix);
00205             image->resizeFrame(tileSize);
00206             p->drawTiledPixmap(elementRect, image->framePixmap());
00207             image->resize(imageSize);
00208         }
00209         image->setUsingRenderingCache(true);
00210     }
00211 
00212 void MeterPrivate::paintForeground(QPainter *p)
00213     {
00214         for (int i = 0; i < labels.count(); ++i) {
00215             text(p, i);
00216         }
00217 
00218         paint(p, "foreground");
00219     }
00220 
00221 void MeterPrivate::setSizePolicyAndPreferredSize()
00222     {
00223         switch (meterType) {
00224             case Meter::BarMeterHorizontal:
00225                 meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
00226                 break;
00227             case Meter::BarMeterVertical:
00228                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
00229                 break;
00230             case Meter::AnalogMeter:
00231             default:
00232                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00233                 break;
00234         }
00235 
00236         if (image) {
00237             //set a sane preferredSize. We can't just use the svg's native size, since that way
00238             //letters get cut off if the user uses a font larger then usual. Check how many rows of
00239             //labels we have, add 1 (the progress bar), and multiply by the font height to get a
00240             //somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
00241             //we look into alternatives for 4.3.
00242             uint i = 0;
00243             uint rows = 0;
00244             qreal prevY = -1;
00245             QString labelName = "label0";
00246             while (image->hasElement(labelName)) {
00247                 if (image->elementRect(labelName).y() > prevY) {
00248                     prevY = image->elementRect(labelName).y();
00249                     rows++;
00250                 }
00251                 i++;
00252                 labelName = QString("label%0").arg(i);
00253             }
00254 
00255             Plasma::Theme *theme = Plasma::Theme::defaultTheme();
00256             QFont font = theme->font(Plasma::Theme::DefaultFont);
00257             QFontMetrics fm(font);
00258 
00259             meter->setPreferredHeight((rows + 1) * fm.height());
00260         } else {
00261             meter->setPreferredSize(QSizeF(30, 30));
00262         }
00263     }
00264 
00265 Meter::Meter(QGraphicsItem *parent) :
00266         QGraphicsWidget(parent),
00267         d(new MeterPrivate(this))
00268 {
00269     d->setSizePolicyAndPreferredSize();
00270 
00271     d->animation = new QPropertyAnimation(d, "meterValue");
00272 }
00273 
00274 Meter::~Meter()
00275 {
00276     delete d->animation;
00277     delete d;
00278 }
00279 
00280 void Meter::setMaximum(int maximum)
00281 {
00282     d->maximum = maximum;
00283 }
00284 
00285 int Meter::maximum() const
00286 {
00287     return d->maximum;
00288 }
00289 
00290 void Meter::setMinimum(int minimum)
00291 {
00292     d->minimum = minimum;
00293 }
00294 
00295 int Meter::minimum() const
00296 {
00297     return d->minimum;
00298 }
00299 
00300 int Meter::value() const
00301 {
00302     return d->value;
00303 }
00304 
00305 void Meter::setValue(int value)
00306 {
00307     if (value == d->targetValue) {
00308         return;
00309     }
00310 
00311     d->targetValue = qBound(d->minimum, value, d->maximum);
00312     int delta = abs(d->value - d->targetValue);
00313 
00314     if (d->animation->state() != QAbstractAnimation::Running) {
00315         d->animation->stop();
00316     }
00317 
00318     //kDebug() << d->targetValue << d->value << delta;
00319     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
00320         delta / qreal(d->maximum) < 0.1) {
00321         d->value = value;
00322         update();
00323     } else  {
00324         d->animation->setStartValue(d->value);
00325         d->animation->setEndValue(value);
00326         d->animation->start();
00327     }
00328 }
00329 
00330 int MeterPrivate::meterValue() const
00331 {
00332     return value;
00333 }
00334 
00335 void MeterPrivate::setMeterValue(int value)
00336 {
00337     progressChanged(value);
00338 }
00339 
00340 void Meter::setLabel(int index, const QString &text)
00341 {
00342     while (d->labels.count() <= index) {
00343         d->labels << QString();
00344     }
00345     d->labels[index] = text;
00346 }
00347 
00348 QString Meter::label(int index) const
00349 {
00350     return d->labels[index];
00351 }
00352 
00353 void Meter::setLabelColor(int index, const QColor &color)
00354 {
00355     while (d->colors.count() <= index) {
00356         d->colors << color;
00357     }
00358     d->colors[index] = color;
00359 }
00360 
00361 QColor Meter::labelColor(int index) const
00362 {
00363     return d->colors[index];
00364 }
00365 
00366 void Meter::setLabelFont(int index, const QFont &font)
00367 {
00368     while (d->fonts.count() <= index) {
00369         d->fonts << font;
00370     }
00371     d->fonts[index] = font;
00372 }
00373 
00374 QFont Meter::labelFont(int index) const
00375 {
00376     return d->fonts[index];
00377 }
00378 
00379 void Meter::setLabelAlignment(int index, const Qt::Alignment alignment)
00380 {
00381     while (d->alignments.count() <= index) {
00382         d->alignments << alignment;
00383     }
00384     d->alignments[index] = alignment;
00385 }
00386 
00387 Qt::Alignment Meter::labelAlignment(int index) const
00388 {
00389     return d->alignments[index];
00390 }
00391 
00392 QRectF Meter::labelRect(int index) const
00393 {
00394     QString elementID = QString("label%1").arg(index);
00395     return d->image->elementRect(elementID);
00396 }
00397 
00398 void Meter::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data)
00399 {
00400     Q_UNUSED(sourceName)
00401 
00402     foreach (const QVariant &v, data) {
00403         if (v.type() == QVariant::Int ||
00404             v.type() == QVariant::UInt ||
00405             v.type() == QVariant::LongLong ||
00406             v.type() == QVariant::ULongLong) {
00407             setValue(v.toInt());
00408             return;
00409         }
00410     }
00411 }
00412 
00413 void Meter::setSvg(const QString &svg)
00414 {
00415     if (d->svg == svg) {
00416         return;
00417     }
00418 
00419     d->svg = svg;
00420     delete d->image;
00421     d->image = new Plasma::FrameSvg(this);
00422     d->image->setImagePath(svg);
00423     // To create renderer and get default size
00424     d->image->resize();
00425     d->setSizePolicyAndPreferredSize();
00426     if (d->image->hasElement("rotateminmax")) {
00427         QRectF r = d->image->elementRect("rotateminmax");
00428         d->minrotate = (int)r.height();
00429         d->maxrotate = (int)r.width();
00430     }
00431 }
00432 
00433 QString Meter::svg() const
00434 {
00435     return d->svg;
00436 }
00437 
00438 void Meter::setMeterType(MeterType meterType)
00439 {
00440     d->meterType = meterType;
00441     if (d->svg.isEmpty()) {
00442         if (meterType == BarMeterHorizontal) {
00443             setSvg("widgets/bar_meter_horizontal");
00444         } else if (meterType == BarMeterVertical) {
00445             setSvg("widgets/bar_meter_vertical");
00446         } else if (meterType == AnalogMeter) {
00447             setSvg("widgets/analog_meter");
00448         }
00449     }
00450     d->setSizePolicyAndPreferredSize();
00451 }
00452 
00453 Meter::MeterType Meter::meterType() const
00454 {
00455     return d->meterType;
00456 }
00457 
00458 void Meter::paint(QPainter *p,
00459                   const QStyleOptionGraphicsItem *option,
00460                   QWidget *widget)
00461 {
00462     Q_UNUSED(option)
00463     Q_UNUSED(widget)
00464 
00465     if (d->svg.isEmpty()) {
00466         setMeterType(d->meterType);
00467     }
00468 
00469     if (!d->image) {
00470         return;
00471     }
00472 
00473     QRectF rect(QPointF(0, 0), size());
00474     QRectF clipRect;
00475     qreal percentage = 0.0;
00476     qreal angle = 0.0;
00477     QPointF rotateCenter;
00478     QSize intSize = QSize((int)size().width(), (int)size().height());
00479 
00480     if (intSize != d->image->size()) {
00481         d->image->resize(intSize);
00482     }
00483 
00484     if (d->maximum != d->minimum) {
00485         percentage = (qreal)(d->value - d->minimum) / (d->maximum - d->minimum);
00486     }
00487 
00488     p->setRenderHint(QPainter::SmoothPixmapTransform);
00489     switch (d->meterType) {
00490     case BarMeterHorizontal:
00491     case BarMeterVertical:
00492         d->paintBackground(p);
00493 
00494         p->save();
00495         clipRect = d->barRect();
00496         if (clipRect.width() > clipRect.height()) {
00497             clipRect.setWidth(clipRect.width() * percentage);
00498         } else {
00499             qreal bottom = clipRect.bottom();
00500             clipRect.setHeight(clipRect.height() * percentage);
00501             clipRect.moveBottom(bottom);
00502         }
00503         p->setClipRect(clipRect, Qt::IntersectClip);
00504 
00505         //be retrocompatible
00506         if (d->image->hasElement("bar-active-center")) {
00507             d->paintBar(p, "bar-active");
00508         } else {
00509             d->paint(p, "bar");
00510         }
00511         p->restore();
00512 
00513         d->paintForeground(p);
00514         break;
00515     case AnalogMeter:
00516         d->paintBackground(p);
00517 
00518         p->save();
00519         if (d->image->hasElement("rotatecenter")) {
00520             QRectF r = d->image->elementRect("rotatecenter");
00521             rotateCenter = QPointF(r.left() + r.width() / 2,
00522                                    r.top() + r.height() / 2);
00523         } else {
00524             rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
00525         }
00526         angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
00527 
00528         if (d->image->hasElement("pointer-shadow")) {
00529             p->save();
00530             p->translate(rotateCenter+QPoint(2,3));
00531             p->rotate(angle);
00532             p->translate(-1 * rotateCenter);
00533             d->paint(p, "pointer-shadow");
00534             p->restore();
00535         }
00536 
00537         p->translate(rotateCenter);
00538         p->rotate(angle);
00539         p->translate(-1 * rotateCenter);
00540         d->paint(p, "pointer");
00541         p->restore();
00542 
00543         d->paintForeground(p);
00544         break;
00545     }
00546 }
00547 
00548 QSizeF Meter::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
00549 {
00550     return QGraphicsWidget::sizeHint(which, constraint);
00551 }
00552 
00553 } // End of namepace
00554 
00555 #include "meter.moc"
00556 #include "../private/meter_p.moc"

Plasma

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal