aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/animations
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-09-20 15:26:03 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-26 17:32:40 +0200
commit57ae961bcf09efd98968b918332f8ff30562cd92 (patch)
tree84692bed8063ba3f520d0117ed11345d6eeb8dc9 /src/qml/animations
parent6d425ebab34030ff12572f9588eac589930f2659 (diff)
Support looping for "uncontrolled animations".
The render thread animations rely heavily on uncontrolled animations, meaning animations with duration=-1. We support this by adding a m_currentLoopStartTime and incrementally counting the finish time of each uncontrolled animation. Change-Id: I1f2ccea09aff4c51b1a7f98a2ddb58636af50557 Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
Diffstat (limited to 'src/qml/animations')
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp69
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h3
-rw-r--r--src/qml/animations/qanimationgroupjob.cpp2
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp13
-rw-r--r--src/qml/animations/qsequentialanimationgroupjob.cpp43
5 files changed, 101 insertions, 29 deletions
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index da961763ed..d9e3aff5a4 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -269,6 +269,7 @@ QAbstractAnimationJob::QAbstractAnimationJob()
, m_currentTime(0)
, m_currentLoop(0)
, m_uncontrolledFinishTime(-1)
+ , m_currentLoopStartTime(0)
, m_nextSibling(0)
, m_previousSibling(0)
, m_wasDeleted(0)
@@ -304,6 +305,14 @@ QAbstractAnimationJob::~QAbstractAnimationJob()
m_group->removeAnimation(this);
}
+void QAbstractAnimationJob::fireTopLevelAnimationLoopChanged()
+{
+ m_uncontrolledFinishTime = -1;
+ if (m_group)
+ m_currentLoopStartTime = 0;
+ topLevelAnimationLoopChanged();
+}
+
void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
{
if (m_state == newState)
@@ -324,6 +333,11 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
//behaves: changing the state or changing the current value
m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
0 : (m_loopCount == -1 ? duration() : totalDuration());
+
+ // Reset uncontrolled finish time and currentLoopStartTime for this run.
+ m_uncontrolledFinishTime = -1;
+ if (!m_group)
+ m_currentLoopStartTime = m_totalCurrentTime;
}
m_state = newState;
@@ -341,7 +355,7 @@ void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
//starting an animation qualifies as a top level loop change
if (newState == Running && oldState == Stopped && !m_group)
- topLevelAnimationLoopChanged();
+ fireTopLevelAnimationLoopChanged();
RETURN_IF_DELETED(updateState(newState, oldState));
@@ -430,30 +444,49 @@ void QAbstractAnimationJob::setCurrentTime(int msecs)
msecs = qMax(msecs, 0);
// Calculate new time and loop.
int dura = duration();
- int totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
- if (totalDura != -1)
- msecs = qMin(totalDura, msecs);
- m_totalCurrentTime = msecs;
-
- // Update new values.
+ int totalDura;
int oldLoop = m_currentLoop;
- m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
- if (m_currentLoop == m_loopCount) {
- //we're at the end
- m_currentTime = qMax(0, dura);
- m_currentLoop = qMax(0, m_loopCount - 1);
+
+ if (dura < 0 && m_direction == Forward) {
+ totalDura = -1;
+ if (m_uncontrolledFinishTime >= 0 && msecs >= m_uncontrolledFinishTime) {
+ msecs = m_uncontrolledFinishTime;
+ if (m_currentLoop == m_loopCount - 1) {
+ totalDura = m_uncontrolledFinishTime;
+ } else {
+ ++m_currentLoop;
+ m_currentLoopStartTime = msecs;
+ m_uncontrolledFinishTime = -1;
+ }
+ }
+ m_totalCurrentTime = msecs;
+ m_currentTime = msecs - m_currentLoopStartTime;
} else {
- if (m_direction == Forward) {
- m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
+ if (totalDura != -1)
+ msecs = qMin(totalDura, msecs);
+ m_totalCurrentTime = msecs;
+
+ // Update new values.
+ m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
+ if (m_currentLoop == m_loopCount) {
+ //we're at the end
+ m_currentTime = qMax(0, dura);
+ m_currentLoop = qMax(0, m_loopCount - 1);
} else {
- m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
- if (m_currentTime == dura)
- --m_currentLoop;
+ if (m_direction == Forward) {
+ m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
+ } else {
+ m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
+ if (m_currentTime == dura)
+ --m_currentLoop;
+ }
}
}
+
if (m_currentLoop != oldLoop && !m_group) //### verify Running as well?
- topLevelAnimationLoopChanged();
+ fireTopLevelAnimationLoopChanged();
RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 95a238405c..d50bc4d849 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -123,6 +123,8 @@ protected:
virtual void updateDirection(QAbstractAnimationJob::Direction direction);
virtual void topLevelAnimationLoopChanged() {}
+ void fireTopLevelAnimationLoopChanged();
+
void setState(QAbstractAnimationJob::State state);
void finished();
@@ -143,6 +145,7 @@ protected:
int m_currentLoop;
//records the finish time for an uncontrolled animation (used by animation groups)
int m_uncontrolledFinishTime;
+ int m_currentLoopStartTime; // used together with m_uncontrolledFinishTime
struct ChangeListener {
ChangeListener(QAnimationJobChangeListener *l, QAbstractAnimationJob::ChangeTypes t) : listener(l), types(t) {}
diff --git a/src/qml/animations/qanimationgroupjob.cpp b/src/qml/animations/qanimationgroupjob.cpp
index 716beb9ce1..afdf07639b 100644
--- a/src/qml/animations/qanimationgroupjob.cpp
+++ b/src/qml/animations/qanimationgroupjob.cpp
@@ -57,7 +57,7 @@ QAnimationGroupJob::~QAnimationGroupJob()
void QAnimationGroupJob::topLevelAnimationLoopChanged()
{
for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling())
- animation->topLevelAnimationLoopChanged();
+ animation->fireTopLevelAnimationLoopChanged();
}
void QAnimationGroupJob::appendAnimation(QAbstractAnimationJob *animation)
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index c49bb873b5..43dda478f7 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -216,11 +216,20 @@ void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimatio
return;
int maxDuration = 0;
- for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling())
+ bool running = false;
+ for (QAbstractAnimationJob *job = firstChild(); job; job = job->nextSibling()) {
+ if (job->state() == Running)
+ running = true;
maxDuration = qMax(maxDuration, job->totalDuration());
+ }
+
+ setUncontrolledAnimationFinishTime(this, qMax(maxDuration, currentTime()));
- if (m_currentTime >= maxDuration)
+ if (!running
+ && ((m_direction == Forward && m_currentLoop == m_loopCount -1)
+ || m_direction == Backward && m_currentLoop == 0)) {
stop();
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/animations/qsequentialanimationgroupjob.cpp b/src/qml/animations/qsequentialanimationgroupjob.cpp
index b82e1850f7..41a83cefa2 100644
--- a/src/qml/animations/qsequentialanimationgroupjob.cpp
+++ b/src/qml/animations/qsequentialanimationgroupjob.cpp
@@ -64,6 +64,7 @@ bool QSequentialAnimationGroupJob::atEnd() const
// 2. the direction is forward
// 3. the current animation is the last one
// 4. the current animation has reached its end
+
const int animTotalCurrentTime = m_currentAnimation->currentTime();
return (m_currentLoop == m_loopCount - 1
&& m_direction == Forward
@@ -101,8 +102,9 @@ QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::index
return ret;
}
- if (anim == m_currentAnimation)
+ if (anim == m_currentAnimation) {
ret.afterCurrent = true;
+ }
// 'animation' has a non-null defined duration and is not the one at time 'msecs'.
ret.timeOffset += duration;
@@ -211,6 +213,7 @@ void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime)
|| (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && newAnimationIndex.afterCurrent)) {
// advancing with forward direction is the same as rewinding with backwards direction
RETURN_IF_DELETED(advanceForwards(newAnimationIndex));
+
} else if (m_previousLoop > m_currentLoop
|| (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && !newAnimationIndex.afterCurrent)) {
// rewinding with forward direction is the same as advancing with backwards direction
@@ -319,17 +322,41 @@ void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimat
setUncontrolledAnimationFinishTime(m_currentAnimation, m_currentAnimation->currentTime());
- if ((m_direction == Forward && m_currentAnimation == lastChild())
- || (m_direction == Backward && m_currentAnimation == firstChild())) {
- // we don't handle looping of a group with undefined duration
- stop();
- } else if (m_direction == Forward) {
+ int totalTime = currentTime();
+ if (m_direction == Forward) {
// set the current animation to be the next one
- setCurrentAnimation(m_currentAnimation->nextSibling());
+ if (m_currentAnimation->nextSibling())
+ setCurrentAnimation(m_currentAnimation->nextSibling());
+
+ for (QAbstractAnimationJob *a = animation->nextSibling(); a; a = a->nextSibling()) {
+ int dur = a->duration();
+ if (dur == -1) {
+ totalTime = -1;
+ break;
+ } else {
+ totalTime += dur;
+ }
+ }
+
} else {
// set the current animation to be the previous one
- setCurrentAnimation(m_currentAnimation->previousSibling());
+ if (m_currentAnimation->previousSibling())
+ setCurrentAnimation(m_currentAnimation->previousSibling());
+
+ for (QAbstractAnimationJob *a = animation->previousSibling(); a; a = a->previousSibling()) {
+ int dur = a->duration();
+ if (dur == -1) {
+ totalTime = -1;
+ break;
+ } else {
+ totalTime += dur;
+ }
+ }
}
+ if (totalTime >= 0)
+ setUncontrolledAnimationFinishTime(this, totalTime);
+ if (atEnd())
+ stop();
}
void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)