• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

panelsvg.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2008 by Aaron Seigo <aseigo@kde.org>
00003  *   Copyright 2008 Marco Martin <notmart@gmail.com>
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU Library General Public License as
00007  *   published by the Free Software Foundation; either version 2, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 
00021 #include "panelsvg.h"
00022 
00023 #include <QPainter>
00024 #include <QSize>
00025 #include <QBitmap>
00026 
00027 #include <KDebug>
00028 
00029 #include <plasma/theme.h>
00030 
00031 namespace Plasma
00032 {
00033 
00034 class PanelData
00035 {
00036 public:
00037     PanelData()
00038       : enabledBorders(PanelSvg::AllBorders),
00039         cachedBackground(0),
00040         panelSize(-1,-1),
00041         contentAtOrigin(false)
00042     {
00043     }
00044 
00045     PanelData(const PanelData &other)
00046       : enabledBorders(other.enabledBorders),
00047         cachedBackground(0),
00048         panelSize(other.panelSize),
00049         contentAtOrigin(other.contentAtOrigin)
00050     {
00051     }
00052 
00053     ~PanelData()
00054     {
00055         delete cachedBackground;
00056     }
00057 
00058     PanelSvg::EnabledBorders enabledBorders;
00059     QPixmap *cachedBackground;
00060     QSizeF panelSize;
00061 
00062     //measures
00063     int topHeight;
00064     int leftWidth;
00065     int rightWidth;
00066     int bottomHeight;
00067 
00068     //size of the svg where the size of the "center"
00069     //element is contentWidth x contentHeight
00070     bool noBorderPadding : 1;
00071     bool stretchBorders : 1;
00072     bool tileCenter : 1;
00073     bool contentAtOrigin : 1;
00074 };
00075 
00076 class PanelSvgPrivate
00077 {
00078 public:
00079     PanelSvgPrivate(PanelSvg *psvg)
00080       : q(psvg),
00081         cacheAll(false)
00082     {
00083     }
00084 
00085     ~PanelSvgPrivate()
00086     {
00087         qDeleteAll(panels);
00088         panels.clear();
00089     }
00090 
00091     void generateBackground(PanelData *panel);
00092     void updateSizes();
00093     void updateNeeded();
00094     void updateAndSignalSizes();
00095 
00096     Location location;
00097     QString prefix;
00098 
00099     PanelSvg *q;
00100 
00101     bool cacheAll : 1;
00102 
00103     QHash<QString, PanelData*> panels;
00104 };
00105 
00106 PanelSvg::PanelSvg(QObject* parent)
00107     : Svg(parent),
00108       d(new PanelSvgPrivate(this))
00109 {
00110     connect(this, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded()));
00111     d->panels.insert(QString(), new PanelData());
00112 }
00113 
00114 PanelSvg::~PanelSvg()
00115 {
00116     delete d;
00117 }
00118 
00119 void PanelSvg::setImagePath(const QString& path)
00120 {
00121     if (path == imagePath()) {
00122         return;
00123     }
00124 
00125     Svg::setImagePath(path);
00126 
00127     clearCache();
00128     d->updateAndSignalSizes();
00129 }
00130 
00131 void PanelSvg::setEnabledBorders(const EnabledBorders borders)
00132 {
00133     if (borders == d->panels[d->prefix]->enabledBorders) {
00134         return;
00135     }
00136 
00137     d->panels[d->prefix]->enabledBorders = borders;
00138     d->updateAndSignalSizes();
00139 }
00140 
00141 PanelSvg::EnabledBorders PanelSvg::enabledBorders() const
00142 {
00143     QHash<QString, PanelData*>::const_iterator it = d->panels.constFind(d->prefix);
00144 
00145     if (it != d->panels.constEnd()) {
00146         return it.value()->enabledBorders;
00147     } else {
00148         return NoBorder;
00149     }
00150 }
00151 
00152 void PanelSvg::setElementPrefix(Plasma::Location location)
00153 {
00154     switch (location) {
00155         case TopEdge:
00156             setElementPrefix("north");
00157             break;
00158         case BottomEdge:
00159             setElementPrefix("south");
00160             break;
00161         case LeftEdge:
00162             setElementPrefix("west");
00163             break;
00164         case RightEdge:
00165             setElementPrefix("east");
00166             break;
00167         default:
00168             setElementPrefix(QString());
00169             break;
00170     }
00171     d->location = location;
00172 }
00173 
00174 void PanelSvg::setElementPrefix(const QString & prefix)
00175 {
00176     const QString oldPrefix(d->prefix);
00177 
00178     if (!hasElement(prefix + "-center")) {
00179         d->prefix.clear();
00180     } else {
00181         d->prefix = prefix;
00182         if (!d->prefix.isEmpty()) {
00183             d->prefix += '-';
00184         }
00185 
00186     }
00187 
00188     if (oldPrefix == d->prefix && d->panels[oldPrefix]) {
00189         return;
00190     }
00191 
00192     if (!d->panels.contains(d->prefix)) {
00193         d->panels.insert(d->prefix, new PanelData(*(d->panels[oldPrefix])));
00194         d->updateSizes();
00195     }
00196 
00197     if (!d->cacheAll) {
00198         delete d->panels[oldPrefix];
00199         d->panels.remove(oldPrefix);
00200     }
00201 
00202     d->location = Floating;
00203 }
00204 
00205 bool PanelSvg::hasElementPrefix(const QString & prefix) const
00206 {
00207     //for now it simply checks if a center element exists,
00208     //because it could make sense for certain themes to not have all the elements
00209     if (prefix.isEmpty()) {
00210         return hasElement("center");
00211     } else {
00212         return hasElement(prefix + "-center");
00213     }
00214 }
00215 
00216 bool PanelSvg::hasElementPrefix(Plasma::Location location) const
00217 {
00218     switch (location) {
00219         case TopEdge:
00220             return hasElementPrefix("north");
00221             break;
00222         case BottomEdge:
00223             return hasElementPrefix("south");
00224             break;
00225         case LeftEdge:
00226             return hasElementPrefix("west");
00227             break;
00228         case RightEdge:
00229             return hasElementPrefix("east");
00230             break;
00231         default:
00232             return hasElementPrefix(QString());
00233             break;
00234     }
00235 }
00236 
00237 QString PanelSvg::prefix()
00238 {
00239     if (d->prefix.isEmpty()) {
00240         return d->prefix;
00241     }
00242 
00243     return d->prefix.left(d->prefix.size() - 1);
00244 }
00245 
00246 void PanelSvg::resizePanel(const QSizeF& size)
00247 {
00248     if (size.isEmpty()) {
00249         kWarning() << "Invalid size" << size;
00250         return;
00251     }
00252 
00253     if (size == d->panels[d->prefix]->panelSize) {
00254         return;
00255     }
00256 
00257     d->updateSizes();
00258     d->panels[d->prefix]->panelSize = size;
00259 }
00260 
00261 QSizeF PanelSvg::panelSize() const
00262 {
00263     QHash<QString, PanelData*>::const_iterator it = d->panels.constFind(d->prefix);
00264 
00265     if (it != d->panels.constEnd()) {
00266         return it.value()->panelSize;
00267     } else {
00268         return QSize(-1, -1);
00269     }
00270 }
00271 
00272 qreal PanelSvg::marginSize(const Plasma::MarginEdge edge) const
00273 {
00274     if (d->panels[d->prefix]->noBorderPadding) {
00275         return .0;
00276     }
00277 
00278     switch (edge) {
00279     case Plasma::TopMargin:
00280         return d->panels[d->prefix]->topHeight;
00281     break;
00282 
00283     case Plasma::LeftMargin:
00284         return d->panels[d->prefix]->leftWidth;
00285     break;
00286 
00287     case Plasma::RightMargin:
00288         return d->panels[d->prefix]->rightWidth;
00289     break;
00290 
00291     //Plasma::BottomMargin
00292     default:
00293         return d->panels[d->prefix]->bottomHeight;
00294     break;
00295     }
00296 }
00297 
00298 void PanelSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const
00299 {
00300     PanelData *panel = d->panels[d->prefix];
00301 
00302     if (!panel || panel->noBorderPadding) {
00303         left = top = right = bottom = 0;
00304         return;
00305     }
00306 
00307     top = panel->topHeight;
00308     left = panel->leftWidth;
00309     right = panel->rightWidth;
00310     bottom = panel->bottomHeight;
00311 }
00312 
00313 QBitmap PanelSvg::mask() const
00314 {
00315     PanelData *panel = d->panels[d->prefix];
00316     if (!panel->cachedBackground) {
00317         d->generateBackground(panel);
00318         Q_ASSERT(panel->cachedBackground);
00319     }
00320 
00321     return panel->cachedBackground->alphaChannel().createMaskFromColor(Qt::black);
00322 }
00323 
00324 void PanelSvg::setCacheAllRenderedPanels(bool cache)
00325 {
00326     if (d->cacheAll && !cache) {
00327         clearCache();
00328     }
00329 
00330     d->cacheAll = cache;
00331 }
00332 
00333 bool PanelSvg::cacheAllRenderedPanels() const
00334 {
00335     return d->cacheAll;
00336 }
00337 
00338 void PanelSvg::clearCache()
00339 {
00340     PanelData *panel = d->panels[d->prefix];
00341 
00342     // delete all the panels that aren't this one
00343     QMutableHashIterator<QString, PanelData*> it(d->panels);
00344     while (it.hasNext()) {
00345         PanelData *p = it.next().value();
00346         if (panel != p) {
00347             delete p;
00348             it.remove();
00349         }
00350     }
00351 }
00352 
00353 void PanelSvg::paintPanel(QPainter* painter, const QRectF& rect, const QPointF& pos)
00354 {
00355     //kDebug();
00356     PanelData *panel = d->panels[d->prefix];
00357     if (!panel->cachedBackground) {
00358         d->generateBackground(panel);
00359         Q_ASSERT(panel->cachedBackground);
00360     }
00361 
00362     //FIXME: this is redundant with generatebackground for now
00363     bool origined = panel->contentAtOrigin;
00364     const int topOffset = origined ? 0 - panel->topHeight : 0;
00365     const int leftOffset = origined ? 0 - panel->leftWidth : 0;
00366 
00367     painter->drawPixmap(rect, *(panel->cachedBackground), rect.translated(-pos.x()-leftOffset,-pos.y()-topOffset));
00368 }
00369 
00370 void PanelSvgPrivate::generateBackground(PanelData *panel)
00371 {
00372     //kDebug() << "generating background";
00373     bool origined = panel->contentAtOrigin;
00374     const int topWidth = q->elementSize(prefix + "top").width();
00375     const int leftHeight = q->elementSize(prefix + "left").height();
00376     const int topOffset = origined ? 0 - panel->topHeight : 0;
00377     const int leftOffset = origined ? 0 - panel->leftWidth : 0;
00378 
00379     if (panel->cachedBackground) {
00380         return;
00381     }
00382 
00383     if (!panel->panelSize.isValid()) {
00384         kWarning() << "Invalid panel size" << panel->panelSize;
00385         panel->cachedBackground = new QPixmap();
00386         return;
00387     }
00388 
00389     const int contentWidth = panel->panelSize.width() - panel->leftWidth  - panel->rightWidth;
00390     const int contentHeight = panel->panelSize.height() - panel->topHeight  - panel->bottomHeight;
00391     int contentTop = 0;
00392     int contentLeft = 0;
00393     int rightOffset = contentWidth;
00394     int bottomOffset = contentHeight;
00395 
00396     panel->cachedBackground = new QPixmap(panel->leftWidth + contentWidth + panel->rightWidth,
00397                                           panel->topHeight + contentHeight + panel->bottomHeight);
00398     panel->cachedBackground->fill(Qt::transparent);
00399     QPainter p(panel->cachedBackground);
00400     p.setCompositionMode(QPainter::CompositionMode_Source);
00401     p.setRenderHint(QPainter::SmoothPixmapTransform);
00402 
00403     if (origined) {
00404         p.translate(panel->leftWidth, panel->topHeight);
00405     }
00406 
00407     //FIXME: This is a hack to fix a drawing problems with svg files where a thin transparent border is drawn around the svg image.
00408     //       the transparent border around the svg seems to vary in size depending on the size of the svg and as a result increasing the
00409     //       svg image by 2 all around didn't resolve the issue. For now it resizes based on the border size.
00410 
00411     //if we must stretch the center or the borders we compute how much we will have to stretch
00412     //the svg to get the desired element sizes
00413     QSizeF  scaledContentSize(0,0);
00414     if (q->elementSize(prefix + "center").width() > 0 &&
00415         q->elementSize(prefix + "center").height() > 0 &&
00416         (!panel->tileCenter || panel->stretchBorders)) {
00417         scaledContentSize = QSizeF(contentWidth * ((qreal)q->size().width() / (qreal)q->elementSize(prefix + "center").width()),
00418                                    contentHeight * ((qreal)q->size().height() / (qreal)q->elementSize(prefix + "center").height()));
00419     }
00420 
00421     //CENTER
00422     if (panel->tileCenter) {
00423         if (contentHeight > 0 && contentWidth > 0) {
00424             int centerTileHeight;
00425             int centerTileWidth;
00426             centerTileHeight = q->elementSize(prefix + "center").height();
00427             centerTileWidth = q->elementSize(prefix + "center").width();
00428             QPixmap center(centerTileWidth, centerTileHeight);
00429             center.fill(Qt::transparent);
00430 
00431             {
00432                 QPainter centerPainter(&center);
00433                 centerPainter.setCompositionMode(QPainter::CompositionMode_Source);
00434                 q->paint(&centerPainter, QPoint(0, 0), prefix + "center");
00435             }
00436 
00437             p.drawTiledPixmap(QRect(panel->leftWidth, panel->topHeight,
00438                                     contentWidth, contentHeight), center);
00439         }
00440     } else {
00441         if (contentHeight > 0 && contentWidth > 0) {
00442             q->resize(scaledContentSize);
00443             q->paint(&p, QRect(panel->leftWidth, panel->topHeight,
00444                                contentWidth, contentHeight),
00445                                prefix + "center");
00446             q->resize();
00447         }
00448     }
00449 
00450     // Corners
00451     if (q->hasElement(prefix + "top") && panel->enabledBorders & PanelSvg::TopBorder) {
00452         if (!origined) {
00453             contentTop = panel->topHeight;
00454             bottomOffset += panel->topHeight;
00455         }
00456 
00457         if (q->hasElement(prefix + "topleft") && panel->enabledBorders & PanelSvg::LeftBorder) {
00458             q->paint(&p, QRect(leftOffset, topOffset, panel->leftWidth, panel->topHeight), prefix + "topleft");
00459 
00460             if (!origined) {
00461                 contentLeft = panel->leftWidth;
00462                 rightOffset = contentWidth + panel->leftWidth;
00463             }
00464         }
00465 
00466         if (q->hasElement(prefix + "topright") && panel->enabledBorders & PanelSvg::RightBorder) {
00467             q->paint(&p, QRect(rightOffset, topOffset, panel->rightWidth, panel->topHeight), prefix + "topright");
00468         }
00469     }
00470 
00471     if (q->hasElement(prefix + "bottom") && panel->enabledBorders & PanelSvg::BottomBorder) {
00472         if (q->hasElement(prefix + "bottomleft") && panel->enabledBorders & PanelSvg::LeftBorder) {
00473             q->paint(&p, QRect(leftOffset, bottomOffset, panel->leftWidth, panel->bottomHeight), prefix + "bottomleft");
00474 
00475             if (!origined) {
00476                 contentLeft = panel->leftWidth;
00477                 rightOffset = contentWidth + panel->leftWidth;
00478             }
00479         }
00480 
00481         if (q->hasElement(prefix + "bottomright") && panel->enabledBorders & PanelSvg::RightBorder) {
00482             q->paint(&p, QRect(rightOffset, bottomOffset, panel->rightWidth, panel->bottomHeight), prefix + "bottomright");
00483         }
00484     }
00485 
00486     // Sides
00487     if (panel->stretchBorders) {
00488         if (panel->enabledBorders & PanelSvg::LeftBorder || panel->enabledBorders & PanelSvg::RightBorder) {
00489             q->resize(q->size().width(), scaledContentSize.height());
00490 
00491             if (q->hasElement(prefix + "left") && panel->enabledBorders & PanelSvg::LeftBorder) {
00492                 q->paint(&p, QRect(leftOffset, contentTop, panel->leftWidth, contentHeight), prefix + "left");
00493             }
00494 
00495             if (q->hasElement(prefix + "right") && panel->enabledBorders & PanelSvg::RightBorder) {
00496                 q->paint(&p, QRect(rightOffset, contentTop, panel->rightWidth, contentHeight), prefix + "right");
00497             }
00498 
00499             q->resize();
00500         }
00501 
00502         if (panel->enabledBorders & PanelSvg::TopBorder || panel->enabledBorders & PanelSvg::BottomBorder) {
00503             q->resize(scaledContentSize.width(), q->size().height());
00504 
00505             if (q->hasElement(prefix + "top") && panel->enabledBorders & PanelSvg::TopBorder) {
00506                 q->paint(&p, QRect(contentLeft, topOffset, contentWidth, panel->topHeight), prefix + "top");
00507             }
00508 
00509             if (q->hasElement(prefix + "bottom") && panel->enabledBorders & PanelSvg::BottomBorder) {
00510                 q->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, panel->bottomHeight), prefix + "bottom");
00511             }
00512 
00513             q->resize();
00514         }
00515     } else {
00516         if (q->hasElement(prefix + "left") && panel->enabledBorders & PanelSvg::LeftBorder) {
00517             QPixmap left(panel->leftWidth, leftHeight);
00518             left.fill(Qt::transparent);
00519 
00520             QPainter sidePainter(&left);
00521             sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
00522             q->paint(&sidePainter, QPoint(0, 0), prefix + "left");
00523 
00524             p.drawTiledPixmap(QRect(leftOffset, contentTop, panel->leftWidth, contentHeight), left);
00525         }
00526 
00527         if (q->hasElement(prefix + "right") && panel->enabledBorders & PanelSvg::RightBorder) {
00528             QPixmap right(panel->rightWidth, leftHeight);
00529             right.fill(Qt::transparent);
00530 
00531             QPainter sidePainter(&right);
00532             sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
00533             q->paint(&sidePainter, QPoint(0, 0), prefix + "right");
00534 
00535             p.drawTiledPixmap(QRect(rightOffset, contentTop, panel->rightWidth, contentHeight), right);
00536         }
00537 
00538         if (q->hasElement(prefix + "top") && panel->enabledBorders & PanelSvg::TopBorder) {
00539             QPixmap top(topWidth, panel->topHeight);
00540             top.fill(Qt::transparent);
00541 
00542             QPainter sidePainter(&top);
00543             sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
00544             q->paint(&sidePainter, QPoint(0, 0), prefix + "top");
00545 
00546             p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, panel->topHeight), top);
00547         }
00548 
00549         if (q->hasElement(prefix + "bottom") && panel->enabledBorders & PanelSvg::BottomBorder) {
00550             QPixmap bottom(topWidth, panel->bottomHeight);
00551             bottom.fill(Qt::transparent);
00552 
00553             QPainter sidePainter(&bottom);
00554             sidePainter.setCompositionMode(QPainter::CompositionMode_Source);
00555             q->paint(&sidePainter, QPoint(0, 0), prefix + "bottom");
00556 
00557             p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, panel->bottomHeight), bottom);
00558         }
00559     }
00560 
00561     // re-enable this once Qt's svg rendering is un-buggered
00562     //q->resize(contentWidth, contentHeight);
00563     //paint(&p, QRect(contentLeft, contentTop, contentWidth, contentHeight), "center");
00564 }
00565 
00566 void PanelSvgPrivate::updateSizes()
00567 {
00568     //kDebug() << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix;
00569     PanelData *panel = panels[prefix];
00570     Q_ASSERT(panel);
00571 
00572     delete panel->cachedBackground;
00573     panel->cachedBackground = 0;
00574 
00575     q->Svg::resize();
00576     if (panel->enabledBorders & PanelSvg::TopBorder) {
00577         panel->topHeight = q->elementSize(prefix + "top").height();
00578     } else {
00579         panel->topHeight = 0;
00580     }
00581 
00582     if (panel->enabledBorders & PanelSvg::LeftBorder) {
00583         panel->leftWidth = q->elementSize(prefix + "left").width();
00584     } else {
00585         panel->leftWidth = 0;
00586     }
00587 
00588     if (panel->enabledBorders & PanelSvg::RightBorder) {
00589         panel->rightWidth = q->elementSize(prefix + "right").width();
00590     } else {
00591         panel->rightWidth = 0;
00592     }
00593 
00594     if (panel->enabledBorders & PanelSvg::BottomBorder) {
00595         panel->bottomHeight = q->elementSize(prefix + "bottom").height();
00596     } else {
00597         panel->bottomHeight = 0;
00598     }
00599 
00600     //since it's rectangular, topWidth and bottomWidth must be the same
00601     panel->tileCenter = q->hasElement("hint-tile-center");
00602     panel->noBorderPadding = q->hasElement("hint-no-border-padding");
00603     panel->stretchBorders = q->hasElement("hint-stretch-borders");
00604 }
00605 
00606 void PanelSvgPrivate::updateNeeded()
00607 {
00608     q->clearCache();
00609     updateSizes();
00610 }
00611 
00612 void PanelSvgPrivate::updateAndSignalSizes()
00613 {
00614     updateSizes();
00615     emit q->repaintNeeded();
00616 }
00617 
00618 } // Plasma namespace
00619 
00620 #include "panelsvg.moc"

libplasma

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

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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