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
qparallelanimationgroup.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 reason:default
4
5/*!
6 \class QParallelAnimationGroup
7 \inmodule QtCore
8 \brief The QParallelAnimationGroup class provides a parallel group of animations.
9 \since 4.6
10 \ingroup animation
11
12 QParallelAnimationGroup--a \l{QAnimationGroup}{container for
13 animations}--starts all its animations when it is
14 \l{QAbstractAnimation::start()}{started} itself, i.e., runs all
15 animations in parallel. The animation group finishes when the
16 longest lasting animation has finished.
17
18 You can treat QParallelAnimationGroup as any other QAbstractAnimation,
19 e.g., pause, resume, or add it to other animation groups.
20
21 \snippet code/src_corelib_animation_qparallelanimationgroup.cpp 0
22
23 In this example, \c anim1 and \c anim2 are two
24 \l{QPropertyAnimation}s that have already been set up.
25
26 \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework}
27*/
28
29
32//#define QANIMATION_DEBUG
33
35
39
40/*!
41 Constructs a QParallelAnimationGroup.
42 \a parent is passed to QObject's constructor.
43*/
44QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent)
45 : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent)
46{
47}
48
49/*!
50 \internal
51*/
52QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd,
53 QObject *parent)
54 : QAnimationGroup(dd, parent)
55{
56}
57
58/*!
59 Destroys the animation group. It will also destroy all its animations.
60*/
61QParallelAnimationGroup::~QParallelAnimationGroup()
62{
63}
64
65/*!
66 \reimp
67*/
68int QParallelAnimationGroup::duration() const
69{
70 Q_D(const QParallelAnimationGroup);
71 int ret = 0;
72
73 for (auto ani : std::as_const(d->animations)) {
74 const int currentDuration = ani->totalDuration();
75 if (currentDuration == -1)
76 return -1; // Undetermined length
77
78 ret = qMax(ret, currentDuration);
79 }
80
81 return ret;
82}
83
84/*!
85 \reimp
86*/
87void QParallelAnimationGroup::updateCurrentTime(int currentTime)
88{
89 Q_D(QParallelAnimationGroup);
90 if (d->animations.isEmpty())
91 return;
92
93 if (d->currentLoop > d->lastLoop) {
94 // simulate completion of the loop
95 int dura = duration();
96 if (dura > 0) {
97 for (auto animation : std::as_const(d->animations)) {
98 if (animation->state() != QAbstractAnimation::Stopped)
99 animation->setCurrentTime(dura); // will stop
100 }
101 }
102 } else if (d->currentLoop < d->lastLoop) {
103 // simulate completion of the loop seeking backwards
104 for (auto animation : std::as_const(d->animations)) {
105 //we need to make sure the animation is in the right state
106 //and then rewind it
107 d->applyGroupState(animation);
108 animation->setCurrentTime(0);
109 animation->stop();
110 }
111 }
112
113#ifdef QANIMATION_DEBUG
114 qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d",
115 __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state());
116#endif
117 // finally move into the actual time of the current loop
118 for (auto animation : std::as_const(d->animations)) {
119 const int dura = animation->totalDuration();
120 //if the loopcount is bigger we should always start all animations
121 if (d->currentLoop > d->lastLoop
122 //if we're at the end of the animation, we need to start it if it wasn't already started in this loop
123 //this happens in Backward direction where not all animations are started at the same time
124 || d->shouldAnimationStart(animation, d->lastCurrentTime > dura /*startIfAtEnd*/)) {
125 d->applyGroupState(animation);
126 }
127
128 if (animation->state() == state()) {
129 animation->setCurrentTime(currentTime);
130 if (dura > 0 && currentTime > dura)
131 animation->stop();
132 }
133 }
134 d->lastLoop = d->currentLoop;
135 d->lastCurrentTime = currentTime;
136}
137
138/*!
139 \reimp
140*/
141void QParallelAnimationGroup::updateState(QAbstractAnimation::State newState,
142 QAbstractAnimation::State oldState)
143{
144 Q_D(QParallelAnimationGroup);
145 QAnimationGroup::updateState(newState, oldState);
146
147 switch (newState) {
148 case Stopped:
149 for (auto ani : std::as_const(d->animations))
150 ani->stop();
151 d->disconnectUncontrolledAnimations();
152 break;
153 case Paused:
154 for (auto ani : std::as_const(d->animations)) {
155 if (ani->state() == Running)
156 ani->pause();
157 }
158 break;
159 case Running:
160 d->connectUncontrolledAnimations();
161 for (auto animation : std::as_const(d->animations)) {
162 if (oldState == Stopped)
163 animation->stop();
164 animation->setDirection(d->direction);
165 if (d->shouldAnimationStart(animation, oldState == Stopped))
166 animation->start();
167 }
168 break;
169 }
170}
171
172void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished()
173{
174 Q_Q(QParallelAnimationGroup);
175
176 QAbstractAnimation *animation = qobject_cast<QAbstractAnimation *>(q->sender());
177 Q_ASSERT(animation);
178
179 int uncontrolledRunningCount = 0;
180 if (animation->duration() == -1 || animation->loopCount() < 0) {
181 for (AnimationTimeHashIt it = uncontrolledFinishTime.begin(), cend = uncontrolledFinishTime.end(); it != cend; ++it) {
182 if (it.key() == animation) {
183 *it = animation->currentTime();
184 }
185 if (it.value() == -1)
186 ++uncontrolledRunningCount;
187 }
188 }
189
190 if (uncontrolledRunningCount > 0)
191 return;
192
193 int maxDuration = 0;
194 for (auto ani : std::as_const(animations))
195 maxDuration = qMax(maxDuration, ani->totalDuration());
196
197 if (currentTime >= maxDuration)
198 q->stop();
199}
200
201void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations()
202{
203 for (AnimationTimeHashConstIt it = uncontrolledFinishTime.constBegin(), cend = uncontrolledFinishTime.constEnd(); it != cend; ++it)
204 disconnectUncontrolledAnimation(it.key());
205
206 uncontrolledFinishTime.clear();
207}
208
209void QParallelAnimationGroupPrivate::connectUncontrolledAnimations()
210{
211 for (auto animation : std::as_const(animations)) {
212 if (animation->duration() == -1 || animation->loopCount() < 0) {
213 uncontrolledFinishTime[animation] = -1;
214 connectUncontrolledAnimation(animation);
215 }
216 }
217}
218
219bool QParallelAnimationGroupPrivate::shouldAnimationStart(QAbstractAnimation *animation, bool startIfAtEnd) const
220{
221 const int dura = animation->totalDuration();
222 if (dura == -1)
223 return !isUncontrolledAnimationFinished(animation);
224 if (startIfAtEnd)
225 return currentTime <= dura;
226 if (direction == QAbstractAnimation::Forward)
227 return currentTime < dura;
228 else //direction == QAbstractAnimation::Backward
229 return currentTime && currentTime <= dura;
230}
231
232void QParallelAnimationGroupPrivate::applyGroupState(QAbstractAnimation *animation)
233{
234 switch (state)
235 {
236 case QAbstractAnimation::Running:
237 animation->start();
238 break;
239 case QAbstractAnimation::Paused:
240 animation->pause();
241 break;
242 case QAbstractAnimation::Stopped:
243 default:
244 break;
245 }
246}
247
248
249bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const
250{
251 return uncontrolledFinishTime.value(anim, -1) >= 0;
252}
253
254void QParallelAnimationGroupPrivate::animationRemoved(qsizetype index, QAbstractAnimation *anim)
255{
256 QAnimationGroupPrivate::animationRemoved(index, anim);
257 disconnectUncontrolledAnimation(anim);
258 uncontrolledFinishTime.remove(anim);
259}
260
261/*!
262 \reimp
263*/
264void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction)
265{
266 Q_D(QParallelAnimationGroup);
267 //we need to update the direction of the current animation
268 if (state() != Stopped) {
269 for (auto ani : std::as_const(d->animations))
270 ani->setDirection(direction);
271 } else {
272 if (direction == Forward) {
273 d->lastLoop = 0;
274 d->lastCurrentTime = 0;
275 } else {
276 // Looping backwards with loopCount == -1 does not really work well...
277 d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1);
278 d->lastCurrentTime = duration();
279 }
280 }
281}
282
283/*!
284 \reimp
285*/
286bool QParallelAnimationGroup::event(QEvent *event)
287{
288 return QAnimationGroup::event(event);
289}
290
291QT_END_NAMESPACE
292
293#include "moc_qparallelanimationgroup.cpp"
QT_BEGIN_NAMESPACE typedef QList< QAbstractAnimation * >::ConstIterator AnimationListConstIt
QHash< QAbstractAnimation *, int >::Iterator AnimationTimeHashIt
QHash< QAbstractAnimation *, int >::ConstIterator AnimationTimeHashConstIt