summaryrefslogtreecommitdiffstats
path: root/src/corelib/animation
diff options
context:
space:
mode:
authorLeonardo Sobral Cunha <leo.cunha@nokia.com>2009-10-06 19:00:34 +0200
committerLeonardo Sobral Cunha <leo.cunha@nokia.com>2009-10-07 17:37:47 +0200
commitcd32bfdd74a9615d28670a197296821d7cf2844d (patch)
tree2701c2e340c91ad4895c0e6014035abdc14104a2 /src/corelib/animation
parent232212660535bddee054f3c60b7e8a9dfcc8c582 (diff)
Avoids timer ticks when there are only pause animations running
When there are only pause animations running, the timer will stop and restart when the closest pause animation finishes. While there are only pause animations running, there are no additional timer ticks, but if there is at least one animation running that is not a group or a pause, then the global animation timer will restore it's update interval. Includes a new auto-test for the QPauseAnimation class. Task-number: QT-941 Reviewed-by: thierry Reviewed-by: janarve
Diffstat (limited to 'src/corelib/animation')
-rw-r--r--src/corelib/animation/qabstractanimation.cpp187
-rw-r--r--src/corelib/animation/qabstractanimation_p.h41
-rw-r--r--src/corelib/animation/qanimationgroup_p.h4
-rw-r--r--src/corelib/animation/qpauseanimation.cpp1
4 files changed, 186 insertions, 47 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index a4a8853ac0..9e50784145 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -144,6 +144,7 @@
#include "qabstractanimation.h"
#include "qanimationgroup.h"
+
#include <QtCore/qdebug.h>
#include "qabstractanimation_p.h"
@@ -176,7 +177,8 @@ Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer)
QUnifiedTimer::QUnifiedTimer() :
QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL),
- currentAnimationIdx(0), consistentTiming(false)
+ currentAnimationIdx(0), consistentTiming(false), isPauseTimerActive(false),
+ runningLeafAnimations(0)
{
}
@@ -192,50 +194,96 @@ QUnifiedTimer *QUnifiedTimer::instance()
return inst;
}
+void QUnifiedTimer::ensureTimerUpdate(QAbstractAnimation *animation)
+{
+ if (isPauseTimerActive) {
+ updateAnimationsTime();
+ } else {
+ // this code is needed when ensureTimerUpdate is called from setState because we update
+ // the currentTime when an animation starts running (otherwise we could remove it)
+ animation->setCurrentTime(animation->currentTime());
+ }
+}
+
+void QUnifiedTimer::updateAnimationsTime()
+{
+ // this is simply the time we last received a tick
+ const int oldLastTick = lastTick;
+ // ignore consistentTiming in case the pause timer is active
+ if (consistentTiming && !isPauseTimerActive)
+ lastTick = oldLastTick + timingInterval;
+ else
+ lastTick = time.elapsed();
+ const int delta = lastTick - oldLastTick;
+
+ //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) {
+ 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);
+ }
+ currentAnimationIdx = 0;
+ }
+}
+
+void QUnifiedTimer::restartAnimationTimer()
+{
+ if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) {
+ int closestTimeToFinish = closestPauseAnimationTimeToFinish();
+ animationTimer.start(closestTimeToFinish, this);
+ isPauseTimerActive = true;
+ } else if (!animationTimer.isActive() || isPauseTimerActive) {
+ animationTimer.start(timingInterval, this);
+ isPauseTimerActive = false;
+ }
+}
+
void QUnifiedTimer::timerEvent(QTimerEvent *event)
{
if (event->timerId() == startStopAnimationTimer.timerId()) {
startStopAnimationTimer.stop();
+
//we transfer the waiting animations into the "really running" state
animations += animationsToStart;
animationsToStart.clear();
if (animations.isEmpty()) {
animationTimer.stop();
- } else if (!animationTimer.isActive()) {
- animationTimer.start(timingInterval, this);
- lastTick = 0;
- time.start();
- }
- } else if (event->timerId() == animationTimer.timerId()) {
- //this is simply the time we last received a tick
- const int oldLastTick = lastTick;
- lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed();
-
- //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 (const int delta = lastTick - oldLastTick) {
- 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);
+ isPauseTimerActive = false;
+ // invalidate the start reference time
+ time = QTime();
+ } else {
+ restartAnimationTimer();
+ if (!time.isValid()) {
+ lastTick = 0;
+ time.start();
}
- currentAnimationIdx = 0;
}
+ } else if (event->timerId() == animationTimer.timerId()) {
+ // update current time on all top level animations
+ updateAnimationsTime();
+ restartAnimationTimer();
}
}
-void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation)
+void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel)
{
- Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
- QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
- animationsToStart << animation;
- startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
+ registerRunningAnimation(animation);
+ if (isTopLevel) {
+ Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer);
+ QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true;
+ animationsToStart << animation;
+ startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this);
+ }
}
void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
{
+ unregisterRunningAnimation(animation);
+
if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer)
return;
@@ -253,6 +301,46 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false;
}
+void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation)
+{
+ if (QAbstractAnimationPrivate::get(animation)->isGroup)
+ return;
+
+ if (QAbstractAnimationPrivate::get(animation)->isPause)
+ runningPauseAnimations << animation;
+ else
+ runningLeafAnimations++;
+}
+
+void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation)
+{
+ if (QAbstractAnimationPrivate::get(animation)->isGroup)
+ return;
+
+ if (QAbstractAnimationPrivate::get(animation)->isPause)
+ runningPauseAnimations.removeOne(animation);
+ else
+ runningLeafAnimations--;
+}
+
+int QUnifiedTimer::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->totalDuration() - QAbstractAnimationPrivate::get(animation)->totalCurrentTime;
+ else
+ timeToFinish = QAbstractAnimationPrivate::get(animation)->totalCurrentTime;
+
+ if (timeToFinish < closestTimeToFinish)
+ closestTimeToFinish = timeToFinish;
+ }
+ return closestTimeToFinish;
+}
+
void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
{
Q_Q(QAbstractAnimation);
@@ -270,7 +358,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
//here we reset the time if needed
//we don't call setCurrentTime because this might change the way the animation
//behaves: changing the state or changing the current value
- totalCurrentTime = currentTime =(direction == QAbstractAnimation::Forward) ?
+ totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
0 : (loopCount == -1 ? q->duration() : q->totalDuration());
}
@@ -292,23 +380,31 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
switch (state) {
case QAbstractAnimation::Paused:
- q->setCurrentTime(currentTime);
+ if (hasRegisteredTimer)
+ // currentTime needs to be updated if pauseTimer is active
+ QUnifiedTimer::instance()->ensureTimerUpdate(q);
if (!guard)
return;
QUnifiedTimer::instance()->unregisterAnimation(q);
break;
case QAbstractAnimation::Running:
- // this ensures that the value is updated now that the animation is running
- if (oldState == QAbstractAnimation::Stopped) {
- q->setCurrentTime(currentTime);
- if (!guard)
- return;
- }
+ {
+ bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped;
+
+ // this ensures that the value is updated now that the animation is running
+ if (oldState == QAbstractAnimation::Stopped) {
+ if (isTopLevel)
+ // currentTime needs to be updated if pauseTimer is active
+ QUnifiedTimer::instance()->ensureTimerUpdate(q);
+ if (!guard)
+ return;
+ }
- if (state == QAbstractAnimation::Running) {
- // Register timer if our parent is not running
- if (!group || group->state() == QAbstractAnimation::Stopped)
- QUnifiedTimer::instance()->registerAnimation(q);
+ // test needed in case we stop in the setCurrentTime inside ensureTimerUpdate (zero duration)
+ if (state == QAbstractAnimation::Running) {
+ // register timer if our parent is not running
+ QUnifiedTimer::instance()->registerAnimation(q, isTopLevel);
+ }
}
break;
case QAbstractAnimation::Stopped:
@@ -453,7 +549,6 @@ void QAbstractAnimation::setDirection(Direction direction)
if (d->direction == direction)
return;
- d->direction = direction;
if (state() == Stopped) {
if (direction == Backward) {
d->currentTime = duration();
@@ -463,7 +558,19 @@ void QAbstractAnimation::setDirection(Direction direction)
d->currentLoop = 0;
}
}
+
+ // 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::instance()->ensureTimerUpdate(this);
+
+ d->direction = direction;
updateDirection(direction);
+
+ if (d->hasRegisteredTimer)
+ // needed to update the timer interval in case of a pause animation
+ QUnifiedTimer::instance()->restartAnimationTimer();
+
emit directionChanged(direction);
}
@@ -660,7 +767,7 @@ void QAbstractAnimation::stop()
/*!
Pauses the animation. When the animation is paused, state() returns Paused.
- The value of currentTime will remain unchanged until resume() or start()
+ The value of currentTime will remain unchanged until resume() or start()
is called. If you want to continue from the current time, call resume().
\sa start(), state(), resume()
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 8066d32971..bef0499624 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -70,12 +70,14 @@ public:
QAbstractAnimationPrivate()
: state(QAbstractAnimation::Stopped),
direction(QAbstractAnimation::Forward),
- deleteWhenStopped(false),
totalCurrentTime(0),
currentTime(0),
loopCount(1),
currentLoop(0),
+ deleteWhenStopped(false),
hasRegisteredTimer(false),
+ isPause(false),
+ isGroup(false),
group(0)
{
}
@@ -89,7 +91,6 @@ public:
QAbstractAnimation::State state;
QAbstractAnimation::Direction direction;
- bool deleteWhenStopped;
void setState(QAbstractAnimation::State state);
int totalCurrentTime;
@@ -97,7 +98,10 @@ public:
int loopCount;
int currentLoop;
+ bool deleteWhenStopped;
bool hasRegisteredTimer;
+ bool isPause;
+ bool isGroup;
QAnimationGroup *group;
@@ -115,14 +119,14 @@ public:
//XXX this is needed by dui
static Q_CORE_EXPORT QUnifiedTimer *instance();
- void registerAnimation(QAbstractAnimation *animation);
+ void registerAnimation(QAbstractAnimation *animation, bool isTopLevel);
void unregisterAnimation(QAbstractAnimation *animation);
//defines the timing interval. Default is DEFAULT_TIMER_INTERVAL
void setTimingInterval(int interval)
{
timingInterval = interval;
- if (animationTimer.isActive()) {
+ if (animationTimer.isActive() && !isPauseTimerActive) {
//we changed the timing interval
animationTimer.start(timingInterval, this);
}
@@ -134,21 +138,46 @@ public:
*/
void setConsistentTiming(bool consistent) { consistentTiming = consistent; }
+ /*
+ 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.
+ */
+ void ensureTimerUpdate(QAbstractAnimation *animation);
+
+ /*
+ this will evaluate the need of restarting the pause timer in case there is still
+ some pause animations running.
+ */
+ void restartAnimationTimer();
protected:
void timerEvent(QTimerEvent *);
private:
- // timer used for all active animations
+ // timer used for all active (running) animations
QBasicTimer animationTimer;
- // timer used to delay the check if we should start/stop the global timer
+ // timer used to delay the check if we should start/stop the animation timer
QBasicTimer startStopAnimationTimer;
+
QTime time;
int lastTick;
int timingInterval;
int currentAnimationIdx;
bool consistentTiming;
+ // bool to indicate that only pause animations are active
+ bool isPauseTimerActive;
+
QList<QAbstractAnimation*> animations, animationsToStart;
+
+ // this is the count of running animations that are not a group neither a pause animation
+ int runningLeafAnimations;
+ QList<QAbstractAnimation*> runningPauseAnimations;
+
+ void registerRunningAnimation(QAbstractAnimation *animation);
+ void unregisterRunningAnimation(QAbstractAnimation *animation);
+
+ void updateAnimationsTime();
+ int closestPauseAnimationTimeToFinish();
};
QT_END_NAMESPACE
diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h
index 45eab58a2a..bb1cfb3e4d 100644
--- a/src/corelib/animation/qanimationgroup_p.h
+++ b/src/corelib/animation/qanimationgroup_p.h
@@ -68,7 +68,9 @@ class QAnimationGroupPrivate : public QAbstractAnimationPrivate
Q_DECLARE_PUBLIC(QAnimationGroup)
public:
QAnimationGroupPrivate()
- { }
+ {
+ isGroup = true;
+ }
virtual void animationInsertedAt(int index) { Q_UNUSED(index) };
virtual void animationRemovedAt(int index);
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
index 2fd12aa5da..d90f0013d0 100644
--- a/src/corelib/animation/qpauseanimation.cpp
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -75,6 +75,7 @@ class QPauseAnimationPrivate : public QAbstractAnimationPrivate
public:
QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(0)
{
+ isPause = true;
}
int duration;