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
42/*!
43 \class QAbstractAnimation
44 \ingroup animation
45 \brief The QAbstractAnimation class is the base of all animations.
46 \since 4.6
47
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.
51
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().
57
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
69 changes.
70
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.
80
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.
90
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.
94
95 \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework}
96*/
97
98/*!
99 \enum QAbstractAnimation::DeletionPolicy
100
101 \value KeepWhenStopped The animation will not be deleted when stopped.
102 \value DeleteWhenStopped The animation will be automatically deleted when
103 stopped.
104*/
105
106/*!
107 \fn QAbstractAnimation::finished()
108
109 QAbstractAnimation emits this signal after the animation has stopped and
110 has reached the end.
111
112 This signal is emitted after stateChanged().
113
114 \sa stateChanged()
115*/
116
117/*!
118 \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
119
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.
123
124 \sa updateState()
125*/
126
127/*!
128 \fn QAbstractAnimation::currentLoopChanged(int currentLoop)
129
130 QAbstractAnimation emits this signal whenever the current loop
131 changes. \a currentLoop is the current loop.
132
133 \sa currentLoop(), loopCount()
134*/
135
136/*!
137 \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection);
138
139 QAbstractAnimation emits this signal whenever the direction has been
140 changed. \a newDirection is the new direction.
141
142 \sa direction
143*/
144
145#include "qabstractanimation.h"
146#include "qanimationgroup.h"
147
148#include <QtCore/qdebug.h>
149
150#include "qabstractanimation_p.h"
151
152#include <QtCore/qmath.h>
153#include <QtCore/qthreadstorage.h>
154#include <QtCore/qcoreevent.h>
155#include <QtCore/qpointer.h>
156
157#ifndef QT_NO_ANIMATION
158
159#define DEFAULT_TIMER_INTERVAL 16
160#define STARTSTOP_TIMER_DELAY 0
161
162QT_BEGIN_NAMESPACE
163
164#ifndef QT_NO_THREAD
165Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
166#endif
167
168QUnifiedTimer::QUnifiedTimer() :
169 QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
170 currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false),
171 slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0)
172{
173 time.invalidate();
174 driver = &defaultDriver;
175}
176
177
178QUnifiedTimer *QUnifiedTimer::instance(bool create)
179{
180 QUnifiedTimer *inst;
181#ifndef QT_NO_THREAD
182 if (create && !unifiedTimer()->hasLocalData()) {
183 inst = new QUnifiedTimer;
184 unifiedTimer()->setLocalData(inst);
185 } else {
186 inst = unifiedTimer()->localData();
187 }
188#else
189 static QUnifiedTimer unifiedTimer;
190 inst = &unifiedTimer;
191#endif
192 return inst;
193}
194
195QUnifiedTimer *QUnifiedTimer::instance()
196{
197 return instance(true);
198}
199
200void QUnifiedTimer::ensureTimerUpdate()
201{
202 QUnifiedTimer *inst = QUnifiedTimer::instance(false);
203 if (inst && inst->isPauseTimerActive)
204 inst->updateAnimationsTime();
205}
206
207void QUnifiedTimer::updateAnimationsTime()
208{
209 //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
210 if(insideTick)
211 return;
212
213 qint64 totalElapsed = time.elapsed();
214 // ignore consistentTiming in case the pause timer is active
215 int delta = (consistentTiming && !isPauseTimerActive) ?
216 timingInterval : totalElapsed - lastTick;
217 if (slowMode) {
218 if (slowdownFactor > 0)
219 delta = qRound(delta / slowdownFactor);
220 else
221 delta = 0;
222 }
223
224 lastTick = totalElapsed;
225
226 //we make sure we only call update time if the time has actually changed
227 //it might happen in some cases that the time doesn't change because events are delayed
228 //when the CPU load is high
229 if (delta) {
230 insideTick = true;
231 for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) {
232 QAbstractAnimation *animation = animations.at(currentAnimationIdx);
233 int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime
234 + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
235 animation->setCurrentTime(elapsed);
236 }
237 insideTick = false;
238 currentAnimationIdx = 0;
239 }
240}
241
242void QUnifiedTimer::updateAnimationTimer()
243{
244 QUnifiedTimer *inst = QUnifiedTimer::instance(false);
245 if (inst)
246 inst->restartAnimationTimer();
247}
248
249void QUnifiedTimer::restartAnimationTimer()
250{
251 if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
252 int closestTimeToFinish = closestPauseAnimationTimeToFinish();
253 if (closestTimeToFinish < 0) {
254 qDebug() << runningPauseAnimations;
255 qDebug() << closestPauseAnimationTimeToFinish();
256 }
257 driver->stop();
258 animationTimer.start(closestTimeToFinish, this);
259 isPauseTimerActive = true;
260 } else if (!driver->isRunning() || isPauseTimerActive) {
261 driver->start();
262 isPauseTimerActive = false;
263 } else if (runningLeafAnimations == 0)
264 driver->stop();
265}
266
267void QUnifiedTimer::setTimingInterval(int interval)
268{
269 timingInterval = interval;
270
271 if (driver->isRunning() && !isPauseTimerActive) {
272 //we changed the timing interval
273 driver->stop();
274 driver->start();
275 }
276}
277
278
279void QUnifiedTimer::timerEvent(QTimerEvent *event)
280{
281 //in the case of consistent timing we make sure the orders in which events come is always the same
282 //for that purpose we do as if the startstoptimer would always fire before the animation timer
283 if ((consistentTiming && startStopAnimationTimer.isActive()) ||
284 event->timerId() == startStopAnimationTimer.timerId()) {
285 startStopAnimationTimer.stop();
286
287 //we transfer the waiting animations into the "really running" state
288 animations += animationsToStart;
289 animationsToStart.clear();
290 if (animations.isEmpty()) {
291 animationTimer.stop();
292 isPauseTimerActive = false;
293 // invalidate the start reference time
294 time.invalidate();
295 } else {
296 restartAnimationTimer();
297 if (!time.isValid()) {
298 lastTick = 0;
299 time.start();
300 }
301 }
302 }
303
304 if (event->timerId() == animationTimer.timerId()) {
305 // update current time on all top level animations
306 updateAnimationsTime();
307 restartAnimationTimer();
308 }
309}
310
311void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
312{
313 QUnifiedTimer *inst = instance(true); //we create the instance if needed
314 inst->registerRunningAnimation(animation);
315 if (isTopLevel) {
316 Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
317 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
318 inst->animationsToStart << animation;
319 if (!inst->startStopAnimationTimer.isActive())
320 inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
321 }
322}
323
324void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
325{
326 QUnifiedTimer *inst = QUnifiedTimer::instance(false);
327 if (inst) {
328 //at this point the unified timer should have been created
329 //but it might also have been already destroyed in case the application is shutting down
330
331 inst->unregisterRunningAnimation(animation);
332
333 if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
334 return;
335
336 int idx = inst->animations.indexOf(animation);
337 if (idx != -1) {
338 inst->animations.removeAt(idx);
339 // this is needed if we unregister an animation while its running
340 if (idx <= inst->currentAnimationIdx)
341 --inst->currentAnimationIdx;
342
343 if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive())
344 inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst);
345 } else {
346 inst->animationsToStart.removeOne(animation);
347 }
348 }
349 QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
350}
351
352void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
353{
354 if (QAbstractAnimationPrivate::get(animation)->isGroup)
355 return;
356
357 if (QAbstractAnimationPrivate::get(animation)->isPause) {
358 runningPauseAnimations << animation;
359 } else
360 runningLeafAnimations++;
361}
362
363void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
364{
365 if (QAbstractAnimationPrivate::get(animation)->isGroup)
366 return;
367
368 if (QAbstractAnimationPrivate::get(animation)->isPause)
369 runningPauseAnimations.removeOne(animation);
370 else
371 runningLeafAnimations--;
372 Q_ASSERT(runningLeafAnimations >= 0);
373}
374
375int QUnifiedTimer::closestPauseAnimationTimeToFinish()
376{
377 int closestTimeToFinish = INT_MAX;
378 for (int i = 0; i < runningPauseAnimations.size(); ++i) {
379 QAbstractAnimation *animation = runningPauseAnimations.at(i);
380 int timeToFinish;
381
382 if (animation->direction() == QAbstractAnimation::Forward)
383 timeToFinish = animation->duration() - animation->currentLoopTime();
384 else
385 timeToFinish = animation->currentLoopTime();
386
387 if (timeToFinish < closestTimeToFinish)
388 closestTimeToFinish = timeToFinish;
389 }
390 return closestTimeToFinish;
391}
392
393void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
394{
395 if (driver) {
396
397 if (driver->isRunning()) {
398 qWarning("QUnifiedTimer: Cannot change animation driver while animations are running");
399 return;
400 }
401
402 if (driver != &defaultDriver)
403 delete driver;
404 }
405
406 driver = d;
407}
408
409/*!
410 \class QAnimationDriver
411
412 \brief The QAnimationDriver class is used to exchange the mechanism that drives animations.
413
414 The default animation system is driven by a timer that fires at regular intervals.
415 In some scenarios, it is better to drive the animation based on other synchronization
416 mechanisms, such as the vertical refresh rate of the screen.
417
418 \internal
419 */
420
421QAnimationDriver::QAnimationDriver(QObject *parent)
422 : QObject(*(new QAnimationDriverPrivate), parent)
423{
424}
425
426QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent)
427 : QObject(dd, parent)
428{
429}
430
431
432/*!
433 Advances the animation based on the current time. This function should
434 be continuously called by the driver while the animation is running.
435
436 \internal
437 */
438void QAnimationDriver::advance()
439{
440 QUnifiedTimer *instance = QUnifiedTimer::instance();
441
442 // update current time on all top level animations
443 instance->updateAnimationsTime();
444 instance->restartAnimationTimer();
445}
446
447
448/*!
449 Installs this animation driver. The animation driver is thread local and
450 will only apply for the thread its installed in.
451
452 \internal
453 */
454void QAnimationDriver::install()
455{
456 QUnifiedTimer *timer = QUnifiedTimer::instance(true);
457 timer->installAnimationDriver(this);
458}
459
460bool QAnimationDriver::isRunning() const
461{
462 return d_func()->running;
463}
464
465
466void QAnimationDriver::start()
467{
468 Q_D(QAnimationDriver);
469 if (!d->running) {
470 started();
471 d->running = true;
472 }
473}
474
475
476void QAnimationDriver::stop()
477{
478 Q_D(QAnimationDriver);
479 if (d->running) {
480 stopped();
481 d->running = false;
482 }
483}
484
485/*!
486 \fn QAnimationDriver::started()
487
488 This function is called by the animation framework to notify the driver
489 that it should start running.
490
491 \internal
492 */
493
494/*!
495 \fn QAnimationDriver::stopped()
496
497 This function is called by the animation framework to notify the driver
498 that it should stop running.
499
500 \internal
501 */
502
503/*!
504 The default animation driver just spins the timer...
505 */
506QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
507 : QAnimationDriver(0), m_unified_timer(timer)
508{
509}
510
511void QDefaultAnimationDriver::timerEvent(QTimerEvent *e)
512{
513 Q_ASSERT(e->timerId() == m_timer.timerId());
514 Q_UNUSED(e); // if the assertions are disabled
515 advance();
516}
517
518void QDefaultAnimationDriver::started()
519{
520 m_timer.start(m_unified_timer->timingInterval, this);
521}
522
523void QDefaultAnimationDriver::stopped()
524{
525 m_timer.stop();
526}
527
528
529
530void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
531{
532 Q_Q(QAbstractAnimation);
533 if (state == newState)
534 return;
535
536 if (loopCount == 0)
537 return;
538
539 QAbstractAnimation::State oldState = state;
540 int oldCurrentTime = currentTime;
541 int oldCurrentLoop = currentLoop;
542 QAbstractAnimation::Direction oldDirection = direction;
543
544 // check if we should Rewind
545 if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
546 && oldState == QAbstractAnimation::Stopped) {
547 //here we reset the time if needed
548 //we don't call setCurrentTime because this might change the way the animation
549 //behaves: changing the state or changing the current value
550 totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
551 0 : (loopCount == -1 ? q->duration() : q->totalDuration());
552 }
553
554 state = newState;
555 QWeakPointer<QAbstractAnimation> guard(q);
556
557 //(un)registration of the animation must always happen before calls to
558 //virtual function (updateState) to ensure a correct state of the timer
559 bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
560 if (oldState == QAbstractAnimation::Running) {
561 if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
562 QUnifiedTimer::ensureTimerUpdate();
563 //the animation, is not running any more
564 QUnifiedTimer::unregisterAnimation(q);
565 } else if (newState == QAbstractAnimation::Running) {
566 QUnifiedTimer::registerAnimation(q, isTopLevel);
567 }
568
569 q->updateState(newState, oldState);
570 if (!guard || newState != state) //this is to be safe if updateState changes the state
571 return;
572
573 // Notify state change
574 emit q->stateChanged(newState, oldState);
575 if (!guard || newState != state) //this is to be safe if updateState changes the state
576 return;
577
578 switch (state) {
579 case QAbstractAnimation::Paused:
580 break;
581 case QAbstractAnimation::Running:
582 {
583
584 // this ensures that the value is updated now that the animation is running
585 if (oldState == QAbstractAnimation::Stopped) {
586 if (isTopLevel) {
587 // currentTime needs to be updated if pauseTimer is active
588 QUnifiedTimer::ensureTimerUpdate();
589 q->setCurrentTime(totalCurrentTime);
590 }
591 }
592 }
593 break;
594 case QAbstractAnimation::Stopped:
595 // Leave running state.
596 int dura = q->duration();
597
598 if (deleteWhenStopped)
599 q->deleteLater();
600
601 if (dura == -1 || loopCount < 0
602 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount))
603 || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) {
604 emit q->finished();
605 }
606 break;
607 }
608}
609
610/*!
611 Constructs the QAbstractAnimation base class, and passes \a parent to
612 QObject's constructor.
613
614 \sa QVariantAnimation, QAnimationGroup
615*/
616QAbstractAnimation::QAbstractAnimation(QObject *parent)
617 : QObject(*new QAbstractAnimationPrivate, 0)
618{
619 // Allow auto-add on reparent
620 setParent(parent);
621}
622
623/*!
624 \internal
625*/
626QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent)
627 : QObject(dd, 0)
628{
629 // Allow auto-add on reparent
630 setParent(parent);
631}
632
633/*!
634 Stops the animation if it's running, then destroys the
635 QAbstractAnimation. If the animation is part of a QAnimationGroup, it is
636 automatically removed before it's destroyed.
637*/
638QAbstractAnimation::~QAbstractAnimation()
639{
640 Q_D(QAbstractAnimation);
641 //we can't call stop here. Otherwise we get pure virtual calls
642 if (d->state != Stopped) {
643 QAbstractAnimation::State oldState = d->state;
644 d->state = Stopped;
645 emit stateChanged(oldState, d->state);
646 if (oldState == QAbstractAnimation::Running)
647 QUnifiedTimer::unregisterAnimation(this);
648 }
649}
650
651/*!
652 \property QAbstractAnimation::state
653 \brief state of the animation.
654
655 This property describes the current state of the animation. When the
656 animation state changes, QAbstractAnimation emits the stateChanged()
657 signal.
658*/
659QAbstractAnimation::State QAbstractAnimation::state() const
660{
661 Q_D(const QAbstractAnimation);
662 return d->state;
663}
664
665/*!
666 If this animation is part of a QAnimationGroup, this function returns a
667 pointer to the group; otherwise, it returns 0.
668
669 \sa QAnimationGroup::addAnimation()
670*/
671QAnimationGroup *QAbstractAnimation::group() const
672{
673 Q_D(const QAbstractAnimation);
674 return d->group;
675}
676
677/*!
678 \enum QAbstractAnimation::State
679
680 This enum describes the state of the animation.
681
682 \value Stopped The animation is not running. This is the initial state
683 of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current
684 time remain unchanged until either setCurrentTime() is
685 called, or the animation is started by calling start().
686
687 \value Paused The animation is paused (i.e., temporarily
688 suspended). Calling resume() will resume animation activity.
689
690 \value Running The animation is running. While control is in the event
691 loop, QAbstractAnimation will update its current time at regular intervals,
692 calling updateCurrentTime() when appropriate.
693
694 \sa state(), stateChanged()
695*/
696
697/*!
698 \enum QAbstractAnimation::Direction
699
700 This enum describes the direction of the animation when in \l Running state.
701
702 \value Forward The current time of the animation increases with time (i.e.,
703 moves from 0 and towards the end / duration).
704
705 \value Backward The current time of the animation decreases with time (i.e.,
706 moves from the end / duration and towards 0).
707
708 \sa direction
709*/
710
711/*!
712 \property QAbstractAnimation::direction
713 \brief the direction of the animation when it is in \l Running
714 state.
715
716 This direction indicates whether the time moves from 0 towards the
717 animation duration, or from the value of the duration and towards 0 after
718 start() has been called.
719
720 By default, this property is set to \l Forward.
721*/
722QAbstractAnimation::Direction QAbstractAnimation::direction() const
723{
724 Q_D(const QAbstractAnimation);
725 return d->direction;
726}
727void QAbstractAnimation::setDirection(Direction direction)
728{
729 Q_D(QAbstractAnimation);
730 if (d->direction == direction)
731 return;
732
733 if (state() == Stopped) {
734 if (direction == Backward) {
735 d->currentTime = duration();
736 d->currentLoop = d->loopCount - 1;
737 } else {
738 d->currentTime = 0;
739 d->currentLoop = 0;
740 }
741 }
742
743 // the commands order below is important: first we need to setCurrentTime with the old direction,
744 // then update the direction on this and all children and finally restart the pauseTimer if needed
745 if (d->hasRegisteredTimer)
746 QUnifiedTimer::ensureTimerUpdate();
747
748 d->direction = direction;
749 updateDirection(direction);
750
751 if (d->hasRegisteredTimer)
752 // needed to update the timer interval in case of a pause animation
753 QUnifiedTimer::updateAnimationTimer();
754
755 emit directionChanged(direction);
756}
757
758/*!
759 \property QAbstractAnimation::duration
760 \brief the duration of the animation.
761
762 If the duration is -1, it means that the duration is undefined.
763 In this case, loopCount is ignored.
764*/
765
766/*!
767 \property QAbstractAnimation::loopCount
768 \brief the loop count of the animation
769
770 This property describes the loop count of the animation as an integer.
771 By default this value is 1, indicating that the animation
772 should run once only, and then stop. By changing it you can let the
773 animation loop several times. With a value of 0, the animation will not
774 run at all, and with a value of -1, the animation will loop forever
775 until stopped.
776 It is not supported to have loop on an animation that has an undefined
777 duration. It will only run once.
778*/
779int QAbstractAnimation::loopCount() const
780{
781 Q_D(const QAbstractAnimation);
782 return d->loopCount;
783}
784void QAbstractAnimation::setLoopCount(int loopCount)
785{
786 Q_D(QAbstractAnimation);
787 d->loopCount = loopCount;
788}
789
790/*!
791 \property QAbstractAnimation::currentLoop
792 \brief the current loop of the animation
793
794 This property describes the current loop of the animation. By default,
795 the animation's loop count is 1, and so the current loop will
796 always be 0. If the loop count is 2 and the animation runs past its
797 duration, it will automatically rewind and restart at current time 0, and
798 current loop 1, and so on.
799
800 When the current loop changes, QAbstractAnimation emits the
801 currentLoopChanged() signal.
802*/
803int QAbstractAnimation::currentLoop() const
804{
805 Q_D(const QAbstractAnimation);
806 return d->currentLoop;
807}
808
809/*!
810 \fn virtual int QAbstractAnimation::duration() const = 0
811
812 This pure virtual function returns the duration of the animation, and
813 defines for how long QAbstractAnimation should update the current
814 time. This duration is local, and does not include the loop count.
815
816 A return value of -1 indicates that the animation has no defined duration;
817 the animation should run forever until stopped. This is useful for
818 animations that are not time driven, or where you cannot easily predict
819 its duration (e.g., event driven audio playback in a game).
820
821 If the animation is a parallel QAnimationGroup, the duration will be the longest
822 duration of all its animations. If the animation is a sequential QAnimationGroup,
823 the duration will be the sum of the duration of all its animations.
824 \sa loopCount
825*/
826
827/*!
828 Returns the total and effective duration of the animation, including the
829 loop count.
830
831 \sa duration(), currentTime
832*/
833int QAbstractAnimation::totalDuration() const
834{
835 int dura = duration();
836 if (dura <= 0)
837 return dura;
838 int loopcount = loopCount();
839 if (loopcount < 0)
840 return -1;
841 return dura * loopcount;
842}
843
844/*!
845 Returns the current time inside the current loop. It can go from 0 to duration().
846
847 \sa duration(), currentTime
848*/
849
850int QAbstractAnimation::currentLoopTime() const
851{
852 Q_D(const QAbstractAnimation);
853 return d->currentTime;
854}
855
856/*!
857 \property QAbstractAnimation::currentTime
858 \brief the current time and progress of the animation
859
860 This property describes the animation's current time. You can change the
861 current time by calling setCurrentTime, or you can call start() and let
862 the animation run, setting the current time automatically as the animation
863 progresses.
864
865 The animation's current time starts at 0, and ends at totalDuration().
866
867 \sa loopCount, currentLoopTime()
868 */
869int QAbstractAnimation::currentTime() const
870{
871 Q_D(const QAbstractAnimation);
872 return d->totalCurrentTime;
873}
874void QAbstractAnimation::setCurrentTime(int msecs)
875{
876 Q_D(QAbstractAnimation);
877 msecs = qMax(msecs, 0);
878
879 // Calculate new time and loop.
880 int dura = duration();
881 int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
882 if (totalDura != -1)
883 msecs = qMin(totalDura, msecs);
884 d->totalCurrentTime = msecs;
885
886 // Update new values.
887 int oldLoop = d->currentLoop;
888 d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
889 if (d->currentLoop == d->loopCount) {
890 //we're at the end
891 d->currentTime = qMax(0, dura);
892 d->currentLoop = qMax(0, d->loopCount - 1);
893 } else {
894 if (d->direction == Forward) {
895 d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
896 } else {
897 d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
898 if (d->currentTime == dura)
899 --d->currentLoop;
900 }
901 }
902
903 updateCurrentTime(d->currentTime);
904 if (d->currentLoop != oldLoop)
905 emit currentLoopChanged(d->currentLoop);
906
907 // All animations are responsible for stopping the animation when their
908 // own end state is reached; in this case the animation is time driven,
909 // and has reached the end.
910 if ((d->direction == Forward && d->totalCurrentTime == totalDura)
911 || (d->direction == Backward && d->totalCurrentTime == 0)) {
912 stop();
913 }
914}
915
916/*!
917 Starts the animation. The \a policy argument says whether or not the
918 animation should be deleted when it's done. When the animation starts, the
919 stateChanged() signal is emitted, and state() returns Running. When control
920 reaches the event loop, the animation will run by itself, periodically
921 calling updateCurrentTime() as the animation progresses.
922
923 If the animation is currently stopped or has already reached the end,
924 calling start() will rewind the animation and start again from the beginning.
925 When the animation reaches the end, the animation will either stop, or
926 if the loop level is more than 1, it will rewind and continue from the beginning.
927
928 If the animation is already running, this function does nothing.
929
930 \sa stop(), state()
931*/
932void QAbstractAnimation::start(DeletionPolicy policy)
933{
934 Q_D(QAbstractAnimation);
935 if (d->state == Running)
936 return;
937 d->deleteWhenStopped = policy;
938 d->setState(Running);
939}
940
941/*!
942 Stops the animation. When the animation is stopped, it emits the stateChanged()
943 signal, and state() returns Stopped. The current time is not changed.
944
945 If the animation stops by itself after reaching the end (i.e.,
946 currentLoopTime() == duration() and currentLoop() > loopCount() - 1), the
947 finished() signal is emitted.
948
949 \sa start(), state()
950 */
951void QAbstractAnimation::stop()
952{
953 Q_D(QAbstractAnimation);
954
955 if (d->state == Stopped)
956 return;
957
958 d->setState(Stopped);
959}
960
961/*!
962 Pauses the animation. When the animation is paused, state() returns Paused.
963 The value of currentTime will remain unchanged until resume() or start()
964 is called. If you want to continue from the current time, call resume().
965
966 \sa start(), state(), resume()
967 */
968void QAbstractAnimation::pause()
969{
970 Q_D(QAbstractAnimation);
971 if (d->state == Stopped) {
972 qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
973 return;
974 }
975
976 d->setState(Paused);
977}
978
979/*!
980 Resumes the animation after it was paused. When the animation is resumed,
981 it emits the resumed() and stateChanged() signals. The currenttime is not
982 changed.
983
984 \sa start(), pause(), state()
985 */
986void QAbstractAnimation::resume()
987{
988 Q_D(QAbstractAnimation);
989 if (d->state != Paused) {
990 qWarning("QAbstractAnimation::resume: "
991 "Cannot resume an animation that is not paused");
992 return;
993 }
994
995 d->setState(Running);
996}
997
998/*!
999 If \a paused is true, the animation is paused.
1000 If \a paused is false, the animation is resumed.
1001
1002 \sa state(), pause(), resume()
1003*/
1004void QAbstractAnimation::setPaused(bool paused)
1005{
1006 if (paused)
1007 pause();
1008 else
1009 resume();
1010}
1011
1012
1013/*!
1014 \reimp
1015*/
1016bool QAbstractAnimation::event(QEvent *event)
1017{
1018 return QObject::event(event);
1019}
1020
1021/*!
1022 \fn virtual void QAbstractAnimation::updateCurrentTime(int currentTime) = 0;
1023
1024 This pure virtual function is called every time the animation's
1025 \a currentTime changes.
1026
1027 \sa updateState()
1028*/
1029
1030/*!
1031 This virtual function is called by QAbstractAnimation when the state
1032 of the animation is changed from \a oldState to \a newState.
1033
1034 \sa start(), stop(), pause(), resume()
1035*/
1036void QAbstractAnimation::updateState(QAbstractAnimation::State newState,
1037 QAbstractAnimation::State oldState)
1038{
1039 Q_UNUSED(oldState);
1040 Q_UNUSED(newState);
1041}
1042
1043/*!
1044 This virtual function is called by QAbstractAnimation when the direction
1045 of the animation is changed. The \a direction argument is the new direction.
1046
1047 \sa setDirection(), direction()
1048*/
1049void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction)
1050{
1051 Q_UNUSED(direction);
1052}
1053
1054
1055QT_END_NAMESPACE
1056
1057#include "moc_qabstractanimation.cpp"
1058
1059#endif //QT_NO_ANIMATION
1060