summaryrefslogtreecommitdiffstats
path: root/src/declarative/util/qdeclarativeeasefollow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/util/qdeclarativeeasefollow.cpp')
-rw-r--r--src/declarative/util/qdeclarativeeasefollow.cpp499
1 files changed, 223 insertions, 276 deletions
diff --git a/src/declarative/util/qdeclarativeeasefollow.cpp b/src/declarative/util/qdeclarativeeasefollow.cpp
index ee181dd..ce2c496 100644
--- a/src/declarative/util/qdeclarativeeasefollow.cpp
+++ b/src/declarative/util/qdeclarativeeasefollow.cpp
@@ -40,86 +40,79 @@
****************************************************************************/
#include "qdeclarativeeasefollow_p.h"
+#include "qdeclarativeeasefollow_p_p.h"
#include "qdeclarativeanimation_p_p.h"
#include <qdeclarativeproperty.h>
+#include "qdeclarativeproperty_p.h"
+
+#include "qdeclarativeglobal_p.h"
#include <QtCore/qdebug.h>
#include <math.h>
+#include <QTimer>
+
+#define DELAY_STOP_TIMER_INTERVAL 32
QT_BEGIN_NAMESPACE
+QSmoothedAnimation::QSmoothedAnimation(QObject *parent)
+ : QAbstractAnimation(parent), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1),
+ reversingMode(QDeclarativeSmoothedAnimation::Eased), initialVelocity(0),
+ trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0)
+{
+ delayedStopTimer.setInterval(DELAY_STOP_TIMER_INTERVAL);
+ delayedStopTimer.setSingleShot(true);
+ connect(&delayedStopTimer, SIGNAL(timeout()), this, SLOT(stop()));
+}
+void QSmoothedAnimation::restart()
+{
+ if (state() != QAbstractAnimation::Running)
+ start();
+ else
+ init();
+}
-class QDeclarativeEaseFollowPrivate : public QObjectPrivate
+void QSmoothedAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/)
{
- Q_DECLARE_PUBLIC(QDeclarativeEaseFollow)
-public:
- QDeclarativeEaseFollowPrivate()
- : source(0), velocity(200), duration(-1), maximumEasingTime(-1),
- reversingMode(QDeclarativeEaseFollow::Eased), initialVelocity(0),
- initialValue(0), invert(false), enabled(true), trackVelocity(0), clockOffset(0),
- lastTick(0), clock(this)
- {}
-
- qreal source;
- qreal velocity;
- qreal duration;
- qreal maximumEasingTime;
- QDeclarativeEaseFollow::ReversingMode reversingMode;
-
- qreal initialVelocity;
- qreal initialValue;
- bool invert;
- bool enabled;
-
- qreal trackVelocity;
-
- QDeclarativeProperty target;
-
- int clockOffset;
- int lastTick;
- void tick(int);
- void clockStart();
- void clockStop();
- QTickAnimationProxy<QDeclarativeEaseFollowPrivate, &QDeclarativeEaseFollowPrivate::tick> clock;
-
- void restart();
-
- // Parameters for use in tick()
- qreal a; // Acceleration
- qreal d; // Deceleration
- qreal tf; // Total time
- qreal tp; // Time at which peak velocity occurs
- qreal td; // Time at which decelleration begins
- qreal vp; // Velocity at tp
- qreal sp; // Displacement at tp
- qreal sd; // Displacement at td
- qreal vi; // "Normalized" initialvelocity
- bool recalc();
-};
-
-bool QDeclarativeEaseFollowPrivate::recalc()
+ if (newState == QAbstractAnimation::Running)
+ init();
+}
+
+void QSmoothedAnimation::delayedStop()
{
- qreal s = source - initialValue;
+ if (!delayedStopTimer.isActive())
+ delayedStopTimer.start();
+}
+
+int QSmoothedAnimation::duration() const
+{
+ return -1;
+}
+
+bool QSmoothedAnimation::recalc()
+{
+ s = to - initialValue;
vi = initialVelocity;
- s = (invert?-1.0:1.0) * s;
- vi = (invert?-1.0:1.0) * vi;
+ s = (invert? -1.0: 1.0) * s;
- if (duration > 0 && velocity > 0) {
+ if (userDuration > 0 && velocity > 0) {
tf = s / velocity;
- if (tf > (duration / 1000.)) tf = (duration / 1000.);
- } else if (duration > 0) {
- tf = duration / 1000.;
+ if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.);
+ } else if (userDuration > 0) {
+ tf = userDuration / 1000.;
} else if (velocity > 0) {
tf = s / velocity;
} else {
return false;
}
+ finalDuration = ceil(tf * 1000.0);
+
if (maximumEasingTime == 0) {
a = 0;
d = 0;
@@ -129,7 +122,6 @@ bool QDeclarativeEaseFollowPrivate::recalc()
sp = 0;
sd = s;
} else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) {
-
qreal met = maximumEasingTime / 1000.;
td = tf - met;
@@ -138,7 +130,6 @@ bool QDeclarativeEaseFollowPrivate::recalc()
qreal c3 = -0.5 * (tf - td) * vi * vi;
qreal vp1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
- // qreal vp2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
vp = vp1;
a = vp / met;
@@ -147,21 +138,16 @@ bool QDeclarativeEaseFollowPrivate::recalc()
sp = vi * tp + 0.5 * a * tp * tp;
sd = sp + (td - tp) * vp;
} else {
-
qreal c1 = 0.25 * tf * tf;
qreal c2 = 0.5 * vi * tf - s;
qreal c3 = -0.25 * vi * vi;
qreal a1 = (-c2 + sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
- //qreal a2 = (-c2 - sqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
- //qreal tp2 = 0.5 * tf - 0.5 * vi / a2;
qreal vp1 = a1 * tp1 + vi;
- //qreal vp2 = a2 * tp2 + vi;
qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
- //qreal sp2 = 0.5 * a2 * tp2 * tp2 + vi * tp2;
a = a1;
d = a1;
@@ -171,92 +157,103 @@ bool QDeclarativeEaseFollowPrivate::recalc()
sp = sp1;
sd = sp1;
}
-
- /*
- qWarning() << "a:" << a << "tf:" << tf << "tp:" << tp << "vp:"
- << vp << "sp:" << sp << "vi:" << vi << "invert:" << invert;
- */
return true;
}
-void QDeclarativeEaseFollowPrivate::clockStart()
+qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
{
- if (clock.state() == QAbstractAnimation::Running) {
- clockOffset = lastTick;
- return;
+ qreal value;
+ if (time_seconds < tp) {
+ trackVelocity = vi + time_seconds * a;
+ value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
+ } else if (time_seconds < td) {
+ time_seconds -= tp;
+ trackVelocity = vp;
+ value = sp + time_seconds * vp;
+ } else if (time_seconds < tf) {
+ time_seconds -= td;
+ trackVelocity = vp - time_seconds * a;
+ value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
} else {
- clockOffset = 0;
- lastTick = 0;
- clock.start();
+ trackVelocity = 0;
+ value = s;
+ delayedStop();
}
-}
-void QDeclarativeEaseFollowPrivate::clockStop()
-{
- clockOffset = 0;
- lastTick = 0;
- clock.stop();
+ // to normalize 's' between [0..1], divide 'value' by 's'
+ return value;
}
-void QDeclarativeEaseFollowPrivate::tick(int t)
+void QSmoothedAnimation::updateCurrentTime(int t)
{
- lastTick = t;
- t -= clockOffset;
-
- qreal time_seconds = qreal(t) / 1000.;
-
- qreal out = 0;
- if (time_seconds < tp) {
-
- trackVelocity = vi + time_seconds * a;
- trackVelocity = (invert?-1.0:1.0) * trackVelocity;
-
- qreal value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
- value = (invert?-1.0:1.0) * value;
- target.write(initialValue + value);
- out = initialValue + value;
- } else if (time_seconds < td) {
+ qreal time_seconds = qreal(t - lastTime) / 1000.;
- time_seconds -= tp;
- trackVelocity = (invert?-1.0:1.0) * vp;
- qreal value = sp + time_seconds * vp;
- value = (invert?-1.0:1.0) * value;
+ qreal value = easeFollow(time_seconds);
+ value *= (invert? -1.0: 1.0);
+ QDeclarativePropertyPrivate::write(target, initialValue + value,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+}
- target.write(initialValue + value);
+void QSmoothedAnimation::init()
+{
+ if (velocity == 0) {
+ stop();
+ return;
+ }
- out = initialValue + value;
- } else if (time_seconds < tf) {
+ if (delayedStopTimer.isActive())
+ delayedStopTimer.stop();
- time_seconds -= td;
+ initialValue = target.read().toReal();
+ lastTime = this->currentTime();
- trackVelocity = vp - time_seconds * a;
- trackVelocity = (invert?-1.0:1.0) * trackVelocity;
+ if (to == initialValue) {
+ stop();
+ return;
+ }
- qreal value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
- value = (invert?-1.0:1.0) * value;
+ bool hasReversed = trackVelocity != 0. &&
+ ((trackVelocity > 0) == ((initialValue - to) > 0));
- target.write(initialValue + value);
+ if (hasReversed) {
+ switch (reversingMode) {
+ default:
+ case QDeclarativeSmoothedAnimation::Eased:
+ break;
+ case QDeclarativeSmoothedAnimation::Sync:
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ return;
+ case QDeclarativeSmoothedAnimation::Immediate:
+ initialVelocity = 0;
+ delayedStop();
+ break;
+ }
+ }
- out = initialValue + value;
- } else {
+ trackVelocity = initialVelocity;
- clock.stop();
+ invert = (to < initialValue);
- trackVelocity = 0;
- target.write(source);
+ if (!recalc()) {
+ QDeclarativePropertyPrivate::write(target, to,
+ QDeclarativePropertyPrivate::BypassInterceptor
+ | QDeclarativePropertyPrivate::DontRemoveBinding);
+ stop();
+ return;
}
-
- //qWarning() << out << trackVelocity << t << a;
}
/*!
- \qmlclass EaseFollow QDeclarativeEaseFollow
+ \qmlclass SmoothedAnimation QDeclarativeSmoothedAnimation
\since 4.7
- \brief The EaseFollow element allows a property to smoothly track a value.
+ \brief The SmoothedAnimation element allows a property to smoothly track a value.
- The EaseFollow smoothly animates a property's value to a set target value
- using an ease in/out quad easing curve. If the target value changes while
- the animation is in progress, the easing curves used to animate to the old
+ The SmoothedAnimation smoothly animates a property's value to a set target value
+ using an ease in/out quad easing curve. If the animation is restarted
+ with a different target value, the easing curves used to animate to the old
and the new target values are spliced together to avoid any obvious visual
glitches.
@@ -282,9 +279,9 @@ Rectangle {
Rectangle {
color: "green"
width: 60; height: 60;
- x: -5; y: -5;
- EaseFollow on x { source: rect1.x - 5; velocity: 200 }
- EaseFollow on y { source: rect1.y - 5; velocity: 200 }
+ x: rect1.x - 5; y: rect1.y - 5;
+ Behavior on x { SmoothedAnimation { velocity: 200 } }
+ Behavior on y { SmoothedAnimation { velocity: 200 } }
}
Rectangle {
@@ -301,7 +298,7 @@ Rectangle {
}
\endcode
- The default velocity of EaseFollow is 200 units/second. Note that if the range of the
+ The default velocity of SmoothedAnimation is 200 units/second. Note that if the range of the
value being animated is small, then the velocity will need to be adjusted
appropriately. For example, the opacity of an item ranges from 0 - 1.0.
To enable a smooth animation in this range the velocity will need to be
@@ -311,226 +308,176 @@ Rectangle {
\sa SpringFollow
*/
-QDeclarativeEaseFollow::QDeclarativeEaseFollow(QObject *parent)
-: QObject(*(new QDeclarativeEaseFollowPrivate), parent)
+QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent)
+: QDeclarativeNumberAnimation(*(new QDeclarativeSmoothedAnimationPrivate), parent)
{
}
-QDeclarativeEaseFollow::~QDeclarativeEaseFollow()
+QDeclarativeSmoothedAnimation::~QDeclarativeSmoothedAnimation()
{
}
-/*!
- \qmlproperty qreal EaseFollow::source
- This property holds the source value which will be tracked.
-
- Bind to a property in order to track its changes.
-*/
-qreal QDeclarativeEaseFollow::sourceValue() const
+QDeclarativeSmoothedAnimationPrivate::QDeclarativeSmoothedAnimationPrivate()
+ : wrapperGroup(new QParallelAnimationGroup), anim(new QSmoothedAnimation)
{
- Q_D(const QDeclarativeEaseFollow);
- return d->source;
+ Q_Q(QDeclarativeSmoothedAnimation);
+ QDeclarative_setParent_noEvent(wrapperGroup, q);
+ QDeclarative_setParent_noEvent(anim, q);
}
-/*!
- \qmlproperty enumeration EaseFollow::reversingMode
-
- Sets how the EaseFollow behaves if an animation direction is reversed.
-
- If reversing mode is \c Eased, the animation will smoothly decelerate, and
- then reverse direction. If the reversing mode is \c Immediate, the
- animation will immediately begin accelerating in the reverse direction,
- begining with a velocity of 0. If the reversing mode is \c Sync, the
- property is immediately set to the target value.
-*/
-QDeclarativeEaseFollow::ReversingMode QDeclarativeEaseFollow::reversingMode() const
+QAbstractAnimation* QDeclarativeSmoothedAnimation::qtAnimation()
{
- Q_D(const QDeclarativeEaseFollow);
- return d->reversingMode;
+ Q_D(QDeclarativeSmoothedAnimation);
+ return d->wrapperGroup;
}
-void QDeclarativeEaseFollow::setReversingMode(ReversingMode m)
+void QDeclarativeSmoothedAnimation::transition(QDeclarativeStateActions &actions,
+ QDeclarativeProperties &modified,
+ TransitionDirection direction)
{
- Q_D(QDeclarativeEaseFollow);
- if (d->reversingMode == m)
+ Q_D(QDeclarativeSmoothedAnimation);
+ QDeclarativeNumberAnimation::transition(actions, modified, direction);
+
+ if (!d->actions)
return;
- d->reversingMode = m;
- emit reversingModeChanged();
-}
+ QSet<QAbstractAnimation*> anims;
+ for (int i = 0; i < d->actions->size(); i++) {
+ QSmoothedAnimation *ease;
+ qreal trackVelocity;
+ bool needsRestart;
+ if (!d->activeAnimations.contains((*d->actions)[i].property)) {
+ ease = new QSmoothedAnimation();
+ d->wrapperGroup->addAnimation(ease);
+ d->activeAnimations.insert((*d->actions)[i].property, ease);
+ trackVelocity = 0.0;
+ needsRestart = false;
+ } else {
+ ease = d->activeAnimations.value((*d->actions)[i].property);
+ trackVelocity = ease->trackVelocity;
+ needsRestart = true;
+ }
-void QDeclarativeEaseFollowPrivate::restart()
-{
- if (!enabled || velocity == 0) {
- clockStop();
- return;
- }
+ ease->target = (*d->actions)[i].property;
+ ease->to = (*d->actions)[i].toValue.toReal();
- initialValue = target.read().toReal();
+ // copying public members from main value holder animation
+ ease->maximumEasingTime = d->anim->maximumEasingTime;
+ ease->reversingMode = d->anim->reversingMode;
+ ease->velocity = d->anim->velocity;
+ ease->userDuration = d->anim->userDuration;
- if (source == initialValue) {
- clockStop();
- return;
- }
+ ease->trackVelocity = trackVelocity;
+ ease->initialVelocity = trackVelocity;
- bool hasReversed = trackVelocity != 0. &&
- ((trackVelocity > 0) == ((initialValue - source) > 0));
+ if (needsRestart)
+ ease->init();
+ anims.insert(ease);
+ }
- if (hasReversed) {
- switch (reversingMode) {
- default:
- case QDeclarativeEaseFollow::Eased:
- break;
- case QDeclarativeEaseFollow::Sync:
- target.write(source);
- return;
- case QDeclarativeEaseFollow::Immediate:
- initialVelocity = 0;
- clockStop();
- break;
+ for (int i = d->wrapperGroup->animationCount() - 1; i >= 0 ; --i) {
+ if (!anims.contains(d->wrapperGroup->animationAt(i))) {
+ QSmoothedAnimation *ease = static_cast<QSmoothedAnimation*>(d->wrapperGroup->animationAt(i));
+ d->activeAnimations.remove(ease->target);
+ d->wrapperGroup->takeAnimation(i);
+ delete ease;
}
}
+}
- trackVelocity = initialVelocity;
-
- invert = (source < initialValue);
+/*!
+ \qmlproperty enumeration SmoothedAnimation::reversingMode
- if (!recalc()) {
- target.write(source);
- clockStop();
- return;
- }
+ Sets how the SmoothedAnimation behaves if an animation direction is reversed.
- clockStart();
+ If reversing mode is \c Eased, the animation will smoothly decelerate, and
+ then reverse direction. If the reversing mode is \c Immediate, the
+ animation will immediately begin accelerating in the reverse direction,
+ begining with a velocity of 0. If the reversing mode is \c Sync, the
+ property is immediately set to the target value.
+*/
+QDeclarativeSmoothedAnimation::ReversingMode QDeclarativeSmoothedAnimation::reversingMode() const
+{
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return (QDeclarativeSmoothedAnimation::ReversingMode) d->anim->reversingMode;
}
-void QDeclarativeEaseFollow::setSourceValue(qreal s)
+void QDeclarativeSmoothedAnimation::setReversingMode(ReversingMode m)
{
- Q_D(QDeclarativeEaseFollow);
-
- if (d->clock.state() == QAbstractAnimation::Running && d->source == s)
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->reversingMode == m)
return;
- d->source = s;
- d->initialVelocity = d->trackVelocity;
- d->restart();
-
- emit sourceChanged();
+ d->anim->reversingMode = m;
+ emit reversingModeChanged();
}
/*!
- \qmlproperty qreal EaseFollow::duration
+ \qmlproperty int SmoothedAnimation::duration
- This property holds the animation duration used when tracking the source.
+ This property holds the animation duration, in msecs, used when tracking the source.
Setting this to -1 (the default) disables the duration value.
*/
-qreal QDeclarativeEaseFollow::duration() const
+int QDeclarativeSmoothedAnimation::duration() const
{
- Q_D(const QDeclarativeEaseFollow);
- return d->duration;
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->userDuration;
}
-void QDeclarativeEaseFollow::setDuration(qreal v)
+void QDeclarativeSmoothedAnimation::setDuration(int duration)
{
- Q_D(QDeclarativeEaseFollow);
- if (d->duration == v)
- return;
-
- d->duration = v;
- d->trackVelocity = 0;
-
- if (d->clock.state() == QAbstractAnimation::Running)
- d->restart();
-
- emit durationChanged();
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (duration != -1)
+ QDeclarativeNumberAnimation::setDuration(duration);
+ d->anim->userDuration = duration;
}
-qreal QDeclarativeEaseFollow::velocity() const
+qreal QDeclarativeSmoothedAnimation::velocity() const
{
- Q_D(const QDeclarativeEaseFollow);
- return d->velocity;
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->velocity;
}
/*!
- \qmlproperty qreal EaseFollow::velocity
+ \qmlproperty qreal SmoothedAnimation::velocity
- This property holds the average velocity allowed when tracking the source.
+ This property holds the average velocity allowed when tracking the 'to' value.
- The default velocity of EaseFollow is 200 units/second.
+ The default velocity of SmoothedAnimation is 200 units/second.
Setting this to -1 disables the velocity value.
*/
-void QDeclarativeEaseFollow::setVelocity(qreal v)
+void QDeclarativeSmoothedAnimation::setVelocity(qreal v)
{
- Q_D(QDeclarativeEaseFollow);
- if (d->velocity == v)
+ Q_D(QDeclarativeSmoothedAnimation);
+ if (d->anim->velocity == v)
return;
- d->velocity = v;
- d->trackVelocity = 0;
-
- if (d->clock.state() == QAbstractAnimation::Running)
- d->restart();
-
+ d->anim->velocity = v;
emit velocityChanged();
}
/*!
- \qmlproperty bool EaseFollow::enabled
- This property holds whether the target will track the source.
-*/
-bool QDeclarativeEaseFollow::enabled() const
-{
- Q_D(const QDeclarativeEaseFollow);
- return d->enabled;
-}
-
-void QDeclarativeEaseFollow::setEnabled(bool enabled)
-{
- Q_D(QDeclarativeEaseFollow);
- if (d->enabled == enabled)
- return;
-
- d->enabled = enabled;
- if (enabled)
- d->restart();
- else
- d->clockStop();
-
- emit enabledChanged();
-}
-
-void QDeclarativeEaseFollow::setTarget(const QDeclarativeProperty &t)
-{
- Q_D(QDeclarativeEaseFollow);
- d->target = t;
-}
+\qmlproperty qreal SmoothedAnimation::maximumEasingTime
-/*!
-\qmlproperty qreal EaseFollow::maximumEasingTime
-
-This property specifies the maximum time an "eases" during the follow should take.
+This property specifies the maximum time, in msecs, an "eases" during the follow should take.
Setting this property causes the velocity to "level out" after at a time. Setting
a negative value reverts to the normal mode of easing over the entire animation
duration.
The default value is -1.
*/
-qreal QDeclarativeEaseFollow::maximumEasingTime() const
+int QDeclarativeSmoothedAnimation::maximumEasingTime() const
{
- Q_D(const QDeclarativeEaseFollow);
- return d->maximumEasingTime;
+ Q_D(const QDeclarativeSmoothedAnimation);
+ return d->anim->maximumEasingTime;
}
-void QDeclarativeEaseFollow::setMaximumEasingTime(qreal v)
+void QDeclarativeSmoothedAnimation::setMaximumEasingTime(int v)
{
- Q_D(QDeclarativeEaseFollow);
- d->maximumEasingTime = v;
-
- if (d->clock.state() == QAbstractAnimation::Running)
- d->restart();
-
+ Q_D(QDeclarativeSmoothedAnimation);
+ d->anim->maximumEasingTime = v;
emit maximumEasingTimeChanged();
}