* 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;
|
||||
};
|
||||
|
||||
struct CustomAnimationState
|
||||
{
|
||||
Phase::CurveShape curve;
|
||||
int frames;
|
||||
int currentFrame;
|
||||
int interval;
|
||||
int currentInterval;
|
||||
Phase::AnimId id;
|
||||
QObject* receiver;
|
||||
char* slot;
|
||||
};
|
||||
|
||||
class Phase::Private
|
||||
{
|
||||
public:
|
||||
|
@ -85,10 +97,27 @@ class Phase::Private
|
|||
{
|
||||
qDeleteAll(animatedItems);
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
switch (state->animation) {
|
||||
|
@ -114,11 +143,11 @@ class Phase::Private
|
|||
{
|
||||
switch (state->movement) {
|
||||
case Phase::SlideIn:
|
||||
kDebug() << "performMovement, SlideIn";
|
||||
//kDebug() << "performMovement, SlideIn";
|
||||
animator->slideIn(amount, state->item, state->start, state->destination);
|
||||
break;
|
||||
case Phase::SlideOut:
|
||||
kDebug() << "performMovement, SlideOut";
|
||||
//kDebug() << "performMovement, SlideOut";
|
||||
animator->slideOut(amount, state->item, state->start, state->destination);
|
||||
break;
|
||||
}
|
||||
|
@ -134,6 +163,7 @@ class Phase::Private
|
|||
QMap<QGraphicsItem*, AnimationState*> animatedItems;
|
||||
QMap<QGraphicsItem*, MovementState*> movingItems;
|
||||
QMap<Phase::AnimId, ElementAnimationState*> animatedElements;
|
||||
QMap<AnimId, CustomAnimationState*> customAnims;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
//kDebug() << "startElementAnimation(AnimId " << animation << ")";
|
||||
|
@ -364,9 +450,7 @@ void Phase::timerEvent(QTimerEvent *event)
|
|||
state->currentFrame += qMax(1, elapsed / state->interval);
|
||||
|
||||
if (state->currentFrame < state->frames) {
|
||||
qreal progress = state->frames;
|
||||
progress = state->currentFrame / progress;
|
||||
progress = qMin(1.0, qMax(0.0, progress));
|
||||
qreal progress = d->calculateProgress(state->frames, state->currentFrame);
|
||||
d->performAnimation(progress, state);
|
||||
state->currentInterval = state->interval;
|
||||
//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);
|
||||
|
||||
if (state->currentFrame < state->frames) {
|
||||
qreal progress = state->frames;
|
||||
progress = state->currentFrame / progress;
|
||||
progress = qMin(1.0, qMax(0.0, progress));
|
||||
d->performMovement(progress, state);
|
||||
d->performMovement(d->calculateProgress(state->frames, state->currentFrame), state);
|
||||
//TODO: calculate a proper interval based on the curve
|
||||
state->currentInterval = state->interval;
|
||||
animationsRemain = true;
|
||||
} else {
|
||||
|
@ -428,10 +510,7 @@ void Phase::timerEvent(QTimerEvent *event)
|
|||
if (state->currentFrame < state->frames) {
|
||||
state->currentInterval = state->interval;
|
||||
//TODO: calculate a proper interval based on the curve
|
||||
qreal progress = state->frames;
|
||||
progress = state->currentFrame / progress;
|
||||
progress = qMin(1.0, qMax(0.0, progress));
|
||||
state->interval *= 1 - progress;
|
||||
state->interval *= 1 - d->calculateProgress(state->frames, state->currentFrame);
|
||||
animationsRemain = true;
|
||||
}
|
||||
} 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) {
|
||||
killTimer(d->timerId);
|
||||
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 moveItem(QGraphicsItem* item, Movement movement, const QPoint &destination);
|
||||
|
||||
AnimId animateElement(QGraphicsItem *obj, ElementAnimation);
|
||||
void stopElementAnimation(AnimId id);
|
||||
void setAnimationPixmap(AnimId id, const QPixmap &pixmap);
|
||||
QPixmap animationResult(AnimId id);
|
||||
/**
|
||||
* Starts a custom animation, preventing the need to create a timeline
|
||||
* with its own timer tick.
|
||||
*
|
||||
* @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:
|
||||
void animationComplete(QGraphicsItem *item, Animation anim);
|
||||
|
@ -98,6 +122,7 @@ protected:
|
|||
|
||||
protected Q_SLOTS:
|
||||
void appletDestroyed(QObject*);
|
||||
void customAnimReceiverDestroyed(QObject*);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
|
Loading…
Reference in New Issue
Block a user