* memory leak: delete all the outstanding movements
* add the ability to use Phase's coordinated tick for custom animations svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=724392
This commit is contained in:
parent
79d929e848
commit
7d29f75f4a
131
phase.cpp
131
phase.cpp
|
@ -70,6 +70,18 @@ struct MovementState
|
||||||
QPoint destination;
|
QPoint destination;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CustomAnimationState
|
||||||
|
{
|
||||||
|
Phase::CurveShape curve;
|
||||||
|
int frames;
|
||||||
|
int currentFrame;
|
||||||
|
int interval;
|
||||||
|
int currentInterval;
|
||||||
|
Phase::AnimId id;
|
||||||
|
QObject* receiver;
|
||||||
|
char* slot;
|
||||||
|
};
|
||||||
|
|
||||||
class Phase::Private
|
class Phase::Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -85,10 +97,27 @@ class Phase::Private
|
||||||
{
|
{
|
||||||
qDeleteAll(animatedItems);
|
qDeleteAll(animatedItems);
|
||||||
qDeleteAll(animatedElements);
|
qDeleteAll(animatedElements);
|
||||||
|
qDeleteAll(movingItems);
|
||||||
|
|
||||||
|
QMutableMapIterator<AnimId, CustomAnimationState*> it(customAnims);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
delete it.value()->slot;
|
||||||
|
delete it.value();
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
|
||||||
// Animator is a QObject
|
// Animator is a QObject
|
||||||
// and we don't own the items
|
// and we don't own the items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal calculateProgress(int frames, int currentFrame)
|
||||||
|
{
|
||||||
|
qreal progress = frames;
|
||||||
|
progress = currentFrame / progress;
|
||||||
|
progress = qMin(1.0, qMax(0.0, progress));
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
void performAnimation(qreal amount, const AnimationState* state)
|
void performAnimation(qreal amount, const AnimationState* state)
|
||||||
{
|
{
|
||||||
switch (state->animation) {
|
switch (state->animation) {
|
||||||
|
@ -114,11 +143,11 @@ class Phase::Private
|
||||||
{
|
{
|
||||||
switch (state->movement) {
|
switch (state->movement) {
|
||||||
case Phase::SlideIn:
|
case Phase::SlideIn:
|
||||||
kDebug() << "performMovement, SlideIn";
|
//kDebug() << "performMovement, SlideIn";
|
||||||
animator->slideIn(amount, state->item, state->start, state->destination);
|
animator->slideIn(amount, state->item, state->start, state->destination);
|
||||||
break;
|
break;
|
||||||
case Phase::SlideOut:
|
case Phase::SlideOut:
|
||||||
kDebug() << "performMovement, SlideOut";
|
//kDebug() << "performMovement, SlideOut";
|
||||||
animator->slideOut(amount, state->item, state->start, state->destination);
|
animator->slideOut(amount, state->item, state->start, state->destination);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -134,6 +163,7 @@ class Phase::Private
|
||||||
QMap<QGraphicsItem*, AnimationState*> animatedItems;
|
QMap<QGraphicsItem*, AnimationState*> animatedItems;
|
||||||
QMap<QGraphicsItem*, MovementState*> movingItems;
|
QMap<QGraphicsItem*, MovementState*> movingItems;
|
||||||
QMap<Phase::AnimId, ElementAnimationState*> animatedElements;
|
QMap<Phase::AnimId, ElementAnimationState*> animatedElements;
|
||||||
|
QMap<AnimId, CustomAnimationState*> customAnims;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhaseSingleton
|
class PhaseSingleton
|
||||||
|
@ -184,6 +214,18 @@ void Phase::appletDestroyed(QObject* o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Phase::customAnimReceiverDestroyed(QObject* o)
|
||||||
|
{
|
||||||
|
QMutableMapIterator<AnimId, CustomAnimationState*> it(d->customAnims);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
if (it.next().value()->receiver == o) {
|
||||||
|
delete it.value()->slot;
|
||||||
|
delete it.value();
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Phase::animateItem(QGraphicsItem* item, Animation animation)
|
void Phase::animateItem(QGraphicsItem* item, Animation animation)
|
||||||
{
|
{
|
||||||
//kDebug();
|
//kDebug();
|
||||||
|
@ -261,6 +303,50 @@ void Phase::moveItem(QGraphicsItem* item, Movement movement, const QPoint &desti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Phase::AnimId Phase::customAnimation(int frames, int duration, Phase::CurveShape curve,
|
||||||
|
QObject* receiver, const char* slot)
|
||||||
|
{
|
||||||
|
if (frames < 1 || duration < 1 || !receiver || !slot) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomAnimationState *state = new CustomAnimationState;
|
||||||
|
state->id = ++d->animId;
|
||||||
|
state->frames = frames;
|
||||||
|
state->currentFrame = 0;
|
||||||
|
state->curve = curve;
|
||||||
|
state->interval = duration / qreal(state->frames);
|
||||||
|
state->interval = (state->interval / 40) * 40;
|
||||||
|
state->currentInterval = state->interval;
|
||||||
|
state->receiver = receiver;
|
||||||
|
state->slot = qstrdup(slot);
|
||||||
|
|
||||||
|
d->customAnims[state->id] = state;
|
||||||
|
|
||||||
|
connect(receiver, SLOT(objectDestroyed(QObject*)),
|
||||||
|
this, SLOT(customAnimReceiverDestroyed(QObject*)));
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(receiver, slot, Q_ARG(qreal, 0));
|
||||||
|
|
||||||
|
if (!d->timerId) {
|
||||||
|
d->timerId = startTimer(40);
|
||||||
|
d->time.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
return state->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Phase::stopCustomAnimation(AnimId id)
|
||||||
|
{
|
||||||
|
QMap<AnimId, CustomAnimationState*>::iterator it = d->customAnims.find(id);
|
||||||
|
if (it != d->customAnims.end()) {
|
||||||
|
delete it.value()->slot;
|
||||||
|
delete it.value();
|
||||||
|
d->customAnims.erase(it);
|
||||||
|
}
|
||||||
|
//kDebug() << "stopCustomAnimation(AnimId " << id << ") done";
|
||||||
|
}
|
||||||
|
|
||||||
Phase::AnimId Phase::animateElement(QGraphicsItem *item, ElementAnimation animation)
|
Phase::AnimId Phase::animateElement(QGraphicsItem *item, ElementAnimation animation)
|
||||||
{
|
{
|
||||||
//kDebug() << "startElementAnimation(AnimId " << animation << ")";
|
//kDebug() << "startElementAnimation(AnimId " << animation << ")";
|
||||||
|
@ -364,9 +450,7 @@ void Phase::timerEvent(QTimerEvent *event)
|
||||||
state->currentFrame += qMax(1, elapsed / state->interval);
|
state->currentFrame += qMax(1, elapsed / state->interval);
|
||||||
|
|
||||||
if (state->currentFrame < state->frames) {
|
if (state->currentFrame < state->frames) {
|
||||||
qreal progress = state->frames;
|
qreal progress = d->calculateProgress(state->frames, state->currentFrame);
|
||||||
progress = state->currentFrame / progress;
|
|
||||||
progress = qMin(1.0, qMax(0.0, progress));
|
|
||||||
d->performAnimation(progress, state);
|
d->performAnimation(progress, state);
|
||||||
state->currentInterval = state->interval;
|
state->currentInterval = state->interval;
|
||||||
//TODO: calculate a proper interval based on the curve
|
//TODO: calculate a proper interval based on the curve
|
||||||
|
@ -390,10 +474,8 @@ void Phase::timerEvent(QTimerEvent *event)
|
||||||
state->currentFrame += qMax(1, elapsed / state->interval);
|
state->currentFrame += qMax(1, elapsed / state->interval);
|
||||||
|
|
||||||
if (state->currentFrame < state->frames) {
|
if (state->currentFrame < state->frames) {
|
||||||
qreal progress = state->frames;
|
d->performMovement(d->calculateProgress(state->frames, state->currentFrame), state);
|
||||||
progress = state->currentFrame / progress;
|
//TODO: calculate a proper interval based on the curve
|
||||||
progress = qMin(1.0, qMax(0.0, progress));
|
|
||||||
d->performMovement(progress, state);
|
|
||||||
state->currentInterval = state->interval;
|
state->currentInterval = state->interval;
|
||||||
animationsRemain = true;
|
animationsRemain = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -428,10 +510,7 @@ void Phase::timerEvent(QTimerEvent *event)
|
||||||
if (state->currentFrame < state->frames) {
|
if (state->currentFrame < state->frames) {
|
||||||
state->currentInterval = state->interval;
|
state->currentInterval = state->interval;
|
||||||
//TODO: calculate a proper interval based on the curve
|
//TODO: calculate a proper interval based on the curve
|
||||||
qreal progress = state->frames;
|
state->interval *= 1 - d->calculateProgress(state->frames, state->currentFrame);
|
||||||
progress = state->currentFrame / progress;
|
|
||||||
progress = qMin(1.0, qMax(0.0, progress));
|
|
||||||
state->interval *= 1 - progress;
|
|
||||||
animationsRemain = true;
|
animationsRemain = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -440,6 +519,32 @@ void Phase::timerEvent(QTimerEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (CustomAnimationState *state, d->customAnims) {
|
||||||
|
if (state->currentInterval <= elapsed) {
|
||||||
|
// advance the frame
|
||||||
|
state->currentFrame += qMax(1, elapsed / state->interval);
|
||||||
|
|
||||||
|
|
||||||
|
if (state->currentFrame < state->frames) {
|
||||||
|
//TODO: calculate a proper interval based on the curve
|
||||||
|
state->currentInterval = state->interval;
|
||||||
|
animationsRemain = true;
|
||||||
|
// signal the object
|
||||||
|
QMetaObject::invokeMethod(state->receiver, state->slot,
|
||||||
|
Q_ARG(qreal,
|
||||||
|
d->calculateProgress(state->frames, state->currentFrame)));
|
||||||
|
} else {
|
||||||
|
QMetaObject::invokeMethod(state->receiver, state->slot, Q_ARG(qreal, 1));
|
||||||
|
d->customAnims.erase(d->customAnims.find(state->id));
|
||||||
|
delete state->slot;
|
||||||
|
delete state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state->currentInterval -= elapsed;
|
||||||
|
animationsRemain = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!animationsRemain && d->timerId) {
|
if (!animationsRemain && d->timerId) {
|
||||||
killTimer(d->timerId);
|
killTimer(d->timerId);
|
||||||
d->timerId = 0;
|
d->timerId = 0;
|
||||||
|
|
33
phase.h
33
phase.h
|
@ -84,10 +84,34 @@ public:
|
||||||
Q_INVOKABLE void animateItem(QGraphicsItem* item, Animation anim);
|
Q_INVOKABLE void animateItem(QGraphicsItem* item, Animation anim);
|
||||||
Q_INVOKABLE void moveItem(QGraphicsItem* item, Movement movement, const QPoint &destination);
|
Q_INVOKABLE void moveItem(QGraphicsItem* item, Movement movement, const QPoint &destination);
|
||||||
|
|
||||||
AnimId animateElement(QGraphicsItem *obj, ElementAnimation);
|
/**
|
||||||
void stopElementAnimation(AnimId id);
|
* Starts a custom animation, preventing the need to create a timeline
|
||||||
void setAnimationPixmap(AnimId id, const QPixmap &pixmap);
|
* with its own timer tick.
|
||||||
QPixmap animationResult(AnimId id);
|
*
|
||||||
|
* @arg frames the number of frames this animation should persist for
|
||||||
|
* @arg duration the length, in milliseconds, the animation will take
|
||||||
|
* @arg curve the curve applied to the frame rate
|
||||||
|
* @arg receive the object that will handle the actual animation
|
||||||
|
* @arg slot the slot to be invoked on each update
|
||||||
|
*
|
||||||
|
* @return an id that can be used to identify this animation.
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE AnimId customAnimation(int frames, int duration, Phase::CurveShape curve,
|
||||||
|
QObject* receiver, const char* slot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a custom animation. Note that it is not necessary to call
|
||||||
|
* this on object destruction, as custom animations associated with
|
||||||
|
* a given QObject are cleaned up automatically on QObject destruction.
|
||||||
|
*
|
||||||
|
* @arg id the id of the animation as returned by customAnimation
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE void stopCustomAnimation(AnimId id);
|
||||||
|
|
||||||
|
Q_INVOKABLE AnimId animateElement(QGraphicsItem *obj, ElementAnimation);
|
||||||
|
Q_INVOKABLE void stopElementAnimation(AnimId id);
|
||||||
|
Q_INVOKABLE void setAnimationPixmap(AnimId id, const QPixmap &pixmap);
|
||||||
|
Q_INVOKABLE QPixmap animationResult(AnimId id);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void animationComplete(QGraphicsItem *item, Animation anim);
|
void animationComplete(QGraphicsItem *item, Animation anim);
|
||||||
|
@ -98,6 +122,7 @@ protected:
|
||||||
|
|
||||||
protected Q_SLOTS:
|
protected Q_SLOTS:
|
||||||
void appletDestroyed(QObject*);
|
void appletDestroyed(QObject*);
|
||||||
|
void customAnimReceiverDestroyed(QObject*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user