Starting to implement pixmap based pulse animation. The first implementation

assumed that there would exist a complete copy of the animated widget to
do the pulse (where another object is kept translucent and when the animation
is triggered, it will expand and fade at same time).

But is expensive to copy the whole widget, so the idea is to draw the target
widget in a pixmap and then do the pulse effect on the pixmap itself.

It is still broken, for some reason the opacity is failing to animate (should
fix this tomorrow).


svn path=/trunk/KDE/kdelibs/; revision=1048277
This commit is contained in:
Adenilson Cavalcanti Da Silva 2009-11-13 01:20:51 +00:00
parent 7f971186ce
commit 702920c810
5 changed files with 172 additions and 54 deletions

View File

@ -106,6 +106,7 @@ set(plasma_LIB_SRCS
private/wallpaperrenderthread.cpp
private/windowpreview.cpp
private/kineticscroll.cpp
private/pulsershadow.cpp
querymatch.cpp
remote/accessmanager.cpp
remote/accessappletjob.cpp

View File

@ -21,7 +21,7 @@
*/
#include "pulser_p.h"
#include "plasma/private/pulsershadow_p.h"
#include <QAbstractAnimation>
#include <QDebug>
#include <QEvent>
@ -30,7 +30,6 @@
#include <QPropertyAnimation>
#include <kdebug.h>
namespace Plasma
{
@ -48,9 +47,14 @@ public :
scaleAnimation(0)
{}
~PulseAnimationPrivate()
{
if (pulseGeometry)
delete pulseGeometry;
}
QAbstractAnimation *animation;
QGraphicsWidget *under;
/* FIXME: clean up this guy */
QRectF *pulseGeometry;
qreal zvalue, mscale, mopacity;
QPropertyAnimation *opacityAnimation;
@ -58,6 +62,7 @@ public :
QPropertyAnimation *scaleAnimation;
};
PulseAnimation::PulseAnimation(): d(new PulseAnimationPrivate)
{
@ -65,76 +70,70 @@ PulseAnimation::PulseAnimation(): d(new PulseAnimationPrivate)
PulseAnimation::~PulseAnimation()
{
//XXX: current plasma::Animation model will delete all animation objects
// delete animation;
// delete pulseGeometry;
delete d;
}
void PulseAnimation::setCopy(QGraphicsWidget *copy)
void PulseAnimation::setCopy()
{
QGraphicsWidget *target = widgetToAnimate();
d->under = copy;
if (d->under == target) {
d->mopacity = d->under->opacity();
} else {
d->under->setParentItem(target);
d->mopacity = 0;
}
/* copy the parent to an image, the animation will happen on the
* pixmap copy.
*/
ShadowFake *shadow = 0;
if (!d->under)
shadow = new ShadowFake;
shadow->copyTarget(target);
if (d->pulseGeometry)
delete d->pulseGeometry;
d->pulseGeometry = new QRectF(target->geometry());
d->mopacity = 0;
d->zvalue = target->zValue();
--d->zvalue;
d->under->setOpacity(0);
d->mscale = target->scale();
d->under = shadow;
d->under->setOpacity(d->mopacity);
d->under->setScale(d->mscale);
d->under->setZValue(d->zvalue);
d->mscale = d->under->scale();
}
void PulseAnimation::resetPulser()
{
d->under->setGeometry(*d->pulseGeometry);
d->under->setGeometry(*(d->pulseGeometry));
d->under->setOpacity(d->mopacity);
d->under->setZValue(d->zvalue);
d->under->setScale(d->mscale);
d->under->setZValue(d->zvalue);
}
void PulseAnimation::createAnimation(qreal duration, qreal scale)
{
bool dirty = false;
QGraphicsWidget *target = widgetToAnimate();
/* Fallback to parent widget if we don't have one 'shadow' widget */
if (!d->under) {
setCopy(target);
} else if (d->under != target) {
delete d->under;
d->under = new QGraphicsWidget(target);
setCopy(d->under);
}
if (!d->under)
setCopy();
QParallelAnimationGroup *anim = dynamic_cast<QParallelAnimationGroup* >(animation());
if (!anim) {
d->pulseGeometry = new QRectF(d->under->geometry());
QParallelAnimationGroup *group = new QParallelAnimationGroup(this);
d->opacityAnimation = new QPropertyAnimation(d->under, "opacity");
d->opacityAnimation->setDuration(duration);
d->opacityAnimation->setStartValue(100);
d->opacityAnimation->setEndValue(0);
group->addAnimation(d->opacityAnimation);
/* TODO: move this to a function */
d->geometryAnimation = new QPropertyAnimation(d->under, "geometry");
d->geometryAnimation->setDuration(duration);
QRectF initial(d->under->geometry());
qreal W = initial.width() * scale * 0.33;
qreal H = initial.height() * scale * 0.33;
QRectF end(initial.x() - W, initial.y() - H, initial.width() * scale,
initial.height() * scale);
d->geometryAnimation->setEndValue(end);
group->addAnimation(d->geometryAnimation);
QPointF tmp(initial.width() * 0.5, initial.height() * 0.5);
d->under->setTransformOriginPoint(tmp);
d->scaleAnimation = new QPropertyAnimation(d->under, "scale");
d->scaleAnimation->setDuration(duration);
d->scaleAnimation->setStartValue(d->mscale);
d->scaleAnimation->setEndValue(scale);
/* The group takes ownership of all animations */
group->addAnimation(d->scaleAnimation);
d->animation = group;
@ -143,8 +142,6 @@ void PulseAnimation::createAnimation(qreal duration, qreal scale)
} else {
/* Stop the animation or the widget will be deformed.
*/
QAbstractAnimation::State temp = anim->state();
if (temp == QAbstractAnimation::Running) {
anim->stop();
@ -152,24 +149,24 @@ void PulseAnimation::createAnimation(qreal duration, qreal scale)
* and *then* reset the geometry
*/
} else {
/* TODO: move this to a function */
*(d->pulseGeometry) = d->under->geometry();
if ((*d->pulseGeometry) != widgetToAnimate()->geometry()) {
/*FIXME: it crashes when deleting old the image in ShadowFake
* setCopy();
*/
qDebug() << "PulseAnimation:: it should update the geom....";
}
d->opacityAnimation->setEndValue(0);
d->scaleAnimation->setEndValue(scale);
QRectF initial(d->under->geometry());
qreal W = initial.width() * scale * 0.33;
qreal H = initial.height() * scale * 0.33;
QRectF end(initial.x() - W, initial.y() - H, initial.width() * scale,
initial.height() * scale);
d->geometryAnimation->setEndValue(end);
QPointF tmp(initial.width() * 0.5, initial.height() * 0.5);
d->under->setTransformOriginPoint(tmp);
}
}
if (dirty) {
//This makes sure that if there is *not* a shadow widget, the
//parent widget will still remain visible
if (dirty)
connect(d->animation, SIGNAL(finished()), this, SLOT(resetPulser()));
}
}
QAbstractAnimation* PulseAnimation::render(QObject* parent)
@ -177,7 +174,6 @@ QAbstractAnimation* PulseAnimation::render(QObject* parent)
Q_UNUSED(parent)
createAnimation(duration());
d->under->setOpacity(1);
return d->animation;
}

View File

@ -36,7 +36,7 @@ public:
~PulseAnimation();
void updateGeometry(QRectF updated, qreal zCoordinate = 0, qreal scale = 1.5);
void setCopy(QGraphicsWidget *copy);
void setCopy();
public Q_SLOTS:
void resetPulser();

71
private/pulsershadow.cpp Normal file
View File

@ -0,0 +1,71 @@
/*********************************************************************/
/* */
/* Copyright(C)2009 Adenilson Cavalcanti adenilson.silva@idnt.org.br */
/* */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version 2 */
/* of the License, 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 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. */
/*********************************************************************/
#include "pulsershadow_p.h"
#include <QPainter>
#include <QImage>
#include <QPixmap>
#include <QDebug>
namespace Plasma
{
ShadowFake::ShadowFake(QGraphicsItem *parent): QGraphicsWidget(parent),
photo(0)
{ }
ShadowFake::~ShadowFake()
{
delete photo;
}
void ShadowFake::copyTarget(QGraphicsWidget *target)
{
setParentItem(target);
setGeometry(target->geometry());
QSize size(target->size().toSize());
if (photo)
delete photo;
photo = new QPixmap(size);
photo->fill(Qt::transparent);
QPainter painter(photo);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.fillRect(target->rect(), Qt::transparent);
target->paint(&painter, 0, 0);
painter.end();
qDebug() << "ShadowFake: copy....";
}
void ShadowFake::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(widget);
Q_UNUSED(option);
qDebug() << "ShadowFake: painter..." << photo->rect();
painter->setRenderHint(QPainter::Antialiasing);
painter->drawPixmap(0, 0, *photo);
}
}

50
private/pulsershadow_p.h Normal file
View File

@ -0,0 +1,50 @@
/*********************************************************************/
/* */
/* Copyright(C)2009 Adenilson Cavalcanti adenilson.silva@idnt.org.br */
/* */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License */
/* as published by the Free Software Foundation; either version 2 */
/* of the License, 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 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 PULSERSHADOW_P_H
#define PULSERSHADOW_P_H
#include <QGraphicsWidget>
namespace Plasma
{
class ShadowFake: public QGraphicsWidget
{
Q_OBJECT
public:
ShadowFake(QGraphicsItem *parent = 0);
~ShadowFake();
void copyTarget(QGraphicsWidget *target);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
private:
QPixmap *photo;
};
}
#endif