On Tuesday 13 January 2009, Marco Martin wrote: > On Monday 12 January 2009, Aaron J. Seigo wrote: > > On Monday 12 January 2009, Marco Martin wrote: > > > if the possible positions are not that much (lets say something like on > > > the 4 corners) maybe using a single pixmap for caching would still be > > > possible? or maybe just if the position is consistent across instances > > > the impact on cache would still be acceptable hmm > > > > as long as this is cool with Pinheiro and his artistic vision, a limited > > # of positions us the best way to go imho. whether that's 4, 6 or 10 > > probably doesn't matter too much. > > > > once its in, we can play with tweaking the parameters around. > > > > > for the randomness: i would say still indicize in the cache for the > > > applet name but attach it to random numbers that controls the actual > > > positioning. the correspondence saved in a config file? like the one > > > for element rects? > > > > another approach is to use a single initially random seed and then just > > use that always. a random sequence is predictable if you know the first > > seed ;) or use that and a combination of the applet id and re-seed the > > generator each time. then we have only two variables max per widget, one > > of which is shared amongst all the widgets, so really only N+1 variables > > in total with the N variables already known to us via applet->id(). by > > reseeding with an initially random number + the id we get a constant set > > of "random" settings even when widgets are deleted. > > hmm, what about simply use applet id as seed and take first 2 sequence > number for the position? > would be quite deterministic and prevedible (given an id always the same > result) but i don't think it would be a problem and could keep things quite > simple > > i'm also experimenting in saving the position on applet config, quite done > also tthat patch(a bit bigger, changes also in applet.cpp) it would have a > bit more entropy
and the latter approach is attached :D (made applet friend of framesvg to avoid a pretty useless new api call) > Cheers, > Marco Martin > > > the random seed could be generated once and stored in corona->config() in > > the top-level, in [General], in [Corona] or in [Containments]. > > > > that means one more int read out of a file we already parse anyways. > > > > > (hmm the thing is becoming complex...) > > > > hehe.. KISS!
Index: framesvg.cpp =================================================================== --- framesvg.cpp (revision 910178) +++ framesvg.cpp (working copy) @@ -19,97 +19,23 @@ */ #include "framesvg.h" +#include "private/framesvg_p.h" #include <QPainter> #include <QSize> #include <QBitmap> #include <QRegion> #include <QTimer> +#include <QCryptographicHash> #include <kdebug.h> #include <plasma/theme.h> +#include <plasma/applet.h> namespace Plasma { -class FrameData -{ -public: - FrameData() - : enabledBorders(FrameSvg::AllBorders), - frameSize(-1,-1) - { - } - - FrameData(const FrameData &other) - : enabledBorders(other.enabledBorders), - frameSize(other.frameSize) - { - } - - ~FrameData() - { - } - - FrameSvg::EnabledBorders enabledBorders; - QPixmap cachedBackground; - QRegion cachedMask; - QSizeF frameSize; - - //measures - int topHeight; - int leftWidth; - int rightWidth; - int bottomHeight; - - //margins, are equal to the measures by default - int topMargin; - int leftMargin; - int rightMargin; - int bottomMargin; - - //size of the svg where the size of the "center" - //element is contentWidth x contentHeight - bool noBorderPadding : 1; - bool stretchBorders : 1; - bool tileCenter : 1; -}; - -class FrameSvgPrivate -{ -public: - FrameSvgPrivate(FrameSvg *psvg) - : q(psvg), - cacheAll(false), - saveTimer(0) - { - } - - ~FrameSvgPrivate() - { - qDeleteAll(frames); - frames.clear(); - } - - void generateBackground(FrameData *frame); - void scheduledCacheUpdate(); - void updateSizes(); - void updateNeeded(); - void updateAndSignalSizes(); - - Location location; - QString prefix; - - FrameSvg *q; - - bool cacheAll : 1; - QStringList framesToSave; - QTimer *saveTimer; - - QHash<QString, FrameData*> frames; -}; - FrameSvg::FrameSvg(QObject *parent) : Svg(parent), d(new FrameSvgPrivate(this)) @@ -338,45 +264,50 @@ } } -QRegion FrameSvg::mask() const +QPixmap FrameSvg::alphaMask() const { FrameData *frame = d->frames[d->prefix]; - if (frame->cachedMask.isEmpty()) { - // ivan: we are testing whether we have the mask prefixed - // elements to use for creating the mask. - if (hasElement("mask-" + d->prefix + "center")) { - QString oldPrefix = d->prefix; + if (hasElement("mask-" + d->prefix + "center")) { + QString oldPrefix = d->prefix; - // We are setting the prefix only temporary to generate - // the needed mask image - d->prefix = "mask-" + oldPrefix; + // We are setting the prefix only temporary to generate + // the needed mask image + d->prefix = "mask-" + oldPrefix; - if (!d->frames.contains(d->prefix)) { - d->frames.insert(d->prefix, new FrameData(*(d->frames[oldPrefix]))); - d->updateSizes(); - } + if (!d->frames.contains(d->prefix)) { + d->frames.insert(d->prefix, new FrameData(*(d->frames[oldPrefix]))); + d->updateSizes(); + } - FrameData *maskFrame = d->frames[d->prefix]; + FrameData *maskFrame = d->frames[d->prefix]; + if (maskFrame->cachedBackground.isNull() || maskFrame->frameSize != frame->frameSize ) { + maskFrame->frameSize = frame->frameSize; + maskFrame->cachedBackground = QPixmap(); + + d->generateBackground(maskFrame); if (maskFrame->cachedBackground.isNull()) { - d->generateBackground(maskFrame); - if (maskFrame->cachedBackground.isNull()) { - return QRegion(); - } + return QPixmap(); } + } - frame->cachedMask = QBitmap(maskFrame->cachedBackground.alphaChannel().createMaskFromColor(Qt::black)); - d->prefix = oldPrefix; - } else { + d->prefix = oldPrefix; + return maskFrame->cachedBackground; + } else { + if (frame->cachedBackground.isNull()) { + d->generateBackground(frame); if (frame->cachedBackground.isNull()) { - d->generateBackground(frame); - if (frame->cachedBackground.isNull()) { - return QRegion(); - } + return QPixmap(); } - frame->cachedMask = QRegion(QBitmap(frame->cachedBackground.alphaChannel().createMaskFromColor(Qt::black))); } + return frame->cachedBackground; } +} + +QRegion FrameSvg::mask() const +{ + FrameData *frame = d->frames[d->prefix]; + frame->cachedMask = QRegion(QBitmap(alphaMask().alphaChannel().createMaskFromColor(Qt::black))); return frame->cachedMask; } @@ -423,7 +354,16 @@ } } - return frame->cachedBackground; + //FIXME: composing with overlay each time makes it way slower, also caching another image isn't sooo good... + if (!hasElement(d->prefix+"hint-overlay-stretch")) { + return frame->cachedBackground; + } else { + QPixmap final = frame->cachedBackground; + QPainter p(&final); + d->generateOverlay(frame); + p.drawPixmap(QPoint(0,0), frame->cachedOverlay); + return final; + } } void FrameSvg::paintFrame(QPainter *painter, const QRectF &target, const QRectF &source) @@ -437,6 +377,11 @@ } painter->drawPixmap(target, frame->cachedBackground, source.isValid() ? source : target); + + d->generateOverlay(frame); + if (!frame->cachedOverlay.isNull()) { + painter->drawPixmap(target, frame->cachedOverlay, source.isValid() ? source : target); + } } void FrameSvg::paintFrame(QPainter *painter, const QPointF &pos) @@ -450,6 +395,11 @@ } painter->drawPixmap(pos, frame->cachedBackground); + + d->generateOverlay(frame); + if (!frame->cachedOverlay.isNull()) { + painter->drawPixmap(pos, frame->cachedOverlay); + } } void FrameSvgPrivate::generateBackground(FrameData *frame) @@ -458,6 +408,7 @@ return; } + QString id = QString::fromLatin1("%5_%4_%3_%2_%1_"). arg(frame->enabledBorders).arg(frame->frameSize.width()).arg(frame->frameSize.height()).arg(prefix).arg(q->imagePath()); @@ -639,9 +590,54 @@ saveTimer->start(300); } +void FrameSvgPrivate::generateOverlay(FrameData *frame) +{ + if (!prefix.startsWith("mask-") && q->hasElement(prefix+"overlay")) { + QPoint pos = QPoint(0, 0); + QSize overlaySize = q->elementSize(prefix+"overlay"); + + //Random pos, stretched and tiled are mutually exclusive + if (q->hasElement(prefix+"hint-overlay-random-pos")) { + pos = overlayPos; + //Stretched or Tiled? + } else if (q->hasElement(prefix+"hint-overlay-stretch") || q->hasElement(prefix+"hint-overlay-tile")) { + overlaySize = frame->frameSize.toSize(); + } + + QString id = QString::fromLatin1("overlay_%7_%6_%5_%4_%3_%2_%1_"). + arg(overlayPos.y()).arg(overlayPos.x()).arg(frame->enabledBorders).arg(frame->frameSize.width()).arg(frame->frameSize.height()).arg(prefix).arg(q->imagePath()); + + frame->cachedOverlay = QPixmap(frame->frameSize.toSize()); + frame->cachedOverlay.fill(Qt::transparent); + QPainter p(&frame->cachedOverlay); + + + QPixmap overlay = q->alphaMask(); + + QPainter overlayPainter(&overlay); + overlayPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + + //Tiling? + if (q->hasElement(prefix+"hint-overlay-tile")) { + q->resize(q->elementSize(prefix+"overlay")); + overlayPainter.drawTiledPixmap(QRect(QPoint(0,0), overlaySize), q->pixmap(prefix+"overlay")); + q->resize(); + } else { + q->paint(&overlayPainter, QRect(overlayPos, overlaySize), prefix+"overlay"); + } + overlayPainter.end(); + + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + + p.drawPixmap(overlayPos, overlay, QRect(overlayPos, overlaySize)); + } +} + + void FrameSvgPrivate::scheduledCacheUpdate() { foreach ( QString prefixToSave, framesToSave) { + //insert background FrameData *frame = frames[prefix]; framesToSave.removeAll(prefixToSave); @@ -651,6 +647,12 @@ //kDebug()<<"Saving to cache frame"<<id; Theme::defaultTheme()->insertIntoCache(id, frame->cachedBackground); + + //insert overlay + id = QString::fromLatin1("overlay_%7_%6_%5_%4_%3_%2_%1_"). + arg(overlayPos.y()).arg(overlayPos.x()).arg(frame->enabledBorders).arg(frame->frameSize.width()).arg(frame->frameSize.height()).arg(prefix).arg(q->imagePath()); + + Theme::defaultTheme()->insertIntoCache(id, frame->cachedBackground); } } Index: applet.h =================================================================== --- applet.h (revision 910178) +++ applet.h (working copy) @@ -36,6 +36,7 @@ #include <plasma/plasma.h> #include <plasma/animator.h> #include <plasma/version.h> +#include <plasma/framesvg.h> class QWidget; @@ -54,6 +55,7 @@ class ExtenderItem; class Package; + /** * @class Applet plasma/applet.h <Plasma/Applet> * Index: framesvg.h =================================================================== --- framesvg.h (revision 910178) +++ framesvg.h (working copy) @@ -76,6 +76,9 @@ class PLASMA_EXPORT FrameSvg : public Svg { Q_OBJECT + + friend class Applet; + public: /** * These flags represents what borders should be drawn @@ -205,6 +208,11 @@ */ Q_INVOKABLE QRegion mask() const; + /** + * @return a pixmap whose alpha channel is the opacity of the frame. It may be the frame itself or a special frame with the mask- prefix + */ + QPixmap alphaMask() const; + /** * Sets whether saving all the rendered prefixes in a cache or not * @arg cache if use the cache or not Index: applet.cpp =================================================================== --- applet.cpp (revision 910178) +++ applet.cpp (working copy) @@ -73,6 +73,7 @@ #include "scripting/appletscript.h" #include "svg.h" #include "framesvg.h" +#include "private/framesvg_p.h" #include "popupapplet.h" #include "theme.h" #include "view.h" @@ -123,6 +124,7 @@ } setParent(parentObject); + // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point d->init(); @@ -760,6 +762,16 @@ setMinimumSize(minimumSize().expandedTo(fitSize)); } d->background->resizeFrame(boundingRect().size()); + + d->background->d->overlayPos = config().readEntry("overlayPos", QPoint()); + if (d->background->d->overlayPos == QPoint()) { + qsrand(QDateTime::currentDateTime().toTime_t()); + QSize overlaySize = d->background->elementSize("overlay"); + d->background->d->overlayPos.rx() = qrand() % (overlaySize.width() + overlaySize.width()+ 1) - overlaySize.width(); + d->background->d->overlayPos.ry() = qrand() % (overlaySize.height() + overlaySize.height() + 1) - overlaySize.height(); + config().writeEntry("overlayPos", d->background->d->overlayPos); + } + } else if (d->background) { qreal left, top, right, bottom; d->background->getMargins(left, top, right, bottom); Index: private/framesvg_p.h =================================================================== --- private/framesvg_p.h (revision 0) +++ private/framesvg_p.h (revision 0) @@ -0,0 +1,111 @@ +/* + * Copyright 2008 by Aaron Seigo <ase...@kde.org> + * Copyright 2008 Marco Martin <notm...@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_FRAMESVG_P_H +#define PLASMA_FRAMESVG_P_H + +#include <QHash> + +namespace Plasma +{ +class FrameData +{ +public: + FrameData() + : enabledBorders(FrameSvg::AllBorders), + frameSize(-1,-1) + { + } + + FrameData(const FrameData &other) + : enabledBorders(other.enabledBorders), + frameSize(other.frameSize) + { + } + + ~FrameData() + { + } + + FrameSvg::EnabledBorders enabledBorders; + QPixmap cachedBackground; + QPixmap cachedOverlay; + QRegion cachedMask; + QSizeF frameSize; + + //measures + int topHeight; + int leftWidth; + int rightWidth; + int bottomHeight; + + //margins, are equal to the measures by default + int topMargin; + int leftMargin; + int rightMargin; + int bottomMargin; + + //size of the svg where the size of the "center" + //element is contentWidth x contentHeight + bool noBorderPadding : 1; + bool stretchBorders : 1; + bool tileCenter : 1; +}; + +class FrameSvgPrivate +{ +public: + FrameSvgPrivate(FrameSvg *psvg) + : q(psvg), + cacheAll(false), + saveTimer(0), + overlayPos(0,0) + { + } + + ~FrameSvgPrivate() + { + qDeleteAll(frames); + frames.clear(); + } + + void generateBackground(FrameData *frame); + void generateOverlay(FrameData *frame); + void scheduledCacheUpdate(); + void updateSizes(); + void updateNeeded(); + void updateAndSignalSizes(); + + Location location; + QString prefix; + + FrameSvg *q; + + bool cacheAll : 1; + QStringList framesToSave; + QTimer *saveTimer; + QPoint overlayPos; + + QHash<QString, FrameData*> frames; +}; + +} + +#endif
_______________________________________________ Plasma-devel mailing list Plasma-devel@kde.org https://mail.kde.org/mailman/listinfo/plasma-devel