00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00063 int topHeight;
00064 int leftWidth;
00065 int rightWidth;
00066 int bottomHeight;
00067
00068
00069
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
00208
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
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
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
00356 PanelData *panel = d->panels[d->prefix];
00357 if (!panel->cachedBackground) {
00358 d->generateBackground(panel);
00359 Q_ASSERT(panel->cachedBackground);
00360 }
00361
00362
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
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
00408
00409
00410
00411
00412
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
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(¢er);
00433 centerPainter.setCompositionMode(QPainter::CompositionMode_Source);
00434 q->paint(¢erPainter, 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
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
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
00562
00563
00564 }
00565
00566 void PanelSvgPrivate::updateSizes()
00567 {
00568
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
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 }
00619
00620 #include "panelsvg.moc"