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 | |
4 | #include "qquickanimator_p_p.h" |
5 | #include "qquickanimatorjob_p.h" |
6 | |
7 | #include <private/qquickitem_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | /*! |
12 | \qmltype Animator |
13 | \instantiates QQuickAnimator |
14 | \inqmlmodule QtQuick |
15 | \since 5.2 |
16 | \ingroup qtquick-transitions-animations |
17 | \inherits Animation |
18 | \brief Is the base of all QML animators. |
19 | |
20 | Animator types are a special type of animation which operate |
21 | directly on Qt Quick's scene graph, rather than the QML objects and their |
22 | properties like regular Animation types do. This has the benefit that |
23 | Animator based animations can animate on the \l |
24 | {Threaded Render Loop ('threaded')}{scene graph's rendering thread} even when the |
25 | UI thread is blocked. |
26 | |
27 | The value of the QML property will be updated after the animation has |
28 | finished. The property is not updated while the animation is running. |
29 | |
30 | The Animator types can be used just like any other Animation type. |
31 | |
32 | \snippet qml/animators.qml mixed |
33 | |
34 | If all sub-animations of ParallelAnimation and SequentialAnimation |
35 | are Animator types, the ParallelAnimation and SequentialAnimation will |
36 | also be treated as an Animator and be run on the scene graph's rendering |
37 | thread when possible. |
38 | |
39 | The Animator types can be used for animations during transitions, but |
40 | they do not support the \l {Transition::reversible}{reversible} |
41 | property. |
42 | |
43 | The Animator type cannot be used directly in a QML file. It exists |
44 | to provide a set of common properties and methods, available across all the |
45 | other animator types that inherit from it. Attempting to use the Animator |
46 | type directly will result in an error. |
47 | */ |
48 | |
49 | QQuickAnimator::QQuickAnimator(QQuickAnimatorPrivate &dd, QObject *parent) |
50 | : QQuickAbstractAnimation(dd, parent) |
51 | { |
52 | } |
53 | |
54 | QQuickAnimator::QQuickAnimator(QObject *parent) |
55 | : QQuickAbstractAnimation(*new QQuickAnimatorPrivate, parent) |
56 | { |
57 | } |
58 | |
59 | /*! |
60 | \qmlproperty QtQuick::Item QtQuick::Animator::target |
61 | |
62 | This property holds the target item of the animator. |
63 | |
64 | \note Animator targets must be Item based types. |
65 | */ |
66 | |
67 | void QQuickAnimator::setTargetItem(QQuickItem *target) |
68 | { |
69 | Q_D(QQuickAnimator); |
70 | if (target == d->target) |
71 | return; |
72 | d->target = target; |
73 | Q_EMIT targetItemChanged(d->target); |
74 | } |
75 | |
76 | QQuickItem *QQuickAnimator::targetItem() const |
77 | { |
78 | Q_D(const QQuickAnimator); |
79 | return d->target; |
80 | } |
81 | |
82 | /*! |
83 | \qmlproperty int QtQuick::Animator::duration |
84 | This property holds the duration of the animation in milliseconds. |
85 | |
86 | The default value is 250. |
87 | */ |
88 | void QQuickAnimator::setDuration(int duration) |
89 | { |
90 | Q_D(QQuickAnimator); |
91 | if (duration == d->duration) |
92 | return; |
93 | d->duration = duration; |
94 | Q_EMIT durationChanged(duration); |
95 | } |
96 | |
97 | int QQuickAnimator::duration() const |
98 | { |
99 | Q_D(const QQuickAnimator); |
100 | return d->duration; |
101 | } |
102 | |
103 | /*! |
104 | \qmlpropertygroup QtQuick::Animator::easing |
105 | \qmlproperty enumeration QtQuick::Animator::easing.type |
106 | \qmlproperty real QtQuick::Animator::easing.amplitude |
107 | \qmlproperty real QtQuick::Animator::easing.overshoot |
108 | \qmlproperty real QtQuick::Animator::easing.period |
109 | \qmlproperty list<real> QtQuick::Animator::easing.bezierCurve |
110 | \include qquickanimation.cpp propertyanimation.easing |
111 | */ |
112 | |
113 | void QQuickAnimator::setEasing(const QEasingCurve &easing) |
114 | { |
115 | Q_D(QQuickAnimator); |
116 | if (easing == d->easing) |
117 | return; |
118 | d->easing = easing; |
119 | Q_EMIT easingChanged(curve: d->easing); |
120 | } |
121 | |
122 | QEasingCurve QQuickAnimator::easing() const |
123 | { |
124 | Q_D(const QQuickAnimator); |
125 | return d->easing; |
126 | } |
127 | |
128 | /*! |
129 | \qmlproperty real QtQuick::Animator::to |
130 | This property holds the end value for the animation. |
131 | |
132 | If the Animator is defined within a \l Transition or \l Behavior, |
133 | this value defaults to the value defined in the end state of the |
134 | \l Transition, or the value of the property change that triggered the |
135 | \l Behavior. |
136 | */ |
137 | |
138 | void QQuickAnimator::setTo(qreal to) |
139 | { |
140 | Q_D(QQuickAnimator); |
141 | if (to == d->to) |
142 | return; |
143 | d->toIsDefined = true; |
144 | d->to = to; |
145 | Q_EMIT toChanged(to: d->to); |
146 | } |
147 | |
148 | qreal QQuickAnimator::to() const |
149 | { |
150 | Q_D(const QQuickAnimator); |
151 | return d->to; |
152 | } |
153 | |
154 | /*! |
155 | \qmlproperty real QtQuick::Animator::from |
156 | This property holds the starting value for the animation. |
157 | |
158 | If the Animator is defined within a \l Transition or \l Behavior, |
159 | this value defaults to the value defined in the starting state of the |
160 | \l Transition, or the current value of the property at the moment the |
161 | \l Behavior is triggered. |
162 | |
163 | \sa {Animation and Transitions in Qt Quick} |
164 | */ |
165 | |
166 | void QQuickAnimator::setFrom(qreal from) |
167 | { |
168 | Q_D(QQuickAnimator); |
169 | d->fromIsDefined = true; |
170 | if (from == d->from) |
171 | return; |
172 | d->from = from; |
173 | Q_EMIT fromChanged(from: d->from); |
174 | } |
175 | |
176 | qreal QQuickAnimator::from() const |
177 | { |
178 | Q_D(const QQuickAnimator); |
179 | return d->from; |
180 | } |
181 | |
182 | void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, |
183 | const QString &propertyName, |
184 | QQuickStateActions &actions, |
185 | QQmlProperties &modified, |
186 | QObject *defaultTarget) |
187 | { |
188 | |
189 | if (actions.size()) { |
190 | for (int i=0; i<actions.size(); ++i) { |
191 | QQuickStateAction &action = actions[i]; |
192 | if (action.property.name() != propertyName) |
193 | continue; |
194 | modified << action.property; |
195 | |
196 | job->setTarget(qobject_cast<QQuickItem *>(o: action.property.object())); |
197 | |
198 | if (fromIsDefined) |
199 | job->setFrom(from); |
200 | else if (action.fromValue.isValid()) |
201 | job->setFrom(action.fromValue.toReal()); |
202 | else |
203 | job->setFrom(action.property.read().toReal()); |
204 | |
205 | if (toIsDefined) |
206 | job->setTo(to); |
207 | else if (action.toValue.isValid()) |
208 | job->setTo(action.toValue.toReal()); |
209 | else |
210 | job->setTo(action.property.read().toReal()); |
211 | |
212 | // This magic line is in sync with what PropertyAnimation does |
213 | // and prevents the animation to end up in the "completeList" |
214 | // which forces action.toValue to be written directly to |
215 | // the item when a transition is cancelled. |
216 | action.fromValue = action.toValue; |
217 | } |
218 | } |
219 | |
220 | if (modified.isEmpty()) { |
221 | job->setTarget(target); |
222 | if (fromIsDefined) |
223 | job->setFrom(from); |
224 | job->setTo(to); |
225 | } |
226 | |
227 | if (!job->target()) { |
228 | if (defaultProperty.object()) |
229 | job->setTarget(qobject_cast<QQuickItem *>(o: defaultProperty.object())); |
230 | else |
231 | job->setTarget(qobject_cast<QQuickItem *>(o: defaultTarget)); |
232 | } |
233 | |
234 | if (modified.isEmpty() && !fromIsDefined && job->target()) |
235 | job->setFrom(job->target()->property(name: propertyName.toLatin1()).toReal()); |
236 | |
237 | job->setDuration(duration); |
238 | job->setLoopCount(loopCount); |
239 | job->setEasingCurve(easing); |
240 | } |
241 | |
242 | QAbstractAnimationJob *QQuickAnimator::transition(QQuickStateActions &actions, |
243 | QQmlProperties &modified, |
244 | TransitionDirection direction, |
245 | QObject *defaultTarget) |
246 | { |
247 | Q_D(QQuickAnimator); |
248 | |
249 | if (d->defaultProperty.isValid() && propertyName() != d->defaultProperty.name()) { |
250 | qmlWarning(me: this) << "property name conflict: \"" |
251 | << propertyName() << "\" != \"" << d->defaultProperty.name() << "\"" ; |
252 | return nullptr; |
253 | } |
254 | |
255 | // The animation system cannot handle backwards uncontrolled animations. |
256 | if (direction == Backward) |
257 | return nullptr; |
258 | |
259 | QQuickAnimatorJob *job = createJob(); |
260 | if (!job) |
261 | return nullptr; |
262 | |
263 | d->apply(job, propertyName: propertyName(), actions, modified, defaultTarget); |
264 | |
265 | if (!job->target()) { |
266 | delete job; |
267 | return nullptr; |
268 | } |
269 | |
270 | return job; |
271 | } |
272 | |
273 | /*! |
274 | \qmltype XAnimator |
275 | \instantiates QQuickXAnimator |
276 | \inqmlmodule QtQuick |
277 | \since 5.2 |
278 | \ingroup qtquick-transitions-animations |
279 | \inherits Animator |
280 | \brief The XAnimator type animates the x position of an Item. |
281 | |
282 | \l{Animator} types are different from normal Animation types. When |
283 | using an Animator, the animation can be run in the render thread |
284 | and the property value will jump to the end when the animation is |
285 | complete. |
286 | |
287 | The value of Item::x is updated after the animation has finished. |
288 | |
289 | The following snippet shows how to use a XAnimator together |
290 | with a Rectangle item. |
291 | |
292 | \snippet qml/animators.qml x target |
293 | |
294 | It is also possible to use the \c on keyword to tie the |
295 | XAnimator directly to an Item instance. |
296 | |
297 | \snippet qml/animators.qml x on |
298 | |
299 | |
300 | */ |
301 | |
302 | QQuickXAnimator::QQuickXAnimator(QObject *parent) : QQuickAnimator(parent) {} |
303 | |
304 | QQuickAnimatorJob *QQuickXAnimator::createJob() const { return new QQuickXAnimatorJob(); } |
305 | |
306 | /*! |
307 | \qmltype YAnimator |
308 | \instantiates QQuickYAnimator |
309 | \inqmlmodule QtQuick |
310 | \since 5.2 |
311 | \ingroup qtquick-transitions-animations |
312 | \inherits Animator |
313 | \brief The YAnimator type animates the y position of an Item. |
314 | |
315 | \l{Animator} types are different from normal Animation types. When |
316 | using an Animator, the animation can be run in the render thread |
317 | and the property value will jump to the end when the animation is |
318 | complete. |
319 | |
320 | The value of Item::y is updated after the animation has finished. |
321 | |
322 | The following snippet shows how to use a YAnimator together |
323 | with a Rectangle item. |
324 | |
325 | \snippet qml/animators.qml y target |
326 | |
327 | It is also possible to use the \c on keyword to tie the |
328 | YAnimator directly to an Item instance. |
329 | |
330 | \snippet qml/animators.qml y on |
331 | |
332 | |
333 | */ |
334 | |
335 | QQuickYAnimator::QQuickYAnimator(QObject *parent) : QQuickAnimator(parent) {} |
336 | |
337 | QQuickAnimatorJob *QQuickYAnimator::createJob() const { return new QQuickYAnimatorJob(); } |
338 | |
339 | /*! |
340 | \qmltype ScaleAnimator |
341 | \instantiates QQuickScaleAnimator |
342 | \inqmlmodule QtQuick |
343 | \since 5.2 |
344 | \ingroup qtquick-transitions-animations |
345 | \inherits Animator |
346 | \brief The ScaleAnimator type animates the scale factor of an Item. |
347 | |
348 | \l{Animator} types are different from normal Animation types. When |
349 | using an Animator, the animation can be run in the render thread |
350 | and the property value will jump to the end when the animation is |
351 | complete. |
352 | |
353 | The value of Item::scale is updated after the animation has finished. |
354 | |
355 | The following snippet shows how to use a ScaleAnimator together |
356 | with a Rectangle item. |
357 | |
358 | \snippet qml/animators.qml scale target |
359 | |
360 | It is also possible to use the \c on keyword to tie the |
361 | ScaleAnimator directly to an Item instance. |
362 | |
363 | \snippet qml/animators.qml scale on |
364 | |
365 | \sa Item::transformOrigin, RotationAnimator |
366 | */ |
367 | |
368 | QQuickScaleAnimator::QQuickScaleAnimator(QObject *parent) : QQuickAnimator(parent) {} |
369 | |
370 | QQuickAnimatorJob *QQuickScaleAnimator::createJob() const { return new QQuickScaleAnimatorJob(); } |
371 | |
372 | /*! |
373 | \qmltype OpacityAnimator |
374 | \instantiates QQuickOpacityAnimator |
375 | \inqmlmodule QtQuick |
376 | \since 5.2 |
377 | \ingroup qtquick-transitions-animations |
378 | \inherits Animator |
379 | \brief The OpacityAnimator type animates the opacity of an Item. |
380 | |
381 | \l{Animator} types are different from normal Animation types. When |
382 | using an Animator, the animation can be run in the render thread |
383 | and the property value will jump to the end when the animation is |
384 | complete. |
385 | |
386 | The value of Item::opacity is updated after the animation has finished. |
387 | |
388 | The following snippet shows how to use a OpacityAnimator together |
389 | with a Rectangle item. |
390 | |
391 | \snippet qml/animators.qml opacity target |
392 | |
393 | It is also possible to use the \c on keyword to tie the |
394 | OpacityAnimator directly to an Item instance. |
395 | |
396 | \snippet qml/animators.qml opacity on |
397 | |
398 | */ |
399 | |
400 | QQuickOpacityAnimator::QQuickOpacityAnimator(QObject *parent) : QQuickAnimator(parent) {} |
401 | |
402 | QQuickAnimatorJob *QQuickOpacityAnimator::createJob() const { return new QQuickOpacityAnimatorJob(); } |
403 | |
404 | /*! |
405 | \qmltype RotationAnimator |
406 | \instantiates QQuickRotationAnimator |
407 | \inqmlmodule QtQuick |
408 | \since 5.2 |
409 | \ingroup qtquick-transitions-animations |
410 | \inherits Animator |
411 | \brief The RotationAnimator type animates the rotation of an Item. |
412 | |
413 | \l{Animator} types are different from normal Animation types. When |
414 | using an Animator, the animation can be run in the render thread |
415 | and the property value will jump to the end when the animation is |
416 | complete. |
417 | |
418 | The value of Item::rotation is updated after the animation has finished. |
419 | |
420 | The following snippet shows how to use a RotationAnimator together |
421 | with a Rectangle item. |
422 | |
423 | \snippet qml/animators.qml rotation target |
424 | |
425 | It is also possible to use the \c on keyword to tie the |
426 | RotationAnimator directly to the \c rotation property of an Item |
427 | instance. |
428 | |
429 | \snippet qml/animators.qml rotation on |
430 | |
431 | \sa Item::transformOrigin, ScaleAnimator |
432 | */ |
433 | |
434 | QQuickRotationAnimator::QQuickRotationAnimator(QObject *parent) |
435 | : QQuickAnimator(*new QQuickRotationAnimatorPrivate, parent) |
436 | { |
437 | } |
438 | |
439 | QQuickAnimatorJob *QQuickRotationAnimator::createJob() const { |
440 | Q_D(const QQuickRotationAnimator); |
441 | QQuickRotationAnimatorJob *job = new QQuickRotationAnimatorJob(); |
442 | job->setDirection(d->direction); |
443 | return job; |
444 | } |
445 | |
446 | /*! |
447 | \qmlproperty enumeration QtQuick::RotationAnimator::direction |
448 | This property holds the direction of the rotation. |
449 | |
450 | Possible values are: |
451 | |
452 | \value RotationAnimator.Numerical |
453 | (default) Rotate by linearly interpolating between the two numbers. |
454 | A rotation from 10 to 350 will rotate 340 degrees clockwise. |
455 | \value RotationAnimator.Clockwise |
456 | Rotate clockwise between the two values |
457 | \value RotationAnimator.Counterclockwise |
458 | Rotate counterclockwise between the two values |
459 | \value RotationAnimator.Shortest |
460 | Rotate in the direction that produces the shortest animation path. |
461 | A rotation from 10 to 350 will rotate 20 degrees counterclockwise. |
462 | */ |
463 | void QQuickRotationAnimator::setDirection(RotationDirection dir) |
464 | { |
465 | Q_D(QQuickRotationAnimator); |
466 | if (d->direction == dir) |
467 | return; |
468 | d->direction = dir; |
469 | Q_EMIT directionChanged(dir: d->direction); |
470 | } |
471 | |
472 | QQuickRotationAnimator::RotationDirection QQuickRotationAnimator::direction() const |
473 | { |
474 | Q_D(const QQuickRotationAnimator); |
475 | return d->direction; |
476 | } |
477 | |
478 | #if QT_CONFIG(quick_shadereffect) |
479 | /*! |
480 | \qmltype UniformAnimator |
481 | \instantiates QQuickUniformAnimator |
482 | \inqmlmodule QtQuick |
483 | \since 5.2 |
484 | \ingroup qtquick-transitions-animations |
485 | \inherits Animator |
486 | \brief The UniformAnimator type animates a uniform of a ShaderEffect. |
487 | |
488 | \l{Animator} types are different from normal Animation types. When |
489 | using an Animator, the animation can be run in the render thread |
490 | and the property value will jump to the end when the animation is |
491 | complete. |
492 | |
493 | The value of the QML property defining the uniform is updated after |
494 | the animation has finished. |
495 | |
496 | The following snippet shows how to use a UniformAnimator together |
497 | with a ShaderEffect item. |
498 | |
499 | \snippet qml/animators.qml shader target |
500 | |
501 | It is also possible to use the \c on keyword to tie the |
502 | UniformAnimator directly to a uniform of a ShaderEffect |
503 | instance. |
504 | |
505 | \snippet qml/animators.qml shader on |
506 | |
507 | \sa ShaderEffect, ShaderEffectSource |
508 | */ |
509 | |
510 | QQuickUniformAnimator::QQuickUniformAnimator(QObject *parent) |
511 | : QQuickAnimator(*new QQuickUniformAnimatorPrivate, parent) |
512 | { |
513 | } |
514 | |
515 | /*! |
516 | \qmlproperty string QtQuick::UniformAnimator::uniform |
517 | This property holds the name of the uniform to animate. |
518 | |
519 | The value of the uniform must correspond to both a property |
520 | on the target ShaderEffect and must be a uniform of type |
521 | \c float in the fragment or vertex shader. |
522 | */ |
523 | void QQuickUniformAnimator::setUniform(const QString &uniform) |
524 | { |
525 | Q_D(QQuickUniformAnimator); |
526 | if (d->uniform == uniform) |
527 | return; |
528 | d->uniform = uniform; |
529 | Q_EMIT uniformChanged(d->uniform); |
530 | } |
531 | |
532 | QString QQuickUniformAnimator::uniform() const |
533 | { |
534 | Q_D(const QQuickUniformAnimator); |
535 | return d->uniform; |
536 | } |
537 | |
538 | QString QQuickUniformAnimator::propertyName() const |
539 | { |
540 | Q_D(const QQuickUniformAnimator); |
541 | if (!d->uniform.isEmpty()) |
542 | return d->uniform; |
543 | return d->defaultProperty.name(); |
544 | } |
545 | |
546 | QQuickAnimatorJob *QQuickUniformAnimator::createJob() const |
547 | { |
548 | QString u = propertyName(); |
549 | if (u.isEmpty()) |
550 | return nullptr; |
551 | |
552 | QQuickUniformAnimatorJob *job = new QQuickUniformAnimatorJob(); |
553 | job->setUniform(u.toLatin1()); |
554 | return job; |
555 | } |
556 | #endif |
557 | |
558 | QT_END_NAMESPACE |
559 | |
560 | #include "moc_qquickanimator_p.cpp" |
561 | |