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:
parent
d26a71da18
commit
fa699c8f96
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user