From 1faa8aa039d6f5681950f5dbab9d4a4f9b8b387c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Wed, 3 Feb 2016 17:36:48 +0100 Subject: [PATCH] allow to retarget animations --- libkwineffects/kwinanimationeffect.cpp | 176 +++++++++++++++---------- libkwineffects/kwinanimationeffect.h | 14 ++ 2 files changed, 122 insertions(+), 68 deletions(-) diff --git a/libkwineffects/kwinanimationeffect.cpp b/libkwineffects/kwinanimationeffect.cpp index d87ec2a11c..69ea7aecb7 100644 --- a/libkwineffects/kwinanimationeffect.cpp +++ b/libkwineffects/kwinanimationeffect.cpp @@ -92,114 +92,133 @@ bool AnimationEffect::isActive() const #define RELATIVE_XY(_FIELD_) const bool relative[2] = { static_cast(metaData(Relative##_FIELD_##X, meta)), \ static_cast(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::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); diff --git a/libkwineffects/kwinanimationeffect.h b/libkwineffects/kwinanimationeffect.h index b2ac712a2c..7925c3da8b 100644 --- a/libkwineffects/kwinanimationeffect.h +++ b/libkwineffects/kwinanimationeffect.h @@ -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();