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 QtCore 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 ****************************************************************************/
43 \class QAbstractAnimation
45 \brief The QAbstractAnimation class is the base of all animations.
48 The class defines the functions for the functionality shared by
49 all animations. By inheriting this class, you can create custom
50 animations that plug into the rest of the animation framework.
52 The progress of an animation is given by its current time
53 (currentLoopTime()), which is measured in milliseconds from the start
54 of the animation (0) to its end (duration()). The value is updated
55 automatically while the animation is running. It can also be set
56 directly with setCurrentTime().
58 At any point an animation is in one of three states:
59 \l{QAbstractAnimation::}{Running},
60 \l{QAbstractAnimation::}{Stopped}, or
61 \l{QAbstractAnimation::}{Paused}--as defined by the
62 \l{QAbstractAnimation::}{State} enum. The current state can be
63 changed by calling start(), stop(), pause(), or resume(). An
64 animation will always reset its \l{currentTime()}{current time}
65 when it is started. If paused, it will continue with the same
66 current time when resumed. When an animation is stopped, it cannot
67 be resumed, but will keep its current time (until started again).
68 QAbstractAnimation will emit stateChanged() whenever its state
71 An animation can loop any number of times by setting the loopCount
72 property. When an animation's current time reaches its duration(),
73 it will reset the current time and keep running. A loop count of 1
74 (the default value) means that the animation will run one time.
75 Note that a duration of -1 means that the animation will run until
76 stopped; the current time will increase indefinitely. When the
77 current time equals duration() and the animation is in its
78 final loop, the \l{QAbstractAnimation::}{Stopped} state is
79 entered, and the finished() signal is emitted.
81 QAbstractAnimation provides pure virtual functions used by
82 subclasses to track the progress of the animation: duration() and
83 updateCurrentTime(). The duration() function lets you report a
84 duration for the animation (as discussed above). The animation
85 framework calls updateCurrentTime() when current time has changed.
86 By reimplementing this function, you can track the animation
87 progress. Note that neither the interval between calls nor the
88 number of calls to this function are defined; though, it will
89 normally be 60 updates per second.
91 By reimplementing updateState(), you can track the animation's
92 state changes, which is particularly useful for animations that
93 are not driven by time.
95 \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework}
99 \enum QAbstractAnimation::DeletionPolicy
101 \value KeepWhenStopped The animation will not be deleted when stopped.
102 \value DeleteWhenStopped The animation will be automatically deleted when
107 \fn QAbstractAnimation::finished()
109 QAbstractAnimation emits this signal after the animation has stopped and
112 This signal is emitted after stateChanged().
118 \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
120 QAbstractAnimation emits this signal whenever the state of the animation has
121 changed from \a oldState to \a newState. This signal is emitted after the virtual
122 updateState() function is called.
128 \fn QAbstractAnimation::currentLoopChanged(int currentLoop)
130 QAbstractAnimation emits this signal whenever the current loop
131 changes. \a currentLoop is the current loop.
133 \sa currentLoop(), loopCount()
137 \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection);
139 QAbstractAnimation emits this signal whenever the direction has been
140 changed. \a newDirection is the new direction.
145 #include "qabstractanimation.h"
146 #include "qanimationgroup.h"
148 #include <QtCore/qdebug.h>
150 #include "qabstractanimation_p.h"
152 #include <QtCore/qmath.h>
153 #include <QtCore/qthreadstorage.h>
154 #include <QtCore/qcoreevent.h>
155 #include <QtCore/qpointer.h>
157 #ifndef QT_NO_ANIMATION
159 #define DEFAULT_TIMER_INTERVAL 16
160 #define PAUSE_TIMER_COARSE_THRESHOLD 2000
165 \class QAbstractAnimationTimer
166 \brief QAbstractAnimationTimer is the base class for animation timers.
169 Subclass QAbstractAnimationTimer to provide an animation timer that is run by
170 QUnifiedTimer and can in turn be used to run any number of animations.
172 Currently two subclasses have been implemented: QAnimationTimer to drive the Qt C++
173 animation framework (QAbstractAnimation and subclasses) and QDeclarativeAnimationTimer
174 to drive the Qt QML animation framework.
178 \fn virtual void QAbstractAnimationTimer::updateAnimationsTime(qint64 delta) = 0;
181 This pure virtual function is called when the animation timer needs to update
182 the current time for all animations it is running.
186 \fn virtual void QAbstractAnimationTimer::restartAnimationTimer() = 0;
189 This pure virtual function restarts the animation timer as needed.
191 Classes implementing this function may choose to pause or resume the timer
192 as appropriate, or conditionally restart it.
196 \fn virtual int QAbstractAnimationTimer::runningAnimationCount() = 0;
199 This pure virtual function returns the number of animations the timer is running.
200 This information is useful for profiling.
205 \brief QUnifiedTimer provides a unified timing mechanism for animations in Qt C++ and QML.
208 QUnifiedTimer allows animations run by Qt to share a single timer. This keeps animations
209 visually in sync, as well as being more efficient than running numerous timers.
211 QUnifiedTimer drives animations indirectly, via QAbstractAnimationTimer.
215 Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
218 QUnifiedTimer::QUnifiedTimer() :
219 QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
220 currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
221 startTimersPending(false), stopTimerPending(false),
222 slowdownFactor(5.0f), profilerCallback(0)
225 driver = &defaultDriver;
229 QUnifiedTimer *QUnifiedTimer::instance(bool create)
233 if (create && !unifiedTimer()->hasLocalData()) {
234 inst = new QUnifiedTimer;
235 unifiedTimer()->setLocalData(inst);
237 inst = unifiedTimer() ? unifiedTimer()->localData() : 0;
240 static QUnifiedTimer unifiedTimer;
241 inst = &unifiedTimer;
246 QUnifiedTimer *QUnifiedTimer::instance()
248 return instance(true);
251 void QUnifiedTimer::maybeUpdateAnimationsToCurrentTime()
253 if (time.elapsed() - lastTick > 50)
254 updateAnimationTimers(driver->elapsed());
257 void QUnifiedTimer::updateAnimationTimers(qint64 currentTick)
259 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
263 qint64 totalElapsed = currentTick >= 0 ? currentTick : time.elapsed();
265 // ignore consistentTiming in case the pause timer is active
266 qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
267 timingInterval : totalElapsed - lastTick;
269 if (slowdownFactor > 0)
270 delta = qRound(delta / slowdownFactor);
275 lastTick = totalElapsed;
277 //we make sure we only call update time if the time has actually changed
278 //it might happen in some cases that the time doesn't change because events are delayed
279 //when the CPU load is high
282 if (profilerCallback)
283 profilerCallback(delta);
284 for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.count(); ++currentAnimationIdx) {
285 QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx);
286 animation->updateAnimationsTime(delta);
289 currentAnimationIdx = 0;
293 int QUnifiedTimer::runningAnimationCount()
296 for (int i = 0; i < animationTimers.count(); ++i)
297 count += animationTimers.at(i)->runningAnimationCount();
301 void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64))
303 profilerCallback = cb;
306 void QUnifiedTimer::localRestart()
311 if (!pausedAnimationTimers.isEmpty() && (animationTimers.count() + animationTimersToStart.count() == pausedAnimationTimers.count())) {
313 int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish();
314 // use a precise timer if the pause will be short
315 Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer;
316 pauseTimer.start(closestTimeToFinish, timerType, this);
317 } else if (!driver->isRunning()) {
318 if (pauseTimer.isActive())
320 driver->setStartTime(time.isValid() ? time.elapsed() : 0);
326 void QUnifiedTimer::restart()
328 insideRestart = true;
329 for (int i = 0; i < animationTimers.count(); ++i)
330 animationTimers.at(i)->restartAnimationTimer();
331 insideRestart = false;
336 void QUnifiedTimer::setTimingInterval(int interval)
338 timingInterval = interval;
340 if (driver->isRunning() && !pauseTimer.isActive()) {
341 //we changed the timing interval
343 driver->setStartTime(time.isValid() ? time.elapsed() : 0);
348 void QUnifiedTimer::startTimers()
350 startTimersPending = false;
351 if (!animationTimers.isEmpty())
352 updateAnimationTimers(-1);
354 //we transfer the waiting animations into the "really running" state
355 animationTimers += animationTimersToStart;
356 animationTimersToStart.clear();
357 if (!animationTimers.isEmpty()) {
359 if (!time.isValid()) {
366 void QUnifiedTimer::stopTimer()
368 stopTimerPending = false;
369 if (animationTimers.isEmpty()) {
372 // invalidate the start reference time
377 void QUnifiedTimer::timerEvent(QTimerEvent *event)
379 //in the case of consistent timing we make sure the order in which events come is always the same
380 //for that purpose we do as if the startstoptimer would always fire before the animation timer
381 if (consistentTiming) {
382 if (stopTimerPending)
384 if (startTimersPending)
388 if (event->timerId() == pauseTimer.timerId()) {
389 // update current time on all timers
390 updateAnimationTimers(-1);
395 void QUnifiedTimer::startAnimationTimer(QAbstractAnimationTimer *timer)
397 if (timer->isRegistered)
399 timer->isRegistered = true;
401 QUnifiedTimer *inst = instance(true); //we create the instance if needed
402 inst->animationTimersToStart << timer;
403 if (!inst->startTimersPending) {
404 inst->startTimersPending = true;
405 QMetaObject::invokeMethod(inst, "startTimers", Qt::QueuedConnection);
409 void QUnifiedTimer::stopAnimationTimer(QAbstractAnimationTimer *timer)
411 QUnifiedTimer *inst = QUnifiedTimer::instance(false);
413 //at this point the unified timer should have been created
414 //but it might also have been already destroyed in case the application is shutting down
416 if (!timer->isRegistered)
418 timer->isRegistered = false;
420 int idx = inst->animationTimers.indexOf(timer);
422 inst->animationTimers.removeAt(idx);
423 // this is needed if we unregister an animation while its running
424 if (idx <= inst->currentAnimationIdx)
425 --inst->currentAnimationIdx;
427 if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) {
428 inst->stopTimerPending = true;
429 QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
432 inst->animationTimersToStart.removeOne(timer);
437 void QUnifiedTimer::pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration)
439 QUnifiedTimer *inst = QUnifiedTimer::instance();
440 if (!timer->isRegistered)
441 inst->startAnimationTimer(timer);
443 bool timerWasPaused = timer->isPaused;
444 timer->isPaused = true;
445 timer->pauseDuration = duration;
447 inst->pausedAnimationTimers << timer;
448 inst->localRestart();
451 void QUnifiedTimer::resumeAnimationTimer(QAbstractAnimationTimer *timer)
453 if (!timer->isPaused)
456 timer->isPaused = false;
457 QUnifiedTimer *inst = QUnifiedTimer::instance();
458 inst->pausedAnimationTimers.removeOne(timer);
459 inst->localRestart();
462 int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish()
464 int closestTimeToFinish = INT_MAX;
465 for (int i = 0; i < pausedAnimationTimers.size(); ++i) {
466 int timeToFinish = pausedAnimationTimers.at(i)->pauseDuration;
467 if (timeToFinish < closestTimeToFinish)
468 closestTimeToFinish = timeToFinish;
470 return closestTimeToFinish;
473 void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
475 if (driver != &defaultDriver) {
476 qWarning("QUnifiedTimer: animation driver already installed...");
480 if (driver->isRunning()) {
482 d->setStartTime(time.isValid() ? time.elapsed() : 0);
490 void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
493 qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
497 driver = &defaultDriver;
499 if (d->isRunning()) {
501 driver->setStartTime(time.isValid() ? time.elapsed() : 0);
507 Returns true if \a d is the currently installed animation driver
508 and is not the default animation driver (which can never be uninstalled).
510 bool QUnifiedTimer::canUninstallAnimationDriver(QAnimationDriver *d)
512 return d == driver && driver != &defaultDriver;
516 Q_GLOBAL_STATIC(QThreadStorage<QAnimationTimer *>, animationTimer)
519 QAnimationTimer::QAnimationTimer() :
520 QAbstractAnimationTimer(), lastTick(0),
521 currentAnimationIdx(0), insideTick(false),
522 startAnimationPending(false), stopTimerPending(false),
523 runningLeafAnimations(0)
527 QAnimationTimer *QAnimationTimer::instance(bool create)
529 QAnimationTimer *inst;
531 if (create && !animationTimer()->hasLocalData()) {
532 inst = new QAnimationTimer;
533 animationTimer()->setLocalData(inst);
535 inst = animationTimer() ? animationTimer()->localData() : 0;
538 static QAnimationTimer animationTimer;
539 inst = &animationTimer;
544 QAnimationTimer *QAnimationTimer::instance()
546 return instance(true);
549 void QAnimationTimer::ensureTimerUpdate()
551 QAnimationTimer *inst = QAnimationTimer::instance(false);
552 QUnifiedTimer *instU = QUnifiedTimer::instance(false);
553 if (instU && inst && inst->isPaused)
554 instU->updateAnimationTimers(-1);
557 void QAnimationTimer::updateAnimationsTime(qint64 delta)
559 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
565 //we make sure we only call update time if the time has actually changed
566 //it might happen in some cases that the time doesn't change because events are delayed
567 //when the CPU load is high
570 for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
571 QAbstractAnimation *animation = animations.at(currentAnimationIdx);
572 int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
573 + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
574 animation->setCurrentTime(elapsed);
577 currentAnimationIdx = 0;
581 void QAnimationTimer::updateAnimationTimer()
583 QAnimationTimer *inst = QAnimationTimer::instance(false);
585 inst->restartAnimationTimer();
588 void QAnimationTimer::restartAnimationTimer()
590 if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
591 QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
593 QUnifiedTimer::resumeAnimationTimer(this);
594 else if (!isRegistered)
595 QUnifiedTimer::startAnimationTimer(this);
598 void QAnimationTimer::startAnimations()
600 startAnimationPending = false;
601 //force timer to update, which prevents large deltas for our newly added animations
602 if (!animations.isEmpty())
603 QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
605 //we transfer the waiting animations into the "really running" state
606 animations += animationsToStart;
607 animationsToStart.clear();
608 if (!animations.isEmpty())
609 restartAnimationTimer();
612 void QAnimationTimer::stopTimer()
614 stopTimerPending = false;
615 if (animations.isEmpty()) {
616 QUnifiedTimer::resumeAnimationTimer(this);
617 QUnifiedTimer::stopAnimationTimer(this);
618 // invalidate the start reference time
623 void QAnimationTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
625 QAnimationTimer *inst = instance(true); //we create the instance if needed
626 inst->registerRunningAnimation(animation);
628 Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
629 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
630 inst->animationsToStart << animation;
631 if (!inst->startAnimationPending) {
632 inst->startAnimationPending = true;
633 QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
638 void QAnimationTimer::unregisterAnimation(QAbstractAnimation *animation)
640 QAnimationTimer *inst = QAnimationTimer::instance(false);
642 //at this point the unified timer should have been created
643 //but it might also have been already destroyed in case the application is shutting down
645 inst->unregisterRunningAnimation(animation);
647 if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
650 int idx = inst->animations.indexOf(animation);
652 inst->animations.removeAt(idx);
653 // this is needed if we unregister an animation while its running
654 if (idx <= inst->currentAnimationIdx)
655 --inst->currentAnimationIdx;
657 if (inst->animations.isEmpty() && !inst->stopTimerPending) {
658 inst->stopTimerPending = true;
659 QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
662 inst->animationsToStart.removeOne(animation);
665 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
668 void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation)
670 if (QAbstractAnimationPrivate::get(animation)->isGroup)
673 if (QAbstractAnimationPrivate::get(animation)->isPause) {
674 runningPauseAnimations << animation;
676 runningLeafAnimations++;
679 void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
681 if (QAbstractAnimationPrivate::get(animation)->isGroup)
684 if (QAbstractAnimationPrivate::get(animation)->isPause)
685 runningPauseAnimations.removeOne(animation);
687 runningLeafAnimations--;
688 Q_ASSERT(runningLeafAnimations >= 0);
691 int QAnimationTimer::closestPauseAnimationTimeToFinish()
693 int closestTimeToFinish = INT_MAX;
694 for (int i = 0; i < runningPauseAnimations.size(); ++i) {
695 QAbstractAnimation *animation = runningPauseAnimations.at(i);
698 if (animation->direction() == QAbstractAnimation::Forward)
699 timeToFinish = animation->duration() - animation->currentLoopTime();
701 timeToFinish = animation->currentLoopTime();
703 if (timeToFinish < closestTimeToFinish)
704 closestTimeToFinish = timeToFinish;
706 return closestTimeToFinish;
710 \class QAnimationDriver
712 \brief The QAnimationDriver class is used to exchange the mechanism that drives animations.
714 The default animation system is driven by a timer that fires at regular intervals.
715 In some scenarios, it is better to drive the animation based on other synchronization
716 mechanisms, such as the vertical refresh rate of the screen.
721 QAnimationDriver::QAnimationDriver(QObject *parent)
722 : QObject(*(new QAnimationDriverPrivate), parent)
726 QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent)
727 : QObject(dd, parent)
731 QAnimationDriver::~QAnimationDriver()
733 QUnifiedTimer *timer = QUnifiedTimer::instance(false);
734 if (timer && timer->canUninstallAnimationDriver(this))
740 Sets the time at which an animation driver should start at.
742 This is to take into account that pauses can occur in running
743 animations which will stop the driver, but the time still
746 void QAnimationDriver::setStartTime(qint64 startTime)
748 Q_D(QAnimationDriver);
749 d->startTime = startTime;
753 Returns the start time of the animation.
755 qint64 QAnimationDriver::startTime() const
757 Q_D(const QAnimationDriver);
763 Advances the animation based to the specified \a timeStep. This function should
764 be continuously called by the driver subclasses while the animation is running.
766 If \a timeStep is positive, it will be used as the current time in the
767 calculations; otherwise, the current clock time will be used.
770 void QAnimationDriver::advanceAnimation(qint64 timeStep)
772 QUnifiedTimer *instance = QUnifiedTimer::instance();
774 // update current time on all top level animations
775 instance->updateAnimationTimers(timeStep);
782 Advances the animation. This function should be continously called
783 by the driver while the animation is running.
786 void QAnimationDriver::advance()
788 advanceAnimation(-1);
794 Installs this animation driver. The animation driver is thread local and
795 will only apply for the thread its installed in.
798 void QAnimationDriver::install()
800 QUnifiedTimer *timer = QUnifiedTimer::instance(true);
801 timer->installAnimationDriver(this);
807 Uninstalls this animation driver.
810 void QAnimationDriver::uninstall()
812 QUnifiedTimer *timer = QUnifiedTimer::instance(true);
813 timer->uninstallAnimationDriver(this);
816 bool QAnimationDriver::isRunning() const
818 return d_func()->running;
822 void QAnimationDriver::start()
824 Q_D(QAnimationDriver);
832 void QAnimationDriver::stop()
834 Q_D(QAnimationDriver);
843 \fn qint64 QAnimationDriver::elapsed() const
845 Returns the number of milliseconds since the animations was started.
848 qint64 QAnimationDriver::elapsed() const
850 // The default implementation picks up the elapsed time from the
851 // unified timer and can ignore the time offset.
852 return QUnifiedTimer::instance()->time.elapsed();
856 \fn QAnimationDriver::started()
858 This signal is emitted by the animation framework to notify the driver
859 that continous animation has started.
865 \fn QAnimationDriver::stopped()
867 This signal is emitted by the animation framework to notify the driver
868 that continous animation has stopped.
874 The default animation driver just spins the timer...
876 QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
877 : QAnimationDriver(0), m_unified_timer(timer)
879 connect(this, SIGNAL(started()), this, SLOT(startTimer()));
880 connect(this, SIGNAL(stopped()), this, SLOT(stopTimer()));
883 void QDefaultAnimationDriver::timerEvent(QTimerEvent *e)
885 Q_ASSERT(e->timerId() == m_timer.timerId());
886 Q_UNUSED(e); // if the assertions are disabled
890 void QDefaultAnimationDriver::startTimer()
892 // always use a precise timer to drive animations
893 m_timer.start(m_unified_timer->timingInterval, Qt::PreciseTimer, this);
896 void QDefaultAnimationDriver::stopTimer()
903 void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
905 Q_Q(QAbstractAnimation);
906 if (state == newState)
912 QAbstractAnimation::State oldState = state;
913 int oldCurrentTime = currentTime;
914 int oldCurrentLoop = currentLoop;
915 QAbstractAnimation::Direction oldDirection = direction;
917 // check if we should Rewind
918 if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
919 && oldState == QAbstractAnimation::Stopped) {
920 //here we reset the time if needed
921 //we don't call setCurrentTime because this might change the way the animation
922 //behaves: changing the state or changing the current value
923 totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
924 0 : (loopCount == -1 ? q->duration() : q->totalDuration());
928 QWeakPointer<QAbstractAnimation> guard(q);
930 //(un)registration of the animation must always happen before calls to
931 //virtual function (updateState) to ensure a correct state of the timer
932 bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
933 if (oldState == QAbstractAnimation::Running) {
934 if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
935 QAnimationTimer::ensureTimerUpdate();
936 //the animation, is not running any more
937 QAnimationTimer::unregisterAnimation(q);
938 } else if (newState == QAbstractAnimation::Running) {
939 QAnimationTimer::registerAnimation(q, isTopLevel);
942 q->updateState(newState, oldState);
943 if (!guard || newState != state) //this is to be safe if updateState changes the state
946 // Notify state change
947 emit q->stateChanged(newState, oldState);
948 if (!guard || newState != state) //this is to be safe if updateState changes the state
952 case QAbstractAnimation::Paused:
954 case QAbstractAnimation::Running:
957 // this ensures that the value is updated now that the animation is running
958 if (oldState == QAbstractAnimation::Stopped) {
960 // currentTime needs to be updated if pauseTimer is active
961 QAnimationTimer::ensureTimerUpdate();
962 q->setCurrentTime(totalCurrentTime);
967 case QAbstractAnimation::Stopped:
968 // Leave running state.
969 int dura = q->duration();
971 if (deleteWhenStopped)
974 if (dura == -1 || loopCount < 0
975 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
976 || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
984 Constructs the QAbstractAnimation base class, and passes \a parent to
985 QObject's constructor.
987 \sa QVariantAnimation, QAnimationGroup
989 QAbstractAnimation::QAbstractAnimation(QObject *parent)
990 : QObject(*new QAbstractAnimationPrivate, 0)
992 // Allow auto-add on reparent
999 QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
1002 // Allow auto-add on reparent
1007 Stops the animation if it's running, then destroys the
1008 QAbstractAnimation. If the animation is part of a QAnimationGroup, it is
1009 automatically removed before it's destroyed.
1011 QAbstractAnimation::~QAbstractAnimation()
1013 Q_D(QAbstractAnimation);
1014 //we can't call stop here. Otherwise we get pure virtual calls
1015 if (d->state != Stopped) {
1016 QAbstractAnimation::State oldState = d->state;
1018 emit stateChanged(oldState, d->state);
1019 if (oldState == QAbstractAnimation::Running)
1020 QAnimationTimer::unregisterAnimation(this);
1025 \property QAbstractAnimation::state
1026 \brief state of the animation.
1028 This property describes the current state of the animation. When the
1029 animation state changes, QAbstractAnimation emits the stateChanged()
1032 QAbstractAnimation::State QAbstractAnimation::state() const
1034 Q_D(const QAbstractAnimation);
1039 If this animation is part of a QAnimationGroup, this function returns a
1040 pointer to the group; otherwise, it returns 0.
1042 \sa QAnimationGroup::addAnimation()
1044 QAnimationGroup *QAbstractAnimation::group() const
1046 Q_D(const QAbstractAnimation);
1051 \enum QAbstractAnimation::State
1053 This enum describes the state of the animation.
1055 \value Stopped The animation is not running. This is the initial state
1056 of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current
1057 time remain unchanged until either setCurrentTime() is
1058 called, or the animation is started by calling start().
1060 \value Paused The animation is paused (i.e., temporarily
1061 suspended). Calling resume() will resume animation activity.
1063 \value Running The animation is running. While control is in the event
1064 loop, QAbstractAnimation will update its current time at regular intervals,
1065 calling updateCurrentTime() when appropriate.
1067 \sa state(), stateChanged()
1071 \enum QAbstractAnimation::Direction
1073 This enum describes the direction of the animation when in \l Running state.
1075 \value Forward The current time of the animation increases with time (i.e.,
1076 moves from 0 and towards the end / duration).
1078 \value Backward The current time of the animation decreases with time (i.e.,
1079 moves from the end / duration and towards 0).
1085 \property QAbstractAnimation::direction
1086 \brief the direction of the animation when it is in \l Running
1089 This direction indicates whether the time moves from 0 towards the
1090 animation duration, or from the value of the duration and towards 0 after
1091 start() has been called.
1093 By default, this property is set to \l Forward.
1095 QAbstractAnimation::Direction QAbstractAnimation::direction() const
1097 Q_D(const QAbstractAnimation);
1098 return d->direction;
1100 void QAbstractAnimation::setDirection(Direction direction)
1102 Q_D(QAbstractAnimation);
1103 if (d->direction == direction)
1106 if (state() == Stopped) {
1107 if (direction == Backward) {
1108 d->currentTime = duration();
1109 d->currentLoop = d->loopCount - 1;
1116 // the commands order below is important: first we need to setCurrentTime with the old direction,
1117 // then update the direction on this and all children and finally restart the pauseTimer if needed
1118 if (d->hasRegisteredTimer)
1119 QAnimationTimer::ensureTimerUpdate();
1121 d->direction = direction;
1122 updateDirection(direction);
1124 if (d->hasRegisteredTimer)
1125 // needed to update the timer interval in case of a pause animation
1126 QAnimationTimer::updateAnimationTimer();
1128 emit directionChanged(direction);
1132 \property QAbstractAnimation::duration
1133 \brief the duration of the animation.
1135 If the duration is -1, it means that the duration is undefined.
1136 In this case, loopCount is ignored.
1140 \property QAbstractAnimation::loopCount
1141 \brief the loop count of the animation
1143 This property describes the loop count of the animation as an integer.
1144 By default this value is 1, indicating that the animation
1145 should run once only, and then stop. By changing it you can let the
1146 animation loop several times. With a value of 0, the animation will not
1147 run at all, and with a value of -1, the animation will loop forever
1149 It is not supported to have loop on an animation that has an undefined
1150 duration. It will only run once.
1152 int QAbstractAnimation::loopCount() const
1154 Q_D(const QAbstractAnimation);
1155 return d->loopCount;
1157 void QAbstractAnimation::setLoopCount(int loopCount)
1159 Q_D(QAbstractAnimation);
1160 d->loopCount = loopCount;
1164 \property QAbstractAnimation::currentLoop
1165 \brief the current loop of the animation
1167 This property describes the current loop of the animation. By default,
1168 the animation's loop count is 1, and so the current loop will
1169 always be 0. If the loop count is 2 and the animation runs past its
1170 duration, it will automatically rewind and restart at current time 0, and
1171 current loop 1, and so on.
1173 When the current loop changes, QAbstractAnimation emits the
1174 currentLoopChanged() signal.
1176 int QAbstractAnimation::currentLoop() const
1178 Q_D(const QAbstractAnimation);
1179 return d->currentLoop;
1183 \fn virtual int QAbstractAnimation::duration() const = 0
1185 This pure virtual function returns the duration of the animation, and
1186 defines for how long QAbstractAnimation should update the current
1187 time. This duration is local, and does not include the loop count.
1189 A return value of -1 indicates that the animation has no defined duration;
1190 the animation should run forever until stopped. This is useful for
1191 animations that are not time driven, or where you cannot easily predict
1192 its duration (e.g., event driven audio playback in a game).
1194 If the animation is a parallel QAnimationGroup, the duration will be the longest
1195 duration of all its animations. If the animation is a sequential QAnimationGroup,
1196 the duration will be the sum of the duration of all its animations.
1201 Returns the total and effective duration of the animation, including the
1204 \sa duration(), currentTime
1206 int QAbstractAnimation::totalDuration() const
1208 int dura = duration();
1211 int loopcount = loopCount();
1214 return dura * loopcount;
1218 Returns the current time inside the current loop. It can go from 0 to duration().
1220 \sa duration(), currentTime
1223 int QAbstractAnimation::currentLoopTime() const
1225 Q_D(const QAbstractAnimation);
1226 return d->currentTime;
1230 \property QAbstractAnimation::currentTime
1231 \brief the current time and progress of the animation
1233 This property describes the animation's current time. You can change the
1234 current time by calling setCurrentTime, or you can call start() and let
1235 the animation run, setting the current time automatically as the animation
1238 The animation's current time starts at 0, and ends at totalDuration().
1240 \sa loopCount, currentLoopTime()
1242 int QAbstractAnimation::currentTime() const
1244 Q_D(const QAbstractAnimation);
1245 return d->totalCurrentTime;
1247 void QAbstractAnimation::setCurrentTime(int msecs)
1249 Q_D(QAbstractAnimation);
1250 msecs = qMax(msecs, 0);
1252 // Calculate new time and loop.
1253 int dura = duration();
1254 int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
1255 if (totalDura != -1)
1256 msecs = qMin(totalDura, msecs);
1257 d->totalCurrentTime = msecs;
1259 // Update new values.
1260 int oldLoop = d->currentLoop;
1261 d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
1262 if (d->currentLoop == d->loopCount) {
1264 d->currentTime = qMax(0, dura);
1265 d->currentLoop = qMax(0, d->loopCount - 1);
1267 if (d->direction == Forward) {
1268 d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
1270 d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
1271 if (d->currentTime == dura)
1276 updateCurrentTime(d->currentTime);
1277 if (d->currentLoop != oldLoop)
1278 emit currentLoopChanged(d->currentLoop);
1280 // All animations are responsible for stopping the animation when their
1281 // own end state is reached; in this case the animation is time driven,
1282 // and has reached the end.
1283 if ((d->direction == Forward && d->totalCurrentTime == totalDura)
1284 || (d->direction == Backward && d->totalCurrentTime == 0)) {
1290 Starts the animation. The \a policy argument says whether or not the
1291 animation should be deleted when it's done. When the animation starts, the
1292 stateChanged() signal is emitted, and state() returns Running. When control
1293 reaches the event loop, the animation will run by itself, periodically
1294 calling updateCurrentTime() as the animation progresses.
1296 If the animation is currently stopped or has already reached the end,
1297 calling start() will rewind the animation and start again from the beginning.
1298 When the animation reaches the end, the animation will either stop, or
1299 if the loop level is more than 1, it will rewind and continue from the beginning.
1301 If the animation is already running, this function does nothing.
1305 void QAbstractAnimation::start(DeletionPolicy policy)
1307 Q_D(QAbstractAnimation);
1308 if (d->state == Running)
1310 d->deleteWhenStopped = policy;
1311 d->setState(Running);
1315 Stops the animation. When the animation is stopped, it emits the stateChanged()
1316 signal, and state() returns Stopped. The current time is not changed.
1318 If the animation stops by itself after reaching the end (i.e.,
1319 currentLoopTime() == duration() and currentLoop() > loopCount() - 1), the
1320 finished() signal is emitted.
1322 \sa start(), state()
1324 void QAbstractAnimation::stop()
1326 Q_D(QAbstractAnimation);
1328 if (d->state == Stopped)
1331 d->setState(Stopped);
1335 Pauses the animation. When the animation is paused, state() returns Paused.
1336 The value of currentTime will remain unchanged until resume() or start()
1337 is called. If you want to continue from the current time, call resume().
1339 \sa start(), state(), resume()
1341 void QAbstractAnimation::pause()
1343 Q_D(QAbstractAnimation);
1344 if (d->state == Stopped) {
1345 qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
1349 d->setState(Paused);
1353 Resumes the animation after it was paused. When the animation is resumed,
1354 it emits the resumed() and stateChanged() signals. The currenttime is not
1357 \sa start(), pause(), state()
1359 void QAbstractAnimation::resume()
1361 Q_D(QAbstractAnimation);
1362 if (d->state != Paused) {
1363 qWarning("QAbstractAnimation::resume: "
1364 "Cannot resume an animation that is not paused");
1368 d->setState(Running);
1372 If \a paused is true, the animation is paused.
1373 If \a paused is false, the animation is resumed.
1375 \sa state(), pause(), resume()
1377 void QAbstractAnimation::setPaused(bool paused)
1389 bool QAbstractAnimation::event(QEvent *event)
1391 return QObject::event(event);
1395 \fn virtual void QAbstractAnimation::updateCurrentTime(int currentTime) = 0;
1397 This pure virtual function is called every time the animation's
1398 \a currentTime changes.
1404 This virtual function is called by QAbstractAnimation when the state
1405 of the animation is changed from \a oldState to \a newState.
1407 \sa start(), stop(), pause(), resume()
1409 void QAbstractAnimation::updateState(QAbstractAnimation::State newState,
1410 QAbstractAnimation::State oldState)
1417 This virtual function is called by QAbstractAnimation when the direction
1418 of the animation is changed. The \a direction argument is the new direction.
1420 \sa setDirection(), direction()
1422 void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction)
1424 Q_UNUSED(direction);
1430 #include "moc_qabstractanimation.cpp"
1432 #endif //QT_NO_ANIMATION