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 "qquickanimationcontroller_p.h"
5#include <QtQml/qqmlinfo.h>
6#include <private/qqmlengine_p.h>
7
8QT_BEGIN_NAMESPACE
9
10
11class QQuickAnimationControllerPrivate : public QObjectPrivate, QAnimationJobChangeListener
12{
13 Q_DECLARE_PUBLIC(QQuickAnimationController)
14public:
15 QQuickAnimationControllerPrivate()
16 : progress(0.0), animation(nullptr), animationInstance(nullptr), finalized(false) {}
17 void animationFinished(QAbstractAnimationJob *job) override;
18 void animationCurrentTimeChanged(QAbstractAnimationJob *job, int currentTime) override;
19
20
21 qreal progress;
22 QQuickAbstractAnimation *animation;
23 QAbstractAnimationJob *animationInstance;
24 bool finalized:1;
25
26};
27
28void QQuickAnimationControllerPrivate::animationFinished(QAbstractAnimationJob *job)
29{
30 Q_Q(QQuickAnimationController);
31 Q_ASSERT(animationInstance && animationInstance == job);
32 Q_UNUSED(job);
33
34 animationInstance->removeAnimationChangeListener(listener: this, QAbstractAnimationJob::Completion | QAbstractAnimationJob::CurrentTime);
35
36 if (animationInstance->direction() == QAbstractAnimationJob::Forward && progress != 1) {
37 progress = 1;
38 emit q->progressChanged();
39 } else if (animationInstance->direction() == QAbstractAnimationJob::Backward && progress != 0) {
40 progress = 0;
41 emit q->progressChanged();
42 }
43
44}
45
46void QQuickAnimationControllerPrivate::animationCurrentTimeChanged(QAbstractAnimationJob *job, int currentTime)
47{
48 Q_Q(QQuickAnimationController);
49 Q_ASSERT(animationInstance && animationInstance == job);
50 Q_UNUSED(job);
51 const qreal newProgress = currentTime * 1.0 / animationInstance->duration();
52 if (progress != newProgress) {
53 progress = newProgress;
54 emit q->progressChanged();
55 }
56}
57
58/*!
59 \qmltype AnimationController
60 \instantiates QQuickAnimationController
61 \inqmlmodule QtQuick
62 \ingroup qtquick-animation-control
63 \brief Enables manual control of animations.
64
65 Normally animations are driven by an internal timer, but the AnimationController
66 allows the given \a animation to be driven by a \a progress value explicitly.
67*/
68
69
70QQuickAnimationController::QQuickAnimationController(QObject *parent)
71: QObject(*(new QQuickAnimationControllerPrivate), parent)
72{
73}
74
75QQuickAnimationController::~QQuickAnimationController()
76{
77 Q_D(QQuickAnimationController);
78 delete d->animationInstance;
79}
80
81/*!
82 \qmlproperty real QtQuick::AnimationController::progress
83 This property holds the animation progress value.
84
85 The valid \c progress value is 0.0 to 1.0, setting values less than 0 will be converted to 0,
86 setting values great than 1 will be converted to 1.
87*/
88qreal QQuickAnimationController::progress() const
89{
90 Q_D(const QQuickAnimationController);
91 return d->progress;
92}
93
94void QQuickAnimationController::setProgress(qreal progress)
95{
96 Q_D(QQuickAnimationController);
97 progress = qBound(min: qreal(0), val: progress, max: qreal(1));
98
99 if (progress != d->progress) {
100 d->progress = progress;
101 updateProgress();
102 emit progressChanged();
103 }
104}
105
106/*!
107 \qmlproperty Animation QtQuick::AnimationController::animation
108 \qmldefault
109
110 This property holds the animation to be controlled by the AnimationController.
111
112 Note:An animation controlled by AnimationController will always have its
113 \c running and \c paused properties set to true. It can not be manually
114 started or stopped (much like an animation in a Behavior can not be manually started or stopped).
115*/
116QQuickAbstractAnimation *QQuickAnimationController::animation() const
117{
118 Q_D(const QQuickAnimationController);
119 return d->animation;
120}
121
122void QQuickAnimationController::setAnimation(QQuickAbstractAnimation *animation)
123{
124 Q_D(QQuickAnimationController);
125
126 if (animation != d->animation) {
127 if (animation) {
128 if (animation->userControlDisabled()) {
129 qmlWarning(me: this) << "QQuickAnimationController::setAnimation: the animation is controlled by others, can't be used in AnimationController.";
130 return;
131 }
132 animation->setDisableUserControl();
133 }
134
135 if (d->animation)
136 d->animation->setEnableUserControl();
137
138 d->animation = animation;
139 reload();
140 emit animationChanged();
141 }
142}
143
144/*!
145 \qmlmethod QtQuick::AnimationController::reload()
146 \brief Reloads the animation properties
147
148 If the animation properties changed, calling this method to reload the animation definations.
149*/
150void QQuickAnimationController::reload()
151{
152 Q_D(QQuickAnimationController);
153 if (!d->finalized)
154 return;
155
156 if (!d->animation) {
157 d->animationInstance = nullptr;
158 } else {
159 QQuickStateActions actions;
160 QQmlProperties properties;
161 QAbstractAnimationJob *oldInstance = d->animationInstance;
162 d->animationInstance = d->animation->transition(actions, modified&: properties, direction: QQuickAbstractAnimation::Forward);
163 if (oldInstance && oldInstance != d->animationInstance)
164 delete oldInstance;
165 if (d->animationInstance) {
166 d->animationInstance->setLoopCount(1);
167 d->animationInstance->setDisableUserControl();
168 d->animationInstance->start();
169 d->animationInstance->pause();
170 updateProgress();
171 }
172 }
173}
174
175void QQuickAnimationController::updateProgress()
176{
177 Q_D(QQuickAnimationController);
178 if (!d->animationInstance)
179 return;
180
181 d->animationInstance->setDisableUserControl();
182 d->animationInstance->start();
183 QQmlAnimationTimer::instance()->unregisterAnimation(animation: d->animationInstance);
184 d->animationInstance->setCurrentTime(d->progress * d->animationInstance->duration());
185}
186
187void QQuickAnimationController::componentFinalized()
188{
189 Q_D(QQuickAnimationController);
190 d->finalized = true;
191 reload();
192}
193
194/*!
195 \qmlmethod QtQuick::AnimationController::completeToBeginning()
196 \brief Finishes running the controlled animation in a backwards direction.
197
198 After calling this method, the animation runs normally from the current progress point
199 in a backwards direction to the beginning state.
200
201 The animation controller's progress value will be automatically updated while the animation is running.
202
203 \sa completeToEnd(), progress
204*/
205void QQuickAnimationController::completeToBeginning()
206{
207 Q_D(QQuickAnimationController);
208 if (!d->animationInstance)
209 return;
210
211 if (d->progress == 0)
212 return;
213
214 d->animationInstance->addAnimationChangeListener(listener: d, QAbstractAnimationJob::Completion | QAbstractAnimationJob::CurrentTime);
215 d->animationInstance->setDirection(QAbstractAnimationJob::Backward);
216
217 //Disable and then enable user control to trigger the animation instance's state change
218 d->animationInstance->setDisableUserControl();
219 d->animationInstance->setEnableUserControl();
220 d->animationInstance->start();
221}
222
223/*!
224 \qmlmethod QtQuick::AnimationController::completeToEnd()
225 \brief Finishes running the controlled animation in a forwards direction.
226
227 After calling this method, the animation runs normally from the current progress point
228 in a forwards direction to the end state.
229
230 The animation controller's progress value will be automatically updated while the animation is running.
231
232 \sa completeToBeginning(), progress
233*/
234void QQuickAnimationController::completeToEnd()
235{
236 Q_D(QQuickAnimationController);
237 if (!d->animationInstance)
238 return;
239
240 if (d->progress == 1)
241 return;
242
243 d->animationInstance->addAnimationChangeListener(listener: d, QAbstractAnimationJob::Completion | QAbstractAnimationJob::CurrentTime);
244 d->animationInstance->setDirection(QAbstractAnimationJob::Forward);
245
246 //Disable and then enable user control to trigger the animation instance's state change
247 d->animationInstance->setDisableUserControl();
248 d->animationInstance->setEnableUserControl();
249 d->animationInstance->start();
250}
251
252
253
254QT_END_NAMESPACE
255
256
257#include "moc_qquickanimationcontroller_p.cpp"
258

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