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 \sa removeAnimation()
138*/
139void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
140{
141 Q_D(QAnimationGroup);
142 insertAnimation(d->animations.size(), animation);
143}
144
145/*!
146 Inserts \a animation into this animation group at \a index.
147 If \a index is 0 the animation is inserted at the beginning.
148 If \a index is animationCount(), the animation is inserted at the end.
149
150 \note The group takes ownership of the animation.
151
152 \sa takeAnimation(), addAnimation(), indexOfAnimation(), removeAnimation()
153*/
154void QAnimationGroup::insertAnimation(int index, QAbstractAnimation *animation)
155{
156 Q_D(QAnimationGroup);
157
158 if (index < 0 || index > d->animations.size()) {
159 qWarning("QAnimationGroup::insertAnimation: index is out of bounds");
160 return;
161 }
162
163 if (QAnimationGroup *oldGroup = animation->group()) {
164 oldGroup->removeAnimation(animation);
165 // ensure we don't insert out of bounds if oldGroup == this
166 index = qMin(index, d->animations.size());
167 }
168
169 d->animations.insert(index, animation);
170 QAbstractAnimationPrivate::get(animation)->group = this;
171 // this will make sure that ChildAdded event is sent to 'this'
172 animation->setParent(this);
173 d->animationInsertedAt(index);
174}
175
176/*!
177 Removes \a animation from this group. The ownership of \a animation is
178 transferred to the caller.
179
180 \sa takeAnimation(), insertAnimation(), addAnimation()
181*/
182void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
183{
184 Q_D(QAnimationGroup);
185
186 if (!animation) {
187 qWarning("QAnimationGroup::remove: cannot remove null animation");
188 return;
189 }
190 qsizetype index = d->animations.indexOf(animation);
191 if (index == -1) {
192 qWarning("QAnimationGroup::remove: animation is not part of this group");
193 return;
194 }
195
196 takeAnimation(index);
197}
198
199/*!
200 Returns the animation at \a index and removes it from the animation group.
201
202 \note The ownership of the animation is transferred to the caller.
203
204 \sa removeAnimation(), addAnimation(), insertAnimation(), indexOfAnimation()
205*/
206QAbstractAnimation *QAnimationGroup::takeAnimation(int index)
207{
208 Q_D(QAnimationGroup);
209 if (index < 0 || index >= d->animations.size()) {
210 qWarning("QAnimationGroup::takeAnimation: no animation at index %d", index);
211 return nullptr;
212 }
213 QAbstractAnimation *animation = d->animations.at(index);
214 QAbstractAnimationPrivate::get(animation)->group = nullptr;
215 // ### removing from list before doing setParent to avoid infinite recursion
216 // in ChildRemoved event
217 d->animations.removeAt(index);
218 animation->setParent(nullptr);
219 d->animationRemoved(index, animation);
220 return animation;
221}
222
223/*!
224 Removes and deletes all animations in this animation group, and resets the current
225 time to 0.
226
227 \sa addAnimation(), removeAnimation()
228*/
229void QAnimationGroup::clear()
230{
231 Q_D(QAnimationGroup);
232 d->clear(false);
233}
234
235/*!
236 \reimp
237*/
238bool QAnimationGroup::event(QEvent *event)
239{
240 Q_D(QAnimationGroup);
241 if (event->type() == QEvent::ChildAdded) {
242 QChildEvent *childEvent = static_cast<QChildEvent *>(event);
243 if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
244 if (a->group() != this)
245 addAnimation(a);
246 }
247 } else if (event->type() == QEvent::ChildRemoved) {
248 QChildEvent *childEvent = static_cast<QChildEvent *>(event);
249 // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
250 // case it might be called from the destructor. Casting down to QAbstractAnimation then
251 // entails undefined behavior, so compare items as QObjects (which std::find does internally):
252 const QList<QAbstractAnimation *>::const_iterator it
253 = std::find(d->animations.cbegin(), d->animations.cend(), childEvent->child());
254 if (it != d->animations.cend())
255 takeAnimation(it - d->animations.cbegin());
256 }
257 return QAbstractAnimation::event(event);
258}
259
260void QAnimationGroupPrivate::clear(bool onDestruction)
261{
262 const QList<QAbstractAnimation *> animationsCopy = animations; // taking a copy
263 animations.clear();
264 // Clearing backwards so the indices doesn't change while we remove animations.
265 for (qsizetype i = animationsCopy.size() - 1; i >= 0; --i) {
266 QAbstractAnimation *animation = animationsCopy.at(i);
267 animation->setParent(nullptr);
268 QAbstractAnimationPrivate::get(animation)->group = nullptr;
269 // If we are in ~QAnimationGroup() it is not safe to called the virtual
270 // animationRemoved method, which can still be a method in a
271 // QAnimationGroupPrivate derived class that assumes q_ptr is still
272 // a valid derived class of QAnimationGroup.
273 if (!onDestruction)
274 animationRemoved(i, animation);
275 delete animation;
276 }
277}
278
279void QAnimationGroupPrivate::animationRemoved(qsizetype index, QAbstractAnimation *)
280{
281 Q_Q(QAnimationGroup);
282 Q_UNUSED(index);
283 if (animations.isEmpty()) {
284 currentTime = 0;
285 q->stop();
286 }
287}
288
289QT_END_NAMESPACE
290
291#include "moc_qanimationgroup.cpp"