Qt 4.8
qdeclarativespringanimation.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "private/qdeclarativespringanimation_p.h"
43 
44 #include "private/qdeclarativeanimation_p_p.h"
45 #include <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 
55 
56 
58 {
60 public:
61 
62 
63  struct SpringAnimation {
65  : currentValue(0), to(0), velocity(0), start(0), duration(0) {}
69  int start;
70  int duration;
71  };
73 
76  int lastTime;
82 
83  bool useMass : 1;
84  bool haveModulus : 1;
85 
86  enum Mode {
90  };
92 
94  : maxVelocity(0), velocityms(0), lastTime(0)
95  , mass(1.0), spring(0.), damping(0.), epsilon(0.01)
96  , modulus(0.0), useMass(false), haveModulus(false)
97  , mode(Track), clock(0)
98  { }
99 
100  void tick(int time);
101  bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed);
102  void updateMode();
103 
105  Clock *clock;
106 };
107 
109 {
110  if (mode == Track) {
111  clock->stop();
112  return;
113  }
114  int elapsed = time - lastTime;
115  if (!elapsed)
116  return;
117 
118  if (mode == Spring) {
119  if (elapsed < 16) // capped at 62fps.
120  return;
121  int count = elapsed / 16;
122  lastTime = time - (elapsed - count * 16);
123  } else {
124  lastTime = time;
125  }
126 
127  QMutableHashIterator<QDeclarativeProperty, SpringAnimation> it(activeAnimations);
128  while (it.hasNext()) {
129  it.next();
130  if (animate(it.key(), it.value(), elapsed))
131  it.remove();
132  }
133 
134  if (activeAnimations.isEmpty())
135  clock->stop();
136 }
137 
139 {
140  qreal srcVal = animation.to;
141 
142  bool stop = false;
143 
144  if (haveModulus) {
145  animation.currentValue = fmod(animation.currentValue, modulus);
146  srcVal = fmod(srcVal, modulus);
147  }
148  if (mode == Spring) {
149  // Real men solve the spring DEs using RK4.
150  // We'll do something much simpler which gives a result that looks fine.
151  int count = elapsed / 16;
152  for (int i = 0; i < count; ++i) {
153  qreal diff = srcVal - animation.currentValue;
154  if (haveModulus && qAbs(diff) > modulus / 2) {
155  if (diff < 0)
156  diff += modulus;
157  else
158  diff -= modulus;
159  }
160  if (useMass)
161  animation.velocity = animation.velocity + (spring * diff - damping * animation.velocity) / mass;
162  else
163  animation.velocity = animation.velocity + spring * diff - damping * animation.velocity;
164  if (maxVelocity > qreal(0.)) {
165  // limit velocity
166  if (animation.velocity > maxVelocity)
167  animation.velocity = maxVelocity;
168  else if (animation.velocity < -maxVelocity)
169  animation.velocity = -maxVelocity;
170  }
171  animation.currentValue += animation.velocity * qreal(16.0) / qreal(1000.0);
172  if (haveModulus) {
173  animation.currentValue = fmod(animation.currentValue, modulus);
174  if (animation.currentValue < qreal(0.0))
175  animation.currentValue += modulus;
176  }
177  }
178  if (qAbs(animation.velocity) < epsilon && qAbs(srcVal - animation.currentValue) < epsilon) {
179  animation.velocity = 0.0;
180  animation.currentValue = srcVal;
181  stop = true;
182  }
183  } else {
184  qreal moveBy = elapsed * velocityms;
185  qreal diff = srcVal - animation.currentValue;
186  if (haveModulus && qAbs(diff) > modulus / 2) {
187  if (diff < 0)
188  diff += modulus;
189  else
190  diff -= modulus;
191  }
192  if (diff > 0) {
193  animation.currentValue += moveBy;
194  if (haveModulus)
195  animation.currentValue = fmod(animation.currentValue, modulus);
196  } else {
197  animation.currentValue -= moveBy;
198  if (haveModulus && animation.currentValue < qreal(0.0))
199  animation.currentValue = fmod(animation.currentValue, modulus) + modulus;
200  }
201  if (lastTime - animation.start >= animation.duration) {
202  animation.currentValue = animation.to;
203  stop = true;
204  }
205  }
206 
207  qreal old_to = animation.to;
208 
212 
213  return (stop && old_to == animation.to); // do not stop if we got restarted
214 }
215 
217 {
218  if (spring == 0. && maxVelocity == 0.)
219  mode = Track;
220  else if (spring > 0.)
221  mode = Spring;
222  else {
223  mode = Velocity;
225  for (it = activeAnimations.begin(); it != activeAnimations.end(); ++it) {
226  SpringAnimation &animation = *it;
227  animation.start = lastTime;
228  qreal dist = qAbs(animation.currentValue - animation.to);
229  if (haveModulus && dist > modulus / 2)
230  dist = modulus - fmod(dist, modulus);
231  animation.duration = dist / velocityms;
232  }
233  }
234 }
235 
269 {
271  d->clock = new QDeclarativeSpringAnimationPrivate::Clock(d, this);
272 }
273 
275 {
276 }
277 
290 {
292  return d->maxVelocity;
293 }
294 
296 {
298  d->maxVelocity = velocity;
299  d->velocityms = velocity / 1000.0;
300  d->updateMode();
301 }
302 
318 {
320  return d->spring;
321 }
322 
324 {
326  d->spring = spring;
327  d->updateMode();
328 }
329 
344 {
346  return d->damping;
347 }
348 
350 {
352  if (damping > 1.)
353  damping = 1.;
354 
355  d->damping = damping;
356 }
357 
358 
373 {
375  return d->epsilon;
376 }
377 
379 {
381  d->epsilon = epsilon;
382 }
383 
395 {
397  return d->modulus;
398 }
399 
401 {
403  if (d->modulus != modulus) {
404  d->haveModulus = modulus != 0.0;
405  d->modulus = modulus;
406  d->updateMode();
408  }
409 }
410 
424 {
426  return d->mass;
427 }
428 
430 {
432  if (d->mass != mass && mass > 0.0) {
433  d->useMass = mass != 1.0;
434  d->mass = mass;
435  emit massChanged();
436  }
437 }
438 
440  QDeclarativeProperties &modified,
442 {
444  Q_UNUSED(direction);
445 
446  if (d->clock->state() != QAbstractAnimation::Running) {
447  d->lastTime = 0;
448  }
449 
450  QDeclarativeNumberAnimation::transition(actions, modified, direction);
451 
452  if (!d->actions)
453  return;
454 
455  if (!d->actions->isEmpty()) {
456  for (int i = 0; i < d->actions->size(); ++i) {
457  const QDeclarativeProperty &property = d->actions->at(i).property;
459  = d->activeAnimations[property];
460  animation.to = d->actions->at(i).toValue.toReal();
461  animation.start = d->lastTime;
462  if (d->fromIsDefined)
463  animation.currentValue = d->actions->at(i).fromValue.toReal();
464  else
465  animation.currentValue = property.read().toReal();
467  qreal dist = qAbs(animation.currentValue - animation.to);
468  if (d->haveModulus && dist > d->modulus / 2)
469  dist = d->modulus - fmod(dist, d->modulus);
470  animation.duration = dist / d->velocityms;
471  }
472  }
473  }
474 }
475 
476 
478 {
480  return d->clock;
481 }
482 
double qreal
Definition: qglobal.h:1193
static double elapsed(qint64 after, qint64 before)
QTickAnimationProxy< QDeclarativeSpringAnimationPrivate, &QDeclarativeSpringAnimationPrivate::tick > Clock
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QDeclarativeParserStatus ** d
#define it(className, varName)
virtual void transition(QDeclarativeStateActions &actions, QDeclarativeProperties &modified, TransitionDirection direction)
virtual QAbstractAnimation * qtAnimation()
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
void stop()
Stops the animation.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define emit
Definition: qobjectdefs.h:76
qreal velocity
This property holds the maximum velocity allowed when tracking the source.
static Bigint * diff(Bigint *a, Bigint *b)
The QAbstractAnimation class is the base of all animations.
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
virtual void transition(QDeclarativeStateActions &actions, QDeclarativeProperties &modified, TransitionDirection direction)
The QHash::iterator class provides an STL-style non-const iterator for QHash and QMultiHash.
Definition: qhash.h:330
const char * property
Definition: qwizard.cpp:138
bool animate(const QDeclarativeProperty &property, SpringAnimation &animation, int elapsed)
QObject * parent
Definition: qobject.h:92
The QDeclarativeProperty class abstracts accessing properties on objects created from QML...
QHash< QDeclarativeProperty, SpringAnimation > activeAnimations
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &, QDeclarativeContextData *, WriteFlags flags=0)
Qt::LayoutDirection direction