Bulk update of QtQuick 1 docs to \qmlmodule syntax
[profile/ivi/qtdeclarative.git] / src / qtquick1 / util / qdeclarativespringanimation.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "QtQuick1/private/qdeclarativespringanimation_p.h"
43
44 #include "QtQuick1/private/qdeclarativeanimation_p_p.h"
45 #include <QtDeclarative/private/qdeclarativeproperty_p.h>
46
47 #include <QtCore/qdebug.h>
48
49 #include <private/qobject_p.h>
50
51 #include <limits.h>
52 #include <math.h>
53
54 QT_BEGIN_NAMESPACE
55
56
57
58
59 class QDeclarative1SpringAnimationPrivate : public QDeclarative1PropertyAnimationPrivate
60 {
61     Q_DECLARE_PUBLIC(QDeclarative1SpringAnimation)
62 public:
63
64
65     struct SpringAnimation {
66         SpringAnimation()
67             : currentValue(0), to(0), velocity(0), start(0), duration(0) {}
68         qreal currentValue;
69         qreal to;
70         qreal velocity;
71         int start;
72         int duration;
73     };
74     QHash<QDeclarativeProperty, SpringAnimation> activeAnimations;
75
76     qreal maxVelocity;
77     qreal velocityms;
78     int lastTime;
79     qreal mass;
80     qreal spring;
81     qreal damping;
82     qreal epsilon;
83     qreal modulus;
84
85     bool useMass : 1;
86     bool haveModulus : 1;
87
88     enum Mode {
89         Track,
90         Velocity,
91         Spring
92     };
93     Mode mode;
94
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)
100     { }
101
102     void tick(int time);
103     bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed);
104     void updateMode();
105
106     typedef QTickAnimationProxy_1<QDeclarative1SpringAnimationPrivate, &QDeclarative1SpringAnimationPrivate::tick> Clock;
107     Clock *clock;
108 };
109
110 void QDeclarative1SpringAnimationPrivate::tick(int time)
111 {
112     if (mode == Track) {
113         clock->stop();
114         return;
115     }
116     int elapsed = time - lastTime;
117     if (!elapsed)
118         return;
119
120     if (mode == Spring) {
121         if (elapsed < 16) // capped at 62fps.
122             return;
123         int count = elapsed / 16;
124         lastTime = time - (elapsed - count * 16);
125     } else {
126         lastTime = time;
127     }
128
129     QMutableHashIterator<QDeclarativeProperty, SpringAnimation> it(activeAnimations);
130     while (it.hasNext()) {
131         it.next();
132         if (animate(it.key(), it.value(), elapsed))
133             it.remove();
134     }
135
136     if (activeAnimations.isEmpty())
137         clock->stop();
138 }
139
140 bool QDeclarative1SpringAnimationPrivate::animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed)
141 {
142     qreal srcVal = animation.to;
143
144     bool stop = false;
145
146     if (haveModulus) {
147         animation.currentValue = fmod(animation.currentValue, modulus);
148         srcVal = fmod(srcVal, modulus);
149     }
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) {
157                 if (diff < 0)
158                     diff += modulus;
159                 else
160                     diff -= modulus;
161             }
162             if (useMass)
163                 animation.velocity = animation.velocity + (spring * diff - damping * animation.velocity) / mass;
164             else
165                 animation.velocity = animation.velocity + spring * diff - damping * animation.velocity;
166             if (maxVelocity > 0.) {
167                 // limit velocity
168                 if (animation.velocity > maxVelocity)
169                     animation.velocity = maxVelocity;
170                 else if (animation.velocity < -maxVelocity)
171                     animation.velocity = -maxVelocity;
172             }
173             animation.currentValue += animation.velocity * 16.0 / 1000.0;
174             if (haveModulus) {
175                 animation.currentValue = fmod(animation.currentValue, modulus);
176                 if (animation.currentValue < 0.0)
177                     animation.currentValue += modulus;
178             }
179         }
180         if (qAbs(animation.velocity) < epsilon && qAbs(srcVal - animation.currentValue) < epsilon) {
181             animation.velocity = 0.0;
182             animation.currentValue = srcVal;
183             stop = true;
184         }
185     } else {
186         qreal moveBy = elapsed * velocityms;
187         qreal diff = srcVal - animation.currentValue;
188         if (haveModulus && qAbs(diff) > modulus / 2) {
189             if (diff < 0)
190                 diff += modulus;
191             else
192                 diff -= modulus;
193         }
194         if (diff > 0) {
195             animation.currentValue += moveBy;
196             if (haveModulus)
197                 animation.currentValue = fmod(animation.currentValue, modulus);
198         } else {
199             animation.currentValue -= moveBy;
200             if (haveModulus && animation.currentValue < 0.0)
201                 animation.currentValue = fmod(animation.currentValue, modulus) + modulus;
202         }
203         if (lastTime - animation.start >= animation.duration) {
204             animation.currentValue = animation.to;
205             stop = true;
206         }
207     }
208
209     qreal old_to = animation.to;
210
211     QDeclarativePropertyPrivate::write(property, animation.currentValue,
212                                        QDeclarativePropertyPrivate::BypassInterceptor |
213                                        QDeclarativePropertyPrivate::DontRemoveBinding);
214
215     return (stop && old_to == animation.to); // do not stop if we got restarted
216 }
217
218 void QDeclarative1SpringAnimationPrivate::updateMode()
219 {
220     if (spring == 0. && maxVelocity == 0.)
221         mode = Track;
222     else if (spring > 0.)
223         mode = Spring;
224     else {
225         mode = Velocity;
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;
234         }
235     }
236 }
237
238 /*!
239     \qmlclass SpringAnimation QDeclarative1SpringAnimation
240     \inqmlmodule QtQuick 1
241     \ingroup qml-animation-transition
242     \inherits NumberAnimation
243     \since QtQuick 1.0
244
245     \brief The SpringAnimation element allows a property to track a value in a spring-like motion.
246
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.
249
250     You can also limit the maximum \l velocity of the animation.
251
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.
256
257     \snippet doc/src/snippets/declarative/springanimation.qml 0
258
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.
263
264     \sa SmoothedAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example}
265 */
266
267 QDeclarative1SpringAnimation::QDeclarative1SpringAnimation(QObject *parent)
268 : QDeclarative1NumberAnimation(*(new QDeclarative1SpringAnimationPrivate),parent)
269 {
270     Q_D(QDeclarative1SpringAnimation);
271     d->clock = new QDeclarative1SpringAnimationPrivate::Clock(d, this);
272 }
273
274 QDeclarative1SpringAnimation::~QDeclarative1SpringAnimation()
275 {
276 }
277
278 /*!
279     \qmlproperty real QtQuick1::SpringAnimation::velocity
280
281     This property holds the maximum velocity allowed when tracking the source.
282
283     The default value is 0 (no maximum velocity).
284 */
285
286 qreal QDeclarative1SpringAnimation::velocity() const
287 {
288     Q_D(const QDeclarative1SpringAnimation);
289     return d->maxVelocity;
290 }
291
292 void QDeclarative1SpringAnimation::setVelocity(qreal velocity)
293 {
294     Q_D(QDeclarative1SpringAnimation);
295     d->maxVelocity = velocity;
296     d->velocityms = velocity / 1000.0;
297     d->updateMode();
298 }
299
300 /*!
301     \qmlproperty real QtQuick1::SpringAnimation::spring
302
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).
305
306     The useful value range is 0 - 5.0.
307
308     When this property is set and the \l velocity value is greater than 0,
309     the \l velocity limits the maximum speed.
310 */
311 qreal QDeclarative1SpringAnimation::spring() const
312 {
313     Q_D(const QDeclarative1SpringAnimation);
314     return d->spring;
315 }
316
317 void QDeclarative1SpringAnimation::setSpring(qreal spring)
318 {
319     Q_D(QDeclarative1SpringAnimation);
320     d->spring = spring;
321     d->updateMode();
322 }
323
324 /*!
325     \qmlproperty real QtQuick1::SpringAnimation::damping
326     This property holds the spring damping value.
327
328     This value describes how quickly the spring-like motion comes to rest.
329     The default value is 0.
330
331     The useful value range is 0 - 1.0. The lower the value, the faster it
332     comes to rest.
333 */
334 qreal QDeclarative1SpringAnimation::damping() const
335 {
336     Q_D(const QDeclarative1SpringAnimation);
337     return d->damping;
338 }
339
340 void QDeclarative1SpringAnimation::setDamping(qreal damping)
341 {
342     Q_D(QDeclarative1SpringAnimation);
343     if (damping > 1.)
344         damping = 1.;
345
346     d->damping = damping;
347 }
348
349
350 /*!
351     \qmlproperty real QtQuick1::SpringAnimation::epsilon
352     This property holds the spring epsilon.
353
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.
357
358     The default is 0.01. Tuning this value can provide small performance improvements.
359 */
360 qreal QDeclarative1SpringAnimation::epsilon() const
361 {
362     Q_D(const QDeclarative1SpringAnimation);
363     return d->epsilon;
364 }
365
366 void QDeclarative1SpringAnimation::setEpsilon(qreal epsilon)
367 {
368     Q_D(QDeclarative1SpringAnimation);
369     d->epsilon = epsilon;
370 }
371
372 /*!
373     \qmlproperty real QtQuick1::SpringAnimation::modulus
374     This property holds the modulus value. The default value is 0.
375
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.
378 */
379 qreal QDeclarative1SpringAnimation::modulus() const
380 {
381     Q_D(const QDeclarative1SpringAnimation);
382     return d->modulus;
383 }
384
385 void QDeclarative1SpringAnimation::setModulus(qreal modulus)
386 {
387     Q_D(QDeclarative1SpringAnimation);
388     if (d->modulus != modulus) {
389         d->haveModulus = modulus != 0.0;
390         d->modulus = modulus;
391         d->updateMode();
392         emit modulusChanged();
393     }
394 }
395
396 /*!
397     \qmlproperty real QtQuick1::SpringAnimation::mass
398     This property holds the "mass" of the property being moved.
399
400     The value is 1.0 by default.
401
402     A greater mass causes slower movement and a greater spring-like
403     motion when an item comes to rest.
404 */
405 qreal QDeclarative1SpringAnimation::mass() const
406 {
407     Q_D(const QDeclarative1SpringAnimation);
408     return d->mass;
409 }
410
411 void QDeclarative1SpringAnimation::setMass(qreal mass)
412 {
413     Q_D(QDeclarative1SpringAnimation);
414     if (d->mass != mass && mass > 0.0) {
415         d->useMass = mass != 1.0;
416         d->mass = mass;
417         emit massChanged();
418     }
419 }
420
421 void QDeclarative1SpringAnimation::transition(QDeclarative1StateActions &actions,
422                                              QDeclarativeProperties &modified,
423                                              TransitionDirection direction)
424 {
425     Q_D(QDeclarative1SpringAnimation);
426     Q_UNUSED(direction);
427
428     if (d->clock->state() != QAbstractAnimation::Running) {
429         d->lastTime = 0;
430     }
431
432     QDeclarative1NumberAnimation::transition(actions, modified, direction);
433
434     if (!d->actions)
435         return;
436
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();
446             else
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;
453             }
454         }
455     }
456 }
457
458
459 QAbstractAnimation *QDeclarative1SpringAnimation::qtAnimation()
460 {
461     Q_D(QDeclarative1SpringAnimation);
462     return d->clock;
463 }
464
465
466
467 QT_END_NAMESPACE