Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickframeanimation.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qcoreapplication.h>
8#include <QtCore/qelapsedtimer.h>
9#include "private/qabstractanimationjob_p.h"
10#include <private/qobject_p.h>
11#include <qdebug.h>
12
14
16{
17 int duration() const override {
18 return 1;
19 }
20};
21
23{
24 Q_DECLARE_PUBLIC(QQuickFrameAnimation)
25public:
27
31
63
64 // Handle the running/pausing state updates.
66 {
68 return;
69
70 if (running && !paused) {
71 if (firstTick) {
72 elapsedTime = 0;
74 }
77 } else {
78 frameJob.stop();
79 }
80 }
81
82private:
84 QElapsedTimer elapsedTimer;
85 int currentFrame = 0;
86 qreal frameTime = 0.0;
87 qreal smoothFrameTime = 0.0;
88 qreal elapsedTime = 0.0;
89 qint64 prevFrameTimeNs = 0;
90 qint64 prevElapsedTimeNs = 0;
91 bool running = false;
92 bool paused = false;
93 bool componentComplete = false;
94 bool firstTick = true;
95};
96
97/*!
98 \qmltype FrameAnimation
99 \nativetype QQuickFrameAnimation
100 \inqmlmodule QtQuick
101 \ingroup qtquick-interceptors
102 \since 6.4
103 \brief Triggers a handler at every animation frame update.
104
105 A FrameAnimation can be used to trigger an action every time animations
106 have progressed and an animation frame has been rendered. See the documentation
107 about the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth
108 information about the threaded and basic render loops.
109
110 For general animations, prefer using \c NumberAnimation and other \c Animation
111 elements as those provide declarative way to describe the animations.
112
113 FrameAnimation on the other hand should be used for custom imperative animations
114 and in use-cases like these:
115 \list
116 \li When you need to run some code on every frame update. Or e.g. every other frame,
117 maybe using progressive rendering.
118 \li When the speed / target is changing during the animation, normal QML animations
119 can be too limiting.
120 \li When more accurate frame update time is needed, e.g. for fps counter.
121 \endlist
122
123 Compared to \c Timer which allows to set the \c interval time, FrameAnimation runs
124 always in synchronization with the animation updates. If you have used \c Timer
125 with a short interval for custom animations like below, please consider switching
126 to use FrameAnimation instead for smoother animations.
127 \code
128 // BAD
129 Timer {
130 interval: 16
131 repeat: true
132 running: true
133 onTriggered: {
134 // Animate something
135 }
136 }
137
138 // GOOD
139 FrameAnimation {
140 running: true
141 onTriggered: {
142 // Animate something
143 }
144 }
145 \endcode
146*/
147QQuickFrameAnimation::QQuickFrameAnimation(QObject *parent)
148 : QObject(*(new QQuickFrameAnimationPrivate), parent)
149{
150 Q_D(QQuickFrameAnimation);
151 d->frameJob.addAnimationChangeListener(d, QAbstractAnimationJob::CurrentLoop);
152 d->frameJob.setLoopCount(-1);
153}
154
155/*!
156 \qmlsignal QtQuick::FrameAnimation::triggered()
157
158 This signal is emitted when the FrameAnimation has progressed to a new frame.
159*/
160
161/*!
162 \qmlproperty bool QtQuick::FrameAnimation::running
163
164 If set to true, starts the frame animation; otherwise stops it.
165
166 \a running defaults to false.
167
168 \sa stop(), start(), restart()
169*/
170bool QQuickFrameAnimation::isRunning() const
171{
172 Q_D(const QQuickFrameAnimation);
173 return d->running;
174}
175
176void QQuickFrameAnimation::setRunning(bool running)
177{
178 Q_D(QQuickFrameAnimation);
179 if (d->running != running) {
180 d->running = running;
181 d->firstTick = true;
182 Q_EMIT runningChanged();
183 d->updateState();
184 }
185}
186
187/*!
188 \qmlproperty bool QtQuick::FrameAnimation::paused
189
190 If set to true, pauses the frame animation; otherwise resumes it.
191
192 \a paused defaults to false.
193
194 \sa pause(), resume()
195*/
196bool QQuickFrameAnimation::isPaused() const
197{
198 Q_D(const QQuickFrameAnimation);
199 return d->paused;
200}
201
202void QQuickFrameAnimation::setPaused(bool paused)
203{
204 Q_D(QQuickFrameAnimation);
205 if (d->paused != paused) {
206 d->paused = paused;
207 Q_EMIT pausedChanged();
208 d->updateState();
209 }
210}
211
212/*!
213 \qmlproperty int QtQuick::FrameAnimation::currentFrame
214 \readonly
215
216 This property holds the number of frame updates since the start.
217 When the frame animation is restarted, currentFrame starts from \c 0.
218
219 The following example shows how to react on frame updates.
220
221 \code
222 FrameAnimation {
223 running: true
224 onTriggered: {
225 // Run code on every frame update.
226 }
227 }
228 \endcode
229
230 This property can also be used for rendering only every nth frame. Consider an
231 advanced usage where the UI contains two heavy elements and to reach smooth 60fps
232 overall frame rate, you decide to render these heavy elements at 30fps, first one
233 on every even frames and second one on every odd frames:
234
235 \code
236 FrameAnimation {
237 running: true
238 onTriggered: {
239 if (currentFrame % 2 == 0)
240 updateUIElement1();
241 else
242 updateUIElement2();
243 }
244 }
245 \endcode
246
247 By default, \c frame is 0.
248*/
249int QQuickFrameAnimation::currentFrame() const
250{
251 Q_D(const QQuickFrameAnimation);
252 return d->currentFrame;
253}
254
255/*!
256 \qmlproperty real QtQuick::FrameAnimation::frameTime
257 \readonly
258
259 This property holds the time (in seconds) since the previous frame update.
260
261 The following example shows how to use frameTime to animate item with
262 varying speed, adjusting to screen refresh rates and possible fps drops.
263
264 \code
265 Rectangle {
266 id: rect
267 property real speed: 90
268 width: 100
269 height: 100
270 color: "red"
271 anchors.centerIn: parent
272 }
273
274 FrameAnimation {
275 id: frameAnimation
276 running: true
277 onTriggered: {
278 // Rotate the item speed-degrees / second.
279 rect.rotation += rect.speed * frameTime
280 }
281 }
282 \endcode
283
284 By default, \c frameTime is 0.
285*/
286qreal QQuickFrameAnimation::frameTime() const
287{
288 Q_D(const QQuickFrameAnimation);
289 return d->frameTime;
290}
291
292/*!
293 \qmlproperty real QtQuick::FrameAnimation::smoothFrameTime
294 \readonly
295
296 This property holds the smoothed time (in seconds) since the previous frame update.
297
298 The following example shows how to use smoothFrameTime to show average fps.
299
300 \code
301 Text {
302 text: "fps: " + frameAnimation.fps.toFixed(0)
303 }
304
305 FrameAnimation {
306 id: frameAnimation
307 property real fps: smoothFrameTime > 0 ? (1.0 / smoothFrameTime) : 0
308 running: true
309 }
310 \endcode
311
312 By default, \c smoothFrameTime is 0.
313*/
314qreal QQuickFrameAnimation::smoothFrameTime() const
315{
316 Q_D(const QQuickFrameAnimation);
317 return d->smoothFrameTime;
318}
319
320/*!
321 \qmlproperty real QtQuick::FrameAnimation::elapsedTime
322 \readonly
323
324 This property holds the time (in seconds) since the previous start.
325
326 By default, \c elapsedTime is 0.
327*/
328qreal QQuickFrameAnimation::elapsedTime() const
329{
330 Q_D(const QQuickFrameAnimation);
331 return d->elapsedTime;
332}
333
334/*!
335 \qmlmethod QtQuick::FrameAnimation::start()
336 \brief Starts the frame animation
337
338 If the frame animation is already running, calling this method has no effect. The
339 \c running property will be true following a call to \c start().
340*/
341void QQuickFrameAnimation::start()
342{
343 setRunning(true);
344}
345
346/*!
347 \qmlmethod QtQuick::FrameAnimation::stop()
348 \brief Stops the frame animation
349
350 If the frame animation is not running, calling this method has no effect. Both the \c running and
351 \c paused properties will be false following a call to \c stop().
352*/
353void QQuickFrameAnimation::stop()
354{
355 setRunning(false);
356 setPaused(false);
357}
358
359/*!
360 \qmlmethod QtQuick::FrameAnimation::restart()
361 \brief Restarts the frame animation
362
363 If the FrameAnimation is not running it will be started, otherwise it will be
364 stopped, reset to initial state and started. The \c running property
365 will be true following a call to \c restart().
366*/
367void QQuickFrameAnimation::restart()
368{
369 stop();
370 start();
371}
372
373/*!
374 \qmlmethod QtQuick::FrameAnimation::pause()
375 \brief Pauses the frame animation
376
377 If the frame animation is already paused or not \c running, calling this method has no effect.
378 The \c paused property will be true following a call to \c pause().
379*/
380void QQuickFrameAnimation::pause()
381{
382 setPaused(true);
383}
384
385/*!
386 \qmlmethod QtQuick::FrameAnimation::resume()
387 \brief Resumes a paused frame animation
388
389 If the frame animation is not paused or not \c running, calling this method has no effect.
390 The \c paused property will be false following a call to \c resume().
391*/
392void QQuickFrameAnimation::resume()
393{
394 setPaused(false);
395}
396
397/*!
398 \qmlmethod QtQuick::FrameAnimation::reset()
399 \brief Resets the frame animation properties
400
401 Calling this method resets the \c frame and \c elapsedTime to their initial
402 values (0). This method has no effect on \c running or \c paused properties
403 and can be called while they are true or false.
404
405 The difference between calling \c reset() and \c restart() is that \c reset()
406 will always initialize the properties while \c restart() initializes them only
407 at the next frame update which doesn't happen e.g. if \c restart() is
408 immediately followed by \c pause().
409*/
410void QQuickFrameAnimation::reset()
411{
412 Q_D(QQuickFrameAnimation);
413 setElapsedTime(0);
414 setCurrentFrame(0);
415 d->prevElapsedTimeNs = 0;
416 d->elapsedTimer.start();
417}
418
419/*!
420 \internal
421 */
422void QQuickFrameAnimation::classBegin()
423{
424 Q_D(QQuickFrameAnimation);
425 d->componentComplete = false;
426}
427
428/*!
429 \internal
430 */
431void QQuickFrameAnimation::componentComplete()
432{
433 Q_D(QQuickFrameAnimation);
434 d->componentComplete = true;
435 d->updateState();
436}
437
438/*!
439 \internal
440 */
441void QQuickFrameAnimation::setCurrentFrame(int frame)
442{
443 Q_D(QQuickFrameAnimation);
444 if (d->currentFrame != frame) {
445 d->currentFrame = frame;
446 Q_EMIT currentFrameChanged();
447 }
448}
449
450/*!
451 \internal
452 */
453void QQuickFrameAnimation::setElapsedTime(qreal elapsedTime)
454{
455 Q_D(QQuickFrameAnimation);
456 if (!qFuzzyCompare(d->elapsedTime, elapsedTime)) {
457 d->elapsedTime = elapsedTime;
458 Q_EMIT elapsedTimeChanged();
459 }
460}
461
462QT_END_NAMESPACE
463
464#include "moc_qquickframeanimation_p.cpp"
int duration() const override