allow to retarget animations

icc-effect-5.14.5
Thomas Lübking 2016-02-03 17:36:48 +01:00
parent 07cc30d136
commit 1faa8aa039
2 changed files with 122 additions and 68 deletions

View File

@ -92,114 +92,133 @@ bool AnimationEffect::isActive() const
#define RELATIVE_XY(_FIELD_) const bool relative[2] = { static_cast<bool>(metaData(Relative##_FIELD_##X, meta)), \
static_cast<bool>(metaData(Relative##_FIELD_##Y, meta)) }
quint64 AnimationEffect::p_animate( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve, int delay, FPx2 from, bool keepAtTarget )
void AnimationEffect::validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, const EffectWindow *w) const
{
const bool waitAtSource = from.isValid();
if (a < NonFloatBase) {
if (a == Scale) {
QRect area = effects->clientArea(ScreenArea , w);
if (from.isValid()) {
if (from && from->isValid()) {
RELATIVE_XY(Source);
from.set( relative[0] ? from[0] * area.width() / w->width() : from[0],
relative[1] ? from[1] * area.height() / w->height() : from[1] );
from->set(relative[0] ? (*from)[0] * area.width() / w->width() : (*from)[0],
relative[1] ? (*from)[1] * area.height() / w->height() : (*from)[1]);
}
if (to.isValid()) {
if (to && to->isValid()) {
RELATIVE_XY(Target);
to.set( relative[0] ? to[0] * area.width() / w->width() : to[0],
relative[1] ? to[1] * area.height() / w->height() : to[1] );
to->set(relative[0] ? (*to)[0] * area.width() / w->width() : (*to)[0],
relative[1] ? (*to)[1] * area.height() / w->height() : (*to)[1] );
}
} else if (a == Rotation) {
if (!from.isValid()) {
setMetaData( SourceAnchor, metaData(TargetAnchor, meta), meta );
from.set(0.0,0.0);
if (from && !from->isValid()) {
setMetaData(SourceAnchor, metaData(TargetAnchor, meta), meta);
from->set(0.0,0.0);
}
if (!to.isValid()) {
setMetaData( TargetAnchor, metaData(SourceAnchor, meta), meta );
to.set(0.0,0.0);
if (to && !to->isValid()) {
setMetaData(TargetAnchor, metaData(SourceAnchor, meta), meta);
to->set(0.0,0.0);
}
}
if (!from.isValid())
from.set(1.0,1.0);
if (!to.isValid())
to.set(1.0,1.0);
if (from && !from->isValid())
from->set(1.0,1.0);
if (to && !to->isValid())
to->set(1.0,1.0);
} else if (a == Position) {
QRect area = effects->clientArea(ScreenArea , w);
QPoint pt = w->geometry().bottomRight(); // cannot be < 0 ;-)
if (from.isValid()) {
RELATIVE_XY(Source);
from.set( relative[0] ? area.x() + from[0] * area.width() : from[0],
relative[1] ? area.y() + from[1] * area.height() : from[1] );
} else {
from.set(pt.x(), pt.y());
setMetaData( SourceAnchor, AnimationEffect::Bottom|AnimationEffect::Right, meta );
if (from) {
if (from->isValid()) {
RELATIVE_XY(Source);
from->set(relative[0] ? area.x() + (*from)[0] * area.width() : (*from)[0],
relative[1] ? area.y() + (*from)[1] * area.height() : (*from)[1]);
} else {
from->set(pt.x(), pt.y());
setMetaData(SourceAnchor, AnimationEffect::Bottom|AnimationEffect::Right, meta);
}
}
if (to.isValid()) {
RELATIVE_XY(Target);
to.set( relative[0] ? area.x() + to[0] * area.width() : to[0],
relative[1] ? area.y() + to[1] * area.height() : to[1] );
} else {
to.set(pt.x(), pt.y());
setMetaData( TargetAnchor, AnimationEffect::Bottom|AnimationEffect::Right, meta );
if (to) {
if (to->isValid()) {
RELATIVE_XY(Target);
to->set(relative[0] ? area.x() + (*to)[0] * area.width() : (*to)[0],
relative[1] ? area.y() + (*to)[1] * area.height() : (*to)[1]);
} else {
to->set(pt.x(), pt.y());
setMetaData( TargetAnchor, AnimationEffect::Bottom|AnimationEffect::Right, meta );
}
}
} else if (a == Size) {
QRect area = effects->clientArea(ScreenArea , w);
if (from.isValid()) {
RELATIVE_XY(Source);
from.set( relative[0] ? from[0] * area.width() : from[0],
relative[1] ? from[1] * area.height() : from[1] );
} else {
from.set(w->width(), w->height());
if (from) {
if (from->isValid()) {
RELATIVE_XY(Source);
from->set(relative[0] ? (*from)[0] * area.width() : (*from)[0],
relative[1] ? (*from)[1] * area.height() : (*from)[1]);
} else {
from->set(w->width(), w->height());
}
}
if (to.isValid()) {
RELATIVE_XY(Target);
to.set( relative[0] ? to[0] * area.width() : to[0],
relative[1] ? to[1] * area.height() : to[1] );
} else {
to.set(w->width(), w->height());
if (to) {
if (from->isValid()) {
RELATIVE_XY(Target);
to->set(relative[0] ? (*to)[0] * area.width() : (*to)[0],
relative[1] ? (*to)[1] * area.height() : (*to)[1]);
} else {
to->set(w->width(), w->height());
}
}
} else if (a == Translation) {
QRect area = w->rect();
if (from.isValid()) {
RELATIVE_XY(Source);
from.set( relative[0] ? from[0] * area.width() : from[0],
relative[1] ? from[1] * area.height() : from[1] );
} else {
from.set(0.0, 0.0);
if (from) {
if (from->isValid()) {
RELATIVE_XY(Source);
from->set(relative[0] ? (*from)[0] * area.width() : (*from)[0],
relative[1] ? (*from)[1] * area.height() : (*from)[1]);
} else {
from->set(0.0, 0.0);
}
}
if (to.isValid()) {
RELATIVE_XY(Target);
to.set( relative[0] ? to[0] * area.width() : to[0],
relative[1] ? to[1] * area.height() : to[1] );
} else {
to.set(0.0, 0.0);
if (to) {
if (from->isValid()) {
RELATIVE_XY(Target);
to->set(relative[0] ? (*to)[0] * area.width() : (*to)[0],
relative[1] ? (*to)[1] * area.height() : (*to)[1]);
} else {
to->set(0.0, 0.0);
}
}
} else if (a == Clip) {
if (!from.isValid()) {
from.set(1.0,1.0);
setMetaData( SourceAnchor, metaData(TargetAnchor, meta), meta );
if (from && !from->isValid()) {
from->set(1.0,1.0);
setMetaData(SourceAnchor, metaData(TargetAnchor, meta), meta);
}
if (!to.isValid()) {
to.set(1.0,1.0);
setMetaData( TargetAnchor, metaData(SourceAnchor, meta), meta );
if (to && !to->isValid()) {
to->set(1.0,1.0);
setMetaData(TargetAnchor, metaData(SourceAnchor, meta), meta);
}
} else if (a == CrossFadePrevious) {
if (!from.isValid()) {
from.set(0.0);
if (from && !from->isValid()) {
from->set(0.0);
}
if (!to.isValid()) {
to.set(1.0);
if (to && !to->isValid()) {
to->set(1.0);
}
w->referencePreviousWindowPixmap();
}
}
quint64 AnimationEffect::p_animate( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve, int delay, FPx2 from, bool keepAtTarget )
{
const bool waitAtSource = from.isValid();
validate(a, meta, &from, &to, w);
if (a == CrossFadePrevious)
w->referencePreviousWindowPixmap();
Q_D(AnimationEffect);
if (!d->m_isInitialized)
@ -233,6 +252,27 @@ quint64 AnimationEffect::p_animate( EffectWindow *w, Attribute a, uint meta, int
return ret_id;
}
bool AnimationEffect::retarget(quint64 animationId, FPx2 newTarget, int newRemainingTime)
{
Q_D(AnimationEffect);
if (animationId == d->m_justEndedAnimation)
return false; // this is just ending, do not try to retarget it
for (AniMap::iterator entry = d->m_animations.begin(),
mapEnd = d->m_animations.end(); entry != mapEnd; ++entry) {
for (QList<AniData>::iterator anim = entry->first.begin(),
animEnd = entry->first.end(); anim != animEnd; ++anim) {
if (quint64(&(*anim)) == animationId) {
anim->from.set(interpolated(*anim, 0), interpolated(*anim, 1));
validate(anim->attribute, anim->meta, nullptr, &newTarget, entry.key());
anim->to.set(newTarget[0], newTarget[1]);
anim->duration = anim->time + newRemainingTime;
return true;
}
}
}
return false; // no animation found
}
bool AnimationEffect::cancel(quint64 animationId)
{
Q_D(AnimationEffect);

View File

@ -172,6 +172,19 @@ protected:
quint64 set( EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, QEasingCurve curve = QEasingCurve(), int delay = 0, FPx2 from = FPx2() )
{ return p_animate(w, a, meta, ms, to, curve, delay, from, true); }
/**
* this allows to alter the target (but not type or curve) of a running animation
* with the ID @param animationId
* @param newTarget alters the "to" parameter of the animation
* If @param newRemainingTime allows to lengthen (or shorten) the remaining time
* of the animation. By default (-1) the remaining time remains unchanged
*
* Please use @function cancel to cancel an animation rather than altering it.
* NOTICE that you can NOT retarget an animation that just has just @function animationEnded !
* @return whether there was such animation and it could be altered
*/
bool retarget(quint64 animationId, FPx2 newTarget, int newRemainingTime = -1);
/**
* Called whenever an animation end, passes the transformed @class EffectWindow @enum Attribute and originally supplied @param meta
* You can reimplement it to keep a constant transformation for the window (ie. keep it a this opacity or position) or to start another animation
@ -200,6 +213,7 @@ private:
float progress( const AniData& ) const;
void disconnectGeometryChanges();
void updateLayerRepaints();
void validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, const EffectWindow *w) const;
private Q_SLOTS:
void init();
void triggerRepaint();