quite mega-patch:

add a new function FrameSvg::alphaMask() that lets define an alpha-layer
for the frame, that can be the frame itself or a mask- prefix
allow for overlay elements on frames that can do a nice
filigrane-effect, they can either be:
-fixed position at 0,0
-random position consistent across plasma runs (only supported for applet
backgrounds)
-tiled
-scaled

svn path=/trunk/KDE/kdelibs/; revision=910655
This commit is contained in:
Marco Martin 2009-01-13 21:46:07 +00:00
parent 22179dffbb
commit 831f2564d8
5 changed files with 227 additions and 109 deletions

View File

@ -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 @@ Applet::Applet(QObject *parentObject, const QVariantList &args)
}
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,26 @@ void Applet::setBackgroundHints(const BackgroundHints hints)
setMinimumSize(minimumSize().expandedTo(fitSize));
}
d->background->resizeFrame(boundingRect().size());
//if the background has an "overlay" element decide a random position for it and then save it so it's consistent across plasma starts
if (d->background->hasElement("overlay")) {
QSize overlaySize = d->background->elementSize("overlay");
d->background->d->overlayPos = config().readEntry("overlayposition", QPoint(overlaySize.width()*2, overlaySize.height()*2));
//position can never be overlaySize.width()*2, overlaySize.height()*2, if it is means we didn't found the position in the config file, or the theme is changed and the overlay size is smaller now
if (d->background->d->overlayPos.x() >= overlaySize.width()*2 ||
d->background->d->overlayPos.y() >= overlaySize.height()*2) {
qsrand(id() + QDateTime::currentDateTime().toTime_t());
d->background->d->overlayPos.rx() = - (overlaySize.width() /4) + (overlaySize.width() /4) * (qrand() % (4 + 1));
d->background->d->overlayPos.ry() = - (overlaySize.height() /4) + (overlaySize.height() /4) * (qrand() % (4 + 1));
config().writeEntry("overlayposition", d->background->d->overlayPos);
}
}
} else if (d->background) {
qreal left, top, right, bottom;
d->background->getMargins(left, top, right, bottom);

View File

@ -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 Extender;
class ExtenderItem;
class Package;
/**
* @class Applet plasma/applet.h <Plasma/Applet>
*

View File

@ -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 @@ QRectF FrameSvg::contentsRect() const
}
}
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();
}
FrameData *maskFrame = d->frames[d->prefix];
if (maskFrame->cachedBackground.isNull()) {
d->generateBackground(maskFrame);
if (maskFrame->cachedBackground.isNull()) {
return QRegion();
}
}
frame->cachedMask = QBitmap(maskFrame->cachedBackground.alphaChannel().createMaskFromColor(Qt::black));
d->prefix = oldPrefix;
} else {
if (frame->cachedBackground.isNull()) {
d->generateBackground(frame);
if (frame->cachedBackground.isNull()) {
return QRegion();
}
}
frame->cachedMask = QRegion(QBitmap(frame->cachedBackground.alphaChannel().createMaskFromColor(Qt::black)));
if (!d->frames.contains(d->prefix)) {
d->frames.insert(d->prefix, new FrameData(*(d->frames[oldPrefix])));
d->updateSizes();
}
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()) {
return QPixmap();
}
}
d->prefix = oldPrefix;
return maskFrame->cachedBackground;
} else {
if (frame->cachedBackground.isNull()) {
d->generateBackground(frame);
if (frame->cachedBackground.isNull()) {
return QPixmap();
}
}
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,6 +354,7 @@ QPixmap FrameSvg::framePixmap()
}
}
return frame->cachedBackground;
}
@ -458,6 +390,7 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
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());
@ -632,6 +565,42 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
}
}
//Overlays
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());
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));
}
if (!framesToSave.contains(prefix)) {
framesToSave.append(prefix);
}
@ -639,9 +608,11 @@ void FrameSvgPrivate::generateBackground(FrameData *frame)
saveTimer->start(300);
}
void FrameSvgPrivate::scheduledCacheUpdate()
{
foreach ( QString prefixToSave, framesToSave) {
//insert background
FrameData *frame = frames[prefix];
framesToSave.removeAll(prefixToSave);
@ -651,6 +622,12 @@ void FrameSvgPrivate::scheduledCacheUpdate()
//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);
}
}

View File

@ -76,6 +76,9 @@ class FrameSvgPrivate;
class PLASMA_EXPORT FrameSvg : public Svg
{
Q_OBJECT
friend class Applet;
public:
/**
* These flags represents what borders should be drawn
@ -205,6 +208,11 @@ class PLASMA_EXPORT FrameSvg : public Svg
*/
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

109
private/framesvg_p.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright 2008 by Aaron Seigo <aseigo@kde.org>
* Copyright 2009 Marco Martin <notmart@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;
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 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