1 | // Copyright (C) 2017 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 | |
4 | #include "qanimationcontroller.h" |
5 | #include "qanimationgroup.h" |
6 | |
7 | #include <private/qanimationcontroller_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | namespace Qt3DAnimation { |
12 | |
13 | /*! |
14 | \class Qt3DAnimation::QAnimationController |
15 | \brief A controller class for animations. |
16 | \inmodule Qt3DAnimation |
17 | \since 5.9 |
18 | \inherits QObject |
19 | |
20 | Qt3DAnimation::QAnimationController class controls the selection and playback of animations. |
21 | The class can be used to find all animations from Qt3DCore::QEntity tree and create |
22 | \l {Qt3DAnimation::QAnimationGroup} {QAnimationGroups} from the animations with the same name. |
23 | The user can select which animation group is currently controlled with the animation |
24 | controller by setting the active animation. The animation position is then propagated to |
25 | that group after scaling and offsetting the provided position value with the |
26 | positionScale and positionOffset values. |
27 | |
28 | \note that the animation controller doesn't have internal timer, but instead the user |
29 | is responsible for updating the position property in timely manner. |
30 | */ |
31 | |
32 | /*! |
33 | \qmltype AnimationController |
34 | \brief A controller type for animations. |
35 | \inqmlmodule Qt3D.Animation |
36 | \since 5.9 |
37 | \instantiates Qt3DAnimation::QAnimationController |
38 | |
39 | AnimationController type controls the selection and playback of animations. |
40 | The type can be used to find all animations from Entity tree and create |
41 | \l {AnimationGroup} {AnimationGroups} from the animations with the same name. |
42 | The user can select which animation group is currently controlled with the animation |
43 | controller by setting the active animation. The animation position is then propagated to |
44 | that group after scaling and offsetting the provided position value with the |
45 | positionScale and positionOffset values. |
46 | |
47 | \note that the animation controller doesn't have internal timer, but instead the user |
48 | is responsible for updating the position property in timely manner. |
49 | */ |
50 | |
51 | /*! |
52 | \property Qt3DAnimation::QAnimationController::activeAnimationGroup |
53 | Holds the currectly active animation group. |
54 | */ |
55 | /*! |
56 | \property Qt3DAnimation::QAnimationController::position |
57 | Holds the current position of the animation. When the position is set, |
58 | it is scaled and offset with positionScale/positionOffset and propagated |
59 | to the active animation group. |
60 | */ |
61 | /*! |
62 | \property Qt3DAnimation::QAnimationController::positionScale |
63 | Holds the position scale of the animation. |
64 | */ |
65 | /*! |
66 | \property Qt3DAnimation::QAnimationController::positionOffset |
67 | Holds the position offset of the animation. |
68 | */ |
69 | /*! |
70 | \property Qt3DAnimation::QAnimationController::entity |
71 | Holds the entity animations are gathered and grouped from. If the controller already |
72 | holds animations, they are cleared. |
73 | */ |
74 | /*! |
75 | \property Qt3DAnimation::QAnimationController::recursive |
76 | Holds whether the recursively search the entity tree when gathering animations from the entity. |
77 | If set to true, the animations are searched also from the child entities of the entity. |
78 | If set to false, only the entity passed to the controller is searched. |
79 | */ |
80 | |
81 | /*! |
82 | \qmlproperty int AnimationController::activeAnimationGroup |
83 | Holds the currectly active animation group. |
84 | */ |
85 | /*! |
86 | \qmlproperty real AnimationController::position |
87 | Holds the current position of the animation. When the position is set, |
88 | it is scaled and offset with positionScale/positionOffset and propagated |
89 | to the active animation group. |
90 | */ |
91 | /*! |
92 | \qmlproperty real AnimationController::positionScale |
93 | Holds the position scale of the animation. |
94 | */ |
95 | /*! |
96 | \qmlproperty real AnimationController::positionOffset |
97 | Holds the position offset of the animation. |
98 | */ |
99 | /*! |
100 | \qmlproperty Entity AnimationController::entity |
101 | Holds the entity animations are gathered and grouped from. If the controller already |
102 | holds animations, they are cleared. |
103 | */ |
104 | /*! |
105 | \qmlproperty bool AnimationController::recursive |
106 | Holds whether the recursively search the entity tree when gathering animations from the entity. |
107 | If set to true, the animations are searched also from the child entities of the entity. |
108 | If set to false, only the entity passed to the controller is searched. |
109 | */ |
110 | /*! |
111 | \qmlproperty list<AnimationGroup> AnimationController::animationGroups |
112 | Holds the list of animation groups in the controller. |
113 | */ |
114 | /*! |
115 | \qmlmethod int Qt3D.Animation::AnimationController::getAnimationIndex(name) |
116 | Returns the index of the animation with \a name. Returns -1 if no AnimationGroup |
117 | with the given name is found. |
118 | */ |
119 | /*! |
120 | \qmlmethod AnimationGroup Qt3D.Animation::AnimationController::getGroup(index) |
121 | Returns the AnimationGroup with the given \a index. |
122 | */ |
123 | |
124 | QAnimationControllerPrivate::QAnimationControllerPrivate() |
125 | : QObjectPrivate() |
126 | , m_activeAnimationGroup(0) |
127 | , m_position(0.0f) |
128 | , m_scaledPosition(0.0f) |
129 | , m_positionScale(1.0f) |
130 | , m_positionOffset(0.0f) |
131 | , m_entity(nullptr) |
132 | , m_recursive(true) |
133 | { |
134 | |
135 | } |
136 | |
137 | void QAnimationControllerPrivate::updatePosition(float position) |
138 | { |
139 | m_position = position; |
140 | m_scaledPosition = scaledPosition(position); |
141 | if (m_activeAnimationGroup >= 0 && m_activeAnimationGroup < m_animationGroups.size()) |
142 | m_animationGroups[m_activeAnimationGroup]->setPosition(m_scaledPosition); |
143 | } |
144 | |
145 | float QAnimationControllerPrivate::scaledPosition(float position) const |
146 | { |
147 | return m_positionScale * position + m_positionOffset; |
148 | } |
149 | |
150 | QAnimationGroup *QAnimationControllerPrivate::findGroup(const QString &name) |
151 | { |
152 | for (QAnimationGroup *g : std::as_const(t&: m_animationGroups)) { |
153 | if (g->name() == name) |
154 | return g; |
155 | } |
156 | return nullptr; |
157 | } |
158 | |
159 | void QAnimationControllerPrivate::() |
160 | { |
161 | Q_Q(QAnimationController); |
162 | if (!m_entity) |
163 | return; |
164 | QList<Qt3DAnimation::QAbstractAnimation *> animations |
165 | = m_entity->findChildren<Qt3DAnimation::QAbstractAnimation *>(aName: QString(), |
166 | options: m_recursive ? Qt::FindChildrenRecursively : Qt::FindDirectChildrenOnly); |
167 | if (animations.size() > 0) { |
168 | for (Qt3DAnimation::QAbstractAnimation *a : animations) { |
169 | QAnimationGroup *group = findGroup(name: a->animationName()); |
170 | if (!group) { |
171 | group = new QAnimationGroup(q); |
172 | group->setName(a->animationName()); |
173 | m_animationGroups.push_back(t: group); |
174 | } |
175 | group->addAnimation(animation: a); |
176 | } |
177 | } |
178 | } |
179 | void QAnimationControllerPrivate::clearAnimations() |
180 | { |
181 | for (Qt3DAnimation::QAnimationGroup *a : std::as_const(t&: m_animationGroups)) |
182 | a->deleteLater(); |
183 | m_animationGroups.clear(); |
184 | m_activeAnimationGroup = 0; |
185 | } |
186 | |
187 | /*! |
188 | Constructs a new QAnimationController with \a parent. |
189 | */ |
190 | QAnimationController::QAnimationController(QObject *parent) |
191 | : QObject(*new QAnimationControllerPrivate, parent) |
192 | { |
193 | |
194 | } |
195 | |
196 | /*! |
197 | Returns the list of animation groups the conroller is currently holding. |
198 | */ |
199 | QList<QAnimationGroup *> QAnimationController::animationGroupList() |
200 | { |
201 | Q_D(QAnimationController); |
202 | return d->m_animationGroups; |
203 | } |
204 | |
205 | int QAnimationController::activeAnimationGroup() const |
206 | { |
207 | Q_D(const QAnimationController); |
208 | return d->m_activeAnimationGroup; |
209 | } |
210 | |
211 | float QAnimationController::position() const |
212 | { |
213 | Q_D(const QAnimationController); |
214 | return d->m_position; |
215 | } |
216 | |
217 | float QAnimationController::positionScale() const |
218 | { |
219 | Q_D(const QAnimationController); |
220 | return d->m_positionScale; |
221 | } |
222 | |
223 | float QAnimationController::positionOffset() const |
224 | { |
225 | Q_D(const QAnimationController); |
226 | return d->m_positionOffset; |
227 | } |
228 | |
229 | Qt3DCore::QEntity *QAnimationController::entity() const |
230 | { |
231 | Q_D(const QAnimationController); |
232 | return d->m_entity; |
233 | } |
234 | |
235 | bool QAnimationController::recursive() const |
236 | { |
237 | Q_D(const QAnimationController); |
238 | return d->m_recursive; |
239 | } |
240 | |
241 | /*! |
242 | Sets the \a animationGroups for the controller. Old groups are cleared. |
243 | */ |
244 | void QAnimationController::setAnimationGroups(const QList<Qt3DAnimation::QAnimationGroup *> &animationGroups) |
245 | { |
246 | Q_D(QAnimationController); |
247 | d->m_animationGroups = animationGroups; |
248 | if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) |
249 | d->m_activeAnimationGroup = 0; |
250 | d->updatePosition(position: d->m_position); |
251 | } |
252 | |
253 | /*! |
254 | Adds the given \a animationGroup to the controller. |
255 | */ |
256 | void QAnimationController::addAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) |
257 | { |
258 | Q_D(QAnimationController); |
259 | if (!d->m_animationGroups.contains(t: animationGroup)) |
260 | d->m_animationGroups.push_back(t: animationGroup); |
261 | } |
262 | |
263 | /*! |
264 | Removes the given \a animationGroup from the controller. |
265 | */ |
266 | void QAnimationController::removeAnimationGroup(Qt3DAnimation::QAnimationGroup *animationGroup) |
267 | { |
268 | Q_D(QAnimationController); |
269 | if (d->m_animationGroups.contains(t: animationGroup)) |
270 | d->m_animationGroups.removeAll(t: animationGroup); |
271 | if (d->m_activeAnimationGroup >= d->m_animationGroups.size()) |
272 | d->m_activeAnimationGroup = 0; |
273 | } |
274 | |
275 | void QAnimationController::setActiveAnimationGroup(int index) |
276 | { |
277 | Q_D(QAnimationController); |
278 | if (d->m_activeAnimationGroup != index) { |
279 | d->m_activeAnimationGroup = index; |
280 | d->updatePosition(position: d->m_position); |
281 | emit activeAnimationGroupChanged(index); |
282 | } |
283 | } |
284 | void QAnimationController::setPosition(float position) |
285 | { |
286 | Q_D(QAnimationController); |
287 | if (!qFuzzyCompare(p1: d->m_scaledPosition, p2: d->scaledPosition(position))) { |
288 | d->updatePosition(position); |
289 | emit positionChanged(position); |
290 | } |
291 | } |
292 | |
293 | void QAnimationController::setPositionScale(float scale) |
294 | { |
295 | Q_D(QAnimationController); |
296 | if (!qFuzzyCompare(p1: d->m_positionScale, p2: scale)) { |
297 | d->m_positionScale = scale; |
298 | emit positionScaleChanged(scale); |
299 | } |
300 | } |
301 | |
302 | void QAnimationController::setPositionOffset(float offset) |
303 | { |
304 | Q_D(QAnimationController); |
305 | if (!qFuzzyCompare(p1: d->m_positionOffset, p2: offset)) { |
306 | d->m_positionOffset = offset; |
307 | emit positionOffsetChanged(offset); |
308 | } |
309 | } |
310 | |
311 | void QAnimationController::setEntity(Qt3DCore::QEntity *entity) |
312 | { |
313 | Q_D(QAnimationController); |
314 | if (d->m_entity != entity) { |
315 | d->clearAnimations(); |
316 | d->m_entity = entity; |
317 | d->extractAnimations(); |
318 | d->updatePosition(position: d->m_position); |
319 | emit entityChanged(entity); |
320 | } |
321 | } |
322 | |
323 | void QAnimationController::setRecursive(bool recursive) |
324 | { |
325 | Q_D(QAnimationController); |
326 | if (d->m_recursive != recursive) { |
327 | d->m_recursive = recursive; |
328 | emit recursiveChanged(recursive); |
329 | } |
330 | } |
331 | |
332 | /*! |
333 | Returns the index of the animation with \a name. Returns -1 if no AnimationGroup |
334 | with the given name is found. |
335 | */ |
336 | int QAnimationController::getAnimationIndex(const QString &name) const |
337 | { |
338 | Q_D(const QAnimationController); |
339 | for (int i = 0; i < d->m_animationGroups.size(); ++i) { |
340 | if (d->m_animationGroups[i]->name() == name) |
341 | return i; |
342 | } |
343 | return -1; |
344 | } |
345 | |
346 | /*! |
347 | Returns the AnimationGroup with the given \a index. |
348 | */ |
349 | QAnimationGroup *QAnimationController::getGroup(int index) const |
350 | { |
351 | Q_D(const QAnimationController); |
352 | return d->m_animationGroups.at(i: index); |
353 | } |
354 | |
355 | } // Qt3DAnimation |
356 | |
357 | QT_END_NAMESPACE |
358 | |
359 | #include "moc_qanimationcontroller.cpp" |
360 | |