Qt 4.8
qabstractanimation.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 QtCore 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 
160 #include "qabstractanimation.h"
161 #include "qanimationgroup.h"
162 
163 #include <QtCore/qdebug.h>
164 
165 #include "qabstractanimation_p.h"
166 
167 #include <QtCore/qmath.h>
168 #include <QtCore/qthreadstorage.h>
169 #include <QtCore/qcoreevent.h>
170 #include <QtCore/qpointer.h>
171 
172 #ifndef QT_NO_ANIMATION
173 
174 #define DEFAULT_TIMER_INTERVAL 16
175 #define STARTSTOP_TIMER_DELAY 0
176 
178 
179 #ifndef QT_NO_THREAD
181 #endif
182 
184  QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
185  currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false),
186  slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0)
187 {
188  time.invalidate();
190 }
191 
192 
194 {
195  QUnifiedTimer *inst;
196 #ifndef QT_NO_THREAD
197  if (create && !unifiedTimer()->hasLocalData()) {
198  inst = new QUnifiedTimer;
199  unifiedTimer()->setLocalData(inst);
200  } else {
201  inst = unifiedTimer()->localData();
202  }
203 #else
204  static QUnifiedTimer unifiedTimer;
205  inst = &unifiedTimer;
206 #endif
207  return inst;
208 }
209 
211 {
212  return instance(true);
213 }
214 
216 {
217  QUnifiedTimer *inst = QUnifiedTimer::instance(false);
218  if (inst && inst->isPauseTimerActive)
219  inst->updateAnimationsTime();
220 }
221 
223 {
224  //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
225  if(insideTick)
226  return;
227 
228  qint64 totalElapsed = time.elapsed();
229  // ignore consistentTiming in case the pause timer is active
230  int delta = (consistentTiming && !isPauseTimerActive) ?
231  timingInterval : totalElapsed - lastTick;
232  if (slowMode) {
233  if (slowdownFactor > 0)
234  delta = qRound(delta / slowdownFactor);
235  else
236  delta = 0;
237  }
238 
239  lastTick = totalElapsed;
240 
241  //we make sure we only call update time if the time has actually changed
242  //it might happen in some cases that the time doesn't change because events are delayed
243  //when the CPU load is high
244  if (delta) {
245  insideTick = true;
249  + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
250  animation->setCurrentTime(elapsed);
251  }
252  insideTick = false;
254  }
255 }
256 
258 {
259  QUnifiedTimer *inst = QUnifiedTimer::instance(false);
260  if (inst)
261  inst->restartAnimationTimer();
262 }
263 
265 {
267  int closestTimeToFinish = closestPauseAnimationTimeToFinish();
268  if (closestTimeToFinish < 0) {
271  }
272  driver->stop();
273  animationTimer.start(closestTimeToFinish, this);
274  isPauseTimerActive = true;
275  } else if (!driver->isRunning() || isPauseTimerActive) {
276  driver->start();
277  isPauseTimerActive = false;
278  } else if (runningLeafAnimations == 0)
279  driver->stop();
280 }
281 
283 {
284  timingInterval = interval;
285 
286  if (driver->isRunning() && !isPauseTimerActive) {
287  //we changed the timing interval
288  driver->stop();
289  driver->start();
290  }
291 }
292 
293 
295 {
296  //in the case of consistent timing we make sure the orders in which events come is always the same
297  //for that purpose we do as if the startstoptimer would always fire before the animation timer
299  event->timerId() == startStopAnimationTimer.timerId()) {
301 
302  //we transfer the waiting animations into the "really running" state
305  if (animations.isEmpty()) {
307  isPauseTimerActive = false;
308  // invalidate the start reference time
309  time.invalidate();
310  } else {
312  if (!time.isValid()) {
313  lastTick = 0;
314  time.start();
315  }
316  }
317  }
318 
319  if (event->timerId() == animationTimer.timerId()) {
320  // update current time on all top level animations
323  }
324 }
325 
326 void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
327 {
328  QUnifiedTimer *inst = instance(true); //we create the instance if needed
329  inst->registerRunningAnimation(animation);
330  if (isTopLevel) {
331  Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
333  inst->animationsToStart << animation;
334  if (!inst->startStopAnimationTimer.isActive())
336  }
337 }
338 
340 {
341  QUnifiedTimer *inst = QUnifiedTimer::instance(false);
342  if (inst) {
343  //at this point the unified timer should have been created
344  //but it might also have been already destroyed in case the application is shutting down
345 
346  inst->unregisterRunningAnimation(animation);
347 
348  if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
349  return;
350 
351  int idx = inst->animations.indexOf(animation);
352  if (idx != -1) {
353  inst->animations.removeAt(idx);
354  // this is needed if we unregister an animation while its running
355  if (idx <= inst->currentAnimationIdx)
356  --inst->currentAnimationIdx;
357 
358  if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive())
360  } else {
361  inst->animationsToStart.removeOne(animation);
362  }
363  }
365 }
366 
368 {
369  if (QAbstractAnimationPrivate::get(animation)->isGroup)
370  return;
371 
372  if (QAbstractAnimationPrivate::get(animation)->isPause) {
373  runningPauseAnimations << animation;
374  } else
376 }
377 
379 {
380  if (QAbstractAnimationPrivate::get(animation)->isGroup)
381  return;
382 
383  if (QAbstractAnimationPrivate::get(animation)->isPause)
385  else
388 }
389 
391 {
392  int closestTimeToFinish = INT_MAX;
393  for (int i = 0; i < runningPauseAnimations.size(); ++i) {
395  int timeToFinish;
396 
397  if (animation->direction() == QAbstractAnimation::Forward)
398  timeToFinish = animation->duration() - animation->currentLoopTime();
399  else
400  timeToFinish = animation->currentLoopTime();
401 
402  if (timeToFinish < closestTimeToFinish)
403  closestTimeToFinish = timeToFinish;
404  }
405  return closestTimeToFinish;
406 }
407 
409 {
410  if (driver) {
411 
412  if (driver->isRunning()) {
413  qWarning("QUnifiedTimer: Cannot change animation driver while animations are running");
414  return;
415  }
416 
417  if (driver != &defaultDriver)
418  delete driver;
419  }
420 
421  driver = d;
422 }
423 
440  : QObject(*(new QAnimationDriverPrivate), parent)
441 {
442 }
443 
445  : QObject(dd, parent)
446 {
447 }
448 
449 
457 {
459 
460  // update current time on all top level animations
461  instance->updateAnimationsTime();
462  instance->restartAnimationTimer();
463 }
464 
465 
473 {
475  timer->installAnimationDriver(this);
476 }
477 
479 {
480  return d_func()->running;
481 }
482 
483 
485 {
487  if (!d->running) {
488  started();
489  d->running = true;
490  }
491 }
492 
493 
495 {
497  if (d->running) {
498  stopped();
499  d->running = false;
500  }
501 }
502 
531  : QAnimationDriver(0), m_unified_timer(timer)
532 {
533 }
534 
536 {
537  Q_ASSERT(e->timerId() == m_timer.timerId());
538  Q_UNUSED(e); // if the assertions are disabled
539  advance();
540 }
541 
543 {
545 }
546 
548 {
549  m_timer.stop();
550 }
551 
552 
553 
555 {
557  if (state == newState)
558  return;
559 
560  if (loopCount == 0)
561  return;
562 
563  QAbstractAnimation::State oldState = state;
564  int oldCurrentTime = currentTime;
565  int oldCurrentLoop = currentLoop;
567 
568  // check if we should Rewind
569  if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
570  && oldState == QAbstractAnimation::Stopped) {
571  //here we reset the time if needed
572  //we don't call setCurrentTime because this might change the way the animation
573  //behaves: changing the state or changing the current value
574  totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
575  0 : (loopCount == -1 ? q->duration() : q->totalDuration());
576  }
577 
578  state = newState;
580 
581  //(un)registration of the animation must always happen before calls to
582  //virtual function (updateState) to ensure a correct state of the timer
583  bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
584  if (oldState == QAbstractAnimation::Running) {
585  if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
587  //the animation, is not running any more
589  } else if (newState == QAbstractAnimation::Running) {
590  QUnifiedTimer::registerAnimation(q, isTopLevel);
591  }
592 
593  q->updateState(newState, oldState);
594  if (!guard || newState != state) //this is to be safe if updateState changes the state
595  return;
596 
597  // Notify state change
598  emit q->stateChanged(newState, oldState);
599  if (!guard || newState != state) //this is to be safe if updateState changes the state
600  return;
601 
602  switch (state) {
604  break;
606  {
607 
608  // this ensures that the value is updated now that the animation is running
609  if (oldState == QAbstractAnimation::Stopped) {
610  if (isTopLevel) {
611  // currentTime needs to be updated if pauseTimer is active
613  q->setCurrentTime(totalCurrentTime);
614  }
615  }
616  }
617  break;
619  // Leave running state.
620  int dura = q->duration();
621 
622  if (deleteWhenStopped)
623  q->deleteLater();
624 
625  if (dura == -1 || loopCount < 0
626  || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
627  || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
628  emit q->finished();
629  }
630  break;
631  }
632 }
633 
642 {
643  // Allow auto-add on reparent
644  setParent(parent);
645 }
646 
651  : QObject(dd, 0)
652 {
653  // Allow auto-add on reparent
654  setParent(parent);
655 }
656 
663 {
665  //we can't call stop here. Otherwise we get pure virtual calls
666  if (d->state != Stopped) {
667  QAbstractAnimation::State oldState = d->state;
668  d->state = Stopped;
669  emit stateChanged(oldState, d->state);
670  if (oldState == QAbstractAnimation::Running)
672  }
673 }
674 
687 {
688  Q_D(const QAbstractAnimation);
689  return d->state;
690 }
691 
699 {
700  Q_D(const QAbstractAnimation);
701  return d->group;
702 }
703 
759 {
760  Q_D(const QAbstractAnimation);
761  return d->direction;
762 }
764 {
766  if (d->direction == direction)
767  return;
768 
769  if (state() == Stopped) {
770  if (direction == Backward) {
771  d->currentTime = duration();
772  d->currentLoop = d->loopCount - 1;
773  } else {
774  d->currentTime = 0;
775  d->currentLoop = 0;
776  }
777  }
778 
779  // the commands order below is important: first we need to setCurrentTime with the old direction,
780  // then update the direction on this and all children and finally restart the pauseTimer if needed
781  if (d->hasRegisteredTimer)
783 
784  d->direction = direction;
785  updateDirection(direction);
786 
787  if (d->hasRegisteredTimer)
788  // needed to update the timer interval in case of a pause animation
790 
791  emit directionChanged(direction);
792 }
793 
822 {
823  Q_D(const QAbstractAnimation);
824  return d->loopCount;
825 }
827 {
829  d->loopCount = loopCount;
830 }
831 
849 {
850  Q_D(const QAbstractAnimation);
851  return d->currentLoop;
852 }
853 
882 {
883  int dura = duration();
884  if (dura <= 0)
885  return dura;
886  int loopcount = loopCount();
887  if (loopcount < 0)
888  return -1;
889  return dura * loopcount;
890 }
891 
899 {
900  Q_D(const QAbstractAnimation);
901  return d->currentTime;
902 }
903 
921 {
922  Q_D(const QAbstractAnimation);
923  return d->totalCurrentTime;
924 }
926 {
928  msecs = qMax(msecs, 0);
929 
930  // Calculate new time and loop.
931  int dura = duration();
932  int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
933  if (totalDura != -1)
934  msecs = qMin(totalDura, msecs);
935  d->totalCurrentTime = msecs;
936 
937  // Update new values.
938  int oldLoop = d->currentLoop;
939  d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
940  if (d->currentLoop == d->loopCount) {
941  //we're at the end
942  d->currentTime = qMax(0, dura);
943  d->currentLoop = qMax(0, d->loopCount - 1);
944  } else {
945  if (d->direction == Forward) {
946  d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
947  } else {
948  d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
949  if (d->currentTime == dura)
950  --d->currentLoop;
951  }
952  }
953 
954  updateCurrentTime(d->currentTime);
955  if (d->currentLoop != oldLoop)
956  emit currentLoopChanged(d->currentLoop);
957 
958  // All animations are responsible for stopping the animation when their
959  // own end state is reached; in this case the animation is time driven,
960  // and has reached the end.
961  if ((d->direction == Forward && d->totalCurrentTime == totalDura)
962  || (d->direction == Backward && d->totalCurrentTime == 0)) {
963  stop();
964  }
965 }
966 
984 {
986  if (d->state == Running)
987  return;
988  d->deleteWhenStopped = policy;
989  d->setState(Running);
990 }
991 
1003 {
1005 
1006  if (d->state == Stopped)
1007  return;
1008 
1009  d->setState(Stopped);
1010 }
1011 
1020 {
1022  if (d->state == Stopped) {
1023  qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
1024  return;
1025  }
1026 
1027  d->setState(Paused);
1028 }
1029 
1038 {
1040  if (d->state != Paused) {
1041  qWarning("QAbstractAnimation::resume: "
1042  "Cannot resume an animation that is not paused");
1043  return;
1044  }
1045 
1046  d->setState(Running);
1047 }
1048 
1056 {
1057  if (paused)
1058  pause();
1059  else
1060  resume();
1061 }
1062 
1063 
1068 {
1069  return QObject::event(event);
1070 }
1071 
1091  QAbstractAnimation::State oldState)
1092 {
1093  Q_UNUSED(oldState);
1094  Q_UNUSED(newState);
1095 }
1096 
1104 {
1105  Q_UNUSED(direction);
1106 }
1107 
1108 
1110 
1111 #include "moc_qabstractanimation.cpp"
1112 
1113 #endif //QT_NO_ANIMATION
double d
Definition: qnumeric_p.h:62
virtual void updateCurrentTime(int currentTime)=0
This pure virtual function is called every time the animation&#39;s currentTime changes.
void installAnimationDriver(QAnimationDriver *driver)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
static double elapsed(qint64 after, qint64 before)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int totalDuration() const
Returns the total and effective duration of the animation, including the loop count.
void setLoopCount(int loopCount)
State
This enum describes the state of the animation.
void unregisterRunningAnimation(QAbstractAnimation *animation)
virtual void started()
This function is called by the animation framework to notify the driver that it should start running...
QDefaultAnimationDriver defaultDriver
int closestPauseAnimationTimeToFinish()
static Expression::Ptr create(Expression *const expr, const YYLTYPE &sourceLocator, const ParserContext *const parseInfo)
State state() const
bool isActive() const
Returns true if the timer is running and has not been stopped; otherwise returns false.
Definition: qbasictimer.h:62
static QAbstractAnimationPrivate * get(QAbstractAnimation *q)
void directionChanged(QAbstractAnimation::Direction)
QAbstractAnimation emits this signal whenever the direction has been changed.
bool isValid() const
Returns false if this object was invalidated by a call to invalidate() and has not been restarted sin...
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
Starts the animation.
static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
EventLoopTimerRef timer
int currentLoop() const
QAnimationDriver * driver
void resume()
Resumes the animation after it was paused.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
#define Q_D(Class)
Definition: qglobal.h:2482
QBasicTimer animationTimer
qint64 elapsed() const
Returns the number of milliseconds since this QElapsedTimer was last started.
void stop()
Stops the animation.
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void started()
This function is called by the animation framework to notify the driver that it should start running...
void setState(QAbstractAnimation::State state)
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
void setParent(QObject *)
Makes the object a child of parent.
Definition: qobject.cpp:1950
#define DEFAULT_TIMER_INTERVAL
#define Q_Q(Class)
Definition: qglobal.h:2483
int currentTime() const
void setPaused(bool)
If paused is true, the animation is paused.
QAnimationGroup * group() const
If this animation is part of a QAnimationGroup, this function returns a pointer to the group; otherwi...
Q_CORE_EXPORT void qDebug(const char *,...)
bool removeOne(const T &t)
Removes the first occurrence of value in the list and returns true on success; otherwise returns fals...
Definition: qlist.h:796
void advance()
Advances the animation based on the current time.
static void updateAnimationTimer()
void stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
QAbstractAnimation emits this signal whenever the state of the animation has changed from oldState to...
int loopCount() const
int currentLoopTime() const
Returns the current time inside the current loop.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Direction
This enum describes the direction of the animation when in Running state.
#define STARTSTOP_TIMER_DELAY
QAbstractAnimation(QObject *parent=0)
Constructs the QAbstractAnimation base class, and passes parent to QObject&#39;s constructor.
void timerEvent(QTimerEvent *)
This event handler can be reimplemented in a subclass to receive timer events for the object...
QAnimationDriver(QObject *parent=0)
QList< QAbstractAnimation * > animationsToStart
virtual void stopped()
This function is called by the animation framework to notify the driver that it should stop running...
QBasicTimer startStopAnimationTimer
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
virtual void updateDirection(QAbstractAnimation::Direction direction)
This virtual function is called by QAbstractAnimation when the direction of the animation is changed...
void setDirection(Direction direction)
Q_CORE_EXPORT void qWarning(const char *,...)
void stopped()
This function is called by the animation framework to notify the driver that it should stop running...
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition: qcoreevent.h:346
void invalidate()
Marks this QElapsedTimer object as invalid.
static void unregisterAnimation(QAbstractAnimation *animation)
QList< QAbstractAnimation * > animations
void clear()
Removes all items from the list.
Definition: qlist.h:764
__int64 qint64
Definition: qglobal.h:942
The QAbstractAnimation class is the base of all animations.
void stop()
Stops the timer.
void registerRunningAnimation(QAbstractAnimation *animation)
void timerEvent(QTimerEvent *e)
This event handler can be reimplemented in a subclass to receive timer events for the object...
void setTimingInterval(int interval)
Direction direction
the direction of the animation when it is in Running state.
QDefaultAnimationDriver(QUnifiedTimer *timer)
The default animation driver just spins the timer...
int indexOf(const T &t, int from=0) const
Returns the index position of the first occurrence of value in the list, searching forward from index...
Definition: qlist.h:847
static void ensureTimerUpdate()
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
static QUnifiedTimer * instance()
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
void currentLoopChanged(int currentLoop)
QAbstractAnimation emits this signal whenever the current loop changes.
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
This virtual function is called by QAbstractAnimation when the state of the animation is changed from...
int timerId() const
Returns the timer&#39;s ID.
Definition: qbasictimer.h:63
void pause()
Pauses the animation.
bool event(QEvent *event)
Reimplemented Function
The QAnimationDriver class is used to exchange the mechanism that drives animations.
virtual int duration() const =0
Direction direction() const
The QAnimationGroup class is an abstract base class for groups of animations.
QList< QAbstractAnimation * > runningPauseAnimations
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
The QThreadStorage class provides per-thread data storage.
#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
void setCurrentTime(int msecs)
void start()
Starts this timer.
#define INT_MAX
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
void start(int msec, QObject *obj)
Starts (or restarts) the timer with a msec milliseconds timeout.
void install()
Installs this animation driver.
The QWeakPointer class holds a weak reference to a shared pointer.
Qt::LayoutDirection direction
int duration
the duration of the animation.
void removeAt(int i)
Removes the item at index position i.
Definition: qlist.h:480
virtual ~QAbstractAnimation()
Stops the animation if it&#39;s running, then destroys the QAbstractAnimation.