Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qparallelanimationgroupjob.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
4
5#include "private/qparallelanimationgroupjob_p.h"
6#include "private/qanimationjobutil_p.h"
7
8QT_BEGIN_NAMESPACE
9
10QParallelAnimationGroupJob::QParallelAnimationGroupJob()
11 : QAnimationGroupJob()
12 , m_previousLoop(0)
13 , m_previousCurrentTime(0)
14{
15}
16
17QParallelAnimationGroupJob::~QParallelAnimationGroupJob()
18{
19}
20
21int QParallelAnimationGroupJob::duration() const
22{
23 int ret = 0;
24
25 for (const QAbstractAnimationJob *animation : m_children) {
26 int currentDuration = animation->totalDuration();
27 if (currentDuration == -1)
28 return -1; // Undetermined length
29 ret = qMax(ret, currentDuration);
30 }
31
32 return ret;
33}
34
35void QParallelAnimationGroupJob::updateCurrentTime(int /*currentTime*/)
36{
37 if (m_children.isEmpty())
38 return;
39
40 if (m_currentLoop > m_previousLoop) {
41 // simulate completion of the loop
42 int dura = duration();
43 if (dura < 0) {
44 // For an uncontrolled parallel group, we need to simulate the end of running animations.
45 // As uncontrolled animation finish time is already reset for this next loop, we pick the
46 // longest of the known stop times.
47 for (QAbstractAnimationJob *animation : m_children) {
48 int currentDuration = animation->totalDuration();
49 if (currentDuration >= 0)
50 dura = qMax(dura, currentDuration);
51 }
52 }
53 if (dura > 0) {
54 for (QAbstractAnimationJob *animation : m_children) {
55 if (!animation->isStopped())
56 RETURN_IF_DELETED(animation->setCurrentTime(dura)); // will stop
57 }
58 }
59 } else if (m_currentLoop < m_previousLoop) {
60 // simulate completion of the loop seeking backwards
61 for (QAbstractAnimationJob *animation : m_children) {
62 //we need to make sure the animation is in the right state
63 //and then rewind it
64 applyGroupState(animation);
65 RETURN_IF_DELETED(animation->setCurrentTime(0));
66 animation->stop();
67 }
68 }
69
70 // finally move into the actual time of the current loop
71 for (QAbstractAnimationJob *animation : m_children) {
72 const int dura = animation->totalDuration();
73 //if the loopcount is bigger we should always start all animations
74 if (m_currentLoop > m_previousLoop
75 //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
76 //this happens in Backward direction where not all animations are started at the same time
77 || shouldAnimationStart(animation, m_previousCurrentTime > dura /*startIfAtEnd*/)) {
78 applyGroupState(animation);
79 }
80
81 if (animation->state() == state()) {
82 RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime));
83 if (dura > 0 && m_currentTime > dura)
84 animation->stop();
85 }
86 }
87 m_previousLoop = m_currentLoop;
88 m_previousCurrentTime = m_currentTime;
89}
90
91void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newState,
92 QAbstractAnimationJob::State oldState)
93{
94 QAnimationGroupJob::updateState(newState, oldState);
95
96 switch (newState) {
97 case Stopped:
98 for (QAbstractAnimationJob *animation : m_children)
99 animation->stop();
100 break;
101 case Paused:
102 for (QAbstractAnimationJob *animation : m_children)
103 if (animation->isRunning())
104 animation->pause();
105 break;
106 case Running:
107 for (QAbstractAnimationJob *animation : m_children) {
108 if (oldState == Stopped) {
109 animation->stop();
110 m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
111 }
112 RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
113 animation->setDirection(m_direction);
114 if (shouldAnimationStart(animation, oldState == Stopped))
115 RETURN_IF_DELETED(animation->start());
116 }
117 break;
118 }
119}
120
121bool QParallelAnimationGroupJob::shouldAnimationStart(QAbstractAnimationJob *animation, bool startIfAtEnd) const
122{
123 const int dura = animation->totalDuration();
124
125 if (dura == -1)
126 return uncontrolledAnimationFinishTime(animation) == -1;
127
128 if (startIfAtEnd)
129 return m_currentTime <= dura;
130 if (m_direction == Forward)
131 return m_currentTime < dura;
132 else //direction == Backward
133 return m_currentTime && m_currentTime <= dura;
134}
135
136void QParallelAnimationGroupJob::applyGroupState(QAbstractAnimationJob *animation)
137{
138 switch (m_state)
139 {
140 case Running:
141 animation->start();
142 break;
143 case Paused:
144 animation->pause();
145 break;
146 case Stopped:
147 default:
148 break;
149 }
150}
151
152void QParallelAnimationGroupJob::updateDirection(QAbstractAnimationJob::Direction direction)
153{
154 //we need to update the direction of the current animation
155 if (!isStopped()) {
156 for (QAbstractAnimationJob *animation : m_children) {
157 animation->setDirection(direction);
158 }
159 } else {
160 if (direction == Forward) {
161 m_previousLoop = 0;
162 m_previousCurrentTime = 0;
163 } else {
164 // Looping backwards with loopCount == -1 does not really work well...
165 m_previousLoop = (m_loopCount == -1 ? 0 : m_loopCount - 1);
166 m_previousCurrentTime = duration();
167 }
168 }
169}
170
171void QParallelAnimationGroupJob::uncontrolledAnimationFinished(QAbstractAnimationJob *animation)
172{
173 Q_ASSERT(animation && (animation->duration() == -1 || animation->loopCount() < 0));
174 int uncontrolledRunningCount = 0;
175
176 for (QAbstractAnimationJob *child : m_children) {
177 if (child == animation) {
178 setUncontrolledAnimationFinishTime(animation, animation->currentTime());
179 } else if (child->duration() == -1 || child->loopCount() < 0) {
180 if (uncontrolledAnimationFinishTime(child) == -1)
181 ++uncontrolledRunningCount;
182 }
183 }
184
185 if (uncontrolledRunningCount > 0)
186 return;
187
188 int maxDuration = 0;
189 bool running = false;
190 for (QAbstractAnimationJob *job : m_children) {
191 if (job->state() == Running)
192 running = true;
193 maxDuration = qMax(maxDuration, job->totalDuration());
194 }
195
196 setUncontrolledAnimationFinishTime(this, qMax(maxDuration + m_currentLoopStartTime, currentTime()));
197
198 if (!running
199 && ((m_direction == Forward && m_currentLoop == m_loopCount -1)
200 || (m_direction == Backward && m_currentLoop == 0))) {
201 stop();
202 }
203}
204
205void QParallelAnimationGroupJob::debugAnimation(QDebug d) const
206{
207 d << "ParallelAnimationGroupJob(" << Qt::hex << (const void *) this << Qt::dec << ")";
208
209 debugChildren(d);
210}
211
212QT_END_NAMESPACE