diff options
author | Gunnar Sletta <gunnar.sletta@digia.com> | 2013-09-20 15:26:03 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-26 17:32:40 +0200 |
commit | 57ae961bcf09efd98968b918332f8ff30562cd92 (patch) | |
tree | 84692bed8063ba3f520d0117ed11345d6eeb8dc9 /src/qml/animations | |
parent | 6d425ebab34030ff12572f9588eac589930f2659 (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.cpp | 69 | ||||
-rw-r--r-- | src/qml/animations/qabstractanimationjob_p.h | 3 | ||||
-rw-r--r-- | src/qml/animations/qanimationgroupjob.cpp | 2 | ||||
-rw-r--r-- | src/qml/animations/qparallelanimationgroupjob.cpp | 13 | ||||
-rw-r--r-- | src/qml/animations/qsequentialanimationgroupjob.cpp | 43 |
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) |