1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativespringanimation_p.h"
44 #include "QtQuick1/private/qdeclarativeanimation_p_p.h"
45 #include <QtDeclarative/private/qdeclarativeproperty_p.h>
47 #include <QtCore/qdebug.h>
49 #include <private/qobject_p.h>
59 class QDeclarative1SpringAnimationPrivate : public QDeclarative1PropertyAnimationPrivate
61 Q_DECLARE_PUBLIC(QDeclarative1SpringAnimation)
65 struct SpringAnimation {
67 : currentValue(0), to(0), velocity(0), start(0), duration(0) {}
74 QHash<QDeclarativeProperty, SpringAnimation> activeAnimations;
95 QDeclarative1SpringAnimationPrivate()
96 : maxVelocity(0), velocityms(0), lastTime(0)
97 , mass(1.0), spring(0.), damping(0.), epsilon(0.01)
98 , modulus(0.0), useMass(false), haveModulus(false)
99 , mode(Track), clock(0)
103 bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed);
106 typedef QTickAnimationProxy_1<QDeclarative1SpringAnimationPrivate, &QDeclarative1SpringAnimationPrivate::tick> Clock;
110 void QDeclarative1SpringAnimationPrivate::tick(int time)
116 int elapsed = time - lastTime;
120 if (mode == Spring) {
121 if (elapsed < 16) // capped at 62fps.
123 int count = elapsed / 16;
124 lastTime = time - (elapsed - count * 16);
129 QMutableHashIterator<QDeclarativeProperty, SpringAnimation> it(activeAnimations);
130 while (it.hasNext()) {
132 if (animate(it.key(), it.value(), elapsed))
136 if (activeAnimations.isEmpty())
140 bool QDeclarative1SpringAnimationPrivate::animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed)
142 qreal srcVal = animation.to;
147 animation.currentValue = fmod(animation.currentValue, modulus);
148 srcVal = fmod(srcVal, modulus);
150 if (mode == Spring) {
151 // Real men solve the spring DEs using RK4.
152 // We'll do something much simpler which gives a result that looks fine.
153 int count = elapsed / 16;
154 for (int i = 0; i < count; ++i) {
155 qreal diff = srcVal - animation.currentValue;
156 if (haveModulus && qAbs(diff) > modulus / 2) {
163 animation.velocity = animation.velocity + (spring * diff - damping * animation.velocity) / mass;
165 animation.velocity = animation.velocity + spring * diff - damping * animation.velocity;
166 if (maxVelocity > 0.) {
168 if (animation.velocity > maxVelocity)
169 animation.velocity = maxVelocity;
170 else if (animation.velocity < -maxVelocity)
171 animation.velocity = -maxVelocity;
173 animation.currentValue += animation.velocity * 16.0 / 1000.0;
175 animation.currentValue = fmod(animation.currentValue, modulus);
176 if (animation.currentValue < 0.0)
177 animation.currentValue += modulus;
180 if (qAbs(animation.velocity) < epsilon && qAbs(srcVal - animation.currentValue) < epsilon) {
181 animation.velocity = 0.0;
182 animation.currentValue = srcVal;
186 qreal moveBy = elapsed * velocityms;
187 qreal diff = srcVal - animation.currentValue;
188 if (haveModulus && qAbs(diff) > modulus / 2) {
195 animation.currentValue += moveBy;
197 animation.currentValue = fmod(animation.currentValue, modulus);
199 animation.currentValue -= moveBy;
200 if (haveModulus && animation.currentValue < 0.0)
201 animation.currentValue = fmod(animation.currentValue, modulus) + modulus;
203 if (lastTime - animation.start >= animation.duration) {
204 animation.currentValue = animation.to;
209 qreal old_to = animation.to;
211 QDeclarativePropertyPrivate::write(property, animation.currentValue,
212 QDeclarativePropertyPrivate::BypassInterceptor |
213 QDeclarativePropertyPrivate::DontRemoveBinding);
215 return (stop && old_to == animation.to); // do not stop if we got restarted
218 void QDeclarative1SpringAnimationPrivate::updateMode()
220 if (spring == 0. && maxVelocity == 0.)
222 else if (spring > 0.)
226 QHash<QDeclarativeProperty, SpringAnimation>::iterator it;
227 for (it = activeAnimations.begin(); it != activeAnimations.end(); ++it) {
228 SpringAnimation &animation = *it;
229 animation.start = lastTime;
230 qreal dist = qAbs(animation.currentValue - animation.to);
231 if (haveModulus && dist > modulus / 2)
232 dist = modulus - fmod(dist, modulus);
233 animation.duration = dist / velocityms;
239 \qmlclass SpringAnimation QDeclarative1SpringAnimation
240 \inqmlmodule QtQuick 1
241 \ingroup qml-animation-transition
242 \inherits NumberAnimation
245 \brief The SpringAnimation element allows a property to track a value in a spring-like motion.
247 SpringAnimation mimics the oscillatory behavior of a spring, with the appropriate \l spring constant to
248 control the acceleration and the \l damping to control how quickly the effect dies away.
250 You can also limit the maximum \l velocity of the animation.
252 The following \l Rectangle moves to the position of the mouse using a
253 SpringAnimation when the mouse is clicked. The use of the \l Behavior
254 on the \c x and \c y values indicates that whenever these values are
255 changed, a SpringAnimation should be applied.
257 \snippet doc/src/snippets/qtquick1/springanimation.qml 0
259 Like any other animation element, a SpringAnimation can be applied in a
260 number of ways, including transitions, behaviors and property value
261 sources. The \l {QML Animation and Transitions} documentation shows a
262 variety of methods for creating animations.
264 \sa SmoothedAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example}
267 QDeclarative1SpringAnimation::QDeclarative1SpringAnimation(QObject *parent)
268 : QDeclarative1NumberAnimation(*(new QDeclarative1SpringAnimationPrivate),parent)
270 Q_D(QDeclarative1SpringAnimation);
271 d->clock = new QDeclarative1SpringAnimationPrivate::Clock(d, this);
274 QDeclarative1SpringAnimation::~QDeclarative1SpringAnimation()
279 \qmlproperty real QtQuick1::SpringAnimation::velocity
281 This property holds the maximum velocity allowed when tracking the source.
283 The default value is 0 (no maximum velocity).
286 qreal QDeclarative1SpringAnimation::velocity() const
288 Q_D(const QDeclarative1SpringAnimation);
289 return d->maxVelocity;
292 void QDeclarative1SpringAnimation::setVelocity(qreal velocity)
294 Q_D(QDeclarative1SpringAnimation);
295 d->maxVelocity = velocity;
296 d->velocityms = velocity / 1000.0;
301 \qmlproperty real QtQuick1::SpringAnimation::spring
303 This property describes how strongly the target is pulled towards the
304 source. The default value is 0 (that is, the spring-like motion is disabled).
306 The useful value range is 0 - 5.0.
308 When this property is set and the \l velocity value is greater than 0,
309 the \l velocity limits the maximum speed.
311 qreal QDeclarative1SpringAnimation::spring() const
313 Q_D(const QDeclarative1SpringAnimation);
317 void QDeclarative1SpringAnimation::setSpring(qreal spring)
319 Q_D(QDeclarative1SpringAnimation);
325 \qmlproperty real QtQuick1::SpringAnimation::damping
326 This property holds the spring damping value.
328 This parameter can be used to tweak the spring behaviour by exerting a resisting force
331 The default value is 0.
333 The useful value range is 0 - 1.0. The higher the value, the faster it
334 usually comes to rest.
336 qreal QDeclarative1SpringAnimation::damping() const
338 Q_D(const QDeclarative1SpringAnimation);
342 void QDeclarative1SpringAnimation::setDamping(qreal damping)
344 Q_D(QDeclarative1SpringAnimation);
348 d->damping = damping;
353 \qmlproperty real QtQuick1::SpringAnimation::epsilon
354 This property holds the spring epsilon.
356 The epsilon is the rate and amount of change in the value which is close enough
357 to 0 to be considered equal to zero. This will depend on the usage of the value.
358 For pixel positions, 0.25 would suffice. For scale, 0.005 will suffice.
360 The default is 0.01. Tuning this value can provide small performance improvements.
362 qreal QDeclarative1SpringAnimation::epsilon() const
364 Q_D(const QDeclarative1SpringAnimation);
368 void QDeclarative1SpringAnimation::setEpsilon(qreal epsilon)
370 Q_D(QDeclarative1SpringAnimation);
371 d->epsilon = epsilon;
375 \qmlproperty real QtQuick1::SpringAnimation::modulus
376 This property holds the modulus value. The default value is 0.
378 Setting a \a modulus forces the target value to "wrap around" at the modulus.
379 For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10.
381 qreal QDeclarative1SpringAnimation::modulus() const
383 Q_D(const QDeclarative1SpringAnimation);
387 void QDeclarative1SpringAnimation::setModulus(qreal modulus)
389 Q_D(QDeclarative1SpringAnimation);
390 if (d->modulus != modulus) {
391 d->haveModulus = modulus != 0.0;
392 d->modulus = modulus;
394 emit modulusChanged();
399 \qmlproperty real QtQuick1::SpringAnimation::mass
400 This property holds the "mass" of the property being moved.
402 The value is 1.0 by default.
404 A greater mass causes slower movement and a greater spring-like
405 motion when an item comes to rest.
407 qreal QDeclarative1SpringAnimation::mass() const
409 Q_D(const QDeclarative1SpringAnimation);
413 void QDeclarative1SpringAnimation::setMass(qreal mass)
415 Q_D(QDeclarative1SpringAnimation);
416 if (d->mass != mass && mass > 0.0) {
417 d->useMass = mass != 1.0;
423 void QDeclarative1SpringAnimation::transition(QDeclarative1StateActions &actions,
424 QDeclarativeProperties &modified,
425 TransitionDirection direction)
427 Q_D(QDeclarative1SpringAnimation);
430 if (d->clock->state() != QAbstractAnimation::Running) {
434 QDeclarative1NumberAnimation::transition(actions, modified, direction);
439 if (!d->actions->isEmpty()) {
440 for (int i = 0; i < d->actions->size(); ++i) {
441 const QDeclarativeProperty &property = d->actions->at(i).property;
442 QDeclarative1SpringAnimationPrivate::SpringAnimation &animation
443 = d->activeAnimations[property];
444 animation.to = d->actions->at(i).toValue.toReal();
445 animation.start = d->lastTime;
446 if (d->fromIsDefined)
447 animation.currentValue = d->actions->at(i).fromValue.toReal();
449 animation.currentValue = property.read().toReal();
450 if (d->mode == QDeclarative1SpringAnimationPrivate::Velocity) {
451 qreal dist = qAbs(animation.currentValue - animation.to);
452 if (d->haveModulus && dist > d->modulus / 2)
453 dist = d->modulus - fmod(dist, d->modulus);
454 animation.duration = dist / d->velocityms;
461 QAbstractAnimation *QDeclarative1SpringAnimation::qtAnimation()
463 Q_D(QDeclarative1SpringAnimation);