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 "qquickanimation_p.h"
5#include "qquickanimation_p_p.h"
6
7#include "qquickanimatorjob_p.h"
8
9#include <private/qquickstatechangescript_p.h>
10#include <private/qqmlcontext_p.h>
11
12#include <qqmlpropertyvaluesource.h>
13#include <qqml.h>
14#include <qqmlinfo.h>
15#include <qqmlexpression.h>
16#include <private/qqmlstringconverters_p.h>
17#include <private/qqmlglobal_p.h>
18#include <private/qqmlmetatype_p.h>
19#include <private/qqmlvaluetype_p.h>
20#include <private/qqmlproperty_p.h>
21#include <private/qqmlengine_p.h>
22
23#include <qvariant.h>
24#include <qcolor.h>
25#include <qfile.h>
26#include "private/qparallelanimationgroupjob_p.h"
27#include "private/qsequentialanimationgroupjob_p.h"
28#include <QtCore/qset.h>
29#include <QtCore/qrect.h>
30#include <QtCore/qpoint.h>
31#include <QtCore/qsize.h>
32#include <QtCore/qmath.h>
33
34QT_BEGIN_NAMESPACE
35
36/*!
37 \qmltype Animation
38 \nativetype QQuickAbstractAnimation
39 \inqmlmodule QtQuick
40 \ingroup qtquick-transitions-animations
41 \brief Is the base of all QML animations.
42
43 The Animation 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 animation types that inherit from it. Attempting to use the Animation
46 type directly will result in an error.
47*/
48
49QQuickAbstractAnimation::QQuickAbstractAnimation(QObject *parent)
50: QObject(*(new QQuickAbstractAnimationPrivate), parent)
51{
52}
53
54QQuickAbstractAnimation::~QQuickAbstractAnimation()
55{
56 Q_D(QQuickAbstractAnimation);
57 if (d->group)
58 setGroup(nullptr); //remove from group
59 delete d->animationInstance;
60}
61
62QQuickAbstractAnimation::QQuickAbstractAnimation(QQuickAbstractAnimationPrivate &dd, QObject *parent)
63: QObject(dd, parent)
64{
65}
66
67QAbstractAnimationJob* QQuickAbstractAnimation::qtAnimation()
68{
69 Q_D(QQuickAbstractAnimation);
70 return d->animationInstance;
71}
72
73/*!
74 \qmlproperty bool QtQuick::Animation::running
75 This property holds whether the animation is currently running.
76
77 The \c running property can be set to declaratively control whether or not
78 an animation is running. The following example will animate a rectangle
79 whenever the \l MouseArea is pressed.
80
81 \code
82 Rectangle {
83 width: 100; height: 100
84 NumberAnimation on x {
85 running: myMouse.pressed
86 from: 0; to: 100
87 }
88 MouseArea { id: myMouse }
89 }
90 \endcode
91
92 Likewise, the \c running property can be read to determine if the animation
93 is running. In the following example the Text item will indicate whether
94 or not the animation is running.
95
96 \code
97 NumberAnimation { id: myAnimation }
98 Text { text: myAnimation.running ? "Animation is running" : "Animation is not running" }
99 \endcode
100
101 Animations can also be started and stopped imperatively from JavaScript
102 using the \c start() and \c stop() methods.
103
104 By default, animations are not running. Though, when the animations are assigned to properties,
105 as property value sources using the \e on syntax, they are set to running by default.
106*/
107bool QQuickAbstractAnimation::isRunning() const
108{
109 Q_D(const QQuickAbstractAnimation);
110 return d->running;
111}
112
113// the behavior calls this function
114void QQuickAbstractAnimation::notifyRunningChanged(bool running)
115{
116 Q_D(QQuickAbstractAnimation);
117 if (d->disableUserControl && d->running != running) {
118 d->running = running;
119 emit runningChanged(running);
120 }
121}
122
123//commence is called to start an animation when it is used as a
124//simple animation, and not as part of a transition
125void QQuickAbstractAnimationPrivate::commence()
126{
127 Q_Q(QQuickAbstractAnimation);
128
129 QQuickStateActions actions;
130 QQmlProperties properties;
131
132 auto *newInstance = q->transition(actions, modified&: properties, direction: QQuickAbstractAnimation::Forward);
133 // transition can return a nullptr; that's the only allowed case were old and new have the same value
134 Q_ASSERT(newInstance != animationInstance || !newInstance);
135 delete animationInstance;
136 animationInstance = newInstance;
137
138 if (animationInstance) {
139 if (q->threadingModel() == QQuickAbstractAnimation::RenderThread)
140 animationInstance = new QQuickAnimatorProxyJob(animationInstance, q);
141 animationInstance->addAnimationChangeListener(listener: this,
142 QAbstractAnimationJob::Completion | QAbstractAnimationJob::CurrentLoop);
143 emit q->started();
144 animationInstance->start();
145 }
146}
147
148QQmlProperty QQuickAbstractAnimationPrivate::createProperty(QObject *obj, const QString &str, QObject *infoObj, QString *errorMessage)
149{
150 QQmlProperty prop(obj, str, qmlContext(infoObj));
151 if (!prop.isValid()) {
152 const QString message = QQuickAbstractAnimation::tr(s: "Cannot animate non-existent property \"%1\"").arg(a: str);
153 if (errorMessage)
154 *errorMessage = message;
155 else
156 qmlWarning(me: infoObj) << message;
157 return QQmlProperty();
158 } else if (!prop.isWritable()) {
159 const QString message = QQuickAbstractAnimation::tr(s: "Cannot animate read-only property \"%1\"").arg(a: str);
160 if (errorMessage)
161 *errorMessage = message;
162 else
163 qmlWarning(me: infoObj) << message;
164 return QQmlProperty();
165 }
166 return prop;
167}
168
169void QQuickAbstractAnimationPrivate::animationGroupDirty()
170{
171 Q_ASSERT(group != nullptr);
172 if (!componentComplete)
173 return;
174
175 auto *animGroupPriv = static_cast<QQuickAnimationGroupPrivate *>(QQuickAnimationGroupPrivate::get(o: group));
176 if (animGroupPriv->running && !animGroupPriv->animationDirty) {
177 animGroupPriv->animationDirty = true;
178
179 if (animGroupPriv->animationInstance && group->currentTime() == 0) {
180 // restart if the animation didn't proceed yet.
181 animGroupPriv->restartFromCurrentLoop();
182 }
183 }
184
185 // check the animationGroup is one of another animationGroup members
186 if (animGroupPriv->group)
187 animGroupPriv->animationGroupDirty();
188}
189
190/*!
191 \qmlsignal QtQuick::Animation::started()
192
193 This signal is emitted when the animation begins.
194
195 It is only triggered for top-level, standalone animations. It will not be
196 triggered for animations in a Behavior or Transition, or animations
197 that are part of an animation group.
198*/
199
200/*!
201 \qmlsignal QtQuick::Animation::stopped()
202
203 This signal is emitted when the animation ends.
204
205 The animation may have been stopped manually, or may have run to completion.
206
207 It is only triggered for top-level, standalone animations. It will not be
208 triggered for animations in a Behavior or Transition, or animations
209 that are part of an animation group.
210
211 If \l alwaysRunToEnd is true, this signal will not be emitted until the animation
212 has completed its current iteration.
213*/
214
215/*!
216 \qmlsignal QtQuick::Animation::finished()
217 \since 5.12
218
219 This signal is emitted when the animation has finished naturally.
220
221 It is not emitted when \l running is set to \c false, nor for animations whose
222 \l loops property is set to \c Animation.Infinite.
223
224 In addition, it is only emitted for top-level, standalone animations. It
225 will not be emitted for animations in a Behavior or Transition, or
226 animations that are part of an animation group.
227
228 If \l alwaysRunToEnd is true, this signal will not be emitted until the
229 animation has completed its current iteration.
230
231 \sa stopped(), started(), running
232*/
233
234void QQuickAbstractAnimation::setRunning(bool r)
235{
236 Q_D(QQuickAbstractAnimation);
237 if (!d->componentComplete) {
238 d->running = r;
239 if (r == false)
240 d->avoidPropertyValueSourceStart = true;
241 else if (!d->needsDeferredSetRunning)
242 d->needsDeferredSetRunning = true;
243 return;
244 }
245
246 if (d->running == r)
247 return;
248
249 if (d->group || d->disableUserControl) {
250 qmlWarning(me: this) << "setRunning() cannot be used on non-root animation nodes.";
251 return;
252 }
253
254 d->running = r;
255 if (d->running) {
256 bool supressStart = false;
257 if (d->alwaysRunToEnd && d->loopCount != 1
258 && d->animationInstance && d->animationInstance->isRunning()) {
259 //we've restarted before the final loop finished; restore proper loop count
260 if (d->loopCount == -1)
261 d->animationInstance->setLoopCount(d->loopCount);
262 else
263 d->animationInstance->setLoopCount(d->animationInstance->currentLoop() + d->loopCount);
264 supressStart = true; //we want the animation to continue, rather than restart
265 }
266 if (!supressStart)
267 d->commence();
268 } else {
269 if (d->paused) {
270 d->paused = false; //reset paused state to false when stopped
271 emit pausedChanged(d->paused);
272 }
273
274 if (d->animationInstance) {
275 if (d->alwaysRunToEnd) {
276 if (d->loopCount != 1)
277 d->animationInstance->setLoopCount(d->animationInstance->currentLoop()+1); //finish the current loop
278 } else {
279 d->animationInstance->stop();
280 emit stopped();
281 }
282 }
283 }
284
285
286 if (r == d->running) {
287 // This might happen if we start an animation with 0 duration: This will result in that
288 // commence() will emit started(), and then when it starts it will call setCurrentTime(0),
289 // (which is both start and end time of the animation), so it will also end up calling
290 // setRunning(false) (recursively) and stop the animation.
291 // Therefore, the state of d->running will in that case be different than r if we are back in
292 // the root stack frame of the recursive calls to setRunning()
293 emit runningChanged(d->running);
294 } else if (d->animationInstance) {
295 // If there was a recursive call, make sure the d->running is set correctly
296 d->running = d->animationInstance->isRunning();
297 } else {
298 d->running = r;
299 }
300}
301
302/*!
303 \qmlproperty bool QtQuick::Animation::paused
304 This property holds whether the animation is currently paused.
305
306 The \c paused property can be set to declaratively control whether or not
307 an animation is paused.
308
309 Animations can also be paused and resumed imperatively from JavaScript
310 using the \c pause() and \c resume() methods.
311
312 By default, animations are not paused.
313*/
314bool QQuickAbstractAnimation::isPaused() const
315{
316 Q_D(const QQuickAbstractAnimation);
317 Q_ASSERT((d->paused && d->running) || !d->paused);
318 return d->paused;
319}
320
321void QQuickAbstractAnimation::setPaused(bool p)
322{
323 Q_D(QQuickAbstractAnimation);
324 if (d->paused == p)
325 return;
326
327 if (!d->running) {
328 qmlWarning(me: this) << "setPaused() cannot be used when animation isn't running.";
329 return;
330 }
331
332 if (d->group || d->disableUserControl) {
333 qmlWarning(me: this) << "setPaused() cannot be used on non-root animation nodes.";
334 return;
335 }
336
337 d->paused = p;
338
339 if (!d->componentComplete || !d->animationInstance)
340 return;
341
342 if (d->paused)
343 d->animationInstance->pause();
344 else
345 d->animationInstance->resume();
346
347 emit pausedChanged(d->paused);
348}
349
350void QQuickAbstractAnimation::classBegin()
351{
352 Q_D(QQuickAbstractAnimation);
353 d->componentComplete = false;
354}
355
356void QQuickAbstractAnimation::componentComplete()
357{
358 Q_D(QQuickAbstractAnimation);
359 d->componentComplete = true;
360 if (d->needsDeferredSetRunning) {
361 if (d->running) {
362 d->running = false;
363 setRunning(true);
364 }
365 if (d->paused) {
366 d->paused = false;
367 setPaused(true);
368 }
369 }
370}
371
372/*!
373 \qmlproperty bool QtQuick::Animation::alwaysRunToEnd
374 This property holds whether the animation should run to completion when it is stopped.
375
376 If this true the animation will complete its current iteration when it
377 is stopped - either by setting the \c running property to false, or by
378 calling the \c stop() method. The \c complete() method is not effected
379 by this value.
380
381 This behavior is most useful when the \c loops property is set, as the
382 animation will finish playing normally but not restart.
383
384 By default, the alwaysRunToEnd property is not set.
385
386 \note alwaysRunToEnd has no effect on animations in a Transition.
387*/
388bool QQuickAbstractAnimation::alwaysRunToEnd() const
389{
390 Q_D(const QQuickAbstractAnimation);
391 return d->alwaysRunToEnd;
392}
393
394void QQuickAbstractAnimation::setAlwaysRunToEnd(bool f)
395{
396 Q_D(QQuickAbstractAnimation);
397 if (d->alwaysRunToEnd == f)
398 return;
399
400 d->alwaysRunToEnd = f;
401 emit alwaysRunToEndChanged(f);
402}
403
404/*!
405 \qmlproperty int QtQuick::Animation::loops
406 This property holds the number of times the animation should play.
407
408 By default, \c loops is 1: the animation will play through once and then stop.
409
410 If set to Animation.Infinite, the animation will continuously repeat until it is explicitly
411 stopped - either by setting the \c running property to false, or by calling
412 the \c stop() method.
413
414 In the following example, the rectangle will spin indefinitely.
415
416 \code
417 Rectangle {
418 width: 100; height: 100; color: "green"
419 RotationAnimation on rotation {
420 loops: Animation.Infinite
421 from: 0
422 to: 360
423 }
424 }
425 \endcode
426*/
427int QQuickAbstractAnimation::loops() const
428{
429 Q_D(const QQuickAbstractAnimation);
430 return d->loopCount;
431}
432
433void QQuickAbstractAnimation::setLoops(int loops)
434{
435 Q_D(QQuickAbstractAnimation);
436 if (loops < 0)
437 loops = -1;
438
439 if (loops == d->loopCount)
440 return;
441
442 d->loopCount = loops;
443 emit loopCountChanged(loops);
444}
445
446int QQuickAbstractAnimation::duration() const
447{
448 Q_D(const QQuickAbstractAnimation);
449 return d->animationInstance ? d->animationInstance->duration() : 0;
450}
451
452int QQuickAbstractAnimation::currentTime()
453{
454 Q_D(QQuickAbstractAnimation);
455 return d->animationInstance ? d->animationInstance->currentLoopTime() : 0;
456}
457
458void QQuickAbstractAnimation::setCurrentTime(int time)
459{
460 Q_D(QQuickAbstractAnimation);
461 if (d->animationInstance)
462 d->animationInstance->setCurrentTime(time);
463 //TODO save value for start?
464}
465
466QQuickAnimationGroup *QQuickAbstractAnimation::group() const
467{
468 Q_D(const QQuickAbstractAnimation);
469 return d->group;
470}
471
472void QQuickAbstractAnimation::setGroup(QQuickAnimationGroup *g, int index)
473{
474 Q_D(QQuickAbstractAnimation);
475 if (d->group == g)
476 return;
477 if (d->group)
478 d->group->d_func()->animations.removeAll(t: this);
479
480 d->group = g;
481
482 if (d->group && !d->group->d_func()->animations.contains(t: this)) {
483 if (index >= 0)
484 d->group->d_func()->animations.insert(i: index, t: this);
485 else
486 d->group->d_func()->animations.append(t: this);
487 }
488}
489
490/*!
491 \qmlmethod QtQuick::Animation::start()
492 \brief Starts the animation
493
494 If the animation is already running, calling this method has no effect. The
495 \c running property will be true following a call to \c start().
496*/
497void QQuickAbstractAnimation::start()
498{
499 setRunning(true);
500}
501
502/*!
503 \qmlmethod QtQuick::Animation::pause()
504 \brief Pauses the animation
505
506 If the animation is already paused or not \c running, calling this method has no effect.
507 The \c paused property will be true following a call to \c pause().
508*/
509void QQuickAbstractAnimation::pause()
510{
511 setPaused(true);
512}
513
514/*!
515 \qmlmethod QtQuick::Animation::resume()
516 \brief Resumes a paused animation
517
518 If the animation is not paused or not \c running, calling this method has no effect.
519 The \c paused property will be false following a call to \c resume().
520*/
521void QQuickAbstractAnimation::resume()
522{
523 setPaused(false);
524}
525
526/*!
527 \qmlmethod QtQuick::Animation::stop()
528 \brief Stops the animation
529
530 If the animation is not running, calling this method has no effect. Both the
531 \c running and \c paused properties will be false following a call to \c stop().
532
533 Normally \c stop() stops the animation immediately, and the animation has
534 no further influence on property values. In this example animation
535 \code
536 Rectangle {
537 NumberAnimation on x { from: 0; to: 100; duration: 500 }
538 }
539 \endcode
540 was stopped at time 250ms, the \c x property will have a value of 50.
541
542 However, if the \c alwaysRunToEnd property is set, the animation will
543 continue running until it completes and then stop. The \c running property
544 will still become false immediately.
545*/
546void QQuickAbstractAnimation::stop()
547{
548 setRunning(false);
549}
550
551/*!
552 \qmlmethod QtQuick::Animation::restart()
553 \brief Restarts the animation
554
555 This is a convenience method, and is equivalent to calling \c stop() and
556 then \c start().
557*/
558void QQuickAbstractAnimation::restart()
559{
560 stop();
561 start();
562}
563
564/*!
565 \qmlmethod QtQuick::Animation::complete()
566 \brief Stops the animation, jumping to the final property values
567
568 If the animation is not running, calling this method has no effect. The
569 \c running property will be false following a call to \c complete().
570
571 Unlike \c stop(), \c complete() immediately fast-forwards the animation to
572 its end. In the following example,
573 \code
574 Rectangle {
575 NumberAnimation on x { from: 0; to: 100; duration: 500 }
576 }
577 \endcode
578 calling \c stop() at time 250ms will result in the \c x property having
579 a value of 50, while calling \c complete() will set the \c x property to
580 100, exactly as though the animation had played the whole way through.
581*/
582void QQuickAbstractAnimation::complete()
583{
584 Q_D(QQuickAbstractAnimation);
585 if (isRunning() && d->animationInstance) {
586 d->animationInstance->setCurrentTime(d->animationInstance->duration());
587 }
588}
589
590void QQuickAbstractAnimation::setTarget(const QQmlProperty &p)
591{
592 Q_D(QQuickAbstractAnimation);
593 d->defaultProperty = p;
594
595 if (!d->avoidPropertyValueSourceStart)
596 setRunning(true);
597}
598
599/*
600 we rely on setTarget only being called when used as a value source
601 so this function allows us to do the same thing as setTarget without
602 that assumption
603*/
604void QQuickAbstractAnimation::setDefaultTarget(const QQmlProperty &p)
605{
606 Q_D(QQuickAbstractAnimation);
607 d->defaultProperty = p;
608}
609
610/*
611 don't allow start/stop/pause/resume to be manually invoked,
612 because something else (like a Behavior) already has control
613 over the animation.
614*/
615void QQuickAbstractAnimation::setDisableUserControl()
616{
617 Q_D(QQuickAbstractAnimation);
618 d->disableUserControl = true;
619}
620
621void QQuickAbstractAnimation::setEnableUserControl()
622{
623 Q_D(QQuickAbstractAnimation);
624 d->disableUserControl = false;
625
626}
627
628bool QQuickAbstractAnimation::userControlDisabled() const
629{
630 Q_D(const QQuickAbstractAnimation);
631 return d->disableUserControl;
632}
633
634QAbstractAnimationJob* QQuickAbstractAnimation::initInstance(QAbstractAnimationJob *animation)
635{
636 Q_D(QQuickAbstractAnimation);
637 animation->setLoopCount(d->loopCount);
638 return animation;
639}
640
641QAbstractAnimationJob* QQuickAbstractAnimation::transition(QQuickStateActions &actions,
642 QQmlProperties &modified,
643 TransitionDirection direction,
644 QObject *defaultTarget)
645{
646 Q_UNUSED(actions);
647 Q_UNUSED(modified);
648 Q_UNUSED(direction);
649 Q_UNUSED(defaultTarget);
650 return nullptr;
651}
652
653void QQuickAbstractAnimationPrivate::animationFinished(QAbstractAnimationJob*)
654{
655 Q_Q(QQuickAbstractAnimation);
656 q->setRunning(false);
657 if (alwaysRunToEnd) {
658 emit q->stopped();
659 //restore the proper loopCount for the next run
660 if (loopCount != 1)
661 animationInstance->setLoopCount(loopCount);
662 }
663 emit q->finished();
664}
665
666QQuickAbstractAnimation::ThreadingModel QQuickAbstractAnimation::threadingModel() const
667{
668 return GuiThread;
669}
670
671/*!
672 \qmltype PauseAnimation
673 \nativetype QQuickPauseAnimation
674 \inqmlmodule QtQuick
675 \ingroup qtquick-transitions-animations
676 \inherits Animation
677 \brief Provides a pause for an animation.
678
679 When used in a SequentialAnimation, PauseAnimation is a step when
680 nothing happens, for a specified duration.
681
682 A 500ms animation sequence, with a 100ms pause between two animations:
683 \code
684 SequentialAnimation {
685 NumberAnimation { ... duration: 200 }
686 PauseAnimation { duration: 100 }
687 NumberAnimation { ... duration: 200 }
688 }
689 \endcode
690
691 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
692*/
693QQuickPauseAnimation::QQuickPauseAnimation(QObject *parent)
694: QQuickAbstractAnimation(*(new QQuickPauseAnimationPrivate), parent)
695{
696}
697
698QQuickPauseAnimation::~QQuickPauseAnimation()
699{
700}
701
702/*!
703 \qmlproperty int QtQuick::PauseAnimation::duration
704 This property holds the duration of the pause in milliseconds
705
706 The default value is 250.
707*/
708int QQuickPauseAnimation::duration() const
709{
710 Q_D(const QQuickPauseAnimation);
711 return d->duration;
712}
713
714void QQuickPauseAnimation::setDuration(int duration)
715{
716 if (duration < 0) {
717 qmlWarning(me: this) << tr(s: "Cannot set a duration of < 0");
718 return;
719 }
720
721 Q_D(QQuickPauseAnimation);
722 if (d->duration == duration)
723 return;
724 d->duration = duration;
725 emit durationChanged(duration);
726 if (d->group)
727 d->animationGroupDirty();
728}
729
730QAbstractAnimationJob* QQuickPauseAnimation::transition(QQuickStateActions &actions,
731 QQmlProperties &modified,
732 TransitionDirection direction,
733 QObject *defaultTarget)
734{
735 Q_D(QQuickPauseAnimation);
736 Q_UNUSED(actions);
737 Q_UNUSED(modified);
738 Q_UNUSED(direction);
739 Q_UNUSED(defaultTarget);
740
741 return initInstance(animation: new QPauseAnimationJob(d->duration));
742}
743
744/*!
745 \qmltype ColorAnimation
746 \nativetype QQuickColorAnimation
747 \inqmlmodule QtQuick
748 \ingroup qtquick-animation-properties
749 \inherits PropertyAnimation
750 \brief Animates changes in color values.
751
752 ColorAnimation is a specialized PropertyAnimation that defines an
753 animation to be applied when a color value changes.
754
755 Here is a ColorAnimation applied to the \c color property of a \l Rectangle
756 as a property value source. It animates the \c color property's value from
757 its current value to a value of "red", over 1000 milliseconds:
758
759 \snippet qml/coloranimation.qml 0
760
761 Like any other animation type, a ColorAnimation can be applied in a
762 number of ways, including transitions, behaviors and property value
763 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
764 variety of methods for creating animations.
765
766 For convenience, when a ColorAnimation is used in a \l Transition, it will
767 animate any \c color properties that have been modified during the state
768 change. If a \l{PropertyAnimation::}{property} or
769 \l{PropertyAnimation::}{properties} are explicitly set for the animation,
770 then those are used instead.
771
772 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
773*/
774QQuickColorAnimation::QQuickColorAnimation(QObject *parent)
775: QQuickPropertyAnimation(parent)
776{
777 Q_D(QQuickPropertyAnimation);
778 d->interpolatorType = QMetaType::QColor;
779 d->defaultToInterpolatorType = true;
780 d->interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: d->interpolatorType);
781}
782
783QQuickColorAnimation::~QQuickColorAnimation()
784{
785}
786
787/*!
788 \qmlproperty color QtQuick::ColorAnimation::from
789 This property holds the color value at which the animation should begin.
790
791 For example, the following animation is not applied until a color value
792 has reached "#c0c0c0":
793
794 \qml
795 Item {
796 states: [
797 // States are defined here...
798 ]
799
800 transitions: Transition {
801 ColorAnimation { from: "#c0c0c0"; duration: 2000 }
802 }
803 }
804 \endqml
805
806 If the ColorAnimation is defined within a \l Transition or \l Behavior,
807 this value defaults to the value defined in the starting state of the
808 \l Transition, or the current value of the property at the moment the
809 \l Behavior is triggered.
810
811 \sa {Animation and Transitions in Qt Quick}
812*/
813QColor QQuickColorAnimation::from() const
814{
815 Q_D(const QQuickPropertyAnimation);
816 return d->from.value<QColor>();
817}
818
819void QQuickColorAnimation::setFrom(const QColor &f)
820{
821 QQuickPropertyAnimation::setFrom(f);
822}
823
824/*!
825 \qmlproperty color QtQuick::ColorAnimation::to
826
827 This property holds the color value at which the animation should end.
828
829 If the ColorAnimation is defined within a \l Transition or \l Behavior,
830 this value defaults to the value defined in the end state of the
831 \l Transition, or the value of the property change that triggered the
832 \l Behavior.
833
834 \sa {Animation and Transitions in Qt Quick}
835*/
836QColor QQuickColorAnimation::to() const
837{
838 Q_D(const QQuickPropertyAnimation);
839 return d->to.value<QColor>();
840}
841
842void QQuickColorAnimation::setTo(const QColor &t)
843{
844 QQuickPropertyAnimation::setTo(t);
845}
846
847QActionAnimation::QActionAnimation()
848 : QAbstractAnimationJob(), animAction(nullptr)
849{
850}
851
852QActionAnimation::QActionAnimation(QAbstractAnimationAction *action)
853 : QAbstractAnimationJob(), animAction(action)
854{
855}
856
857QActionAnimation::~QActionAnimation()
858{
859 delete animAction;
860}
861
862int QActionAnimation::duration() const
863{
864 return 0;
865}
866
867void QActionAnimation::setAnimAction(QAbstractAnimationAction *action)
868{
869 if (isRunning())
870 stop();
871 animAction = action;
872}
873
874void QActionAnimation::updateCurrentTime(int)
875{
876}
877
878void QActionAnimation::updateState(State newState, State oldState)
879{
880 Q_UNUSED(oldState);
881
882 if (newState == Running) {
883 if (animAction) {
884 animAction->doAction();
885 }
886 }
887}
888
889void QActionAnimation::debugAnimation(QDebug d) const
890{
891 d << "ActionAnimation(" << Qt::hex << (const void *) this << Qt::dec << ")";
892
893 if (animAction) {
894 int indentLevel = 1;
895 const QAbstractAnimationJob *job = this;
896 while ((job = job->group()))
897 ++indentLevel;
898 animAction->debugAction(d, indentLevel);
899 }
900}
901
902/*!
903 \qmltype ScriptAction
904 \nativetype QQuickScriptAction
905 \inqmlmodule QtQuick
906 \ingroup qtquick-transitions-animations
907 \inherits Animation
908 \brief Defines scripts to be run during an animation.
909
910 ScriptAction can be used to run a script at a specific point in an animation.
911
912 \qml
913 SequentialAnimation {
914 NumberAnimation {
915 // ...
916 }
917 ScriptAction { script: doSomething(); }
918 NumberAnimation {
919 // ...
920 }
921 }
922 \endqml
923
924 When used as part of a Transition, you can also target a specific
925 StateChangeScript to run using the \c scriptName property.
926
927 \snippet qml/states/statechangescript.qml state and transition
928
929 \sa StateChangeScript
930*/
931QQuickScriptAction::QQuickScriptAction(QObject *parent)
932 :QQuickAbstractAnimation(*(new QQuickScriptActionPrivate), parent)
933{
934}
935
936QQuickScriptAction::~QQuickScriptAction()
937{
938}
939
940QQuickScriptActionPrivate::QQuickScriptActionPrivate()
941 : QQuickAbstractAnimationPrivate(), hasRunScriptScript(false), reversing(false){}
942
943/*!
944 \qmlproperty script QtQuick::ScriptAction::script
945 This property holds the script to run.
946*/
947QQmlScriptString QQuickScriptAction::script() const
948{
949 Q_D(const QQuickScriptAction);
950 return d->script;
951}
952
953void QQuickScriptAction::setScript(const QQmlScriptString &script)
954{
955 Q_D(QQuickScriptAction);
956 d->script = script;
957}
958
959/*!
960 \qmlproperty string QtQuick::ScriptAction::scriptName
961 This property holds the name of the StateChangeScript to run.
962
963 This property is only valid when ScriptAction is used as part of a transition.
964 If both script and scriptName are set, scriptName will be used.
965
966 \note When using scriptName in a reversible transition, the script will only
967 be run when the transition is being run forwards.
968*/
969QString QQuickScriptAction::stateChangeScriptName() const
970{
971 Q_D(const QQuickScriptAction);
972 return d->name;
973}
974
975void QQuickScriptAction::setStateChangeScriptName(const QString &name)
976{
977 Q_D(QQuickScriptAction);
978 d->name = name;
979}
980
981QAbstractAnimationAction* QQuickScriptActionPrivate::createAction()
982{
983 return new Proxy(this);
984}
985
986void QQuickScriptActionPrivate::debugAction(QDebug d, int indentLevel) const
987{
988 QQmlScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
989
990 if (!scriptStr.isEmpty()) {
991 QQmlExpression expr(scriptStr);
992
993 QByteArray ind(indentLevel, u' ');
994 QString exprStr = expr.expression();
995 int endOfFirstLine = exprStr.indexOf(ch: u'\n');
996 d << "\n" << ind.constData() << QStringView{exprStr}.left(n: endOfFirstLine);
997 if (endOfFirstLine != -1 && endOfFirstLine < exprStr.size())
998 d << "...";
999 }
1000}
1001
1002void QQuickScriptActionPrivate::execute()
1003{
1004 Q_Q(QQuickScriptAction);
1005 if (hasRunScriptScript && reversing)
1006 return;
1007
1008 QQmlScriptString scriptStr = hasRunScriptScript ? runScriptScript : script;
1009
1010 if (!scriptStr.isEmpty()) {
1011 QQmlExpression expr(scriptStr);
1012 expr.evaluate();
1013 if (expr.hasError())
1014 qmlWarning(me: q) << expr.error();
1015 }
1016}
1017
1018QAbstractAnimationJob* QQuickScriptAction::transition(QQuickStateActions &actions,
1019 QQmlProperties &modified,
1020 TransitionDirection direction,
1021 QObject *defaultTarget)
1022{
1023 Q_D(QQuickScriptAction);
1024 Q_UNUSED(modified);
1025 Q_UNUSED(defaultTarget);
1026
1027 d->hasRunScriptScript = false;
1028 d->reversing = (direction == Backward);
1029 if (!d->name.isEmpty()) {
1030 for (int ii = 0; ii < actions.size(); ++ii) {
1031 QQuickStateAction &action = actions[ii];
1032
1033 if (action.event && action.event->type() == QQuickStateActionEvent::Script
1034 && static_cast<QQuickStateChangeScript*>(action.event)->name() == d->name) {
1035 d->runScriptScript = static_cast<QQuickStateChangeScript*>(action.event)->script();
1036 d->hasRunScriptScript = true;
1037 action.actionDone = true;
1038 break; //only match one (names should be unique)
1039 }
1040 }
1041 }
1042 return initInstance(animation: new QActionAnimation(d->createAction()));
1043}
1044
1045/*!
1046 \qmltype PropertyAction
1047 \nativetype QQuickPropertyAction
1048 \inqmlmodule QtQuick
1049 \ingroup qtquick-transitions-animations
1050 \inherits Animation
1051 \brief Specifies immediate property changes during animation.
1052
1053 PropertyAction is used to specify an immediate property change during an
1054 animation. The property change is not animated.
1055
1056 It is useful for setting non-animated property values during an animation.
1057
1058 For example, here is a SequentialAnimation that sets the image's
1059 \l {Item::}{opacity} property to \c .5, animates the width of the image,
1060 then sets \l {Item::}{opacity} back to \c 1:
1061
1062 \snippet qml/propertyaction.qml standalone
1063
1064 PropertyAction is also useful for setting the exact point at which a property
1065 change should occur during a \l Transition. For example, if PropertyChanges
1066 was used in a \l State to rotate an item around a particular
1067 \l {Item::}{transformOrigin}, it might be implemented like this:
1068
1069 \snippet qml/propertyaction.qml transition
1070
1071 However, with this code, the \c transformOrigin is not set until \e after
1072 the animation, as a \l State is taken to define the values at the \e end of
1073 a transition. The animation would rotate at the default \c transformOrigin,
1074 then jump to \c Item.BottomRight. To fix this, insert a PropertyAction
1075 before the RotationAnimation begins:
1076
1077 \snippet qml/propertyaction-sequential.qml sequential
1078
1079 This immediately sets the \c transformOrigin property to the value defined
1080 in the end state of the \l Transition (i.e. the value defined in the
1081 PropertyAction object) so that the rotation animation begins with the
1082 correct transform origin.
1083
1084 \sa {Animation and Transitions in Qt Quick}, {Qt Qml}
1085*/
1086QQuickPropertyAction::QQuickPropertyAction(QObject *parent)
1087: QQuickAbstractAnimation(*(new QQuickPropertyActionPrivate), parent)
1088{
1089}
1090
1091QQuickPropertyAction::~QQuickPropertyAction()
1092{
1093}
1094
1095QObject *QQuickPropertyAction::target() const
1096{
1097 Q_D(const QQuickPropertyAction);
1098 return d->target;
1099}
1100
1101void QQuickPropertyAction::setTargetObject(QObject *o)
1102{
1103 Q_D(QQuickPropertyAction);
1104 if (d->target == o)
1105 return;
1106 d->target = o;
1107 emit targetChanged();
1108 if (d->group)
1109 d->animationGroupDirty();
1110}
1111
1112QString QQuickPropertyAction::property() const
1113{
1114 Q_D(const QQuickPropertyAction);
1115 return d->propertyName;
1116}
1117
1118void QQuickPropertyAction::setProperty(const QString &n)
1119{
1120 Q_D(QQuickPropertyAction);
1121 if (d->propertyName == n)
1122 return;
1123 d->propertyName = n;
1124 emit propertyChanged();
1125 if (d->group)
1126 d->animationGroupDirty();
1127}
1128
1129/*!
1130 \qmlproperty QtObject QtQuick::PropertyAction::target
1131 \qmlproperty list<QtObject> QtQuick::PropertyAction::targets
1132 \qmlproperty string QtQuick::PropertyAction::property
1133 \qmlproperty string QtQuick::PropertyAction::properties
1134
1135 These properties determine the items and their properties that are
1136 affected by this action.
1137
1138 The details of how these properties are interpreted in different situations
1139 is covered in the \l{PropertyAnimation::properties}{corresponding} PropertyAnimation
1140 documentation.
1141
1142 \sa exclude
1143*/
1144QString QQuickPropertyAction::properties() const
1145{
1146 Q_D(const QQuickPropertyAction);
1147 return d->properties;
1148}
1149
1150void QQuickPropertyAction::setProperties(const QString &p)
1151{
1152 Q_D(QQuickPropertyAction);
1153 if (d->properties == p)
1154 return;
1155 d->properties = p;
1156 emit propertiesChanged(p);
1157 if (d->group)
1158 d->animationGroupDirty();
1159}
1160
1161QQmlListProperty<QObject> QQuickPropertyAction::targets()
1162{
1163 Q_D(QQuickPropertyAction);
1164 return QQmlListProperty<QObject>(this, &(d->targets));
1165}
1166
1167/*!
1168 \qmlproperty list<QtObject> QtQuick::PropertyAction::exclude
1169 This property holds the objects that should not be affected by this action.
1170
1171 \sa targets
1172*/
1173QQmlListProperty<QObject> QQuickPropertyAction::exclude()
1174{
1175 Q_D(QQuickPropertyAction);
1176 return QQmlListProperty<QObject>(this, &(d->exclude));
1177}
1178
1179/*!
1180 \qmlproperty var QtQuick::PropertyAction::value
1181 This property holds the value to be set on the property.
1182
1183 If the PropertyAction is defined within a \l Transition or \l Behavior,
1184 this value defaults to the value defined in the end state of the
1185 \l Transition, or the value of the property change that triggered the
1186 \l Behavior.
1187*/
1188QVariant QQuickPropertyAction::value() const
1189{
1190 Q_D(const QQuickPropertyAction);
1191 return d->value;
1192}
1193
1194void QQuickPropertyAction::setValue(const QVariant &v)
1195{
1196 Q_D(QQuickPropertyAction);
1197 if (!d->value.isValid() || d->value != v) {
1198 d->value = v;
1199 emit valueChanged(v);
1200 }
1201}
1202
1203QAbstractAnimationJob* QQuickPropertyAction::transition(QQuickStateActions &actions,
1204 QQmlProperties &modified,
1205 TransitionDirection direction,
1206 QObject *defaultTarget)
1207{
1208 Q_D(QQuickPropertyAction);
1209 Q_UNUSED(direction);
1210
1211 struct QQuickSetPropertyAnimationAction : public QAbstractAnimationAction
1212 {
1213 QQuickStateActions actions;
1214 void doAction() override
1215 {
1216 for (int ii = 0; ii < actions.size(); ++ii) {
1217 const QQuickStateAction &action = actions.at(i: ii);
1218 QQmlPropertyPrivate::write(that: action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
1219 }
1220 }
1221 void debugAction(QDebug d, int indentLevel) const override {
1222 QByteArray ind(indentLevel, ' ');
1223 for (int ii = 0; ii < actions.size(); ++ii) {
1224 const QQuickStateAction &action = actions.at(i: ii);
1225 d << "\n" << ind.constData() << "target:" << action.property.object() << "property:" << action.property.name()
1226 << "value:" << action.toValue;
1227 }
1228 }
1229 };
1230
1231 QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(sep: QLatin1Char(','));
1232 for (int ii = 0; ii < props.size(); ++ii)
1233 props[ii] = props.at(i: ii).trimmed();
1234 if (!d->propertyName.isEmpty())
1235 props << d->propertyName;
1236
1237 QList<QObject*> targets = d->targets;
1238 if (d->target)
1239 targets.append(t: d->target);
1240
1241 bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
1242
1243 if (d->defaultProperty.isValid() && !hasSelectors) {
1244 props << d->defaultProperty.name();
1245 targets << d->defaultProperty.object();
1246 }
1247
1248 if (defaultTarget && targets.isEmpty())
1249 targets << defaultTarget;
1250
1251 QQuickSetPropertyAnimationAction *data = new QQuickSetPropertyAnimationAction;
1252
1253 bool hasExplicit = false;
1254 //an explicit animation has been specified
1255 if (d->value.isValid()) {
1256 for (int i = 0; i < props.size(); ++i) {
1257 for (int j = 0; j < targets.size(); ++j) {
1258 QQuickStateAction myAction;
1259 myAction.property = d->createProperty(obj: targets.at(i: j), str: props.at(i), infoObj: this);
1260 if (myAction.property.isValid()) {
1261 myAction.toValue = d->value;
1262 QQuickPropertyAnimationPrivate::convertVariant(variant&: myAction.toValue, type: myAction.property.propertyMetaType());
1263 data->actions << myAction;
1264 hasExplicit = true;
1265 for (int ii = 0; ii < actions.size(); ++ii) {
1266 QQuickStateAction &action = actions[ii];
1267 if (action.property.object() == myAction.property.object() &&
1268 myAction.property.name() == action.property.name()) {
1269 modified << action.property;
1270 break; //### any chance there could be multiples?
1271 }
1272 }
1273 }
1274 }
1275 }
1276 }
1277
1278 if (!hasExplicit)
1279 for (int ii = 0; ii < actions.size(); ++ii) {
1280 QQuickStateAction &action = actions[ii];
1281
1282 QObject *obj = action.property.object();
1283 QString propertyName = action.property.name();
1284 QObject *sObj = action.specifiedObject;
1285 QString sPropertyName = action.specifiedProperty;
1286 bool same = (obj == sObj);
1287
1288 if ((targets.isEmpty() || targets.contains(t: obj) || (!same && targets.contains(t: sObj))) &&
1289 (!d->exclude.contains(t: obj)) && (same || (!d->exclude.contains(t: sObj))) &&
1290 (props.contains(str: propertyName) || (!same && props.contains(str: sPropertyName)))) {
1291 QQuickStateAction myAction = action;
1292
1293 if (d->value.isValid())
1294 myAction.toValue = d->value;
1295 QQuickPropertyAnimationPrivate::convertVariant(variant&: myAction.toValue, type: myAction.property.propertyMetaType());
1296
1297 modified << action.property;
1298 data->actions << myAction;
1299 action.fromValue = myAction.toValue;
1300 }
1301 }
1302
1303 QActionAnimation *action = new QActionAnimation;
1304 if (data->actions.size()) {
1305 action->setAnimAction(data);
1306 } else {
1307 delete data;
1308 }
1309 return initInstance(animation: action);
1310}
1311
1312/*!
1313 \qmltype NumberAnimation
1314 \nativetype QQuickNumberAnimation
1315 \inqmlmodule QtQuick
1316 \ingroup qtquick-animation-properties
1317 \inherits PropertyAnimation
1318 \brief Animates changes in qreal-type values.
1319
1320 NumberAnimation is a specialized PropertyAnimation that defines an
1321 animation to be applied when a numerical value changes.
1322
1323 Here is a NumberAnimation applied to the \c x property of a \l Rectangle
1324 as a property value source. It animates the \c x value from its current
1325 value to a value of 50, over 1000 milliseconds:
1326
1327 \snippet qml/numberanimation.qml 0
1328
1329 Like any other animation type, a NumberAnimation can be applied in a
1330 number of ways, including transitions, behaviors and property value
1331 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
1332 variety of methods for creating animations.
1333
1334 Note that NumberAnimation may not animate smoothly if there are irregular
1335 changes in the number value that it is tracking. If this is the case, use
1336 SmoothedAnimation instead.
1337
1338 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
1339*/
1340QQuickNumberAnimation::QQuickNumberAnimation(QObject *parent)
1341: QQuickPropertyAnimation(parent)
1342{
1343 init();
1344}
1345
1346QQuickNumberAnimation::QQuickNumberAnimation(QQuickPropertyAnimationPrivate &dd, QObject *parent)
1347: QQuickPropertyAnimation(dd, parent)
1348{
1349 init();
1350}
1351
1352QQuickNumberAnimation::~QQuickNumberAnimation()
1353{
1354}
1355
1356void QQuickNumberAnimation::init()
1357{
1358 Q_D(QQuickPropertyAnimation);
1359 d->interpolatorType = QMetaType::QReal;
1360 d->interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: d->interpolatorType);
1361}
1362
1363/*!
1364 \qmlproperty real QtQuick::NumberAnimation::from
1365 This property holds the starting value for the animation.
1366
1367 For example, the following animation is not applied until the \c x value
1368 has reached 100:
1369
1370 \qml
1371 Item {
1372 states: [
1373 // ...
1374 ]
1375
1376 transitions: Transition {
1377 NumberAnimation { properties: "x"; from: 100; duration: 200 }
1378 }
1379 }
1380 \endqml
1381
1382 If the NumberAnimation is defined within a \l Transition or \l Behavior,
1383 this value defaults to the value defined in the starting state of the
1384 \l Transition, or the current value of the property at the moment the
1385 \l Behavior is triggered.
1386
1387 \sa {Animation and Transitions in Qt Quick}
1388*/
1389
1390qreal QQuickNumberAnimation::from() const
1391{
1392 Q_D(const QQuickPropertyAnimation);
1393 return d->from.toReal();
1394}
1395
1396void QQuickNumberAnimation::setFrom(qreal f)
1397{
1398 QQuickPropertyAnimation::setFrom(f);
1399}
1400
1401/*!
1402 \qmlproperty real QtQuick::NumberAnimation::to
1403 This property holds the end value for the animation.
1404
1405 If the NumberAnimation is defined within a \l Transition or \l Behavior,
1406 this value defaults to the value defined in the end state of the
1407 \l Transition, or the value of the property change that triggered the
1408 \l Behavior.
1409
1410 \sa {Animation and Transitions in Qt Quick}
1411*/
1412qreal QQuickNumberAnimation::to() const
1413{
1414 Q_D(const QQuickPropertyAnimation);
1415 return d->to.toReal();
1416}
1417
1418void QQuickNumberAnimation::setTo(qreal t)
1419{
1420 QQuickPropertyAnimation::setTo(t);
1421}
1422
1423
1424
1425/*!
1426 \qmltype Vector3dAnimation
1427 \nativetype QQuickVector3dAnimation
1428 \inqmlmodule QtQuick
1429 \ingroup qtquick-animation-properties
1430 \inherits PropertyAnimation
1431 \brief Animates changes in QVector3d values.
1432
1433 Vector3dAnimation is a specialized PropertyAnimation that defines an
1434 animation to be applied when a Vector3d value changes.
1435
1436 Like any other animation type, a Vector3dAnimation can be applied in a
1437 number of ways, including transitions, behaviors and property value
1438 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
1439 variety of methods for creating animations.
1440
1441 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
1442*/
1443QQuickVector3dAnimation::QQuickVector3dAnimation(QObject *parent)
1444: QQuickPropertyAnimation(parent)
1445{
1446 Q_D(QQuickPropertyAnimation);
1447 d->interpolatorType = QMetaType::QVector3D;
1448 d->defaultToInterpolatorType = true;
1449 d->interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: d->interpolatorType);
1450}
1451
1452QQuickVector3dAnimation::~QQuickVector3dAnimation()
1453{
1454}
1455
1456/*!
1457 \qmlproperty vector3d QtQuick::Vector3dAnimation::from
1458 This property holds the starting value for the animation.
1459
1460 If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
1461 this value defaults to the value defined in the starting state of the
1462 \l Transition, or the current value of the property at the moment the
1463 \l Behavior is triggered.
1464
1465 \sa {Animation and Transitions in Qt Quick}
1466*/
1467QVector3D QQuickVector3dAnimation::from() const
1468{
1469 Q_D(const QQuickPropertyAnimation);
1470 return d->from.value<QVector3D>();
1471}
1472
1473void QQuickVector3dAnimation::setFrom(QVector3D f)
1474{
1475 QQuickPropertyAnimation::setFrom(f);
1476}
1477
1478/*!
1479 \qmlproperty vector3d QtQuick::Vector3dAnimation::to
1480 This property holds the end value for the animation.
1481
1482 If the Vector3dAnimation is defined within a \l Transition or \l Behavior,
1483 this value defaults to the value defined in the end state of the
1484 \l Transition, or the value of the property change that triggered the
1485 \l Behavior.
1486
1487 \sa {Animation and Transitions in Qt Quick}
1488*/
1489QVector3D QQuickVector3dAnimation::to() const
1490{
1491 Q_D(const QQuickPropertyAnimation);
1492 return d->to.value<QVector3D>();
1493}
1494
1495void QQuickVector3dAnimation::setTo(QVector3D t)
1496{
1497 QQuickPropertyAnimation::setTo(t);
1498}
1499
1500
1501
1502/*!
1503 \qmltype RotationAnimation
1504 \nativetype QQuickRotationAnimation
1505 \inqmlmodule QtQuick
1506 \ingroup qtquick-animation-properties
1507 \inherits PropertyAnimation
1508 \brief Animates changes in rotation values.
1509
1510 RotationAnimation is a specialized PropertyAnimation that gives control
1511 over the direction of rotation during an animation.
1512
1513 By default, it rotates in the direction
1514 of the numerical change; a rotation from 0 to 240 will rotate 240 degrees
1515 clockwise, while a rotation from 240 to 0 will rotate 240 degrees
1516 counterclockwise. The \l direction property can be set to specify the
1517 direction in which the rotation should occur.
1518
1519 In the following example we use RotationAnimation to animate the rotation
1520 between states via the shortest path:
1521
1522 \snippet qml/rotationanimation.qml 0
1523
1524 Notice the RotationAnimation did not need to set a \c target
1525 value. As a convenience, when used in a transition, RotationAnimation will rotate all
1526 properties named "rotation" or "angle". You can override this by providing
1527 your own properties via \l {PropertyAnimation::properties}{properties} or
1528 \l {PropertyAnimation::property}{property}.
1529
1530 Also, note the \l Rectangle will be rotated around its default
1531 \l {Item::}{transformOrigin} (which is \c Item.Center). To use a different
1532 transform origin, set the origin in the PropertyChanges object and apply
1533 the change at the start of the animation using PropertyAction. See the
1534 PropertyAction documentation for more details.
1535
1536 Like any other animation type, a RotationAnimation can be applied in a
1537 number of ways, including transitions, behaviors and property value
1538 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
1539 variety of methods for creating animations.
1540
1541 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
1542*/
1543QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress)
1544{
1545 qreal newt = t;
1546 qreal diff = t-f;
1547 while(diff > 180.0){
1548 newt -= 360.0;
1549 diff -= 360.0;
1550 }
1551 while(diff < -180.0){
1552 newt += 360.0;
1553 diff += 360.0;
1554 }
1555 return QVariant(f + (newt - f) * progress);
1556}
1557
1558QVariant _q_interpolateClockwiseRotation(qreal &f, qreal &t, qreal progress)
1559{
1560 qreal newt = t;
1561 qreal diff = t-f;
1562 while(diff < 0.0){
1563 newt += 360.0;
1564 diff += 360.0;
1565 }
1566 return QVariant(f + (newt - f) * progress);
1567}
1568
1569QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal progress)
1570{
1571 qreal newt = t;
1572 qreal diff = t-f;
1573 while(diff > 0.0){
1574 newt -= 360.0;
1575 diff -= 360.0;
1576 }
1577 return QVariant(f + (newt - f) * progress);
1578}
1579
1580QQuickRotationAnimation::QQuickRotationAnimation(QObject *parent)
1581: QQuickPropertyAnimation(*(new QQuickRotationAnimationPrivate), parent)
1582{
1583 Q_D(QQuickRotationAnimation);
1584 d->interpolatorType = QMetaType::QReal;
1585 d->interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: d->interpolatorType);
1586 d->defaultProperties = QLatin1String("rotation,angle");
1587}
1588
1589QQuickRotationAnimation::~QQuickRotationAnimation()
1590{
1591}
1592
1593/*!
1594 \qmlproperty real QtQuick::RotationAnimation::from
1595 This property holds the starting value for the animation.
1596
1597 For example, the following animation is not applied until the \c angle value
1598 has reached 100:
1599
1600 \qml
1601 Item {
1602 states: [
1603 // ...
1604 ]
1605
1606 transitions: Transition {
1607 RotationAnimation { properties: "angle"; from: 100; duration: 2000 }
1608 }
1609 }
1610 \endqml
1611
1612 If the RotationAnimation is defined within a \l Transition or \l Behavior,
1613 this value defaults to the value defined in the starting state of the
1614 \l Transition, or the current value of the property at the moment the
1615 \l Behavior is triggered.
1616
1617 \sa {Animation and Transitions in Qt Quick}
1618*/
1619qreal QQuickRotationAnimation::from() const
1620{
1621 Q_D(const QQuickRotationAnimation);
1622 return d->from.toReal();
1623}
1624
1625void QQuickRotationAnimation::setFrom(qreal f)
1626{
1627 QQuickPropertyAnimation::setFrom(f);
1628}
1629
1630/*!
1631 \qmlproperty real QtQuick::RotationAnimation::to
1632 This property holds the end value for the animation..
1633
1634 If the RotationAnimation is defined within a \l Transition or \l Behavior,
1635 this value defaults to the value defined in the end state of the
1636 \l Transition, or the value of the property change that triggered the
1637 \l Behavior.
1638
1639 \sa {Animation and Transitions in Qt Quick}
1640*/
1641qreal QQuickRotationAnimation::to() const
1642{
1643 Q_D(const QQuickRotationAnimation);
1644 return d->to.toReal();
1645}
1646
1647void QQuickRotationAnimation::setTo(qreal t)
1648{
1649 QQuickPropertyAnimation::setTo(t);
1650}
1651
1652/*!
1653 \qmlproperty enumeration QtQuick::RotationAnimation::direction
1654 This property holds the direction of the rotation.
1655
1656 Possible values are:
1657
1658 \value RotationAnimation.Numerical
1659 (default) Rotate by linearly interpolating between the two numbers.
1660 A rotation from \c 10 to \c 350 will rotate 340 degrees clockwise.
1661 \value RotationAnimation.Clockwise
1662 Rotate clockwise between the two values
1663 \value RotationAnimation.Counterclockwise
1664 Rotate counterclockwise between the two values
1665 \value RotationAnimation.Shortest
1666 Rotate in the direction that produces the shortest animation path.
1667 A rotation from \c 10 to \c 350 will rotate \c 20 degrees counterclockwise.
1668*/
1669QQuickRotationAnimation::RotationDirection QQuickRotationAnimation::direction() const
1670{
1671 Q_D(const QQuickRotationAnimation);
1672 return d->direction;
1673}
1674
1675void QQuickRotationAnimation::setDirection(QQuickRotationAnimation::RotationDirection direction)
1676{
1677 Q_D(QQuickRotationAnimation);
1678 if (d->direction == direction)
1679 return;
1680
1681 d->direction = direction;
1682 switch(d->direction) {
1683 case Clockwise:
1684 d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&_q_interpolateClockwiseRotation));
1685 break;
1686 case Counterclockwise:
1687 d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&_q_interpolateCounterclockwiseRotation));
1688 break;
1689 case Shortest:
1690 d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&_q_interpolateShortestRotation));
1691 break;
1692 default:
1693 d->interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: d->interpolatorType);
1694 break;
1695 }
1696 emit directionChanged();
1697}
1698
1699
1700
1701QQuickAnimationGroup::QQuickAnimationGroup(QObject *parent)
1702: QQuickAbstractAnimation(*(new QQuickAnimationGroupPrivate), parent)
1703{
1704}
1705
1706QQuickAnimationGroup::QQuickAnimationGroup(QQuickAnimationGroupPrivate &dd, QObject *parent)
1707 : QQuickAbstractAnimation(dd, parent)
1708{
1709}
1710
1711void QQuickAnimationGroupPrivate::append_animation(QQmlListProperty<QQuickAbstractAnimation> *list, QQuickAbstractAnimation *a)
1712{
1713 QQuickAnimationGroup *q = qmlobject_cast<QQuickAnimationGroup *>(object: list->object);
1714 if (q && a)
1715 a->setGroup(g: q);
1716}
1717
1718QQuickAbstractAnimation *QQuickAnimationGroupPrivate::at_animation(QQmlListProperty<QQuickAbstractAnimation> *list, qsizetype index)
1719{
1720 if (auto q = qmlobject_cast<QQuickAnimationGroup *>(object: list->object))
1721 return q->d_func()->animations.at(i: index);
1722 return nullptr;
1723}
1724
1725qsizetype QQuickAnimationGroupPrivate::count_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
1726{
1727 if (auto q = qmlobject_cast<QQuickAnimationGroup *>(object: list->object))
1728 return q->d_func()->animations.size();
1729 return 0;
1730}
1731
1732void QQuickAnimationGroupPrivate::clear_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
1733{
1734 QQuickAnimationGroup *q = qobject_cast<QQuickAnimationGroup *>(object: list->object);
1735 if (q) {
1736 while (q->d_func()->animations.size()) {
1737 QQuickAbstractAnimation *firstAnim = q->d_func()->animations.at(i: 0);
1738 firstAnim->setGroup(g: nullptr);
1739 }
1740 }
1741}
1742
1743void QQuickAnimationGroupPrivate::replace_animation(QQmlListProperty<QQuickAbstractAnimation> *list,
1744 qsizetype i, QQuickAbstractAnimation *a)
1745{
1746 if (auto *q = qmlobject_cast<QQuickAnimationGroup *>(object: list->object)) {
1747 if (QQuickAbstractAnimation *anim = q->d_func()->animations.at(i))
1748 anim->setGroup(g: nullptr);
1749 if (a)
1750 a->setGroup(g: q, index: i);
1751 }
1752}
1753
1754void QQuickAnimationGroupPrivate::removeLast_animation(QQmlListProperty<QQuickAbstractAnimation> *list)
1755{
1756 if (auto *q = qobject_cast<QQuickAnimationGroup *>(object: list->object))
1757 q->d_func()->animations.last()->setGroup(g: nullptr);
1758}
1759
1760void QQuickAnimationGroupPrivate::restartFromCurrentLoop()
1761{
1762 Q_Q(QQuickAnimationGroup);
1763 if (!animationDirty)
1764 return;
1765
1766 animationDirty = false;
1767
1768 Q_ASSERT(animationInstance);
1769 const int currentLoop = animationInstance->currentLoop();
1770
1771 QSignalBlocker signalBlocker(q);
1772 q->stop();
1773 q->start();
1774
1775 Q_ASSERT(animationInstance);
1776 // Restarting adjusts animationInstance's loopCount
1777 // Since we just want to start it from this loop,
1778 // it will be restored again.
1779 if (loopCount != -1)
1780 animationInstance->setLoopCount(loopCount - currentLoop);
1781}
1782
1783void QQuickAnimationGroupPrivate::animationCurrentLoopChanged(QAbstractAnimationJob *)
1784{
1785 if (!animationDirty)
1786 return;
1787 restartFromCurrentLoop();
1788}
1789
1790QQuickAnimationGroup::~QQuickAnimationGroup()
1791{
1792 Q_D(QQuickAnimationGroup);
1793 for (int i = 0; i < d->animations.size(); ++i)
1794 d->animations.at(i)->d_func()->group = nullptr;
1795 d->animations.clear();
1796}
1797
1798QQmlListProperty<QQuickAbstractAnimation> QQuickAnimationGroup::animations()
1799{
1800 Q_D(QQuickAnimationGroup);
1801 return QQmlListProperty<QQuickAbstractAnimation>(
1802 this, &(d->animations),
1803 &QQuickAnimationGroupPrivate::append_animation,
1804 &QQuickAnimationGroupPrivate::count_animation,
1805 &QQuickAnimationGroupPrivate::at_animation,
1806 &QQuickAnimationGroupPrivate::clear_animation,
1807 &QQuickAnimationGroupPrivate::replace_animation,
1808 &QQuickAnimationGroupPrivate::removeLast_animation);
1809}
1810
1811/*!
1812 \qmltype SequentialAnimation
1813 \nativetype QQuickSequentialAnimation
1814 \inqmlmodule QtQuick
1815 \ingroup qtquick-transitions-animations
1816 \inherits Animation
1817 \brief Allows animations to be run sequentially.
1818
1819 The SequentialAnimation and ParallelAnimation types allow multiple
1820 animations to be run together. Animations defined in a SequentialAnimation
1821 are run one after the other, while animations defined in a ParallelAnimation
1822 are run at the same time.
1823
1824 The following example runs two number animations in a sequence. The \l Rectangle
1825 animates to a \c x position of 50, then to a \c y position of 50.
1826
1827 \snippet qml/sequentialanimation.qml 0
1828
1829 Animations defined within a \l Transition are automatically run in parallel,
1830 so SequentialAnimation can be used to enclose the animations in a \l Transition
1831 if this is the preferred behavior.
1832
1833 Like any other animation type, a SequentialAnimation can be applied in a
1834 number of ways, including transitions, behaviors and property value
1835 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
1836 variety of methods for creating animations.
1837
1838 \note Once an animation has been grouped into a SequentialAnimation or
1839 ParallelAnimation, it cannot be individually started and stopped; the
1840 SequentialAnimation or ParallelAnimation must be started and stopped as a group.
1841
1842 \sa ParallelAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
1843*/
1844
1845QQuickSequentialAnimation::QQuickSequentialAnimation(QObject *parent) :
1846 QQuickAnimationGroup(parent)
1847{
1848}
1849
1850QQuickSequentialAnimation::~QQuickSequentialAnimation()
1851{
1852}
1853
1854QQuickAbstractAnimation::ThreadingModel QQuickSequentialAnimation::threadingModel() const
1855{
1856 Q_D(const QQuickAnimationGroup);
1857
1858 ThreadingModel style = AnyThread;
1859 for (int i=0; i<d->animations.size(); ++i) {
1860 ThreadingModel ces = d->animations.at(i)->threadingModel();
1861 if (ces == GuiThread)
1862 return GuiThread;
1863 else if (ces == RenderThread)
1864 style = RenderThread;
1865 }
1866 return style;
1867}
1868
1869QAbstractAnimationJob* QQuickSequentialAnimation::transition(QQuickStateActions &actions,
1870 QQmlProperties &modified,
1871 TransitionDirection direction,
1872 QObject *defaultTarget)
1873{
1874 Q_D(QQuickAnimationGroup);
1875
1876 QSequentialAnimationGroupJob *ag = new QSequentialAnimationGroupJob;
1877
1878 int inc = 1;
1879 int from = 0;
1880 if (direction == Backward) {
1881 inc = -1;
1882 from = d->animations.size() - 1;
1883 }
1884
1885 ThreadingModel execution = threadingModel();
1886
1887 bool valid = d->defaultProperty.isValid();
1888 QAbstractAnimationJob* anim;
1889 for (int ii = from; ii < d->animations.size() && ii >= 0; ii += inc) {
1890 if (valid)
1891 d->animations.at(i: ii)->setDefaultTarget(d->defaultProperty);
1892 anim = d->animations.at(i: ii)->transition(actions, modified, direction, defaultTarget);
1893 if (anim) {
1894 if (d->animations.at(i: ii)->threadingModel() == RenderThread && execution != RenderThread)
1895 anim = new QQuickAnimatorProxyJob(anim, this);
1896 inc == -1 ? ag->prependAnimation(animation: anim) : ag->appendAnimation(animation: anim);
1897 }
1898 }
1899
1900 return initInstance(animation: ag);
1901}
1902
1903
1904
1905/*!
1906 \qmltype ParallelAnimation
1907 \nativetype QQuickParallelAnimation
1908 \inqmlmodule QtQuick
1909 \ingroup qtquick-transitions-animations
1910 \inherits Animation
1911 \brief Enables animations to be run in parallel.
1912
1913 The SequentialAnimation and ParallelAnimation types allow multiple
1914 animations to be run together. Animations defined in a SequentialAnimation
1915 are run one after the other, while animations defined in a ParallelAnimation
1916 are run at the same time.
1917
1918 The following animation runs two number animations in parallel. The \l Rectangle
1919 moves to (50,50) by animating its \c x and \c y properties at the same time.
1920
1921 \snippet qml/parallelanimation.qml 0
1922
1923 Like any other animation type, a ParallelAnimation can be applied in a
1924 number of ways, including transitions, behaviors and property value
1925 sources. The \l {Animation and Transitions in Qt Quick} documentation shows a
1926 variety of methods for creating animations.
1927
1928 \note Once an animation has been grouped into a SequentialAnimation or
1929 ParallelAnimation, it cannot be individually started and stopped; the
1930 SequentialAnimation or ParallelAnimation must be started and stopped as a group.
1931
1932 \sa SequentialAnimation, {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
1933*/
1934QQuickParallelAnimation::QQuickParallelAnimation(QObject *parent) :
1935 QQuickAnimationGroup(parent)
1936{
1937}
1938
1939QQuickParallelAnimation::~QQuickParallelAnimation()
1940{
1941}
1942
1943QQuickAbstractAnimation::ThreadingModel QQuickParallelAnimation::threadingModel() const
1944{
1945 Q_D(const QQuickAnimationGroup);
1946
1947 ThreadingModel style = AnyThread;
1948 for (int i=0; i<d->animations.size(); ++i) {
1949 ThreadingModel ces = d->animations.at(i)->threadingModel();
1950 if (ces == GuiThread)
1951 return GuiThread;
1952 else if (ces == RenderThread)
1953 style = RenderThread;
1954 }
1955 return style;
1956}
1957
1958
1959
1960QAbstractAnimationJob* QQuickParallelAnimation::transition(QQuickStateActions &actions,
1961 QQmlProperties &modified,
1962 TransitionDirection direction,
1963 QObject *defaultTarget)
1964{
1965 Q_D(QQuickAnimationGroup);
1966 QParallelAnimationGroupJob *ag = new QParallelAnimationGroupJob;
1967
1968 ThreadingModel style = threadingModel();
1969
1970 bool valid = d->defaultProperty.isValid();
1971 QAbstractAnimationJob* anim;
1972 for (int ii = 0; ii < d->animations.size(); ++ii) {
1973 if (valid)
1974 d->animations.at(i: ii)->setDefaultTarget(d->defaultProperty);
1975 anim = d->animations.at(i: ii)->transition(actions, modified, direction, defaultTarget);
1976 if (anim) {
1977 if (d->animations.at(i: ii)->threadingModel() == RenderThread && style != RenderThread)
1978 anim = new QQuickAnimatorProxyJob(anim, this);
1979 ag->appendAnimation(animation: anim);
1980 }
1981 }
1982 return initInstance(animation: ag);
1983}
1984
1985void QQuickPropertyAnimationPrivate::animationCurrentLoopChanged(QAbstractAnimationJob *)
1986{
1987 Q_Q(QQuickPropertyAnimation);
1988 // We listen to current loop changes in order to restart the animation if e.g. from, to, etc.
1989 // are modified while the animation is running.
1990 // Restarting is a bit drastic but there is a lot of stuff that commence() (and therefore
1991 // QQuickPropertyAnimation::transition() and QQuickPropertyAnimation::createTransitionActions())
1992 // does, so we want to avoid trying to take a shortcut and just restart the whole thing.
1993 if (ourPropertiesDirty) {
1994 ourPropertiesDirty = false;
1995
1996 // We use animationInstance everywhere for simplicity - if we defined the job parameter
1997 // it would be deleted as soon as we call stop().
1998 Q_ASSERT(animationInstance);
1999 const int currentLoop = animationInstance->currentLoop();
2000
2001 QSignalBlocker signalBlocker(q);
2002 q->stop();
2003 q->start();
2004
2005 Q_ASSERT(animationInstance);
2006 // We multiply it ourselves here instead of just saving currentTime(), because otherwise
2007 // it seems to accumulate, and changing our properties while the animation is running
2008 // can result in the animation starting mid-way through a loop, which is not we want;
2009 // we want it to start from the beginning.
2010 animationInstance->setCurrentTime(currentLoop * animationInstance->duration());
2011 }
2012}
2013
2014//convert a variant from string type to another animatable type
2015void QQuickPropertyAnimationPrivate::convertVariant(QVariant &variant, QMetaType type)
2016{
2017 if (variant.userType() != QMetaType::QString) {
2018 variant.convert(type);
2019 return;
2020 }
2021
2022 switch (type.id()) {
2023 case QMetaType::QRect:
2024 case QMetaType::QRectF:
2025 case QMetaType::QPoint:
2026 case QMetaType::QPointF:
2027 case QMetaType::QSize:
2028 case QMetaType::QSizeF:
2029 case QMetaType::QColor:
2030 case QMetaType::QVector3D:
2031 {
2032 bool ok = false;
2033 variant = QQmlStringConverters::variantFromString(variant.toString(), preferredType: type, ok: &ok);
2034 }
2035 break;
2036 default:
2037 if (QQmlMetaType::isValueType(type)) {
2038 variant.convert(type: QMetaType(type));
2039 }
2040 break;
2041 }
2042}
2043
2044QQuickBulkValueAnimator::QQuickBulkValueAnimator()
2045 : QAbstractAnimationJob(), animValue(nullptr), fromIsSourced(nullptr), m_duration(250)
2046{
2047}
2048
2049QQuickBulkValueAnimator::~QQuickBulkValueAnimator()
2050{
2051 delete animValue;
2052}
2053
2054void QQuickBulkValueAnimator::setAnimValue(QQuickBulkValueUpdater *value)
2055{
2056 if (isRunning())
2057 stop();
2058 animValue = value;
2059}
2060
2061void QQuickBulkValueAnimator::updateCurrentTime(int currentTime)
2062{
2063 if (isStopped())
2064 return;
2065
2066 const qreal progress = easing.valueForProgress(progress: ((m_duration == 0) ? qreal(1) : qreal(currentTime) / qreal(m_duration)));
2067
2068 if (animValue)
2069 animValue->setValue(progress);
2070}
2071
2072void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
2073{
2074 // Check for new "from" value only when animation has one loop.
2075 // Otherwise use the initial "from" value for every iteration.
2076 if (m_loopCount == 1 && fromIsSourced)
2077 *fromIsSourced = false;
2078 QAbstractAnimationJob::topLevelAnimationLoopChanged();
2079}
2080
2081void QQuickBulkValueAnimator::debugAnimation(QDebug d) const
2082{
2083 d << "BulkValueAnimation(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << duration();
2084
2085 if (animValue) {
2086 int indentLevel = 1;
2087 const QAbstractAnimationJob *job = this;
2088 while ((job = job->group()))
2089 ++indentLevel;
2090 animValue->debugUpdater(d, indentLevel);
2091 }
2092}
2093
2094/*!
2095 \qmltype PropertyAnimation
2096 \nativetype QQuickPropertyAnimation
2097 \inqmlmodule QtQuick
2098 \ingroup qtquick-animation-properties
2099 \inherits Animation
2100 \brief Animates changes in property values.
2101
2102 PropertyAnimation provides a way to animate changes to a property's value.
2103
2104 It can be used to define animations in a number of ways:
2105
2106 \list
2107 \li In a \l Transition
2108
2109 For example, to animate any objects that have changed their \c x or \c y properties
2110 as a result of a state change, using an \c InOutQuad easing curve:
2111
2112 \snippet qml/propertyanimation.qml transition
2113
2114
2115 \li In a \l Behavior
2116
2117 For example, to animate all changes to a rectangle's \c x property:
2118
2119 \snippet qml/propertyanimation.qml behavior
2120
2121
2122 \li As a property value source
2123
2124 For example, to repeatedly animate the rectangle's \c x property:
2125
2126 \snippet qml/propertyanimation.qml propertyvaluesource
2127
2128
2129 \li In a signal handler
2130
2131 For example, to fade out \c theObject when clicked:
2132 \qml
2133 MouseArea {
2134 anchors.fill: theObject
2135 onClicked: PropertyAnimation { target: theObject; property: "opacity"; to: 0 }
2136 }
2137 \endqml
2138
2139 \li Standalone
2140
2141 For example, to animate \c rect's \c width property over 500ms, from its current width to 30:
2142
2143 \snippet qml/propertyanimation.qml standalone
2144
2145 \endlist
2146
2147 Depending on how the animation is used, the set of properties normally used will be
2148 different. For more information see the individual property documentation, as well
2149 as the \l{Animation and Transitions in Qt Quick} introduction.
2150
2151 Note that PropertyAnimation inherits the abstract \l Animation type.
2152 This includes additional properties and methods for controlling the animation.
2153
2154 \section1 Modifying running animations
2155
2156 Since Qt 6.4, it is possible to set the \l from, \l to, \l duration, and
2157 \l easing properties on a top-level animation while it is running. The
2158 animation will take the changes into account on the next loop.
2159
2160 \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation}
2161*/
2162
2163QQuickPropertyAnimation::QQuickPropertyAnimation(QObject *parent)
2164: QQuickAbstractAnimation(*(new QQuickPropertyAnimationPrivate), parent)
2165{
2166}
2167
2168QQuickPropertyAnimation::QQuickPropertyAnimation(QQuickPropertyAnimationPrivate &dd, QObject *parent)
2169: QQuickAbstractAnimation(dd, parent)
2170{
2171}
2172
2173QQuickPropertyAnimation::~QQuickPropertyAnimation()
2174{
2175}
2176
2177/*!
2178 \qmlproperty int QtQuick::PropertyAnimation::duration
2179 This property holds the duration of the animation, in milliseconds.
2180
2181 The default value is 250.
2182*/
2183int QQuickPropertyAnimation::duration() const
2184{
2185 Q_D(const QQuickPropertyAnimation);
2186 return d->duration;
2187}
2188
2189void QQuickPropertyAnimation::setDuration(int duration)
2190{
2191 if (duration < 0) {
2192 qmlWarning(me: this) << tr(s: "Cannot set a duration of < 0");
2193 return;
2194 }
2195
2196 Q_D(QQuickPropertyAnimation);
2197 if (d->duration == duration)
2198 return;
2199 d->duration = duration;
2200 if (d->componentComplete && d->running)
2201 d->ourPropertiesDirty = true;
2202 emit durationChanged(duration);
2203 if (d->group)
2204 d->animationGroupDirty();
2205}
2206
2207/*!
2208 \qmlproperty variant QtQuick::PropertyAnimation::from
2209 This property holds the starting value for the animation.
2210
2211 If the PropertyAnimation is defined within a \l Transition or \l Behavior,
2212 this value defaults to the value defined in the starting state of the
2213 \l Transition, or the current value of the property at the moment the
2214 \l Behavior is triggered.
2215
2216 \sa {Animation and Transitions in Qt Quick}
2217*/
2218QVariant QQuickPropertyAnimation::from() const
2219{
2220 Q_D(const QQuickPropertyAnimation);
2221 return d->from;
2222}
2223
2224void QQuickPropertyAnimation::setFrom(const QVariant &f)
2225{
2226 Q_D(QQuickPropertyAnimation);
2227 if (d->fromIsDefined && f == d->from)
2228 return;
2229 d->from = f;
2230 d->fromIsDefined = f.isValid();
2231 if (d->componentComplete && d->running)
2232 d->ourPropertiesDirty = true;
2233 emit fromChanged();
2234 if (d->group)
2235 d->animationGroupDirty();
2236}
2237
2238/*!
2239 \qmlproperty variant QtQuick::PropertyAnimation::to
2240 This property holds the end value for the animation.
2241
2242 If the PropertyAnimation is defined within a \l Transition or \l Behavior,
2243 this value defaults to the value defined in the end state of the
2244 \l Transition, or the value of the property change that triggered the
2245 \l Behavior.
2246
2247 \sa {Animation and Transitions in Qt Quick}
2248*/
2249QVariant QQuickPropertyAnimation::to() const
2250{
2251 Q_D(const QQuickPropertyAnimation);
2252 return d->to;
2253}
2254
2255void QQuickPropertyAnimation::setTo(const QVariant &t)
2256{
2257 Q_D(QQuickPropertyAnimation);
2258 if (d->toIsDefined && t == d->to)
2259 return;
2260 d->to = t;
2261 d->toIsDefined = t.isValid();
2262 if (d->componentComplete && d->running)
2263 d->ourPropertiesDirty = true;
2264 emit toChanged();
2265 if (d->group)
2266 d->animationGroupDirty();
2267}
2268
2269/*!
2270 \qmlpropertygroup QtQuick::PropertyAnimation::easing
2271 \qmlproperty enumeration QtQuick::PropertyAnimation::easing.type
2272 \qmlproperty real QtQuick::PropertyAnimation::easing.amplitude
2273 \qmlproperty real QtQuick::PropertyAnimation::easing.overshoot
2274 \qmlproperty real QtQuick::PropertyAnimation::easing.period
2275 \qmlproperty list<real> QtQuick::PropertyAnimation::easing.bezierCurve
2276
2277//! propertyanimation.easing
2278 \brief Specifies the easing curve used for the animation
2279
2280 To specify an easing curve you need to specify at least the type. For some curves you can also specify
2281 amplitude, period and/or overshoot (more details provided after the table). The default easing curve is
2282 \c Easing.Linear.
2283
2284 \qml
2285 PropertyAnimation { properties: "y";
2286 easing.type: Easing.InOutElastic;
2287 easing.amplitude: 2.0;
2288 easing.period: 1.5 }
2289 \endqml
2290
2291 Available types are:
2292
2293 \table
2294 \row
2295 \li \c Easing.Linear
2296 \li Easing curve for a linear (t) function: velocity is constant.
2297 \li \inlineimage qeasingcurve-linear.png
2298 \row
2299 \li \c Easing.InQuad
2300 \li Easing curve for a quadratic (t^2) function: accelerating from zero velocity.
2301 \li \inlineimage qeasingcurve-inquad.png
2302 \row
2303 \li \c Easing.OutQuad
2304 \li Easing curve for a quadratic (t^2) function: decelerating to zero velocity.
2305 \li \inlineimage qeasingcurve-outquad.png
2306 \row
2307 \li \c Easing.InOutQuad
2308 \li Easing curve for a quadratic (t^2) function: acceleration until halfway, then deceleration.
2309 \li \inlineimage qeasingcurve-inoutquad.png
2310 \row
2311 \li \c Easing.OutInQuad
2312 \li Easing curve for a quadratic (t^2) function: deceleration until halfway, then acceleration.
2313 \li \inlineimage qeasingcurve-outinquad.png
2314 \row
2315 \li \c Easing.InCubic
2316 \li Easing curve for a cubic (t^3) function: accelerating from zero velocity.
2317 \li \inlineimage qeasingcurve-incubic.png
2318 \row
2319 \li \c Easing.OutCubic
2320 \li Easing curve for a cubic (t^3) function: decelerating to zero velocity.
2321 \li \inlineimage qeasingcurve-outcubic.png
2322 \row
2323 \li \c Easing.InOutCubic
2324 \li Easing curve for a cubic (t^3) function: acceleration until halfway, then deceleration.
2325 \li \inlineimage qeasingcurve-inoutcubic.png
2326 \row
2327 \li \c Easing.OutInCubic
2328 \li Easing curve for a cubic (t^3) function: deceleration until halfway, then acceleration.
2329 \li \inlineimage qeasingcurve-outincubic.png
2330 \row
2331 \li \c Easing.InQuart
2332 \li Easing curve for a quartic (t^4) function: accelerating from zero velocity.
2333 \li \inlineimage qeasingcurve-inquart.png
2334 \row
2335 \li \c Easing.OutQuart
2336 \li Easing curve for a quartic (t^4) function: decelerating to zero velocity.
2337 \li \inlineimage qeasingcurve-outquart.png
2338 \row
2339 \li \c Easing.InOutQuart
2340 \li Easing curve for a quartic (t^4) function: acceleration until halfway, then deceleration.
2341 \li \inlineimage qeasingcurve-inoutquart.png
2342 \row
2343 \li \c Easing.OutInQuart
2344 \li Easing curve for a quartic (t^4) function: deceleration until halfway, then acceleration.
2345 \li \inlineimage qeasingcurve-outinquart.png
2346 \row
2347 \li \c Easing.InQuint
2348 \li Easing curve for a quintic (t^5) function: accelerating from zero velocity.
2349 \li \inlineimage qeasingcurve-inquint.png
2350 \row
2351 \li \c Easing.OutQuint
2352 \li Easing curve for a quintic (t^5) function: decelerating to zero velocity.
2353 \li \inlineimage qeasingcurve-outquint.png
2354 \row
2355 \li \c Easing.InOutQuint
2356 \li Easing curve for a quintic (t^5) function: acceleration until halfway, then deceleration.
2357 \li \inlineimage qeasingcurve-inoutquint.png
2358 \row
2359 \li \c Easing.OutInQuint
2360 \li Easing curve for a quintic (t^5) function: deceleration until halfway, then acceleration.
2361 \li \inlineimage qeasingcurve-outinquint.png
2362 \row
2363 \li \c Easing.InSine
2364 \li Easing curve for a sinusoidal (sin(t)) function: accelerating from zero velocity.
2365 \li \inlineimage qeasingcurve-insine.png
2366 \row
2367 \li \c Easing.OutSine
2368 \li Easing curve for a sinusoidal (sin(t)) function: decelerating to zero velocity.
2369 \li \inlineimage qeasingcurve-outsine.png
2370 \row
2371 \li \c Easing.InOutSine
2372 \li Easing curve for a sinusoidal (sin(t)) function: acceleration until halfway, then deceleration.
2373 \li \inlineimage qeasingcurve-inoutsine.png
2374 \row
2375 \li \c Easing.OutInSine
2376 \li Easing curve for a sinusoidal (sin(t)) function: deceleration until halfway, then acceleration.
2377 \li \inlineimage qeasingcurve-outinsine.png
2378 \row
2379 \li \c Easing.InExpo
2380 \li Easing curve for an exponential (2^t) function: accelerating from zero velocity.
2381 \li \inlineimage qeasingcurve-inexpo.png
2382 \row
2383 \li \c Easing.OutExpo
2384 \li Easing curve for an exponential (2^t) function: decelerating to zero velocity.
2385 \li \inlineimage qeasingcurve-outexpo.png
2386 \row
2387 \li \c Easing.InOutExpo
2388 \li Easing curve for an exponential (2^t) function: acceleration until halfway, then deceleration.
2389 \li \inlineimage qeasingcurve-inoutexpo.png
2390 \row
2391 \li \c Easing.OutInExpo
2392 \li Easing curve for an exponential (2^t) function: deceleration until halfway, then acceleration.
2393 \li \inlineimage qeasingcurve-outinexpo.png
2394 \row
2395 \li \c Easing.InCirc
2396 \li Easing curve for a circular (sqrt(1-t^2)) function: accelerating from zero velocity.
2397 \li \inlineimage qeasingcurve-incirc.png
2398 \row
2399 \li \c Easing.OutCirc
2400 \li Easing curve for a circular (sqrt(1-t^2)) function: decelerating to zero velocity.
2401 \li \inlineimage qeasingcurve-outcirc.png
2402 \row
2403 \li \c Easing.InOutCirc
2404 \li Easing curve for a circular (sqrt(1-t^2)) function: acceleration until halfway, then deceleration.
2405 \li \inlineimage qeasingcurve-inoutcirc.png
2406 \row
2407 \li \c Easing.OutInCirc
2408 \li Easing curve for a circular (sqrt(1-t^2)) function: deceleration until halfway, then acceleration.
2409 \li \inlineimage qeasingcurve-outincirc.png
2410 \row
2411 \li \c Easing.InElastic
2412 \li Easing curve for an elastic (exponentially decaying sine wave) function: accelerating from zero velocity.
2413 \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
2414 \li \inlineimage qeasingcurve-inelastic.png
2415 \row
2416 \li \c Easing.OutElastic
2417 \li Easing curve for an elastic (exponentially decaying sine wave) function: decelerating to zero velocity.
2418 \br The peak amplitude can be set with the \e amplitude parameter, and the period of decay by the \e period parameter.
2419 \li \inlineimage qeasingcurve-outelastic.png
2420 \row
2421 \li \c Easing.InOutElastic
2422 \li Easing curve for an elastic (exponentially decaying sine wave) function: acceleration until halfway, then deceleration.
2423 \li \inlineimage qeasingcurve-inoutelastic.png
2424 \row
2425 \li \c Easing.OutInElastic
2426 \li Easing curve for an elastic (exponentially decaying sine wave) function: deceleration until halfway, then acceleration.
2427 \li \inlineimage qeasingcurve-outinelastic.png
2428 \row
2429 \li \c Easing.InBack
2430 \li Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity.
2431 \li \inlineimage qeasingcurve-inback.png
2432 \row
2433 \li \c Easing.OutBack
2434 \li Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing out: decelerating to zero velocity.
2435 \li \inlineimage qeasingcurve-outback.png
2436 \row
2437 \li \c Easing.InOutBack
2438 \li Easing curve for a back (overshooting cubic function: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration.
2439 \li \inlineimage qeasingcurve-inoutback.png
2440 \row
2441 \li \c Easing.OutInBack
2442 \li Easing curve for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration.
2443 \li \inlineimage qeasingcurve-outinback.png
2444 \row
2445 \li \c Easing.InBounce
2446 \li Easing curve for a bounce (exponentially decaying parabolic bounce) function: accelerating from zero velocity.
2447 \li \inlineimage qeasingcurve-inbounce.png
2448 \row
2449 \li \c Easing.OutBounce
2450 \li Easing curve for a bounce (exponentially decaying parabolic bounce) function: decelerating to zero velocity.
2451 \li \inlineimage qeasingcurve-outbounce.png
2452 \row
2453 \li \c Easing.InOutBounce
2454 \li Easing curve for a bounce (exponentially decaying parabolic bounce) function easing in/out: acceleration until halfway, then deceleration.
2455 \li \inlineimage qeasingcurve-inoutbounce.png
2456 \row
2457 \li \c Easing.OutInBounce
2458 \li Easing curve for a bounce (exponentially decaying parabolic bounce) function easing out/in: deceleration until halfway, then acceleration.
2459 \li \inlineimage qeasingcurve-outinbounce.png
2460 \row
2461 \li \c Easing.BezierSpline
2462 \li Custom easing curve defined by the easing.bezierCurve property.
2463 \li
2464 \endtable
2465
2466 \c easing.amplitude is only applicable for bounce and elastic curves (curves of type
2467 \c Easing.InBounce, \c Easing.OutBounce, \c Easing.InOutBounce, \c Easing.OutInBounce, \c Easing.InElastic,
2468 \c Easing.OutElastic, \c Easing.InOutElastic or \c Easing.OutInElastic).
2469
2470 \c easing.overshoot is only applicable if \c easing.type is: \c Easing.InBack, \c Easing.OutBack,
2471 \c Easing.InOutBack or \c Easing.OutInBack.
2472
2473 \c easing.period is only applicable if easing.type is: \c Easing.InElastic, \c Easing.OutElastic,
2474 \c Easing.InOutElastic or \c Easing.OutInElastic.
2475
2476 \c easing.bezierCurve is only applicable if easing.type is: \c Easing.BezierSpline. This property is a list<real> containing
2477 groups of three points defining a curve from 0,0 to 1,1 - control1, control2,
2478 end point: [cx1, cy1, cx2, cy2, endx, endy, ...]. The last point must be 1,1.
2479
2480 See the \l {Qt Quick Examples - Animation#Easing Curves}{Easing Curves} for a demonstration of the different easing settings.
2481//! propertyanimation.easing
2482*/
2483QEasingCurve QQuickPropertyAnimation::easing() const
2484{
2485 Q_D(const QQuickPropertyAnimation);
2486 return d->easing;
2487}
2488
2489void QQuickPropertyAnimation::setEasing(const QEasingCurve &e)
2490{
2491 Q_D(QQuickPropertyAnimation);
2492 if (d->easing == e)
2493 return;
2494
2495 d->easing = e;
2496 if (d->componentComplete && d->running)
2497 d->ourPropertiesDirty = true;
2498 emit easingChanged(e);
2499 if (d->group)
2500 d->animationGroupDirty();
2501}
2502
2503QObject *QQuickPropertyAnimation::target() const
2504{
2505 Q_D(const QQuickPropertyAnimation);
2506 return d->target;
2507}
2508
2509void QQuickPropertyAnimation::setTargetObject(QObject *o)
2510{
2511 Q_D(QQuickPropertyAnimation);
2512 if (d->target == o)
2513 return;
2514 d->target = o;
2515 emit targetChanged();
2516 if (d->group)
2517 d->animationGroupDirty();
2518}
2519
2520QString QQuickPropertyAnimation::property() const
2521{
2522 Q_D(const QQuickPropertyAnimation);
2523 return d->propertyName;
2524}
2525
2526void QQuickPropertyAnimation::setProperty(const QString &n)
2527{
2528 Q_D(QQuickPropertyAnimation);
2529 if (d->propertyName == n)
2530 return;
2531 d->propertyName = n;
2532 emit propertyChanged();
2533 if (d->group)
2534 d->animationGroupDirty();
2535}
2536
2537QString QQuickPropertyAnimation::properties() const
2538{
2539 Q_D(const QQuickPropertyAnimation);
2540 return d->properties;
2541}
2542
2543void QQuickPropertyAnimation::setProperties(const QString &prop)
2544{
2545 Q_D(QQuickPropertyAnimation);
2546 if (d->properties == prop)
2547 return;
2548
2549 d->properties = prop;
2550 emit propertiesChanged(prop);
2551 if (d->group)
2552 d->animationGroupDirty();
2553}
2554
2555/*!
2556 \qmlproperty string QtQuick::PropertyAnimation::properties
2557 \qmlproperty list<QtObject> QtQuick::PropertyAnimation::targets
2558 \qmlproperty string QtQuick::PropertyAnimation::property
2559 \qmlproperty QtObject QtQuick::PropertyAnimation::target
2560
2561 These properties are used as a set to determine which properties should be animated.
2562 The singular and plural forms are functionally identical, e.g.
2563 \qml
2564 NumberAnimation { target: theItem; property: "x"; to: 500 }
2565 \endqml
2566 has the same meaning as
2567 \qml
2568 NumberAnimation { targets: theItem; properties: "x"; to: 500 }
2569 \endqml
2570 The singular forms are slightly optimized, so if you do have only a single target/property
2571 to animate you should try to use them.
2572
2573 The \c targets property allows multiple targets to be set. For example, this animates the
2574 \c x property of both \c itemA and \c itemB:
2575
2576 \qml
2577 NumberAnimation { targets: [itemA, itemB]; properties: "x"; to: 500 }
2578 \endqml
2579
2580 In many cases these properties do not need to be explicitly specified, as they can be
2581 inferred from the animation framework:
2582
2583 \table 80%
2584 \row
2585 \li Value Source / Behavior
2586 \li When an animation is used as a value source or in a Behavior, the default target and property
2587 name to be animated can both be inferred.
2588 \qml
2589 Rectangle {
2590 id: theRect
2591 width: 100; height: 100
2592 color: Qt.rgba(0,0,1)
2593 NumberAnimation on x { to: 500; loops: Animation.Infinite } //animate theRect's x property
2594 Behavior on y { NumberAnimation {} } //animate theRect's y property
2595 }
2596 \endqml
2597 \row
2598 \li Transition
2599 \li When used in a transition, a property animation is assumed to match \e all targets
2600 but \e no properties. In practice, that means you need to specify at least the properties
2601 in order for the animation to do anything.
2602 \qml
2603 Rectangle {
2604 id: theRect
2605 width: 100; height: 100
2606 color: Qt.rgba(0,0,1)
2607 Item { id: uselessItem }
2608 states: State {
2609 name: "state1"
2610 PropertyChanges {
2611 theRect {
2612 x: 200
2613 y: 200
2614 z: 4
2615 }
2616 uselessItem {
2617 x: 10
2618 y: 10
2619 z: 2
2620 }
2621 }
2622 }
2623 transitions: Transition {
2624 //animate both theRect's and uselessItem's x and y to their final values
2625 NumberAnimation { properties: "x,y" }
2626
2627 //animate theRect's z to its final value
2628 NumberAnimation { target: theRect; property: "z" }
2629 }
2630 }
2631 \endqml
2632 \row
2633 \li Standalone
2634 \li When an animation is used standalone, both the target and property need to be
2635 explicitly specified.
2636 \qml
2637 Rectangle {
2638 id: theRect
2639 width: 100; height: 100
2640 color: Qt.rgba(0,0,1)
2641 //need to explicitly specify target and property
2642 NumberAnimation { id: theAnim; target: theRect; property: "x"; to: 500 }
2643 MouseArea {
2644 anchors.fill: parent
2645 onClicked: theAnim.start()
2646 }
2647 }
2648 \endqml
2649 \endtable
2650
2651 As seen in the above example, properties is specified as a comma-separated string of property names to animate.
2652
2653 \sa exclude, {Animation and Transitions in Qt Quick}
2654*/
2655QQmlListProperty<QObject> QQuickPropertyAnimation::targets()
2656{
2657 Q_D(QQuickPropertyAnimation);
2658 using ListPtr = QList<QPointer<QObject>> *;
2659 using LP = QQmlListProperty<QObject>;
2660 LP::AppendFunction appendFn = [](LP *prop, QObject *value)
2661 {
2662 static_cast<ListPtr>(prop->data)->append(t: value);
2663 };
2664 LP::CountFunction countFn = [](LP *prop)
2665 {
2666 return static_cast<ListPtr>(prop->data)->size();
2667 };
2668
2669 LP::AtFunction atFn = [](LP *prop, qsizetype index) -> QObject *
2670 {
2671 return static_cast<ListPtr>(prop->data)->at(i: index);
2672 };
2673
2674 LP::ClearFunction clearFN = [](LP *prop)
2675 {
2676 return static_cast<ListPtr>(prop->data)->clear();
2677 };
2678
2679 LP::ReplaceFunction replaceFn = [](LP *prop, qsizetype index, QObject *value)
2680 {
2681 static_cast<ListPtr>(prop->data)->replace(i: index, t: value);
2682 };
2683
2684 LP::RemoveLastFunction removeLastFn = [](LP *prop)
2685 {
2686 static_cast<ListPtr>(prop->data)->removeLast();
2687 };
2688
2689 return QQmlListProperty<QObject>(this, &(d->targets), appendFn, countFn, atFn, clearFN, replaceFn, removeLastFn);
2690}
2691
2692/*!
2693 \qmlproperty list<QtObject> QtQuick::PropertyAnimation::exclude
2694 This property holds the items not to be affected by this animation.
2695 \sa PropertyAnimation::targets
2696*/
2697QQmlListProperty<QObject> QQuickPropertyAnimation::exclude()
2698{
2699 Q_D(QQuickPropertyAnimation);
2700 return QQmlListProperty<QObject>(this, &(d->exclude));
2701}
2702
2703void QQuickAnimationPropertyUpdater::setValue(qreal v)
2704{
2705 bool deleted = false;
2706 wasDeleted = &deleted;
2707 if (reverse)
2708 v = 1 - v;
2709 for (int ii = 0; ii < actions.size(); ++ii) {
2710 QQuickStateAction &action = actions[ii];
2711
2712 if (v == 1.) {
2713 QQmlPropertyPrivate::write(that: action.property, action.toValue, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
2714 } else {
2715 if (!fromIsSourced && !fromIsDefined) {
2716 action.fromValue = action.property.read();
2717 if (interpolatorType) {
2718 QQuickPropertyAnimationPrivate::convertVariant(variant&: action.fromValue, type: QMetaType(interpolatorType));
2719 }
2720 }
2721 if (!interpolatorType) {
2722 int propType = action.property.propertyType();
2723 if (!prevInterpolatorType || prevInterpolatorType != propType) {
2724 prevInterpolatorType = propType;
2725 interpolator = QVariantAnimationPrivate::getInterpolator(interpolationType: prevInterpolatorType);
2726 }
2727 }
2728 if (interpolator)
2729 QQmlPropertyPrivate::write(that: action.property, interpolator(action.fromValue.constData(), action.toValue.constData(), v), QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
2730 }
2731 if (deleted)
2732 return;
2733 }
2734 wasDeleted = nullptr;
2735 fromIsSourced = true;
2736}
2737
2738void QQuickAnimationPropertyUpdater::debugUpdater(QDebug d, int indentLevel) const
2739{
2740 QByteArray ind(indentLevel, ' ');
2741 for (int i = 0; i < actions.size(); ++i) {
2742 const QQuickStateAction &action = actions.at(i);
2743 d << "\n" << ind.constData() << "target:" << action.property.object() << "property:" << action.property.name()
2744 << "from:" << action.fromValue << "to:" << action.toValue;
2745 }
2746}
2747
2748QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateActions &actions,
2749 QQmlProperties &modified,
2750 QObject *defaultTarget)
2751{
2752 Q_D(QQuickPropertyAnimation);
2753 QQuickStateActions newActions;
2754
2755 QStringList props = d->properties.isEmpty() ? QStringList() : d->properties.split(sep: QLatin1Char(','));
2756 for (int ii = 0; ii < props.size(); ++ii)
2757 props[ii] = props.at(i: ii).trimmed();
2758 if (!d->propertyName.isEmpty())
2759 props << d->propertyName;
2760
2761 QList<QPointer<QObject>> targets = d->targets;
2762 if (d->target)
2763 targets.append(t: d->target);
2764
2765 bool hasSelectors = !props.isEmpty() || !targets.isEmpty() || !d->exclude.isEmpty();
2766 bool useType = (props.isEmpty() && d->defaultToInterpolatorType) ? true : false;
2767
2768 if (d->defaultProperty.isValid() && !hasSelectors) {
2769 props << d->defaultProperty.name();
2770 targets << d->defaultProperty.object();
2771 }
2772
2773 if (defaultTarget && targets.isEmpty())
2774 targets << defaultTarget;
2775
2776 bool usingDefaultProperties = false;
2777 if (props.isEmpty() && !d->defaultProperties.isEmpty()) {
2778 props << d->defaultProperties.split(sep: QLatin1Char(','));
2779 usingDefaultProperties = true;
2780 }
2781
2782 bool hasExplicit = false;
2783 //an explicit animation has been specified
2784 if (d->toIsDefined) {
2785 QVector<QString> errorMessages;
2786 bool successfullyCreatedDefaultProperty = false;
2787
2788 for (int i = 0; i < props.size(); ++i) {
2789 for (int j = 0; j < targets.size(); ++j) {
2790 const auto& guarded = targets.at(i: j);
2791 if (guarded.isNull())
2792 continue;
2793 QObject *target = guarded.get();
2794 QQuickStateAction myAction;
2795 QString errorMessage;
2796 const QString &propertyName = props.at(i);
2797 myAction.property = d->createProperty(obj: target, str: propertyName, infoObj: this, errorMessage: &errorMessage);
2798 if (myAction.property.isValid()) {
2799 if (usingDefaultProperties)
2800 successfullyCreatedDefaultProperty = true;
2801
2802 if (d->fromIsDefined) {
2803 myAction.fromValue = d->from;
2804 d->convertVariant(variant&: myAction.fromValue, type: d->interpolatorType ? QMetaType(d->interpolatorType) : myAction.property.propertyMetaType());
2805 }
2806 myAction.toValue = d->to;
2807 d->convertVariant(variant&: myAction.toValue, type: d->interpolatorType ? QMetaType(d->interpolatorType) : myAction.property.propertyMetaType());
2808 newActions << myAction;
2809 hasExplicit = true;
2810 for (int ii = 0; ii < actions.size(); ++ii) {
2811 QQuickStateAction &action = actions[ii];
2812 if (action.property.object() == myAction.property.object() &&
2813 myAction.property.name() == action.property.name()) {
2814 modified << action.property;
2815 break; //### any chance there could be multiples?
2816 }
2817 }
2818 } else {
2819 errorMessages.append(t: errorMessage);
2820 }
2821 }
2822 }
2823
2824 if (!successfullyCreatedDefaultProperty) {
2825 for (const QString &errorMessage : std::as_const(t&: errorMessages))
2826 qmlWarning(me: this) << errorMessage;
2827 }
2828 }
2829
2830 if (!hasExplicit)
2831 for (int ii = 0; ii < actions.size(); ++ii) {
2832 QQuickStateAction &action = actions[ii];
2833
2834 QObject *obj = action.property.object();
2835 QString propertyName = action.property.name();
2836 QObject *sObj = action.specifiedObject;
2837 QString sPropertyName = action.specifiedProperty;
2838 bool same = (obj == sObj);
2839
2840 if ((targets.isEmpty() || targets.contains(t: obj) || (!same && targets.contains(t: sObj))) &&
2841 (!d->exclude.contains(t: obj)) && (same || (!d->exclude.contains(t: sObj))) &&
2842 (props.contains(str: propertyName) || (!same && props.contains(str: sPropertyName))
2843 || (useType && action.property.propertyType() == d->interpolatorType))) {
2844 QQuickStateAction myAction = action;
2845
2846 if (d->fromIsDefined)
2847 myAction.fromValue = d->from;
2848 else
2849 myAction.fromValue = QVariant();
2850 if (d->toIsDefined)
2851 myAction.toValue = d->to;
2852
2853 d->convertVariant(variant&: myAction.fromValue, type: d->interpolatorType ? QMetaType(d->interpolatorType) : myAction.property.propertyMetaType());
2854 d->convertVariant(variant&: myAction.toValue, type: d->interpolatorType ? QMetaType(d->interpolatorType) : myAction.property.propertyMetaType());
2855
2856 modified << action.property;
2857
2858 newActions << myAction;
2859 action.fromValue = myAction.toValue;
2860 }
2861 }
2862 return newActions;
2863}
2864
2865QAbstractAnimationJob* QQuickPropertyAnimation::transition(QQuickStateActions &actions,
2866 QQmlProperties &modified,
2867 TransitionDirection direction,
2868 QObject *defaultTarget)
2869{
2870 Q_D(QQuickPropertyAnimation);
2871
2872 QQuickStateActions dataActions = createTransitionActions(actions, modified, defaultTarget);
2873
2874 QQuickBulkValueAnimator *animator = new QQuickBulkValueAnimator;
2875 animator->setDuration(d->duration);
2876 animator->setEasingCurve(d->easing);
2877
2878 if (!dataActions.isEmpty()) {
2879 QQuickAnimationPropertyUpdater *data = new QQuickAnimationPropertyUpdater;
2880 data->interpolatorType = d->interpolatorType;
2881 data->interpolator = d->interpolator;
2882 data->reverse = direction == Backward ? true : false;
2883 data->fromIsSourced = false;
2884 data->fromIsDefined = d->fromIsDefined;
2885 data->actions = dataActions;
2886 animator->setAnimValue(data);
2887 animator->setFromIsSourcedValue(&data->fromIsSourced);
2888 d->actions = &data->actions; //remove this?
2889 }
2890
2891 return initInstance(animation: animator);
2892}
2893
2894QQuickAnimationPropertyUpdater::~QQuickAnimationPropertyUpdater()
2895{
2896 if (wasDeleted) *wasDeleted = true;
2897}
2898
2899QT_END_NAMESPACE
2900
2901#include "moc_qquickanimation_p.cpp"
2902

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quick/util/qquickanimation.cpp