5#include "private/qsequentialanimationgroupjob_p.h"
6#include "private/qpauseanimationjob_p.h"
7#include "private/qanimationjobutil_p.h"
11QSequentialAnimationGroupJob::QSequentialAnimationGroupJob()
12 : QAnimationGroupJob()
13 , m_currentAnimation(
nullptr)
18QSequentialAnimationGroupJob::~QSequentialAnimationGroupJob()
22bool QSequentialAnimationGroupJob::atEnd()
const
31 const int animTotalCurrentTime = m_currentAnimation->currentTime();
32 return (m_currentLoop == m_loopCount - 1
33 && m_direction == Forward
34 && !m_children.next(m_currentAnimation)
35 && animTotalCurrentTime == animationActualTotalDuration(m_currentAnimation));
38int QSequentialAnimationGroupJob::animationActualTotalDuration(
39 const QAbstractAnimationJob *anim)
const
41 int ret = anim->totalDuration();
43 int done = uncontrolledAnimationFinishTime(anim);
45 if (done >= 0 && (anim->loopCount() - 1 == anim->currentLoop() || anim->state() == Stopped))
51QSequentialAnimationGroupJob::AnimationIndex QSequentialAnimationGroupJob::indexForCurrentTime()
const
53 Q_ASSERT(!m_children.isEmpty());
58 for (
const QAbstractAnimationJob *anim : m_children) {
59 duration = animationActualTotalDuration(anim);
66 if (duration == -1 || m_currentTime < (ret.timeOffset + duration)
67 || (m_currentTime == (ret.timeOffset + duration) && m_direction == QAbstractAnimationJob::Backward)) {
72 if (anim == m_currentAnimation) {
73 ret.afterCurrent =
true;
77 ret.timeOffset += duration;
83 ret.timeOffset -= duration;
84 ret.animation = m_children.last();
88void QSequentialAnimationGroupJob::restart()
91 if (m_direction == Forward) {
93 if (m_currentAnimation == m_children.first())
94 activateCurrentAnimation();
96 setCurrentAnimation(m_children.first());
99 m_previousLoop = m_loopCount - 1;
100 if (m_currentAnimation == m_children.last())
101 activateCurrentAnimation();
103 setCurrentAnimation(m_children.last());
107void QSequentialAnimationGroupJob::advanceForwards(
const AnimationIndex &newAnimationIndex)
109 if (m_previousLoop < m_currentLoop) {
111 for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = m_children.next(anim)) {
112 RETURN_IF_DELETED(setCurrentAnimation(anim,
true));
113 RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
116 if (m_children.count() == 1) {
118 RETURN_IF_DELETED(activateCurrentAnimation());
120 RETURN_IF_DELETED(setCurrentAnimation(m_children.first(),
true));
125 for (QAbstractAnimationJob *anim = m_currentAnimation;
126 anim && anim != newAnimationIndex.animation; anim = m_children.next(anim)) {
127 RETURN_IF_DELETED(setCurrentAnimation(anim,
true));
128 RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim)));
133void QSequentialAnimationGroupJob::rewindForwards(
const AnimationIndex &newAnimationIndex)
135 if (m_previousLoop > m_currentLoop) {
137 for (QAbstractAnimationJob *anim = m_currentAnimation; anim;
138 anim = m_children.prev(anim)) {
139 RETURN_IF_DELETED(setCurrentAnimation(anim,
true));
140 RETURN_IF_DELETED(anim->setCurrentTime(0));
143 if (m_children.count() == 1) {
145 RETURN_IF_DELETED(activateCurrentAnimation());
147 RETURN_IF_DELETED(setCurrentAnimation(m_children.last(),
true));
152 for (QAbstractAnimationJob *anim = m_currentAnimation;
153 anim && anim != newAnimationIndex.animation; anim = m_children.prev(anim)) {
154 RETURN_IF_DELETED(setCurrentAnimation(anim,
true));
155 RETURN_IF_DELETED(anim->setCurrentTime(0));
160int QSequentialAnimationGroupJob::duration()
const
164 for (
const QAbstractAnimationJob *anim : m_children) {
165 const int currentDuration = anim->totalDuration();
166 if (currentDuration == -1)
169 ret += currentDuration;
175void QSequentialAnimationGroupJob::clear()
178 QAnimationGroupJob::clear();
181 Q_ASSERT(m_currentAnimation ==
nullptr);
184void QSequentialAnimationGroupJob::updateCurrentTime(
int currentTime)
186 if (!m_currentAnimation)
189 const QSequentialAnimationGroupJob::AnimationIndex newAnimationIndex = indexForCurrentTime();
192 if (m_previousLoop < m_currentLoop
193 || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && newAnimationIndex.afterCurrent)) {
195 RETURN_IF_DELETED(advanceForwards(newAnimationIndex));
197 }
else if (m_previousLoop > m_currentLoop
198 || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && !newAnimationIndex.afterCurrent)) {
200 RETURN_IF_DELETED(rewindForwards(newAnimationIndex));
203 RETURN_IF_DELETED(setCurrentAnimation(newAnimationIndex.animation));
205 const int newCurrentTime = currentTime - newAnimationIndex.timeOffset;
207 if (m_currentAnimation) {
208 RETURN_IF_DELETED(m_currentAnimation->setCurrentTime(newCurrentTime));
211 m_currentTime += m_currentAnimation->currentTime() - newCurrentTime;
212 RETURN_IF_DELETED(stop());
217 Q_ASSERT(m_children.isEmpty());
219 RETURN_IF_DELETED(stop());
222 m_previousLoop = m_currentLoop;
225void QSequentialAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
226 QAbstractAnimationJob::State oldState)
228 QAnimationGroupJob::updateState(newState, oldState);
230 if (!m_currentAnimation)
235 m_currentAnimation->stop();
238 if (oldState == m_currentAnimation->state() && oldState == Running)
239 m_currentAnimation->pause();
244 if (oldState == m_currentAnimation->state() && oldState == Paused)
245 m_currentAnimation->start();
252void QSequentialAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
255 if (!isStopped() && m_currentAnimation)
256 m_currentAnimation->setDirection(direction);
259void QSequentialAnimationGroupJob::setCurrentAnimation(
260 const QAbstractAnimationJob *anim,
bool intermediate)
263 Q_ASSERT(m_children.isEmpty());
264 m_currentAnimation =
nullptr;
268 if (anim == m_currentAnimation)
272 if (m_currentAnimation)
273 m_currentAnimation->stop();
276 Q_ASSERT(m_children.contains(anim));
280 m_currentAnimation =
const_cast<QAbstractAnimationJob *>(anim);
282 activateCurrentAnimation(intermediate);
285void QSequentialAnimationGroupJob::activateCurrentAnimation(
bool intermediate)
287 if (!m_currentAnimation || isStopped())
290 m_currentAnimation->stop();
293 m_currentAnimation->setDirection(m_direction);
296 if (m_currentAnimation->totalDuration() == -1)
297 resetUncontrolledAnimationFinishTime(m_currentAnimation);
299 RETURN_IF_DELETED(m_currentAnimation->start());
300 if (!intermediate && isPaused())
301 m_currentAnimation->pause();
304void QSequentialAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
307 Q_ASSERT(animation == m_currentAnimation);
309 setUncontrolledAnimationFinishTime(m_currentAnimation, m_currentAnimation->currentTime());
311 int totalTime = currentTime();
312 if (m_direction == Forward) {
314 if (
auto *anim = m_children.next(m_currentAnimation))
315 RETURN_IF_DELETED(setCurrentAnimation(anim));
317 for (QAbstractAnimationJob *a = m_children.next(animation); a; a = m_children.next(a)) {
318 int dur = a->duration();
329 if (
auto *anim = m_children.prev(m_currentAnimation))
330 RETURN_IF_DELETED(setCurrentAnimation(anim));
332 for (QAbstractAnimationJob *a = m_children.prev(animation); a; a = m_children.prev(a)) {
333 int dur = a->duration();
343 setUncontrolledAnimationFinishTime(
this, totalTime);
348void QSequentialAnimationGroupJob::animationInserted(QAbstractAnimationJob *anim)
350 if (m_currentAnimation ==
nullptr)
351 RETURN_IF_DELETED(setCurrentAnimation(m_children.first()));
353 if (m_currentAnimation == m_children.next(anim)
354 && m_currentAnimation->currentTime() == 0 && m_currentAnimation->currentLoop() == 0) {
356 RETURN_IF_DELETED(setCurrentAnimation(anim));
366void QSequentialAnimationGroupJob::animationRemoved(QAbstractAnimationJob *anim, QAbstractAnimationJob *prev, QAbstractAnimationJob *next)
368 QAnimationGroupJob::animationRemoved(anim, prev, next);
370 Q_ASSERT(m_currentAnimation);
372 bool removingCurrent = anim == m_currentAnimation;
373 if (removingCurrent) {
375 RETURN_IF_DELETED(setCurrentAnimation(next));
377 RETURN_IF_DELETED(setCurrentAnimation(prev));
379 RETURN_IF_DELETED(setCurrentAnimation(
nullptr));
384 for (QAbstractAnimationJob *job : m_children) {
385 if (job == m_currentAnimation)
387 m_currentTime += animationActualTotalDuration(job);
391 if (!removingCurrent) {
394 m_currentTime += m_currentAnimation->currentTime();
398 m_totalCurrentTime = m_currentTime + m_loopCount * duration();
401void QSequentialAnimationGroupJob::debugAnimation(QDebug d)
const
403 d <<
"SequentialAnimationGroupJob(" << Qt::hex << (
const void *)
this << Qt::dec <<
")" <<
"currentAnimation:" << (
void *)m_currentAnimation;