• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • 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 
00022 #include <cmath>
00023 
00024 #include <QPainter>
00025 #include <QTimeLine>
00026 
00027 #include <kdebug.h>
00028 #include <kglobalsettings.h>
00029 
00030 #include "plasma/animator.h"
00031 #include "plasma/framesvg.h"
00032 #include "plasma/theme.h"
00033 
00034 namespace Plasma {
00035 
00036 class MeterPrivate
00037 {
00038 public:
00039     MeterPrivate(Meter *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           movementId(0)
00050     {
00051     }
00052 
00053     void progressChanged(qreal progress)
00054     {
00055         bool over = qFuzzyCompare(progress, qreal(1.0));
00056 
00057         if (value == targetValue) {
00058             if (!over && movementId) {
00059                 Animator::self()->stopCustomAnimation(movementId);
00060             }
00061 
00062             return;
00063         }
00064 
00065         if (over) {
00066             value = targetValue;
00067             //kDebug() << "done";
00068             movementId = 0;
00069         } else {
00070             int frame = progress * 10;
00071             int delta = targetValue - value;
00072             value += (delta / qreal(10 - frame));
00073             //kDebug() << frame << value << targetValue;
00074         }
00075 
00076         meter->update();
00077     }
00078 
00079     void paint(QPainter *p, const QString &elementID)
00080     {
00081         if (image->hasElement(elementID)) {
00082             QRectF elementRect = image->elementRect(elementID);
00083             image->paint(p, elementRect, elementID);
00084         }
00085     }
00086 
00087     void text(QPainter *p, int index)
00088     {
00089         QString elementID = QString("label%1").arg(index);
00090         QString text = labels[index];
00091 
00092         if (image->hasElement(elementID)) {
00093             QRectF elementRect = image->elementRect(elementID);
00094             Qt::Alignment align = Qt::AlignCenter;
00095 
00096             if (colors.count() > index) {
00097                 p->setPen(QPen(colors[index]));
00098             }
00099             if (fonts.count() > index) {
00100                 p->setFont(fonts[index]);
00101             }
00102             if (alignments.count() > index) {
00103                 align = alignments[index];
00104             }
00105             if (elementRect.width() > elementRect.height()) {
00106                 p->drawText(elementRect, align, text);
00107             } else {
00108                 p->save();
00109                 QPointF rotateCenter(
00110                         elementRect.left() + elementRect.width() / 2,
00111                         elementRect.top() + elementRect.height() / 2);
00112                 p->translate(rotateCenter);
00113                 p->rotate(-90);
00114                 p->translate(elementRect.height() / -2,
00115                              elementRect.width() / -2);
00116                 QRectF r(0, 0, elementRect.height(), elementRect.width());
00117                 p->drawText(r, align, text);
00118                 p->restore();
00119             }
00120         }
00121     }
00122 
00123     QRectF barRect()
00124     {
00125         QRectF elementRect;
00126 
00127         if (labels.count() > 0) {
00128             elementRect = image->elementRect("background");
00129         } else {
00130             elementRect = QRectF(QPoint(0,0), meter->size());
00131         }
00132 
00133         if (image->hasElement("hint-bar-stretch") || !image->hasElement("bar-active-center")) {
00134             return elementRect;
00135         }
00136 
00137         QSize imageSize = image->size();
00138         image->resize();
00139         QSize tileSize = image->elementSize("bar-active-center");
00140         image->resize(imageSize);
00141 
00142         if (elementRect.width() > elementRect.height()) {
00143             qreal ratio = qMax(1, tileSize.height() / tileSize.width());
00144             int numTiles = qMax(qreal(1.0), qreal(elementRect.width())/(qreal(elementRect.height())/ratio));
00145             tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
00146 
00147             QPoint center = elementRect.center().toPoint();
00148             elementRect.setWidth(tileSize.width()*numTiles);
00149             elementRect.moveCenter(center);
00150         } else {
00151             qreal ratio = qMax(1, tileSize.width() / tileSize.height());
00152             int numTiles = qMax(qreal(1.0), qreal(elementRect.height())/(qreal(elementRect.width())/ratio));
00153             tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
00154 
00155             QPoint center = elementRect.center().toPoint();
00156             elementRect.setHeight(tileSize.height()*numTiles);
00157             elementRect.moveCenter(center);
00158         }
00159 
00160         return elementRect;
00161     }
00162 
00163     void paintBackground(QPainter *p)
00164     {
00165         //be retrocompatible with themes for kde <= 4.1
00166         if (image->hasElement("background-center")) {
00167             QRectF elementRect = barRect();
00168             if (elementRect.isEmpty())
00169                 return; // nothing to be done 
00170             QSize imageSize = image->size();
00171             image->resize();
00172 
00173             image->setElementPrefix("background");
00174             image->resizeFrame(elementRect.size());
00175             image->paintFrame(p, elementRect.topLeft());
00176             image->resize(imageSize);
00177 
00178             paintBar(p, "bar-inactive");
00179         } else {
00180             paint(p, "background");
00181         }
00182     }
00183 
00184     void paintBar(QPainter *p, const QString &prefix)
00185     {
00186         QRectF elementRect = barRect();
00187 
00188         if (image->hasElement("hint-bar-stretch")) {
00189             image->resizeFrame(elementRect.size());
00190             image->paintFrame(p);
00191         } else {
00192             QSize imageSize = image->size();
00193             image->resize();
00194             QSize tileSize = image->elementSize("bar-active-center");
00195 
00196             if (elementRect.width() > elementRect.height()) {
00197                 qreal ratio = tileSize.height() / tileSize.width();
00198                 int numTiles = elementRect.width()/(elementRect.height()/ratio);
00199                 tileSize = QSize(elementRect.width()/numTiles, elementRect.height());
00200             } else {
00201                 qreal ratio = tileSize.width() / tileSize.height();
00202                 int numTiles = elementRect.height()/(elementRect.width()/ratio);
00203                 tileSize = QSize(elementRect.width(), elementRect.height()/numTiles);
00204             }
00205 
00206             image->setElementPrefix(prefix);
00207             image->resizeFrame(tileSize);
00208             p->drawTiledPixmap(elementRect, image->framePixmap());
00209             image->resize(imageSize);
00210         }
00211     }
00212 
00213     void paintForeground(QPainter *p)
00214     {
00215         for (int i = 0; i < labels.count(); ++i) {
00216             text(p, i);
00217         }
00218 
00219         paint(p, "foreground");
00220     }
00221 
00222     void setSizePolicyAndPreferredSize()
00223     {
00224         switch (meterType) {
00225             case Meter::BarMeterHorizontal:
00226                 meter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
00227                 break;
00228             case Meter::BarMeterVertical:
00229                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
00230                 break;
00231             case Meter::AnalogMeter:
00232             default:
00233                 meter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00234                 break;
00235         }
00236 
00237         if (image) {
00238             //set a sane preferredSize. We can't just use the svg's native size, since that way
00239             //letters get cut off if the user uses a font larger then usual. Check how many rows of
00240             //labels we have, add 1 (the progress bar), and multiply by the font height to get a
00241             //somewhat sane size height. This is not perfect but work well enough for 4.2. I suggest
00242             //we look into alternatives for 4.3.
00243             uint i = 0;
00244             uint rows = 0;
00245             qreal prevY = -1;
00246             QString labelName = "label0";
00247             while (image->hasElement(labelName)) {
00248                 if (image->elementRect(labelName).y() > prevY) {
00249                     prevY = image->elementRect(labelName).y();
00250                     rows++;
00251                 }
00252                 i++;
00253                 labelName = QString("label%0").arg(i);
00254             }
00255 
00256             Plasma::Theme *theme = Plasma::Theme::defaultTheme();
00257             QFont font = theme->font(Plasma::Theme::DefaultFont);
00258             QFontMetrics fm(font);
00259 
00260             meter->setPreferredHeight((rows + 1) * fm.height());
00261         } else {
00262             meter->setPreferredSize(QSizeF(30, 30));
00263         }
00264     }
00265 
00266     int minimum;
00267     int maximum;
00268     int value;
00269     int targetValue;
00270     QStringList labels;
00271     QList<Qt::Alignment> alignments;
00272     QList<QColor> colors;
00273     QList<QFont> fonts;
00274     QString svg;
00275     Meter::MeterType meterType;
00276     Plasma::FrameSvg *image;
00277     int minrotate;
00278     int maxrotate;
00279     Meter *meter;
00280     int movementId;
00281 };
00282 
00283 Meter::Meter(QGraphicsItem *parent) :
00284         QGraphicsWidget(parent),
00285         d(new MeterPrivate(this))
00286 {
00287     d->setSizePolicyAndPreferredSize();
00288 }
00289 
00290 Meter::~Meter()
00291 {
00292     delete d;
00293 }
00294 
00295 void Meter::setMaximum(int maximum)
00296 {
00297     d->maximum = maximum;
00298 }
00299 
00300 int Meter::maximum() const
00301 {
00302     return d->maximum;
00303 }
00304 
00305 void Meter::setMinimum(int minimum)
00306 {
00307     d->minimum = minimum;
00308 }
00309 
00310 int Meter::minimum() const
00311 {
00312     return d->minimum;
00313 }
00314 
00315 void Meter::setValue(int value)
00316 {
00317     if (value == d->targetValue) {
00318         return;
00319     }
00320 
00321     d->targetValue = qBound(d->minimum, value, d->maximum);
00322     int delta = abs(d->value - d->targetValue);
00323 
00324     if (d->movementId) {
00325         Animator::self()->stopCustomAnimation(d->movementId);
00326         d->movementId = 0;
00327     }
00328 
00329     //kDebug() << d->targetValue << d->value << delta;
00330     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects) ||
00331         delta / qreal(d->maximum) < 0.1) {
00332         d->value = value;
00333         update();
00334     } else  {
00335         d->movementId = Animator::self()->customAnimation(10, 100, Animator::EaseOutCurve,
00336                                                           this, "progressChanged");
00337     }
00338 }
00339 
00340 int Meter::value() const
00341 {
00342     return d->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, 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     d->svg = svg;
00421     delete d->image;
00422     d->image = new Plasma::FrameSvg(this);
00423     d->image->setImagePath(svg);
00424     // To create renderer and get default size
00425     d->image->resize();
00426     d->setSizePolicyAndPreferredSize();
00427     if (d->image->hasElement("rotateminmax")) {
00428         QRectF r = d->image->elementRect("rotateminmax");
00429         d->minrotate = (int)r.height();
00430         d->maxrotate = (int)r.width();
00431     }
00432 }
00433 
00434 QString Meter::svg() const
00435 {
00436     return d->svg;
00437 }
00438 
00439 void Meter::setMeterType(MeterType meterType)
00440 {
00441     d->meterType = meterType;
00442     if (d->svg.isEmpty()) {
00443         if (meterType == BarMeterHorizontal) {
00444             setSvg("widgets/bar_meter_horizontal");
00445         } else if (meterType == BarMeterVertical) {
00446             setSvg("widgets/bar_meter_vertical");
00447         } else if (meterType == AnalogMeter) {
00448             setSvg("widgets/analog_meter");
00449         }
00450     }
00451     d->setSizePolicyAndPreferredSize();
00452 }
00453 
00454 Meter::MeterType Meter::meterType() const
00455 {
00456     return d->meterType;
00457 }
00458 
00459 void Meter::paint(QPainter *p,
00460                   const QStyleOptionGraphicsItem *option,
00461                   QWidget *widget)
00462 {
00463     Q_UNUSED(option)
00464     Q_UNUSED(widget)
00465 
00466     if (!d->image) {
00467         return;
00468     }
00469 
00470     QRectF rect(QPointF(0, 0), size());
00471     QRectF clipRect;
00472     qreal percentage = 0.0;
00473     qreal angle = 0.0;
00474     QPointF rotateCenter;
00475     QSize intSize = QSize((int)size().width(), (int)size().height());
00476 
00477     if (intSize != d->image->size()) {
00478         d->image->resize(intSize);
00479     }
00480 
00481     if (d->maximum != d->minimum) {
00482         percentage = (qreal)d->value / (d->maximum - d->minimum);
00483     }
00484     p->setRenderHint(QPainter::SmoothPixmapTransform);
00485     switch (d->meterType) {
00486     case BarMeterHorizontal:
00487     case BarMeterVertical:
00488         d->paintBackground(p);
00489 
00490         p->save();
00491         clipRect = d->barRect();
00492         if (clipRect.width() > clipRect.height()) {
00493             clipRect.setWidth(clipRect.width() * percentage);
00494         } else {
00495             qreal bottom = clipRect.bottom();
00496             clipRect.setHeight(clipRect.height() * percentage);
00497             clipRect.moveBottom(bottom);
00498         }
00499         p->setClipRect(clipRect);
00500         //be retrocompatible
00501         if (d->image->hasElement("bar-active-center")) {
00502             d->paintBar(p, "bar-active");
00503         } else {
00504             d->paint(p, "bar");
00505         }
00506         p->restore();
00507 
00508         d->paintForeground(p);
00509         break;
00510     case AnalogMeter:
00511         d->paintBackground(p);
00512 
00513         p->save();
00514         if (d->image->hasElement("rotatecenter")) {
00515             QRectF r = d->image->elementRect("rotatecenter");
00516             rotateCenter = QPointF(r.left() + r.width() / 2,
00517                                    r.top() + r.height() / 2);
00518         } else {
00519             rotateCenter = QPointF(rect.width() / 2, rect.height() / 2);
00520         }
00521         angle = percentage * (d->maxrotate - d->minrotate) + d->minrotate;
00522 
00523         if (d->image->hasElement("pointer-shadow")) {
00524             p->save();
00525             p->translate(rotateCenter+QPoint(2,3));
00526             p->rotate(angle);
00527             p->translate(-1 * rotateCenter);
00528             d->paint(p, "pointer-shadow");
00529             p->restore();
00530         }
00531 
00532         p->translate(rotateCenter);
00533         p->rotate(angle);
00534         p->translate(-1 * rotateCenter);
00535         d->paint(p, "pointer");
00536         p->restore();
00537 
00538         d->paintForeground(p);
00539         break;
00540     }
00541 }
00542 
00543 } // End of namepace
00544 
00545 #include "meter.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
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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