diff options
-rw-r--r-- | src/corelib/animation/qabstractanimation.cpp | 441 | ||||
-rw-r--r-- | src/corelib/animation/qabstractanimation_p.h | 103 |
2 files changed, 414 insertions, 130 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 19a9384132..040715f54a 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -157,20 +157,69 @@ #ifndef QT_NO_ANIMATION #define DEFAULT_TIMER_INTERVAL 16 -#define STARTSTOP_TIMER_DELAY 0 #define PAUSE_TIMER_COARSE_THRESHOLD 2000 QT_BEGIN_NAMESPACE +/*! + \class QAbstractAnimationTimer + \brief QAbstractAnimationTimer is the base class for animation timers. + \internal + + Subclass QAbstractAnimationTimer to provide an animation timer that is run by + QUnifiedTimer and can in turn be used to run any number of animations. + + Currently two subclasses have been implemented: QAnimationTimer to drive the Qt C++ + animation framework (QAbstractAnimation and subclasses) and QDeclarativeAnimationTimer + to drive the Qt QML animation framework. +*/ + +/*! + \fn virtual void QAbstractAnimationTimer::updateAnimationsTime(qint64 delta) = 0; + \internal + + This pure virtual function is called when the animation timer needs to update + the current time for all animations it is running. +*/ + +/*! + \fn virtual void QAbstractAnimationTimer::restartAnimationTimer() = 0; + \internal + + This pure virtual function restarts the animation timer as needed. + + Classes implementing this function may choose to pause or resume the timer + as appropriate, or conditionally restart it. +*/ + +/*! + \fn virtual int QAbstractAnimationTimer::runningAnimationCount() = 0; + \internal + + This pure virtual function returns the number of animations the timer is running. + This information is useful for profiling. +*/ + +/*! + \class QUnifiedTimer + \brief QUnifiedTimer provides a unified timing mechanism for animations in Qt C++ and QML. + \internal + + QUnifiedTimer allows animations run by Qt to share a single timer. This keeps animations + visually in sync, as well as being more efficient than running numerous timers. + + QUnifiedTimer drives animations indirectly, via QAbstractAnimationTimer. +*/ + #ifndef QT_NO_THREAD Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) #endif QUnifiedTimer::QUnifiedTimer() : QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), - currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false), - startAnimationPending(false), stopTimerPending(false), - slowdownFactor(5.0f), runningLeafAnimations(0), profilerCallback(0) + currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false), + startTimersPending(false), stopTimerPending(false), + slowdownFactor(5.0f), profilerCallback(0) { time.invalidate(); driver = &defaultDriver; @@ -185,7 +234,7 @@ QUnifiedTimer *QUnifiedTimer::instance(bool create) inst = new QUnifiedTimer; unifiedTimer()->setLocalData(inst); } else { - inst = unifiedTimer()->localData(); + inst = unifiedTimer() ? unifiedTimer()->localData() : 0; } #else static QUnifiedTimer unifiedTimer; @@ -199,23 +248,16 @@ QUnifiedTimer *QUnifiedTimer::instance() return instance(true); } -void QUnifiedTimer::ensureTimerUpdate() -{ - QUnifiedTimer *inst = QUnifiedTimer::instance(false); - if (inst && inst->pauseTimer.isActive()) - inst->updateAnimationsTime(-1); -} - -void QUnifiedTimer::updateAnimationsTime(qint64 timeStep) +void QUnifiedTimer::updateAnimationTimers(qint64 currentTick) { //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations if(insideTick) return; - qint64 totalElapsed = timeStep >= 0 ? timeStep : time.elapsed(); + qint64 totalElapsed = currentTick >= 0 ? currentTick : time.elapsed(); // ignore consistentTiming in case the pause timer is active - int delta = (consistentTiming && !pauseTimer.isActive()) ? + qint64 delta = (consistentTiming && !pauseTimer.isActive()) ? timingInterval : totalElapsed - lastTick; if (slowMode) { if (slowdownFactor > 0) @@ -233,38 +275,36 @@ void QUnifiedTimer::updateAnimationsTime(qint64 timeStep) insideTick = true; if (profilerCallback) profilerCallback(delta); - for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { - QAbstractAnimation *animation = animations.at(currentAnimationIdx); - int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime - + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); - animation->setCurrentTime(elapsed); + for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.count(); ++currentAnimationIdx) { + QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx); + animation->updateAnimationsTime(delta); } insideTick = false; currentAnimationIdx = 0; } } -void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64)) +int QUnifiedTimer::runningAnimationCount() { - profilerCallback = cb; + int count = 0; + for (int i = 0; i < animationTimers.count(); ++i) + count += animationTimers.at(i)->runningAnimationCount(); + return count; } -void QUnifiedTimer::updateAnimationTimer() +void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64)) { - QUnifiedTimer *inst = QUnifiedTimer::instance(false); - if (inst) - inst->restartAnimationTimer(); + profilerCallback = cb; } -void QUnifiedTimer::restartAnimationTimer() +void QUnifiedTimer::localRestart() { - if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { - int closestTimeToFinish = closestPauseAnimationTimeToFinish(); - if (closestTimeToFinish < 0) { - qDebug() << runningPauseAnimations; - qDebug() << closestPauseAnimationTimeToFinish(); - } + if (insideRestart) + return; + + if (!pausedAnimationTimers.isEmpty() && (animationTimers.count() + animationTimersToStart.count() == pausedAnimationTimers.count())) { driver->stop(); + int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish(); // use a precise timer if the pause will be short Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer; pauseTimer.start(closestTimeToFinish, timerType, this); @@ -273,6 +313,17 @@ void QUnifiedTimer::restartAnimationTimer() pauseTimer.stop(); driver->start(); } + +} + +void QUnifiedTimer::restart() +{ + insideRestart = true; + for (int i = 0; i < animationTimers.count(); ++i) + animationTimers.at(i)->restartAnimationTimer(); + insideRestart = false; + + localRestart(); } void QUnifiedTimer::setTimingInterval(int interval) @@ -286,18 +337,17 @@ void QUnifiedTimer::setTimingInterval(int interval) } } -void QUnifiedTimer::startAnimations() +void QUnifiedTimer::startTimers() { - startAnimationPending = false; - //force timer to update, which prevents large deltas for our newly added animations - if (!animations.isEmpty()) - updateAnimationsTime(-1); + startTimersPending = false; + if (!animationTimers.isEmpty()) + updateAnimationTimers(-1); //we transfer the waiting animations into the "really running" state - animations += animationsToStart; - animationsToStart.clear(); - if (!animations.isEmpty()) { - restartAnimationTimer(); + animationTimers += animationTimersToStart; + animationTimersToStart.clear(); + if (!animationTimers.isEmpty()) { + localRestart(); if (!time.isValid()) { lastTick = 0; time.start(); @@ -308,7 +358,7 @@ void QUnifiedTimer::startAnimations() void QUnifiedTimer::stopTimer() { stopTimerPending = false; - if (animations.isEmpty()) { + if (animationTimers.isEmpty()) { driver->stop(); pauseTimer.stop(); // invalidate the start reference time @@ -318,109 +368,100 @@ void QUnifiedTimer::stopTimer() void QUnifiedTimer::timerEvent(QTimerEvent *event) { - //in the case of consistent timing we make sure the orders in which events come is always the same + //in the case of consistent timing we make sure the order in which events come is always the same //for that purpose we do as if the startstoptimer would always fire before the animation timer if (consistentTiming) { if (stopTimerPending) stopTimer(); - if (startAnimationPending) - startAnimations(); + if (startTimersPending) + startTimers(); } if (event->timerId() == pauseTimer.timerId()) { - // update current time on all top level animations - updateAnimationsTime(-1); - restartAnimationTimer(); + // update current time on all timers + updateAnimationTimers(-1); + restart(); } } -void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel) +void QUnifiedTimer::startAnimationTimer(QAbstractAnimationTimer *timer) { + if (timer->isRegistered) + return; + timer->isRegistered = true; + QUnifiedTimer *inst = instance(true); //we create the instance if needed - inst->registerRunningAnimation(animation); - if (isTopLevel) { - Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); - QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; - inst->animationsToStart << animation; - if (!inst->startAnimationPending) { - inst->startAnimationPending = true; - QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection); - } + inst->animationTimersToStart << timer; + if (!inst->startTimersPending) { + inst->startTimersPending = true; + QMetaObject::invokeMethod(inst, "startTimers", Qt::QueuedConnection); } } -void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) +void QUnifiedTimer::stopAnimationTimer(QAbstractAnimationTimer *timer) { QUnifiedTimer *inst = QUnifiedTimer::instance(false); if (inst) { //at this point the unified timer should have been created //but it might also have been already destroyed in case the application is shutting down - inst->unregisterRunningAnimation(animation); - - if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) + if (!timer->isRegistered) return; + timer->isRegistered = false; - int idx = inst->animations.indexOf(animation); + int idx = inst->animationTimers.indexOf(timer); if (idx != -1) { - inst->animations.removeAt(idx); + inst->animationTimers.removeAt(idx); // this is needed if we unregister an animation while its running if (idx <= inst->currentAnimationIdx) --inst->currentAnimationIdx; - if (inst->animations.isEmpty() && !inst->stopTimerPending) { + if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) { inst->stopTimerPending = true; QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection); } } else { - inst->animationsToStart.removeOne(animation); + inst->animationTimersToStart.removeOne(timer); } } - QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; } -void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation) +void QUnifiedTimer::pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration) { - if (QAbstractAnimationPrivate::get(animation)->isGroup) - return; - - if (QAbstractAnimationPrivate::get(animation)->isPause) { - runningPauseAnimations << animation; - } else - runningLeafAnimations++; + QUnifiedTimer *inst = QUnifiedTimer::instance(); + if (!timer->isRegistered) + inst->startAnimationTimer(timer); + + bool timerWasPaused = timer->isPaused; + timer->isPaused = true; + timer->pauseDuration = duration; + if (!timerWasPaused) + inst->pausedAnimationTimers << timer; + inst->localRestart(); } -void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation) +void QUnifiedTimer::resumeAnimationTimer(QAbstractAnimationTimer *timer) { - if (QAbstractAnimationPrivate::get(animation)->isGroup) + if (!timer->isPaused) return; - if (QAbstractAnimationPrivate::get(animation)->isPause) - runningPauseAnimations.removeOne(animation); - else - runningLeafAnimations--; - Q_ASSERT(runningLeafAnimations >= 0); + timer->isPaused = false; + QUnifiedTimer *inst = QUnifiedTimer::instance(); + inst->pausedAnimationTimers.removeOne(timer); + inst->localRestart(); } -int QUnifiedTimer::closestPauseAnimationTimeToFinish() +int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish() { int closestTimeToFinish = INT_MAX; - for (int i = 0; i < runningPauseAnimations.size(); ++i) { - QAbstractAnimation *animation = runningPauseAnimations.at(i); - int timeToFinish; - - if (animation->direction() == QAbstractAnimation::Forward) - timeToFinish = animation->duration() - animation->currentLoopTime(); - else - timeToFinish = animation->currentLoopTime(); - + for (int i = 0; i < pausedAnimationTimers.size(); ++i) { + int timeToFinish = pausedAnimationTimers.at(i)->pauseDuration; if (timeToFinish < closestTimeToFinish) closestTimeToFinish = timeToFinish; } return closestTimeToFinish; } - void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d) { if (driver != &defaultDriver) { @@ -437,7 +478,6 @@ void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d) } - void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d) { if (driver != d) { @@ -462,6 +502,199 @@ bool QUnifiedTimer::canUninstallAnimationDriver(QAnimationDriver *d) return d == driver && driver != &defaultDriver; } +#ifndef QT_NO_THREAD +Q_GLOBAL_STATIC(QThreadStorage<QAnimationTimer *>, animationTimer) +#endif + +QAnimationTimer::QAnimationTimer() : + QAbstractAnimationTimer(), lastTick(0), + currentAnimationIdx(0), insideTick(false), + startAnimationPending(false), stopTimerPending(false), + runningLeafAnimations(0) +{ +} + +QAnimationTimer *QAnimationTimer::instance(bool create) +{ + QAnimationTimer *inst; +#ifndef QT_NO_THREAD + if (create && !animationTimer()->hasLocalData()) { + inst = new QAnimationTimer; + animationTimer()->setLocalData(inst); + } else { + inst = animationTimer() ? animationTimer()->localData() : 0; + } +#else + static QAnimationTimer animationTimer; + inst = &animationTimer; +#endif + return inst; +} + +QAnimationTimer *QAnimationTimer::instance() +{ + return instance(true); +} + +void QAnimationTimer::ensureTimerUpdate() +{ + QAnimationTimer *inst = QAnimationTimer::instance(false); + QUnifiedTimer *instU = QUnifiedTimer::instance(false); + if (instU && inst && inst->isPaused) + instU->updateAnimationTimers(-1); +} + +void QAnimationTimer::updateAnimationsTime(qint64 delta) +{ + //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations + if (insideTick) + return; + + lastTick += delta; + + //we make sure we only call update time if the time has actually changed + //it might happen in some cases that the time doesn't change because events are delayed + //when the CPU load is high + if (delta) { + insideTick = true; + for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { + QAbstractAnimation *animation = animations.at(currentAnimationIdx); + int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime + + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); + animation->setCurrentTime(elapsed); + } + insideTick = false; + currentAnimationIdx = 0; + } +} + +void QAnimationTimer::updateAnimationTimer() +{ + QAnimationTimer *inst = QAnimationTimer::instance(false); + if (inst) + inst->restartAnimationTimer(); +} + +void QAnimationTimer::restartAnimationTimer() +{ + if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) + QUnifiedTimer::pauseAnimationTimer(this, closestPauseAnimationTimeToFinish()); + else if (isPaused) + QUnifiedTimer::resumeAnimationTimer(this); + else if (!isRegistered) + QUnifiedTimer::startAnimationTimer(this); +} + +void QAnimationTimer::startAnimations() +{ + startAnimationPending = false; + //force timer to update, which prevents large deltas for our newly added animations + if (!animations.isEmpty()) + QUnifiedTimer::instance()->updateAnimationTimers(-1); + + //we transfer the waiting animations into the "really running" state + animations += animationsToStart; + animationsToStart.clear(); + if (!animations.isEmpty()) + restartAnimationTimer(); +} + +void QAnimationTimer::stopTimer() +{ + stopTimerPending = false; + if (animations.isEmpty()) { + QUnifiedTimer::resumeAnimationTimer(this); + QUnifiedTimer::stopAnimationTimer(this); + // invalidate the start reference time + lastTick = 0; + } +} + +void QAnimationTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel) +{ + QAnimationTimer *inst = instance(true); //we create the instance if needed + inst->registerRunningAnimation(animation); + if (isTopLevel) { + Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); + QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; + inst->animationsToStart << animation; + if (!inst->startAnimationPending) { + inst->startAnimationPending = true; + QMetaObject::invokeMethod(inst, "startAnimations", Qt::QueuedConnection); + } + } +} + +void QAnimationTimer::unregisterAnimation(QAbstractAnimation *animation) +{ + QAnimationTimer *inst = QAnimationTimer::instance(false); + if (inst) { + //at this point the unified timer should have been created + //but it might also have been already destroyed in case the application is shutting down + + inst->unregisterRunningAnimation(animation); + + if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) + return; + + int idx = inst->animations.indexOf(animation); + if (idx != -1) { + inst->animations.removeAt(idx); + // this is needed if we unregister an animation while its running + if (idx <= inst->currentAnimationIdx) + --inst->currentAnimationIdx; + + if (inst->animations.isEmpty() && !inst->stopTimerPending) { + inst->stopTimerPending = true; + QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection); + } + } else { + inst->animationsToStart.removeOne(animation); + } + } + QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; +} + +void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation) +{ + if (QAbstractAnimationPrivate::get(animation)->isGroup) + return; + + if (QAbstractAnimationPrivate::get(animation)->isPause) { + runningPauseAnimations << animation; + } else + runningLeafAnimations++; +} + +void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation) +{ + if (QAbstractAnimationPrivate::get(animation)->isGroup) + return; + + if (QAbstractAnimationPrivate::get(animation)->isPause) + runningPauseAnimations.removeOne(animation); + else + runningLeafAnimations--; + Q_ASSERT(runningLeafAnimations >= 0); +} + +int QAnimationTimer::closestPauseAnimationTimeToFinish() +{ + int closestTimeToFinish = INT_MAX; + for (int i = 0; i < runningPauseAnimations.size(); ++i) { + QAbstractAnimation *animation = runningPauseAnimations.at(i); + int timeToFinish; + + if (animation->direction() == QAbstractAnimation::Forward) + timeToFinish = animation->duration() - animation->currentLoopTime(); + else + timeToFinish = animation->currentLoopTime(); + + if (timeToFinish < closestTimeToFinish) + closestTimeToFinish = timeToFinish; + } + return closestTimeToFinish; +} /*! \class QAnimationDriver @@ -507,8 +740,8 @@ void QAnimationDriver::advanceAnimation(qint64 timeStep) QUnifiedTimer *instance = QUnifiedTimer::instance(); // update current time on all top level animations - instance->updateAnimationsTime(timeStep); - instance->restartAnimationTimer(); + instance->updateAnimationTimers(timeStep); + instance->restart(); } @@ -665,11 +898,11 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; if (oldState == QAbstractAnimation::Running) { if (newState == QAbstractAnimation::Paused && hasRegisteredTimer) - QUnifiedTimer::ensureTimerUpdate(); + QAnimationTimer::ensureTimerUpdate(); //the animation, is not running any more - QUnifiedTimer::unregisterAnimation(q); + QAnimationTimer::unregisterAnimation(q); } else if (newState == QAbstractAnimation::Running) { - QUnifiedTimer::registerAnimation(q, isTopLevel); + QAnimationTimer::registerAnimation(q, isTopLevel); } q->updateState(newState, oldState); @@ -691,7 +924,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) if (oldState == QAbstractAnimation::Stopped) { if (isTopLevel) { // currentTime needs to be updated if pauseTimer is active - QUnifiedTimer::ensureTimerUpdate(); + QAnimationTimer::ensureTimerUpdate(); q->setCurrentTime(totalCurrentTime); } } @@ -750,7 +983,7 @@ QAbstractAnimation::~QAbstractAnimation() d->state = Stopped; emit stateChanged(oldState, d->state); if (oldState == QAbstractAnimation::Running) - QUnifiedTimer::unregisterAnimation(this); + QAnimationTimer::unregisterAnimation(this); } } @@ -849,14 +1082,14 @@ void QAbstractAnimation::setDirection(Direction direction) // the commands order below is important: first we need to setCurrentTime with the old direction, // then update the direction on this and all children and finally restart the pauseTimer if needed if (d->hasRegisteredTimer) - QUnifiedTimer::ensureTimerUpdate(); + QAnimationTimer::ensureTimerUpdate(); d->direction = direction; updateDirection(direction); if (d->hasRegisteredTimer) // needed to update the timer interval in case of a pause animation - QUnifiedTimer::updateAnimationTimer(); + QAnimationTimer::updateAnimationTimer(); emit directionChanged(direction); } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index a079a71242..2b2d5b8872 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -140,7 +140,20 @@ public: bool running; }; -typedef QElapsedTimer ElapsedTimer; +class Q_CORE_EXPORT QAbstractAnimationTimer : public QObject +{ + Q_OBJECT +public: + QAbstractAnimationTimer() : isRegistered(false), isPaused(false), pauseDuration(0) {} + + virtual void updateAnimationsTime(qint64 delta) = 0; + virtual void restartAnimationTimer() = 0; + virtual int runningAnimationCount() = 0; + + bool isRegistered; + bool isPaused; + int pauseDuration; +}; class Q_CORE_EXPORT QUnifiedTimer : public QObject { @@ -149,12 +162,14 @@ private: QUnifiedTimer(); public: - //XXX this is needed by dui static QUnifiedTimer *instance(); static QUnifiedTimer *instance(bool create); - static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); - static void unregisterAnimation(QAbstractAnimation *animation); + static void startAnimationTimer(QAbstractAnimationTimer *timer); + static void stopAnimationTimer(QAbstractAnimationTimer *timer); + + static void pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration); + static void resumeAnimationTimer(QAbstractAnimationTimer *timer); //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL void setTimingInterval(int interval); @@ -169,34 +184,22 @@ public: void setSlowModeEnabled(bool enabled) { slowMode = enabled; } void setSlowdownFactor(qreal factor) { slowdownFactor = factor; } - /* - this is used for updating the currentTime of all animations in case the pause - timer is active or, otherwise, only of the animation passed as parameter. - */ - static void ensureTimerUpdate(); - - /* - this will evaluate the need of restarting the pause timer in case there is still - some pause animations running. - */ - static void updateAnimationTimer(); - void installAnimationDriver(QAnimationDriver *driver); void uninstallAnimationDriver(QAnimationDriver *driver); bool canUninstallAnimationDriver(QAnimationDriver *driver); - void restartAnimationTimer(); - void updateAnimationsTime(qint64 timeStep); + void restart(); + void updateAnimationTimers(qint64 currentTick); //useful for profiling/debugging - int runningAnimationCount() { return animations.count(); } + int runningAnimationCount(); void registerProfilerCallback(void (*cb)(qint64)); protected: void timerEvent(QTimerEvent *); private Q_SLOTS: - void startAnimations(); + void startTimers(); void stopTimer(); private: @@ -207,18 +210,17 @@ private: QDefaultAnimationDriver defaultDriver; QBasicTimer pauseTimer; - // timer used to delay the check if we should start/stop the animation timer - QBasicTimer startStopAnimationTimer; - ElapsedTimer time; + QElapsedTimer time; qint64 lastTick; int timingInterval; int currentAnimationIdx; bool insideTick; + bool insideRestart; bool consistentTiming; bool slowMode; - bool startAnimationPending; + bool startTimersPending; bool stopTimerPending; // This factor will be used to divide the DEFAULT_TIMER_INTERVAL at each tick @@ -226,6 +228,57 @@ private: // stops all animations. qreal slowdownFactor; + QList<QAbstractAnimationTimer*> animationTimers, animationTimersToStart; + QList<QAbstractAnimationTimer*> pausedAnimationTimers; + + void localRestart(); + int closestPausedAnimationTimerTimeToFinish(); + + void (*profilerCallback)(qint64); +}; + +class QAnimationTimer : public QAbstractAnimationTimer +{ + Q_OBJECT +private: + QAnimationTimer(); + +public: + static QAnimationTimer *instance(); + static QAnimationTimer *instance(bool create); + + static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); + static void unregisterAnimation(QAbstractAnimation *animation); + + /* + this is used for updating the currentTime of all animations in case the pause + timer is active or, otherwise, only of the animation passed as parameter. + */ + static void ensureTimerUpdate(); + + /* + this will evaluate the need of restarting the pause timer in case there is still + some pause animations running. + */ + static void updateAnimationTimer(); + + void restartAnimationTimer(); + void updateAnimationsTime(qint64 delta); + + //useful for profiling/debugging + int runningAnimationCount() { return animations.count(); } + +private Q_SLOTS: + void startAnimations(); + void stopTimer(); + +private: + qint64 lastTick; + int currentAnimationIdx; + bool insideTick; + bool startAnimationPending; + bool stopTimerPending; + QList<QAbstractAnimation*> animations, animationsToStart; // this is the count of running animations that are not a group neither a pause animation @@ -236,8 +289,6 @@ private: void unregisterRunningAnimation(QAbstractAnimation *animation); int closestPauseAnimationTimeToFinish(); - - void (*profilerCallback)(qint64); }; QT_END_NAMESPACE |