Abstract QUnifiedTimer.

QUnifiedTimer now controls QAbstractAnimationTimers, which
in turn can be used to drive specific animation systems.

The purpose of this change is to allow the QML animation
system to be rewritten so that it does not depend on
QAbstractAnimation.

Change-Id: If06475002e41ba85b1b86b5dd4788de6d27d035d
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
This commit is contained in:
Michael Brasser 2011-12-14 15:01:34 +10:00 committed by Qt by Nokia
parent d26a71da18
commit fa699c8f96
2 changed files with 426 additions and 142 deletions

View File

@ -157,20 +157,69 @@
#ifndef QT_NO_ANIMATION #ifndef QT_NO_ANIMATION
#define DEFAULT_TIMER_INTERVAL 16 #define DEFAULT_TIMER_INTERVAL 16
#define STARTSTOP_TIMER_DELAY 0
#define PAUSE_TIMER_COARSE_THRESHOLD 2000 #define PAUSE_TIMER_COARSE_THRESHOLD 2000
QT_BEGIN_NAMESPACE 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 #ifndef QT_NO_THREAD
Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
#endif #endif
QUnifiedTimer::QUnifiedTimer() : QUnifiedTimer::QUnifiedTimer() :
QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false), currentAnimationIdx(0), insideTick(false), insideRestart(false), consistentTiming(false), slowMode(false),
startAnimationPending(false), stopTimerPending(false), startTimersPending(false), stopTimerPending(false),
slowdownFactor(5.0f), runningLeafAnimations(0), profilerCallback(0) slowdownFactor(5.0f), profilerCallback(0)
{ {
time.invalidate(); time.invalidate();
driver = &defaultDriver; driver = &defaultDriver;
@ -185,7 +234,7 @@ QUnifiedTimer *QUnifiedTimer::instance(bool create)
inst = new QUnifiedTimer; inst = new QUnifiedTimer;
unifiedTimer()->setLocalData(inst); unifiedTimer()->setLocalData(inst);
} else { } else {
inst = unifiedTimer()->localData(); inst = unifiedTimer() ? unifiedTimer()->localData() : 0;
} }
#else #else
static QUnifiedTimer unifiedTimer; static QUnifiedTimer unifiedTimer;
@ -199,23 +248,16 @@ QUnifiedTimer *QUnifiedTimer::instance()
return instance(true); return instance(true);
} }
void QUnifiedTimer::ensureTimerUpdate() void QUnifiedTimer::updateAnimationTimers(qint64 currentTick)
{
QUnifiedTimer *inst = QUnifiedTimer::instance(false);
if (inst && inst->pauseTimer.isActive())
inst->updateAnimationsTime(-1);
}
void QUnifiedTimer::updateAnimationsTime(qint64 timeStep)
{ {
//setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations
if(insideTick) if(insideTick)
return; return;
qint64 totalElapsed = timeStep >= 0 ? timeStep : time.elapsed(); qint64 totalElapsed = currentTick >= 0 ? currentTick : time.elapsed();
// ignore consistentTiming in case the pause timer is active // ignore consistentTiming in case the pause timer is active
int delta = (consistentTiming && !pauseTimer.isActive()) ? qint64 delta = (consistentTiming && !pauseTimer.isActive()) ?
timingInterval : totalElapsed - lastTick; timingInterval : totalElapsed - lastTick;
if (slowMode) { if (slowMode) {
if (slowdownFactor > 0) if (slowdownFactor > 0)
@ -233,38 +275,36 @@ void QUnifiedTimer::updateAnimationsTime(qint64 timeStep)
insideTick = true; insideTick = true;
if (profilerCallback) if (profilerCallback)
profilerCallback(delta); profilerCallback(delta);
for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { for (currentAnimationIdx = 0; currentAnimationIdx < animationTimers.count(); ++currentAnimationIdx) {
QAbstractAnimation *animation = animations.at(currentAnimationIdx); QAbstractAnimationTimer *animation = animationTimers.at(currentAnimationIdx);
int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime animation->updateAnimationsTime(delta);
+ (animation->direction() == QAbstractAnimation::Forward ? delta : -delta);
animation->setCurrentTime(elapsed);
} }
insideTick = false; insideTick = false;
currentAnimationIdx = 0; currentAnimationIdx = 0;
} }
} }
int QUnifiedTimer::runningAnimationCount()
{
int count = 0;
for (int i = 0; i < animationTimers.count(); ++i)
count += animationTimers.at(i)->runningAnimationCount();
return count;
}
void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64)) void QUnifiedTimer::registerProfilerCallback(void (*cb)(qint64))
{ {
profilerCallback = cb; profilerCallback = cb;
} }
void QUnifiedTimer::updateAnimationTimer() void QUnifiedTimer::localRestart()
{ {
QUnifiedTimer *inst = QUnifiedTimer::instance(false); if (insideRestart)
if (inst) return;
inst->restartAnimationTimer();
}
void QUnifiedTimer::restartAnimationTimer() if (!pausedAnimationTimers.isEmpty() && (animationTimers.count() + animationTimersToStart.count() == pausedAnimationTimers.count())) {
{
if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
int closestTimeToFinish = closestPauseAnimationTimeToFinish();
if (closestTimeToFinish < 0) {
qDebug() << runningPauseAnimations;
qDebug() << closestPauseAnimationTimeToFinish();
}
driver->stop(); driver->stop();
int closestTimeToFinish = closestPausedAnimationTimerTimeToFinish();
// use a precise timer if the pause will be short // use a precise timer if the pause will be short
Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer; Qt::TimerType timerType = closestTimeToFinish < PAUSE_TIMER_COARSE_THRESHOLD ? Qt::PreciseTimer : Qt::CoarseTimer;
pauseTimer.start(closestTimeToFinish, timerType, this); pauseTimer.start(closestTimeToFinish, timerType, this);
@ -273,6 +313,17 @@ void QUnifiedTimer::restartAnimationTimer()
pauseTimer.stop(); pauseTimer.stop();
driver->start(); 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) void QUnifiedTimer::setTimingInterval(int interval)
@ -286,18 +337,17 @@ void QUnifiedTimer::setTimingInterval(int interval)
} }
} }
void QUnifiedTimer::startAnimations() void QUnifiedTimer::startTimers()
{ {
startAnimationPending = false; startTimersPending = false;
//force timer to update, which prevents large deltas for our newly added animations if (!animationTimers.isEmpty())
if (!animations.isEmpty()) updateAnimationTimers(-1);
updateAnimationsTime(-1);
//we transfer the waiting animations into the "really running" state //we transfer the waiting animations into the "really running" state
animations += animationsToStart; animationTimers += animationTimersToStart;
animationsToStart.clear(); animationTimersToStart.clear();
if (!animations.isEmpty()) { if (!animationTimers.isEmpty()) {
restartAnimationTimer(); localRestart();
if (!time.isValid()) { if (!time.isValid()) {
lastTick = 0; lastTick = 0;
time.start(); time.start();
@ -308,7 +358,7 @@ void QUnifiedTimer::startAnimations()
void QUnifiedTimer::stopTimer() void QUnifiedTimer::stopTimer()
{ {
stopTimerPending = false; stopTimerPending = false;
if (animations.isEmpty()) { if (animationTimers.isEmpty()) {
driver->stop(); driver->stop();
pauseTimer.stop(); pauseTimer.stop();
// invalidate the start reference time // invalidate the start reference time
@ -318,25 +368,251 @@ void QUnifiedTimer::stopTimer()
void QUnifiedTimer::timerEvent(QTimerEvent *event) 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 //for that purpose we do as if the startstoptimer would always fire before the animation timer
if (consistentTiming) { if (consistentTiming) {
if (stopTimerPending) if (stopTimerPending)
stopTimer(); stopTimer();
if (startAnimationPending) if (startTimersPending)
startAnimations(); startTimers();
} }
if (event->timerId() == pauseTimer.timerId()) { if (event->timerId() == pauseTimer.timerId()) {
// update current time on all top level animations // update current time on all timers
updateAnimationsTime(-1); updateAnimationTimers(-1);
restartAnimationTimer(); 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 QUnifiedTimer *inst = instance(true); //we create the instance if needed
inst->animationTimersToStart << timer;
if (!inst->startTimersPending) {
inst->startTimersPending = true;
QMetaObject::invokeMethod(inst, "startTimers", Qt::QueuedConnection);
}
}
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
if (!timer->isRegistered)
return;
timer->isRegistered = false;
int idx = inst->animationTimers.indexOf(timer);
if (idx != -1) {
inst->animationTimers.removeAt(idx);
// this is needed if we unregister an animation while its running
if (idx <= inst->currentAnimationIdx)
--inst->currentAnimationIdx;
if (inst->animationTimers.isEmpty() && !inst->stopTimerPending) {
inst->stopTimerPending = true;
QMetaObject::invokeMethod(inst, "stopTimer", Qt::QueuedConnection);
}
} else {
inst->animationTimersToStart.removeOne(timer);
}
}
}
void QUnifiedTimer::pauseAnimationTimer(QAbstractAnimationTimer *timer, int duration)
{
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::resumeAnimationTimer(QAbstractAnimationTimer *timer)
{
if (!timer->isPaused)
return;
timer->isPaused = false;
QUnifiedTimer *inst = QUnifiedTimer::instance();
inst->pausedAnimationTimers.removeOne(timer);
inst->localRestart();
}
int QUnifiedTimer::closestPausedAnimationTimerTimeToFinish()
{
int closestTimeToFinish = INT_MAX;
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) {
qWarning("QUnifiedTimer: animation driver already installed...");
return;
}
if (driver->isRunning()) {
driver->stop();
d->start();
}
driver = d;
}
void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
{
if (driver != d) {
qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
return;
}
driver = &defaultDriver;
if (d->isRunning()) {
d->stop();
driver->start();
}
}
/*!
Returns true if \a d is the currently installed animation driver
and is not the default animation driver (which can never be uninstalled).
*/
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); inst->registerRunningAnimation(animation);
if (isTopLevel) { if (isTopLevel) {
Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
@ -349,9 +625,9 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopL
} }
} }
void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) void QAnimationTimer::unregisterAnimation(QAbstractAnimation *animation)
{ {
QUnifiedTimer *inst = QUnifiedTimer::instance(false); QAnimationTimer *inst = QAnimationTimer::instance(false);
if (inst) { if (inst) {
//at this point the unified timer should have been created //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 //but it might also have been already destroyed in case the application is shutting down
@ -379,7 +655,7 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
} }
void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation) void QAnimationTimer::registerRunningAnimation(QAbstractAnimation *animation)
{ {
if (QAbstractAnimationPrivate::get(animation)->isGroup) if (QAbstractAnimationPrivate::get(animation)->isGroup)
return; return;
@ -390,7 +666,7 @@ void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
runningLeafAnimations++; runningLeafAnimations++;
} }
void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation) void QAnimationTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
{ {
if (QAbstractAnimationPrivate::get(animation)->isGroup) if (QAbstractAnimationPrivate::get(animation)->isGroup)
return; return;
@ -402,7 +678,7 @@ void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
Q_ASSERT(runningLeafAnimations >= 0); Q_ASSERT(runningLeafAnimations >= 0);
} }
int QUnifiedTimer::closestPauseAnimationTimeToFinish() int QAnimationTimer::closestPauseAnimationTimeToFinish()
{ {
int closestTimeToFinish = INT_MAX; int closestTimeToFinish = INT_MAX;
for (int i = 0; i < runningPauseAnimations.size(); ++i) { for (int i = 0; i < runningPauseAnimations.size(); ++i) {
@ -420,49 +696,6 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish()
return closestTimeToFinish; return closestTimeToFinish;
} }
void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d)
{
if (driver != &defaultDriver) {
qWarning("QUnifiedTimer: animation driver already installed...");
return;
}
if (driver->isRunning()) {
driver->stop();
d->start();
}
driver = d;
}
void QUnifiedTimer::uninstallAnimationDriver(QAnimationDriver *d)
{
if (driver != d) {
qWarning("QUnifiedTimer: trying to uninstall a driver that is not installed...");
return;
}
driver = &defaultDriver;
if (d->isRunning()) {
d->stop();
driver->start();
}
}
/*!
Returns true if \a d is the currently installed animation driver
and is not the default animation driver (which can never be uninstalled).
*/
bool QUnifiedTimer::canUninstallAnimationDriver(QAnimationDriver *d)
{
return d == driver && driver != &defaultDriver;
}
/*! /*!
\class QAnimationDriver \class QAnimationDriver
@ -507,8 +740,8 @@ void QAnimationDriver::advanceAnimation(qint64 timeStep)
QUnifiedTimer *instance = QUnifiedTimer::instance(); QUnifiedTimer *instance = QUnifiedTimer::instance();
// update current time on all top level animations // update current time on all top level animations
instance->updateAnimationsTime(timeStep); instance->updateAnimationTimers(timeStep);
instance->restartAnimationTimer(); instance->restart();
} }
@ -665,11 +898,11 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
if (oldState == QAbstractAnimation::Running) { if (oldState == QAbstractAnimation::Running) {
if (newState == QAbstractAnimation::Paused && hasRegisteredTimer) if (newState == QAbstractAnimation::Paused && hasRegisteredTimer)
QUnifiedTimer::ensureTimerUpdate(); QAnimationTimer::ensureTimerUpdate();
//the animation, is not running any more //the animation, is not running any more
QUnifiedTimer::unregisterAnimation(q); QAnimationTimer::unregisterAnimation(q);
} else if (newState == QAbstractAnimation::Running) { } else if (newState == QAbstractAnimation::Running) {
QUnifiedTimer::registerAnimation(q, isTopLevel); QAnimationTimer::registerAnimation(q, isTopLevel);
} }
q->updateState(newState, oldState); q->updateState(newState, oldState);
@ -691,7 +924,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
if (oldState == QAbstractAnimation::Stopped) { if (oldState == QAbstractAnimation::Stopped) {
if (isTopLevel) { if (isTopLevel) {
// currentTime needs to be updated if pauseTimer is active // currentTime needs to be updated if pauseTimer is active
QUnifiedTimer::ensureTimerUpdate(); QAnimationTimer::ensureTimerUpdate();
q->setCurrentTime(totalCurrentTime); q->setCurrentTime(totalCurrentTime);
} }
} }
@ -750,7 +983,7 @@ QAbstractAnimation::~QAbstractAnimation()
d->state = Stopped; d->state = Stopped;
emit stateChanged(oldState, d->state); emit stateChanged(oldState, d->state);
if (oldState == QAbstractAnimation::Running) 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, // 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 // then update the direction on this and all children and finally restart the pauseTimer if needed
if (d->hasRegisteredTimer) if (d->hasRegisteredTimer)
QUnifiedTimer::ensureTimerUpdate(); QAnimationTimer::ensureTimerUpdate();
d->direction = direction; d->direction = direction;
updateDirection(direction); updateDirection(direction);
if (d->hasRegisteredTimer) if (d->hasRegisteredTimer)
// needed to update the timer interval in case of a pause animation // needed to update the timer interval in case of a pause animation
QUnifiedTimer::updateAnimationTimer(); QAnimationTimer::updateAnimationTimer();
emit directionChanged(direction); emit directionChanged(direction);
} }

View File

@ -140,7 +140,20 @@ public:
bool running; 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 class Q_CORE_EXPORT QUnifiedTimer : public QObject
{ {
@ -149,12 +162,14 @@ private:
QUnifiedTimer(); QUnifiedTimer();
public: public:
//XXX this is needed by dui
static QUnifiedTimer *instance(); static QUnifiedTimer *instance();
static QUnifiedTimer *instance(bool create); static QUnifiedTimer *instance(bool create);
static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); static void startAnimationTimer(QAbstractAnimationTimer *timer);
static void unregisterAnimation(QAbstractAnimation *animation); 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 //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL
void setTimingInterval(int interval); void setTimingInterval(int interval);
@ -169,6 +184,72 @@ public:
void setSlowModeEnabled(bool enabled) { slowMode = enabled; } void setSlowModeEnabled(bool enabled) { slowMode = enabled; }
void setSlowdownFactor(qreal factor) { slowdownFactor = factor; } void setSlowdownFactor(qreal factor) { slowdownFactor = factor; }
void installAnimationDriver(QAnimationDriver *driver);
void uninstallAnimationDriver(QAnimationDriver *driver);
bool canUninstallAnimationDriver(QAnimationDriver *driver);
void restart();
void updateAnimationTimers(qint64 currentTick);
//useful for profiling/debugging
int runningAnimationCount();
void registerProfilerCallback(void (*cb)(qint64));
protected:
void timerEvent(QTimerEvent *);
private Q_SLOTS:
void startTimers();
void stopTimer();
private:
friend class QDefaultAnimationDriver;
friend class QAnimationDriver;
QAnimationDriver *driver;
QDefaultAnimationDriver defaultDriver;
QBasicTimer pauseTimer;
QElapsedTimer time;
qint64 lastTick;
int timingInterval;
int currentAnimationIdx;
bool insideTick;
bool insideRestart;
bool consistentTiming;
bool slowMode;
bool startTimersPending;
bool stopTimerPending;
// This factor will be used to divide the DEFAULT_TIMER_INTERVAL at each tick
// when slowMode is enabled. Setting it to 0 or higher than DEFAULT_TIMER_INTERVAL (16)
// 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 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. timer is active or, otherwise, only of the animation passed as parameter.
@ -181,51 +262,23 @@ public:
*/ */
static void updateAnimationTimer(); static void updateAnimationTimer();
void installAnimationDriver(QAnimationDriver *driver);
void uninstallAnimationDriver(QAnimationDriver *driver);
bool canUninstallAnimationDriver(QAnimationDriver *driver);
void restartAnimationTimer(); void restartAnimationTimer();
void updateAnimationsTime(qint64 timeStep); void updateAnimationsTime(qint64 delta);
//useful for profiling/debugging //useful for profiling/debugging
int runningAnimationCount() { return animations.count(); } int runningAnimationCount() { return animations.count(); }
void registerProfilerCallback(void (*cb)(qint64));
protected:
void timerEvent(QTimerEvent *);
private Q_SLOTS: private Q_SLOTS:
void startAnimations(); void startAnimations();
void stopTimer(); void stopTimer();
private: private:
friend class QDefaultAnimationDriver;
friend class QAnimationDriver;
QAnimationDriver *driver;
QDefaultAnimationDriver defaultDriver;
QBasicTimer pauseTimer;
// timer used to delay the check if we should start/stop the animation timer
QBasicTimer startStopAnimationTimer;
ElapsedTimer time;
qint64 lastTick; qint64 lastTick;
int timingInterval;
int currentAnimationIdx; int currentAnimationIdx;
bool insideTick; bool insideTick;
bool consistentTiming;
bool slowMode;
bool startAnimationPending; bool startAnimationPending;
bool stopTimerPending; bool stopTimerPending;
// This factor will be used to divide the DEFAULT_TIMER_INTERVAL at each tick
// when slowMode is enabled. Setting it to 0 or higher than DEFAULT_TIMER_INTERVAL (16)
// stops all animations.
qreal slowdownFactor;
QList<QAbstractAnimation*> animations, animationsToStart; QList<QAbstractAnimation*> animations, animationsToStart;
// this is the count of running animations that are not a group neither a pause animation // 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); void unregisterRunningAnimation(QAbstractAnimation *animation);
int closestPauseAnimationTimeToFinish(); int closestPauseAnimationTimeToFinish();
void (*profilerCallback)(qint64);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE