1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40/*!
41 \class QAbstractAnimation
42 \inmodule QtCore
43 \ingroup animation
44 \brief The QAbstractAnimation class is the base of all animations.
45 \since 4.6
46
47 The class defines the functions for the functionality shared by
48 all animations. By inheriting this class, you can create custom
49 animations that plug into the rest of the animation framework.
50
51 The progress of an animation is given by its current time
52 (currentLoopTime()), which is measured in milliseconds from the start
53 of the animation (0) to its end (duration()). The value is updated
54 automatically while the animation is running. It can also be set
55 directly with setCurrentTime().
56
57 At any point an animation is in one of three states:
58 \l{QAbstractAnimation::}{Running},
59 \l{QAbstractAnimation::}{Stopped}, or
60 \l{QAbstractAnimation::}{Paused}--as defined by the
61 \l{QAbstractAnimation::}{State} enum. The current state can be
62 changed by calling start(), stop(), pause(), or resume(). An
63 animation will always reset its \l{currentTime()}{current time}
64 when it is started. If paused, it will continue with the same
65 current time when resumed. When an animation is stopped, it cannot
66 be resumed, but will keep its current time (until started again).
67 QAbstractAnimation will emit stateChanged() whenever its state
68 changes.
69
70 An animation can loop any number of times by setting the loopCount
71 property. When an animation's current time reaches its duration(),
72 it will reset the current time and keep running. A loop count of 1
73 (the default value) means that the animation will run one time.
74 Note that a duration of -1 means that the animation will run until
75 stopped; the current time will increase indefinitely. When the
76 current time equals duration() and the animation is in its
77 final loop, the \l{QAbstractAnimation::}{Stopped} state is
78 entered, and the finished() signal is emitted.
79
80 QAbstractAnimation provides pure virtual functions used by
81 subclasses to track the progress of the animation: duration() and
82 updateCurrentTime(). The duration() function lets you report a
83 duration for the animation (as discussed above). The animation
84 framework calls updateCurrentTime() when current time has changed.
85 By reimplementing this function, you can track the animation
86 progress. Note that neither the interval between calls nor the
87 number of calls to this function are defined; though, it will
88 normally be 60 updates per second.
89
90 By reimplementing updateState(), you can track the animation's
91 state changes, which is particularly useful for animations that
92 are not driven by time.
93
94 \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework}
95*/
96
97/*!
98 \enum QAbstractAnimation::DeletionPolicy
99
100 \value KeepWhenStopped The animation will not be deleted when stopped.
101 \value DeleteWhenStopped The animation will be automatically deleted when
102 stopped.
103*/
104
105/*!
106 \fn void QAbstractAnimation::finished()
107
108 QAbstractAnimation emits this signal after the animation has stopped and
109 has reached the end.
110
111 This signal is emitted after stateChanged().
112
113 \sa stateChanged()
114*/
115
116/*!
117 \fn void QAbstractAnimation::stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
118
119 QAbstractAnimation emits this signal whenever the state of the animation has
120 changed from \a oldState to \a newState. This signal is emitted after the virtual
121 updateState() function is called.
122
123 \sa updateState()
124*/
125
126/*!
127 \fn void QAbstractAnimation::currentLoopChanged(int currentLoop)
128
129 QAbstractAnimation emits this signal whenever the current loop
130 changes. \a currentLoop is the current loop.
131
132 \sa currentLoop(), loopCount()
133*/
134
135/*!
136 \fn void QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection);
137
138 QAbstractAnimation emits this signal whenever the direction has been
139 changed. \a newDirection is the new direction.
140
141 \sa direction
142*/
143
144#include "qabstractanimation.h"
145#include "qanimationgroup.h"
146
147#include <QtCore/qdebug.h>
148
149#include "qabstractanimation_p.h"
150
151#include <QtCore/qmath.h>
152#include <QtCore/qthreadstorage.h>
153#include <QtCore/qcoreevent.h>
154#include <QtCore/qpointer.h>
155#include <QtCore/qscopedvaluerollback.h>
156
157#define DEFAULT_TIMER_INTERVAL 16
158#define PAUSE_TIMER_COARSE_THRESHOLD 2000
159
160QT_BEGIN_NAMESPACE
161
162typedef QList<QAbstractAnimationTimer*>::ConstIterator TimerListConstIt;
163typedef QList<QAbstractAnimation*>::ConstIterator AnimationListConstIt;
164
165/*!
166 \class QAbstractAnimationTimer
167 \inmodule QtCore
168 \brief QAbstractAnimationTimer is the base class for animation timers.
169 \internal
170
171 Subclass QAbstractAnimationTimer to provide an animation timer that is run by
172 QUnifiedTimer and can in turn be used to run any number of animations.
173
174 Currently two subclasses have been implemented: QAnimationTimer to drive the Qt C++
175 animation framework (QAbstractAnimation and subclasses) and QDeclarativeAnimationTimer
176 to drive the Qt QML animation framework.
177*/
178
179/*!
180 \fn virtual void QAbstractAnimationTimer::updateAnimationsTime(qint64 delta) = 0;
181 \internal
182
183 This pure virtual function is called when the animation timer needs to update
184 the current time for all animations it is running.
185*/
186
187/*!
188 \fn virtual void QAbstractAnimationTimer::restartAnimationTimer() = 0;
189 \internal
190
191 This pure virtual function restarts the animation timer as needed.
192
193 Classes implementing this function may choose to pause or resume the timer
194 as appropriate, or conditionally restart it.
195*/
196
197/*!
198 \fn virtual int QAbstractAnimationTimer::runningAnimationCount() = 0;
199 \internal
200
201 This pure virtual function returns the number of animations the timer is running.
202 This information is useful for profiling.
203*/
204
205/*!
206 \class QUnifiedTimer
207 \inmodule QtCore
208 \brief QUnifiedTimer provides a unified timing mechanism for animations in Qt C++ and QML.
209 \internal
210
211 QUnifiedTimer allows animations run by Qt to share a single timer. This keeps animations
212 visually in sync, as well as being more efficient than running numerous timers.
213
214 QUnifiedTimer drives animations indirectly, via QAbstractAnimationTimer.
215*/
216
217Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
218
219QUnifiedTimer::QUnifiedTimer() :
220 QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
221 currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
222 startTimersPending(false), stopTimerPending(false),
223 slowdownFactor(5.0f), profilerCallback(nullptr),
224 driverStartTime(0), temporalDrift(0)
225{
226 time.invalidate();
227 driver = &defaultDriver;
228}
229
230
231QUnifiedTimer *QUnifiedTimer::instance(bool create)
232{
233 QUnifiedTimer *inst;
234 if (create && !unifiedTimer()->hasLocalData()) {
235 inst = new QUnifiedTimer;
236 unifiedTimer()->setLocalData(inst);
237 } else {
238 inst = unifiedTimer() ? unifiedTimer()->localData() : nullptr;
239 }
240 return inst;
241}
242
243QUnifiedTimer *QUnifiedTimer::instance()
244{
245 return instance(true);
246}
247
248void QUnifiedTimer::maybeUpdateAnimationsToCurrentTime()
249{
250 if (elapsed() - lastTick > 50)
251 updateAnimationTimers();
252}
253
254qint64 QUnifiedTimer::elapsed() const
255{
256 if (driver->isRunning())
257 return driverStartTime + driver->elapsed();
258 else if (time.isValid())
259 return time.elapsed() + temporalDrift;
260
261 // Reaching here would normally indicate that the function is called
262 // under the wrong circumstances as neither pauses nor actual animations
263 // are running and there should be no need to query for elapsed().
264 return 0;
265}
266
267void QUnifiedTimer::startAnimationDriver()
268{
269 if (driver->isRunning()) {
270 qWarning("QUnifiedTimer::startAnimationDriver: driver is already running...");
271 return;
272 }
273 // Set the start time to the currently elapsed() value before starting.
274 // This means we get the animation system time including the temporal drift
275 // which is what we want.
276 driverStartTime = elapsed();
277 driver->start();
278}
279
280void QUnifiedTimer::stopAnimationDriver()
281{
282 if (!driver->isRunning()) {
283 qWarning("QUnifiedTimer::stopAnimationDriver: driver is not running");
284 return;
285 }
286 // Update temporal drift. Since the driver is running, elapsed() will
287 // return the total animation time in driver-time. Subtract the current
288 // wall time to get the delta.
289 temporalDrift = elapsed() - time.elapsed();
290 driver->stop();
291}
292
293void QUnifiedTimer::updateAnimationTimers()
294{
295 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
296 if(insideTick)
297 return;
298
299 const qint64 totalElapsed = elapsed();
300
301 // ignore consistentTiming in case the pause timer is active
302 qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
303 timingInterval : totalElapsed - lastTick;
304 if (slowMode) {
305 if (slowdownFactor > 0)
306 delta = qRound(delta / slowdownFactor);
307 else
308 delta = 0;
309 }
310
311 lastTick = totalElapsed;
312
313 //we make sure we only call update time if the time has actually advanced
314 //* it might happen in some cases that the time doesn't change because events are delayed
315 // when the CPU load is high
316 //* it might happen in some cases that the delta is negative because the animation driver
317 // advances faster than time.elapsed()
318 if (delta > 0) {
319 QScopedValueRollback<bool> guard(insideTick, true);
320 if (profilerCallback)
321 profilerCallback(delta);
322 for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.count(); ++currentAnimationIdx) {
323 QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx);
324 animation->updateAnimationsTime(delta);
325 }
326 currentAnimationIdx = 0;
327 }
328}
329
330int QUnifiedTimer::runningAnimationCount()
331{
332 int count = 0;
333 for (int i = 0; i < animationTimers.count(); ++i)
334 count += animationTimers.at(i)->runningAnimationCount();
335 return count;
336}
337
338void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64))
339{
340 profilerCallback = cb;
341}
342
343void QUnifiedTimer::localRestart()
344{
345 if (insideRestart)
346 return;
347
348 if (!pausedAnimationTimers.isEmpty() && (animationTimers.count() + animationTimersToStart.count() == pausedAnimationTimers.count())) {
349 driver->stop();
350 int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish();
351 // use a precise timer if the pause will be short
352 Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer;
353 pauseTimer.start(closestTimeToFinish, timerType, this);
354 } else if (!driver->isRunning()) {
355 if (pauseTimer.isActive())
356 pauseTimer.stop();
357 startAnimationDriver();
358 }
359
360}
361
362void QUnifiedTimer::restart()
363{
364 {
365 QScopedValueRollback<bool> guard(insideRestart, true);
366 for (int i = 0; i < animationTimers.count(); ++i)
367 animationTimers.at(i)->restartAnimationTimer();
368 }
369
370 localRestart();
371}
372
373void QUnifiedTimer::setTimingInterval(int interval)
374{
375 timingInterval = interval;
376
377 if (driver->isRunning() && !pauseTimer.isActive()) {
378 //we changed the timing interval
379 stopAnimationDriver();
380 startAnimationDriver();
381 }
382}
383
384void QUnifiedTimer::startTimers()
385{
386 startTimersPending = false;
387
388 //we transfer the waiting animations into the "really running" state
389 animationTimers += animationTimersToStart;
390 animationTimersToStart.clear();
391 if (!animationTimers.isEmpty()) {
392 if (!time.isValid()) {
393 lastTick = 0;
394 time.start();
395 temporalDrift = 0;
396 driverStartTime = 0;
397 }
398 localRestart();
399 }
400}
401
402void QUnifiedTimer::stopTimer()
403{
404 stopTimerPending = false;
405 if (animationTimers.isEmpty()) {
406 stopAnimationDriver();
407 pauseTimer.stop();
408 // invalidate the start reference time
409 time.invalidate();
410 }
411}
412
413void QUnifiedTimer::timerEvent(QTimerEvent *event)
414{
415 //in the case of consistent timing we make sure the order in which events come is always the same
416 //for that purpose we do as if the startstoptimer would always fire before the animation timer
417 if (consistentTiming) {
418 if (stopTimerPending)
419 stopTimer();
420 if (startTimersPending)
421 startTimers();
422 }
423
424 if (event->timerId() == pauseTimer.timerId()) {
425 // update current time on all timers
426 updateAnimationTimers();
427 restart();
428 }
429}
430
431void QUnifiedTimer::startAnimationTimer(QAbstractAnimationTimer *timer)
432{
433 if (timer->isRegistered)
434 return;
435 timer->isRegistered = true;
436
437 QUnifiedTimer *inst = instance(true); //we create the instance if needed
438 inst->animationTimersToStart << timer;
439 if (!inst->startTimersPending) {
440 inst->startTimersPending = true;
441 QMetaObject::invokeMethod(inst, "startTimers", Qt::QueuedConnection);
442 }
443}
444
445void QUnifiedTimer::stopAnimationTimer(QAbstractAnimationTimer *timer)
446{
447 QUnifiedTimer *inst = QUnifiedTimer::instance(false);
448 if (inst) {
449 //at this point the unified timer should have been created
450 //but it might also have been already destroyed in case the application is shutting down
451
452 if (!timer->isRegistered)
453 return;
454 timer->isRegistered = false;
455
456 int idx = inst->animationTimers.indexOf(timer);
457 if (idx != -1) {
458 inst->animationTimers.removeAt(idx);
459 // this is needed if we unregister an animation while its running
460 if (idx <= inst->currentAnimationIdx)
461 --inst->currentAnimationIdx;
462
463 if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) {
464 inst->stopTimerPending = true;
465 QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
466 }
467 } else {
468 inst->animationTimersToStart.removeOne(timer);
469 }
470 }
471}
472
473void QUnifiedTimer::pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration)
474{
475 QUnifiedTimer *inst = QUnifiedTimer::instance();
476 if (!timer->isRegistered)
477 inst->startAnimationTimer(timer);
478
479 bool timerWasPaused = timer->isPaused;
480 timer->isPaused = true;
481 timer->pauseDuration = duration;
482 if (!timerWasPaused)
483 inst->pausedAnimationTimers << timer;
484 inst->localRestart();
485}
486
487void QUnifiedTimer::resumeAnimationTimer(QAbstractAnimationTimer *timer)
488{
489 if (!timer->isPaused)
490 return;
491
492 timer->isPaused = false;
493 QUnifiedTimer *inst = QUnifiedTimer::instance();
494 inst->pausedAnimationTimers.removeOne(timer);
495 inst->localRestart();
496}
497
498int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish()
499{
500 int closestTimeToFinish = INT_MAX;
501 for (TimerListConstIt it = pausedAnimationTimers.constBegin(), cend = pausedAnimationTimers.constEnd(); it != cend; ++it) {
502 const int timeToFinish = (*it)->pauseDuration;
503 if (timeToFinish < closestTimeToFinish)
504 closestTimeToFinish = timeToFinish;
505 }
506 return closestTimeToFinish;
507}
508
509void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
510{
511 if (driver != &defaultDriver) {
512 qWarning("QUnifiedTimer: animation driver already installed...");
513 return;
514 }
515
516 bool running = driver->isRunning();
517 if (running)
518 stopAnimationDriver();
519 driver = d;
520 if (running)
521 startAnimationDriver();
522}
523
524void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
525{
526 if (driver != d) {
527 qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
528 return;
529 }
530
531 bool running = driver->isRunning();
532 if (running)
533 stopAnimationDriver();
534 driver = &defaultDriver;
535 if (running)
536 startAnimationDriver();
537}
538
539/*!
540 Returns \c true if \a d is the currently installed animation driver
541 and is not the default animation driver (which can never be uninstalled).
542*/
543bool QUnifiedTimer::canUninstallAnimationDriver(QAnimationDriver *d)
544{
545 return d == driver && driver != &defaultDriver;
546}
547
548#if QT_CONFIG(thread)
549Q_GLOBAL_STATIC(QThreadStorage<QAnimationTimer *>, animationTimer)
550#endif
551
552QAnimationTimer::QAnimationTimer() :
553 QAbstractAnimationTimer(), lastTick(0),
554 currentAnimationIdx(0), insideTick(false),
555 startAnimationPending(false), stopTimerPending(false),
556 runningLeafAnimations(0)
557{
558}
559
560QAnimationTimer *QAnimationTimer::instance(bool create)
561{
562 QAnimationTimer *inst;
563#if QT_CONFIG(thread)
564 if (create && !animationTimer()->hasLocalData()) {
565 inst = new QAnimationTimer;
566 animationTimer()->setLocalData(inst);
567 } else {
568 inst = animationTimer() ? animationTimer()->localData() : nullptr;
569 }
570#else
571 Q_UNUSED(create);
572 static QAnimationTimer animationTimer;
573 inst = &animationTimer;
574#endif
575 return inst;
576}
577
578QAnimationTimer *QAnimationTimer::instance()
579{
580 return instance(true);
581}
582
583void QAnimationTimer::ensureTimerUpdate()
584{
585 QAnimationTimer *inst = QAnimationTimer::instance(false);
586 QUnifiedTimer *instU = QUnifiedTimer::instance(false);
587 if (instU && inst && inst->isPaused)
588 instU->updateAnimationTimers();
589}
590
591void QAnimationTimer::updateAnimationsTime(qint64 delta)
592{
593 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
594 if (insideTick)
595 return;
596
597 lastTick += delta;
598
599 //we make sure we only call update time if the time has actually changed
600 //it might happen in some cases that the time doesn't change because events are delayed
601 //when the CPU load is high
602 if (delta) {
603 QScopedValueRollback<bool> guard(insideTick, true);
604 for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
605 QAbstractAnimation *animation = animations.at(currentAnimationIdx);
606 int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
607 + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
608 animation->setCurrentTime(elapsed);
609 }
610 currentAnimationIdx = 0;
611 }
612}
613
614void QAnimationTimer::updateAnimationTimer()
615{
616 QAnimationTimer *inst = QAnimationTimer::instance(false);
617 if (inst)
618 inst->restartAnimationTimer();
619}
620
621void QAnimationTimer::restartAnimationTimer()
622{
623 if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty())
624 QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish());
625 else if (isPaused)
626 QUnifiedTimer::resumeAnimationTimer(this);
627 else if (!isRegistered)
628 QUnifiedTimer::startAnimationTimer(this);
629}
630
631void QAnimationTimer::startAnimations()
632{
633 if (!startAnimationPending)
634 return;
635 startAnimationPending = false;
636
637 //force timer to update, which prevents large deltas for our newly added animations
638 QUnifiedTimer::instance()->maybeUpdateAnimationsToCurrentTime();
639
640 //we transfer the waiting animations into the "really running" state
641 animations += animationsToStart;
642 animationsToStart.clear();
643 if (!animations.isEmpty())
644 restartAnimationTimer();
645}
646
647void QAnimationTimer::stopTimer()
648{
649 stopTimerPending = false;
650 bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
651 if (animations.isEmpty() && !pendingStart) {
652 QUnifiedTimer::resumeAnimationTimer(this);
653 QUnifiedTimer::stopAnimationTimer(this);
654 // invalidate the start reference time
655 lastTick = 0;
656 }
657}
658
659void QAnimationTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
660{
661 QAnimationTimer *inst = instance(true); //we create the instance if needed
662 inst->registerRunningAnimation(animation);
663 if (isTopLevel) {
664 Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
665 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
666 inst->animationsToStart << animation;
667 if (!inst->startAnimationPending) {
668 inst->startAnimationPending = true;
669 QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection);
670 }
671 }
672}
673
674void QAnimationTimer::unregisterAnimation(QAbstractAnimation *animation)
675{
676 QAnimationTimer *inst = QAnimationTimer::instance(false);
677 if (inst) {
678 //at this point the unified timer should have been created
679 //but it might also have been already destroyed in case the application is shutting down
680
681 inst->unregisterRunningAnimation(animation);
682
683 if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
684 return;
685
686 int idx = inst->animations.indexOf(animation);
687 if (idx != -1) {
688 inst->animations.removeAt(idx);
689 // this is needed if we unregister an animation while its running
690 if (idx <= inst->currentAnimationIdx)
691 --inst->currentAnimationIdx;
692
693 if (inst->animations.isEmpty() && !inst->stopTimerPending) {
694 inst->stopTimerPending = true;
695 QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
696 }
697 } else {
698 inst->animationsToStart.removeOne(animation);
699 }
700 }
701 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
702}
703
704void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation)
705{
706 if (QAbstractAnimationPrivate::get(animation)->isGroup)
707 return;
708
709 if (QAbstractAnimationPrivate::get(animation)->isPause) {
710 runningPauseAnimations << animation;
711 } else
712 runningLeafAnimations++;
713}
714
715void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
716{
717 if (QAbstractAnimationPrivate::get(animation)->isGroup)
718 return;
719
720 if (QAbstractAnimationPrivate::get(animation)->isPause)
721 runningPauseAnimations.removeOne(animation);
722 else
723 runningLeafAnimations--;
724 Q_ASSERT(runningLeafAnimations >= 0);
725}
726
727int QAnimationTimer::closestPauseAnimationTimeToFinish()
728{
729 int closestTimeToFinish = INT_MAX;
730 for (AnimationListConstIt it = runningPauseAnimations.constBegin(), cend = runningPauseAnimations.constEnd(); it != cend; ++it) {
731 const QAbstractAnimation *animation = *it;
732 int timeToFinish;
733
734 if (animation->direction() == QAbstractAnimation::Forward)
735 timeToFinish = animation->duration() - animation->currentLoopTime();
736 else
737 timeToFinish = animation->currentLoopTime();
738
739 if (timeToFinish < closestTimeToFinish)
740 closestTimeToFinish = timeToFinish;
741 }
742 return closestTimeToFinish;
743}
744
745/*!
746 \class QAnimationDriver
747 \inmodule QtCore
748
749 \brief The QAnimationDriver class is used to exchange the mechanism that drives animations.
750
751 The default animation system is driven by a timer that fires at regular intervals.
752 In some scenarios, it is better to drive the animation based on other synchronization
753 mechanisms, such as the vertical refresh rate of the screen.
754
755 \internal
756 */
757
758QAnimationDriver::QAnimationDriver(QObject *parent)
759 : QObject(*(new QAnimationDriverPrivate), parent)
760{
761}
762
763QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent)
764 : QObject(dd, parent)
765{
766}
767
768QAnimationDriver::~QAnimationDriver()
769{
770 QUnifiedTimer *timer = QUnifiedTimer::instance(false);
771 if (timer && timer->canUninstallAnimationDriver(this))
772 uninstall();
773}
774
775/*!
776 Advances the animation. This function should be continuously called by
777 the driver subclasses while the animation is running.
778
779 The calculation of the new current time will use elapsed() in combination
780 with the internal time offsets of the animation system.
781 */
782
783void QAnimationDriver::advanceAnimation()
784{
785 QUnifiedTimer *instance = QUnifiedTimer::instance();
786
787 // update current time on all top level animations
788 instance->updateAnimationTimers();
789 instance->restart();
790}
791
792
793
794/*!
795 Advances the animation. This function should be continously called
796 by the driver while the animation is running.
797 */
798
799void QAnimationDriver::advance()
800{
801 advanceAnimation();
802}
803
804
805
806/*!
807 Installs this animation driver. The animation driver is thread local and
808 will only apply for the thread its installed in.
809 */
810
811void QAnimationDriver::install()
812{
813 QUnifiedTimer *timer = QUnifiedTimer::instance(true);
814 timer->installAnimationDriver(this);
815}
816
817
818
819/*!
820 Uninstalls this animation driver.
821 */
822
823void QAnimationDriver::uninstall()
824{
825 QUnifiedTimer *timer = QUnifiedTimer::instance(true);
826 timer->uninstallAnimationDriver(this);
827}
828
829bool QAnimationDriver::isRunning() const
830{
831 return d_func()->running;
832}
833
834
835void QAnimationDriver::start()
836{
837 Q_D(QAnimationDriver);
838 if (!d->running) {
839 d->running = true;
840 d->timer.start();
841 emit started();
842 }
843}
844
845
846void QAnimationDriver::stop()
847{
848 Q_D(QAnimationDriver);
849 if (d->running) {
850 d->running = false;
851 emit stopped();
852 }
853}
854
855
856/*!
857 \fn qint64 QAnimationDriver::elapsed() const
858
859 Returns the number of milliseconds since the animations was started.
860 */
861
862qint64 QAnimationDriver::elapsed() const
863{
864 Q_D(const QAnimationDriver);
865 return d->running ? d->timer.elapsed() : 0;
866}
867
868/*!
869 \fn QAnimationDriver::started()
870
871 This signal is emitted by the animation framework to notify the driver
872 that continuous animation has started.
873
874 \internal
875 */
876
877/*!
878 \fn QAnimationDriver::stopped()
879
880 This signal is emitted by the animation framework to notify the driver
881 that continuous animation has stopped.
882
883 \internal
884 */
885
886/*!
887 The default animation driver just spins the timer...
888 */
889QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
890 : QAnimationDriver(nullptr), m_unified_timer(timer)
891{
892 connect(this, SIGNAL(started()), this, SLOT(startTimer()));
893 connect(this, SIGNAL(stopped()), this, SLOT(stopTimer()));
894}
895
896void QDefaultAnimationDriver::timerEvent(QTimerEvent *e)
897{
898 Q_ASSERT(e->timerId() == m_timer.timerId());
899 Q_UNUSED(e); // if the assertions are disabled
900 advance();
901}
902
903void QDefaultAnimationDriver::startTimer()
904{
905 // always use a precise timer to drive animations
906 m_timer.start(m_unified_timer->timingInterval, Qt::PreciseTimer, this);
907}
908
909void QDefaultAnimationDriver::stopTimer()
910{
911 m_timer.stop();
912}
913
914
915
916void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
917{
918 Q_Q(QAbstractAnimation);
919 if (state == newState)
920 return;
921
922 if (loopCount == 0)
923 return;
924
925 QAbstractAnimation::State oldState = state;
926 int oldCurrentTime = currentTime;
927 int oldCurrentLoop = currentLoop;
928 QAbstractAnimation::Direction oldDirection = direction;
929
930 // check if we should Rewind
931 if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
932 && oldState == QAbstractAnimation::Stopped) {
933 //here we reset the time if needed
934 //we don't call setCurrentTime because this might change the way the animation
935 //behaves: changing the state or changing the current value
936 totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
937 0 : (loopCount == -1 ? q->duration() : q->totalDuration());
938 }
939
940 state = newState;
941 QPointer<QAbstractAnimation> guard(q);
942
943 //(un)registration of the animation must always happen before calls to
944 //virtual function (updateState) to ensure a correct state of the timer
945 bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
946 if (oldState == QAbstractAnimation::Running) {
947 if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
948 QAnimationTimer::ensureTimerUpdate();
949 //the animation, is not running any more
950 QAnimationTimer::unregisterAnimation(q);
951 } else if (newState == QAbstractAnimation::Running) {
952 QAnimationTimer::registerAnimation(q, isTopLevel);
953 }
954
955 q->updateState(newState, oldState);
956 if (!guard || newState != state) //this is to be safe if updateState changes the state
957 return;
958
959 // Notify state change
960 emit q->stateChanged(newState, oldState);
961 if (!guard || newState != state) //this is to be safe if updateState changes the state
962 return;
963
964 switch (state) {
965 case QAbstractAnimation::Paused:
966 break;
967 case QAbstractAnimation::Running:
968 {
969
970 // this ensures that the value is updated now that the animation is running
971 if (oldState == QAbstractAnimation::Stopped) {
972 if (isTopLevel) {
973 // currentTime needs to be updated if pauseTimer is active
974 QAnimationTimer::ensureTimerUpdate();
975 q->setCurrentTime(totalCurrentTime);
976 }
977 }
978 }
979 break;
980 case QAbstractAnimation::Stopped:
981 // Leave running state.
982 int dura = q->duration();
983
984 if (deleteWhenStopped)
985 q->deleteLater();
986
987 if (dura == -1 || loopCount < 0
988 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
989 || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
990 emit q->finished();
991 }
992 break;
993 }
994}
995
996/*!
997 Constructs the QAbstractAnimation base class, and passes \a parent to
998 QObject's constructor.
999
1000 \sa QVariantAnimation, QAnimationGroup
1001*/
1002QAbstractAnimation::QAbstractAnimation(QObject *parent)
1003 : QObject(*new QAbstractAnimationPrivate, nullptr)
1004{
1005 // Allow auto-add on reparent
1006 setParent(parent);
1007}
1008
1009/*!
1010 \internal
1011*/
1012QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
1013 : QObject(dd, nullptr)
1014{
1015 // Allow auto-add on reparent
1016 setParent(parent);
1017}
1018
1019/*!
1020 Stops the animation if it's running, then destroys the
1021 QAbstractAnimation. If the animation is part of a QAnimationGroup, it is
1022 automatically removed before it's destroyed.
1023*/
1024QAbstractAnimation::~QAbstractAnimation()
1025{
1026 Q_D(QAbstractAnimation);
1027 //we can't call stop here. Otherwise we get pure virtual calls
1028 if (d->state != Stopped) {
1029 QAbstractAnimation::State oldState = d->state;
1030 d->state = Stopped;
1031 emit stateChanged(d->state, oldState);
1032 if (oldState == QAbstractAnimation::Running)
1033 QAnimationTimer::unregisterAnimation(this);
1034 }
1035 if (d->group)
1036 d->group->removeAnimation(this);
1037}
1038
1039/*!
1040 \property QAbstractAnimation::state
1041 \brief state of the animation.
1042
1043 This property describes the current state of the animation. When the
1044 animation state changes, QAbstractAnimation emits the stateChanged()
1045 signal.
1046*/
1047QAbstractAnimation::State QAbstractAnimation::state() const
1048{
1049 Q_D(const QAbstractAnimation);
1050 return d->state;
1051}
1052
1053/*!
1054 If this animation is part of a QAnimationGroup, this function returns a
1055 pointer to the group; otherwise, it returns \nullptr.
1056
1057 \sa QAnimationGroup::addAnimation()
1058*/
1059QAnimationGroup *QAbstractAnimation::group() const
1060{
1061 Q_D(const QAbstractAnimation);
1062 return d->group;
1063}
1064
1065/*!
1066 \enum QAbstractAnimation::State
1067
1068 This enum describes the state of the animation.
1069
1070 \value Stopped The animation is not running. This is the initial state
1071 of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current
1072 time remain unchanged until either setCurrentTime() is
1073 called, or the animation is started by calling start().
1074
1075 \value Paused The animation is paused (i.e., temporarily
1076 suspended). Calling resume() will resume animation activity.
1077
1078 \value Running The animation is running. While control is in the event
1079 loop, QAbstractAnimation will update its current time at regular intervals,
1080 calling updateCurrentTime() when appropriate.
1081
1082 \sa state(), stateChanged()
1083*/
1084
1085/*!
1086 \enum QAbstractAnimation::Direction
1087
1088 This enum describes the direction of the animation when in \l Running state.
1089
1090 \value Forward The current time of the animation increases with time (i.e.,
1091 moves from 0 and towards the end / duration).
1092
1093 \value Backward The current time of the animation decreases with time (i.e.,
1094 moves from the end / duration and towards 0).
1095
1096 \sa direction
1097*/
1098
1099/*!
1100 \property QAbstractAnimation::direction
1101 \brief the direction of the animation when it is in \l Running
1102 state.
1103
1104 This direction indicates whether the time moves from 0 towards the
1105 animation duration, or from the value of the duration and towards 0 after
1106 start() has been called.
1107
1108 By default, this property is set to \l Forward.
1109*/
1110QAbstractAnimation::Direction QAbstractAnimation::direction() const
1111{
1112 Q_D(const QAbstractAnimation);
1113 return d->direction;
1114}
1115void QAbstractAnimation::setDirection(Direction direction)
1116{
1117 Q_D(QAbstractAnimation);
1118 if (d->direction == direction)
1119 return;
1120
1121 if (state() == Stopped) {
1122 if (direction == Backward) {
1123 d->currentTime = duration();
1124 d->currentLoop = d->loopCount - 1;
1125 } else {
1126 d->currentTime = 0;
1127 d->currentLoop = 0;
1128 }
1129 }
1130
1131 // the commands order below is important: first we need to setCurrentTime with the old direction,
1132 // then update the direction on this and all children and finally restart the pauseTimer if needed
1133 if (d->hasRegisteredTimer)
1134 QAnimationTimer::ensureTimerUpdate();
1135
1136 d->direction = direction;
1137 updateDirection(direction);
1138
1139 if (d->hasRegisteredTimer)
1140 // needed to update the timer interval in case of a pause animation
1141 QAnimationTimer::updateAnimationTimer();
1142
1143 emit directionChanged(direction);
1144}
1145
1146/*!
1147 \property QAbstractAnimation::duration
1148 \brief the duration of the animation.
1149
1150 If the duration is -1, it means that the duration is undefined.
1151 In this case, loopCount is ignored.
1152*/
1153
1154/*!
1155 \property QAbstractAnimation::loopCount
1156 \brief the loop count of the animation
1157
1158 This property describes the loop count of the animation as an integer.
1159 By default this value is 1, indicating that the animation
1160 should run once only, and then stop. By changing it you can let the
1161 animation loop several times. With a value of 0, the animation will not
1162 run at all, and with a value of -1, the animation will loop forever
1163 until stopped.
1164 It is not supported to have loop on an animation that has an undefined
1165 duration. It will only run once.
1166*/
1167int QAbstractAnimation::loopCount() const
1168{
1169 Q_D(const QAbstractAnimation);
1170 return d->loopCount;
1171}
1172void QAbstractAnimation::setLoopCount(int loopCount)
1173{
1174 Q_D(QAbstractAnimation);
1175 d->loopCount = loopCount;
1176}
1177
1178/*!
1179 \property QAbstractAnimation::currentLoop
1180 \brief the current loop of the animation
1181
1182 This property describes the current loop of the animation. By default,
1183 the animation's loop count is 1, and so the current loop will
1184 always be 0. If the loop count is 2 and the animation runs past its
1185 duration, it will automatically rewind and restart at current time 0, and
1186 current loop 1, and so on.
1187
1188 When the current loop changes, QAbstractAnimation emits the
1189 currentLoopChanged() signal.
1190*/
1191int QAbstractAnimation::currentLoop() const
1192{
1193 Q_D(const QAbstractAnimation);
1194 return d->currentLoop;
1195}
1196
1197/*!
1198 \fn virtual int QAbstractAnimation::duration() const = 0
1199
1200 This pure virtual function returns the duration of the animation, and
1201 defines for how long QAbstractAnimation should update the current
1202 time. This duration is local, and does not include the loop count.
1203
1204 A return value of -1 indicates that the animation has no defined duration;
1205 the animation should run forever until stopped. This is useful for
1206 animations that are not time driven, or where you cannot easily predict
1207 its duration (e.g., event driven audio playback in a game).
1208
1209 If the animation is a parallel QAnimationGroup, the duration will be the longest
1210 duration of all its animations. If the animation is a sequential QAnimationGroup,
1211 the duration will be the sum of the duration of all its animations.
1212 \sa loopCount
1213*/
1214
1215/*!
1216 Returns the total and effective duration of the animation, including the
1217 loop count.
1218
1219 \sa duration(), currentTime
1220*/
1221int QAbstractAnimation::totalDuration() const
1222{
1223 int dura = duration();
1224 if (dura <= 0)
1225 return dura;
1226 int loopcount = loopCount();
1227 if (loopcount < 0)
1228 return -1;
1229 return dura * loopcount;
1230}
1231
1232/*!
1233 Returns the current time inside the current loop. It can go from 0 to duration().
1234
1235 \sa duration(), currentTime
1236*/
1237
1238int QAbstractAnimation::currentLoopTime() const
1239{
1240 Q_D(const QAbstractAnimation);
1241 return d->currentTime;
1242}
1243
1244/*!
1245 \property QAbstractAnimation::currentTime
1246 \brief the current time and progress of the animation
1247
1248 This property describes the animation's current time. You can change the
1249 current time by calling setCurrentTime, or you can call start() and let
1250 the animation run, setting the current time automatically as the animation
1251 progresses.
1252
1253 The animation's current time starts at 0, and ends at totalDuration().
1254
1255 \sa loopCount, currentLoopTime()
1256 */
1257int QAbstractAnimation::currentTime() const
1258{
1259 Q_D(const QAbstractAnimation);
1260 return d->totalCurrentTime;
1261}
1262void QAbstractAnimation::setCurrentTime(int msecs)
1263{
1264 Q_D(QAbstractAnimation);
1265 msecs = qMax(msecs, 0);
1266
1267 // Calculate new time and loop.
1268 int dura = duration();
1269 int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
1270 if (totalDura != -1)
1271 msecs = qMin(totalDura, msecs);
1272 d->totalCurrentTime = msecs;
1273
1274 // Update new values.
1275 int oldLoop = d->currentLoop;
1276 d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
1277 if (d->currentLoop == d->loopCount) {
1278 //we're at the end
1279 d->currentTime = qMax(0, dura);
1280 d->currentLoop = qMax(0, d->loopCount - 1);
1281 } else {
1282 if (d->direction == Forward) {
1283 d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
1284 } else {
1285 d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
1286 if (d->currentTime == dura)
1287 --d->currentLoop;
1288 }
1289 }
1290
1291 updateCurrentTime(d->currentTime);
1292 if (d->currentLoop != oldLoop)
1293 emit currentLoopChanged(d->currentLoop);
1294
1295 // All animations are responsible for stopping the animation when their
1296 // own end state is reached; in this case the animation is time driven,
1297 // and has reached the end.
1298 if ((d->direction == Forward && d->totalCurrentTime == totalDura)
1299 || (d->direction == Backward && d->totalCurrentTime == 0)) {
1300 stop();
1301 }
1302}
1303
1304/*!
1305 Starts the animation. The \a policy argument says whether or not the
1306 animation should be deleted when it's done. When the animation starts, the
1307 stateChanged() signal is emitted, and state() returns Running. When control
1308 reaches the event loop, the animation will run by itself, periodically
1309 calling updateCurrentTime() as the animation progresses.
1310
1311 If the animation is currently stopped or has already reached the end,
1312 calling start() will rewind the animation and start again from the beginning.
1313 When the animation reaches the end, the animation will either stop, or
1314 if the loop level is more than 1, it will rewind and continue from the beginning.
1315
1316 If the animation is already running, this function does nothing.
1317
1318 \sa stop(), state()
1319*/
1320void QAbstractAnimation::start(DeletionPolicy policy)
1321{
1322 Q_D(QAbstractAnimation);
1323 if (d->state == Running)
1324 return;
1325 d->deleteWhenStopped = policy;
1326 d->setState(Running);
1327}
1328
1329/*!
1330 Stops the animation. When the animation is stopped, it emits the stateChanged()
1331 signal, and state() returns Stopped. The current time is not changed.
1332
1333 If the animation stops by itself after reaching the end (i.e.,
1334 currentLoopTime() == duration() and currentLoop() > loopCount() - 1), the
1335 finished() signal is emitted.
1336
1337 \sa start(), state()
1338 */
1339void QAbstractAnimation::stop()
1340{
1341 Q_D(QAbstractAnimation);
1342
1343 if (d->state == Stopped)
1344 return;
1345
1346 d->setState(Stopped);
1347}
1348
1349/*!
1350 Pauses the animation. When the animation is paused, state() returns Paused.
1351 The value of currentTime will remain unchanged until resume() or start()
1352 is called. If you want to continue from the current time, call resume().
1353
1354 \sa start(), state(), resume()
1355 */
1356void QAbstractAnimation::pause()
1357{
1358 Q_D(QAbstractAnimation);
1359 if (d->state == Stopped) {
1360 qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
1361 return;
1362 }
1363
1364 d->setState(Paused);
1365}
1366
1367/*!
1368 Resumes the animation after it was paused. When the animation is resumed,
1369 it emits the resumed() and stateChanged() signals. The currenttime is not
1370 changed.
1371
1372 \sa start(), pause(), state()
1373 */
1374void QAbstractAnimation::resume()
1375{
1376 Q_D(QAbstractAnimation);
1377 if (d->state != Paused) {
1378 qWarning("QAbstractAnimation::resume: "
1379 "Cannot resume an animation that is not paused");
1380 return;
1381 }
1382
1383 d->setState(Running);
1384}
1385
1386/*!
1387 If \a paused is true, the animation is paused.
1388 If \a paused is false, the animation is resumed.
1389
1390 \sa state(), pause(), resume()
1391*/
1392void QAbstractAnimation::setPaused(bool paused)
1393{
1394 if (paused)
1395 pause();
1396 else
1397 resume();
1398}
1399
1400
1401/*!
1402 \reimp
1403*/
1404bool QAbstractAnimation::event(QEvent *event)
1405{
1406 return QObject::event(event);
1407}
1408
1409/*!
1410 \fn virtual void QAbstractAnimation::updateCurrentTime(int currentTime) = 0;
1411
1412 This pure virtual function is called every time the animation's
1413 \a currentTime changes.
1414
1415 \sa updateState()
1416*/
1417
1418/*!
1419 This virtual function is called by QAbstractAnimation when the state
1420 of the animation is changed from \a oldState to \a newState.
1421
1422 \sa start(), stop(), pause(), resume()
1423*/
1424void QAbstractAnimation::updateState(QAbstractAnimation::State newState,
1425 QAbstractAnimation::State oldState)
1426{
1427 Q_UNUSED(oldState);
1428 Q_UNUSED(newState);
1429}
1430
1431/*!
1432 This virtual function is called by QAbstractAnimation when the direction
1433 of the animation is changed. The \a direction argument is the new direction.
1434
1435 \sa setDirection(), direction()
1436*/
1437void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction)
1438{
1439 Q_UNUSED(direction);
1440}
1441
1442
1443QT_END_NAMESPACE
1444
1445#include "moc_qabstractanimation.cpp"
1446#include "moc_qabstractanimation_p.cpp"
1447