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
qanimationgroup.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 QAnimationGroup
7 \inmodule QtCore
8 \brief The QAnimationGroup class is an abstract base class for groups of animations.
9 \since 4.6
10 \ingroup animation
11
12 An animation group is a container for animations (subclasses of
13 QAbstractAnimation). A group is usually responsible for managing
14 the \l{QAbstractAnimation::State}{state} of its animations, i.e.,
15 it decides when to start, stop, resume, and pause them. Currently,
16 Qt provides two such groups: QParallelAnimationGroup and
17 QSequentialAnimationGroup. Look up their class descriptions for
18 details.
19
20 Since QAnimationGroup inherits from QAbstractAnimation, you can
21 combine groups, and easily construct complex animation graphs.
22 You can query QAbstractAnimation for the group it belongs to
23 (using the \l{QAbstractAnimation::}{group()} function).
24
25 To start a top-level animation group, you simply use the
26 \l{QAbstractAnimation::}{start()} function from
27 QAbstractAnimation. By a top-level animation group, we think of a
28 group that itself is not contained within another group. Starting
29 sub groups directly is not supported, and may lead to unexpected
30 behavior.
31
32 \omit OK, we'll put in a snippet on this here \endomit
33
34 QAnimationGroup provides methods for adding and retrieving
35 animations. Besides that, you can remove animations by calling
36 \l removeAnimation(), and clear the animation group by calling
37 clear(). You may keep track of changes in the group's
38 animations by listening to QEvent::ChildAdded and
39 QEvent::ChildRemoved events.
40
41 \omit OK, let's find a snippet here as well. \endomit
42
43 QAnimationGroup takes ownership of the animations it manages, and
44 ensures that they are deleted when the animation group is deleted.
45
46 \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework}
47*/
48
50#include <QtCore/qdebug.h>
51#include <QtCore/qcoreevent.h>
53
54#include <algorithm>
55
56QT_BEGIN_NAMESPACE
57
58
59/*!
60 Constructs a QAnimationGroup.
61 \a parent is passed to QObject's constructor.
62*/
63QAnimationGroup::QAnimationGroup(QObject *parent)
64 : QAbstractAnimation(*new QAnimationGroupPrivate, parent)
65{
66}
67
68/*!
69 \internal
70*/
71QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent)
72 : QAbstractAnimation(dd, parent)
73{
74}
75
76/*!
77 Destroys the animation group. It will also destroy all its animations.
78*/
79QAnimationGroup::~QAnimationGroup()
80{
81 Q_D(QAnimationGroup);
82 // We need to clear the animations now while we are still a valid QAnimationGroup.
83 // If we wait until ~QObject() the QAbstractAnimation's pointer back to us would
84 // point to a QObject, not a valid QAnimationGroup.
85 d->clear(true);
86}
87
88/*!
89 Returns a pointer to the animation at \a index in this group. This
90 function is useful when you need access to a particular animation. \a
91 index is between 0 and animationCount() - 1.
92
93 \sa animationCount(), indexOfAnimation()
94*/
95QAbstractAnimation *QAnimationGroup::animationAt(int index) const
96{
97 Q_D(const QAnimationGroup);
98
99 if (index < 0 || index >= d->animations.size()) {
100 qWarning("QAnimationGroup::animationAt: index is out of bounds");
101 return nullptr;
102 }
103
104 return d->animations.at(index);
105}
106
107
108/*!
109 Returns the number of animations managed by this group.
110
111 \sa indexOfAnimation(), addAnimation(), animationAt()
112*/
113int QAnimationGroup::animationCount() const
114{
115 Q_D(const QAnimationGroup);
116 return d->animations.size();
117}
118
119/*!
120 Returns the index of \a animation. The returned index can be passed
121 to the other functions that take an index as an argument.
122
123 \sa insertAnimation(), animationAt(), takeAnimation()
124*/
125int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const
126{
127 Q_D(const QAnimationGroup);
128 return d->animations.indexOf(animation);
129}
130
131/*!
132 Adds \a animation to this group. This will call insertAnimation with
133 index equals to animationCount().
134
135 \note The group takes ownership of the animation.
136
137//! [animation-loop]
138 \warning This method does not check for animation loops. It's the
139 developer's responsibility to make sure that the added \a animation does not
140 include \c {this} animation group directly or indirectly.
141//! [animation-loop]
142
143 \sa removeAnimation()
144*/
145void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
146{
147 Q_D(QAnimationGroup);
148 insertAnimation(d->animations.size(), animation);
149}
150
151/*!
152 Inserts \a animation into this animation group at \a index.
153 If \a index is 0 the animation is inserted at the beginning.
154 If \a index is animationCount(), the animation is inserted at the end.
155
156 \note The group takes ownership of the animation.
157
158 \include qanimationgroup.cpp animation-loop
159
160 \sa takeAnimation(), addAnimation(), indexOfAnimation(), removeAnimation()
161*/
162void QAnimationGroup::insertAnimation(int index, QAbstractAnimation *animation)
163{
164 Q_D(QAnimationGroup);
165
166 if (index < 0 || index > d->animations.size()) {
167 qWarning("QAnimationGroup::insertAnimation: index is out of bounds");
168 return;
169 }
170
171 if (QAnimationGroup *oldGroup = animation->group()) {
172 oldGroup->removeAnimation(animation);
173 // ensure we don't insert out of bounds if oldGroup == this
174 index = qMin(index, d->animations.size());
175 }
176
177 d->animations.insert(index, animation);
178 QAbstractAnimationPrivate::get(animation)->group = this;
179 // this will make sure that ChildAdded event is sent to 'this'
180 animation->setParent(this);
181 d->animationInsertedAt(index);
182}
183
184/*!
185 Removes \a animation from this group. The ownership of \a animation is
186 transferred to the caller.
187
188 \sa takeAnimation(), insertAnimation(), addAnimation()
189*/
190void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
191{
192 Q_D(QAnimationGroup);
193
194 if (!animation) {
195 qWarning("QAnimationGroup::remove: cannot remove null animation");
196 return;
197 }
198 qsizetype index = d->animations.indexOf(animation);
199 if (index == -1) {
200 qWarning("QAnimationGroup::remove: animation is not part of this group");
201 return;
202 }
203
204 takeAnimation(index);
205}
206
207/*!
208 Returns the animation at \a index and removes it from the animation group.
209
210 \note The ownership of the animation is transferred to the caller.
211
212 \sa removeAnimation(), addAnimation(), insertAnimation(), indexOfAnimation()
213*/
214QAbstractAnimation *QAnimationGroup::takeAnimation(int index)
215{
216 Q_D(QAnimationGroup);
217 if (index < 0 || index >= d->animations.size()) {
218 qWarning("QAnimationGroup::takeAnimation: no animation at index %d", index);
219 return nullptr;
220 }
221 QAbstractAnimation *animation = d->animations.at(index);
222 QAbstractAnimationPrivate::get(animation)->group = nullptr;
223 // ### removing from list before doing setParent to avoid infinite recursion
224 // in ChildRemoved event
225 d->animations.removeAt(index);
226 animation->setParent(nullptr);
227 d->animationRemoved(index, animation);
228 return animation;
229}
230
231/*!
232 Removes and deletes all animations in this animation group, and resets the current
233 time to 0.
234
235 \sa addAnimation(), removeAnimation()
236*/
237void QAnimationGroup::clear()
238{
239 Q_D(QAnimationGroup);
240 d->clear(false);
241}
242
243/*!
244 \reimp
245*/
246bool QAnimationGroup::event(QEvent *event)
247{
248 Q_D(QAnimationGroup);
249 if (event->type() == QEvent::ChildAdded) {
250 QChildEvent *childEvent = static_cast<QChildEvent *>(event);
251 if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
252 if (a->group() != this)
253 addAnimation(a);
254 }
255 } else if (event->type() == QEvent::ChildRemoved) {
256 QChildEvent *childEvent = static_cast<QChildEvent *>(event);
257 // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
258 // case it might be called from the destructor. Casting down to QAbstractAnimation then
259 // entails undefined behavior, so compare items as QObjects (which std::find does internally):
260 const QList<QAbstractAnimation *>::const_iterator it
261 = std::find(d->animations.cbegin(), d->animations.cend(), childEvent->child());
262 if (it != d->animations.cend())
263 takeAnimation(it - d->animations.cbegin());
264 }
265 return QAbstractAnimation::event(event);
266}
267
268void QAnimationGroupPrivate::clear(bool onDestruction)
269{
270 const QList<QAbstractAnimation *> animationsCopy = animations; // taking a copy
271 animations.clear();
272 // Clearing backwards so the indices doesn't change while we remove animations.
273 for (qsizetype i = animationsCopy.size() - 1; i >= 0; --i) {
274 QAbstractAnimation *animation = animationsCopy.at(i);
275 animation->setParent(nullptr);
276 QAbstractAnimationPrivate::get(animation)->group = nullptr;
277 // If we are in ~QAnimationGroup() it is not safe to called the virtual
278 // animationRemoved method, which can still be a method in a
279 // QAnimationGroupPrivate derived class that assumes q_ptr is still
280 // a valid derived class of QAnimationGroup.
281 if (!onDestruction)
282 animationRemoved(i, animation);
283 delete animation;
284 }
285}
286
287void QAnimationGroupPrivate::animationRemoved(qsizetype index, QAbstractAnimation *)
288{
289 Q_Q(QAnimationGroup);
290 Q_UNUSED(index);
291 if (animations.isEmpty()) {
292 currentTime = 0;
293 q->stop();
294 }
295}
296
297QT_END_NAMESPACE
298
299#include "moc_qanimationgroup.cpp"