1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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/declarative/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 value describes how quickly the spring-like motion comes to rest.
329 The default value is 0.
331 The useful value range is 0 - 1.0. The lower the value, the faster it
334 qreal QDeclarative1SpringAnimation::damping() const
336 Q_D(const QDeclarative1SpringAnimation);
340 void QDeclarative1SpringAnimation::setDamping(qreal damping)
342 Q_D(QDeclarative1SpringAnimation);
346 d->damping = damping;
351 \qmlproperty real QtQuick1::SpringAnimation::epsilon
352 This property holds the spring epsilon.
354 The epsilon is the rate and amount of change in the value which is close enough
355 to 0 to be considered equal to zero. This will depend on the usage of the value.
356 For pixel positions, 0.25 would suffice. For scale, 0.005 will suffice.
358 The default is 0.01. Tuning this value can provide small performance improvements.
360 qreal QDeclarative1SpringAnimation::epsilon() const
362 Q_D(const QDeclarative1SpringAnimation);
366 void QDeclarative1SpringAnimation::setEpsilon(qreal epsilon)
368 Q_D(QDeclarative1SpringAnimation);
369 d->epsilon = epsilon;
373 \qmlproperty real QtQuick1::SpringAnimation::modulus
374 This property holds the modulus value. The default value is 0.
376 Setting a \a modulus forces the target value to "wrap around" at the modulus.
377 For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10.
379 qreal QDeclarative1SpringAnimation::modulus() const
381 Q_D(const QDeclarative1SpringAnimation);
385 void QDeclarative1SpringAnimation::setModulus(qreal modulus)
387 Q_D(QDeclarative1SpringAnimation);
388 if (d->modulus != modulus) {
389 d->haveModulus = modulus != 0.0;
390 d->modulus = modulus;
392 emit modulusChanged();
397 \qmlproperty real QtQuick1::SpringAnimation::mass
398 This property holds the "mass" of the property being moved.
400 The value is 1.0 by default.
402 A greater mass causes slower movement and a greater spring-like
403 motion when an item comes to rest.
405 qreal QDeclarative1SpringAnimation::mass() const
407 Q_D(const QDeclarative1SpringAnimation);
411 void QDeclarative1SpringAnimation::setMass(qreal mass)
413 Q_D(QDeclarative1SpringAnimation);
414 if (d->mass != mass && mass > 0.0) {
415 d->useMass = mass != 1.0;
421 void QDeclarative1SpringAnimation::transition(QDeclarative1StateActions &actions,
422 QDeclarativeProperties &modified,
423 TransitionDirection direction)
425 Q_D(QDeclarative1SpringAnimation);
428 if (d->clock->state() != QAbstractAnimation::Running) {
432 QDeclarative1NumberAnimation::transition(actions, modified, direction);
437 if (!d->actions->isEmpty()) {
438 for (int i = 0; i < d->actions->size(); ++i) {
439 const QDeclarativeProperty &property = d->actions->at(i).property;
440 QDeclarative1SpringAnimationPrivate::SpringAnimation &animation
441 = d->activeAnimations[property];
442 animation.to = d->actions->at(i).toValue.toReal();
443 animation.start = d->lastTime;
444 if (d->fromIsDefined)
445 animation.currentValue = d->actions->at(i).fromValue.toReal();
447 animation.currentValue = property.read().toReal();
448 if (d->mode == QDeclarative1SpringAnimationPrivate::Velocity) {
449 qreal dist = qAbs(animation.currentValue - animation.to);
450 if (d->haveModulus && dist > d->modulus / 2)
451 dist = d->modulus - fmod(dist, d->modulus);
452 animation.duration = dist / d->velocityms;
459 QAbstractAnimation *QDeclarative1SpringAnimation::qtAnimation()
461 Q_D(QDeclarative1SpringAnimation);