Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquicksmoothedanimation.cpp
Go to the documentation of this file.
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
6
8#include "private/qcontinuinganimationgroupjob_p.h"
9
10#include <qmath.h>
11#include <qqmlproperty.h>
12#include <private/qqmlproperty_p.h>
13
14#include <private/qqmlglobal_p.h>
15
16#include <QtCore/qdebug.h>
17
18
19#define DELAY_STOP_TIMER_INTERVAL 32
20
22
23
25 : QTimer(parent)
26 , m_animation(animation)
27{
28 connect(this, SIGNAL(timeout()), this, SLOT(stopAnimation()));
29}
30
32{
33}
34
36{
37 m_animation->stop();
38}
39
41 : QAbstractAnimationJob(), to(0), velocity(200), userDuration(-1), maximumEasingTime(-1),
42 reversingMode(QQuickSmoothedAnimation::Eased), initialVelocity(0),
43 trackVelocity(0), initialValue(0), invert(false), finalDuration(-1), lastTime(0),
44 skipUpdate(false), delayedStopTimer(new QSmoothedAnimationTimer(this)), animationTemplate(priv)
45{
46 delayedStopTimer->setInterval(DELAY_STOP_TIMER_INTERVAL);
47 delayedStopTimer->setSingleShot(true);
48}
49
51{
52 delete delayedStopTimer;
53 if (animationTemplate) {
54 if (target.object()) {
56 animationTemplate->activeAnimations.find(target);
57 if (it != animationTemplate->activeAnimations.end() && it.value() == this)
58 animationTemplate->activeAnimations.erase(it);
59 } else {
60 //target is no longer valid, need to search linearly
62 for (it = animationTemplate->activeAnimations.begin(); it != animationTemplate->activeAnimations.end(); ++it) {
63 if (it.value() == this) {
64 animationTemplate->activeAnimations.erase(it);
65 break;
66 }
67 }
68 }
69 }
70}
71
73{
75 if (isRunning())
76 init();
77 else
78 start();
79}
80
82{
84 if (isRunning()) {
85 //we are joining a new wrapper group while running, our times need to be restarted
86 skipUpdate = true;
87 init();
88 lastTime = 0;
89 } else {
90 skipUpdate = false;
91 //we'll be started when the group starts, which will force an init()
92 }
93}
94
96{
98 init();
99}
100
101void QSmoothedAnimation::delayedStop()
102{
103 if (!delayedStopTimer->isActive())
104 delayedStopTimer->start();
105}
106
108{
109 return -1;
110}
111
112bool QSmoothedAnimation::recalc()
113{
114 s = to - initialValue;
115 vi = initialVelocity;
116
117 s = (invert? -1.0: 1.0) * s;
118
119 if (userDuration >= 0 && velocity > 0) {
120 tf = s / velocity;
121 if (tf > (userDuration / 1000.)) tf = (userDuration / 1000.);
122 } else if (userDuration >= 0) {
123 tf = userDuration / 1000.;
124 } else if (velocity > 0) {
125 tf = s / velocity;
126 } else {
127 return false;
128 }
129
130 finalDuration = qCeil(tf * 1000.0);
131
132 if (maximumEasingTime == 0) {
133 a = 0;
134 d = 0;
135 tp = 0;
136 td = tf;
137 vp = velocity;
138 sp = 0;
139 sd = s;
140 } else if (maximumEasingTime != -1 && tf > (maximumEasingTime / 1000.)) {
141 qreal met = maximumEasingTime / 1000.;
142 /* tp| |td
143 * vp_ _______
144 * / \
145 * vi_ / \
146 * \
147 * \ _ 0
148 * |ta| |ta|
149 */
150 qreal ta = met / 2.;
151 a = (s - (vi * tf - 0.5 * vi * ta)) / (tf * ta - ta * ta);
152
153 vp = vi + a * ta;
154 d = vp / ta;
155 tp = ta;
156 sp = vi * ta + 0.5 * a * tp * tp;
157 sd = sp + vp * (tf - 2 * ta);
158 td = tf - ta;
159 } else {
160 qreal c1 = 0.25 * tf * tf;
161 qreal c2 = 0.5 * vi * tf - s;
162 qreal c3 = -0.25 * vi * vi;
163
164 qreal a1 = (-c2 + qSqrt(c2 * c2 - 4 * c1 * c3)) / (2. * c1);
165
166 qreal tp1 = 0.5 * tf - 0.5 * vi / a1;
167 qreal vp1 = a1 * tp1 + vi;
168
169 qreal sp1 = 0.5 * a1 * tp1 * tp1 + vi * tp1;
170
171 a = a1;
172 d = a1;
173 tp = tp1;
174 td = tp1;
175 vp = vp1;
176 sp = sp1;
177 sd = sp1;
178 }
179 return true;
180}
181
182qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
183{
184 qreal value;
185 if (time_seconds < tp) {
186 trackVelocity = vi + time_seconds * a;
187 value = 0.5 * a * time_seconds * time_seconds + vi * time_seconds;
188 } else if (time_seconds < td) {
189 time_seconds -= tp;
190 trackVelocity = vp;
191 value = sp + time_seconds * vp;
192 } else if (time_seconds < tf) {
193 time_seconds -= td;
194 trackVelocity = vp - time_seconds * a;
195 value = sd - 0.5 * d * time_seconds * time_seconds + vp * time_seconds;
196 } else {
197 trackVelocity = 0;
198 value = s;
199 delayedStop();
200 }
201
202 // to normalize 's' between [0..1], divide 'value' by 's'
203 return value;
204}
205
207{
208 if (skipUpdate) {
209 skipUpdate = false;
210 return;
211 }
212
213 if (!isRunning() && !isPaused()) // This can happen if init() stops the animation in some cases
214 return;
215
216 qreal time_seconds = qreal(t - lastTime) / 1000.;
217
218 qreal value = easeFollow(time_seconds);
219 value *= (invert? -1.0: 1.0);
223}
224
226{
227 if (velocity == 0) {
228 stop();
229 return;
230 }
231
232 if (delayedStopTimer->isActive())
233 delayedStopTimer->stop();
234
235 initialValue = target.read().toReal();
236 lastTime = this->currentTime();
237
238 if (to == initialValue) {
239 stop();
240 return;
241 }
242
243 bool hasReversed = trackVelocity != 0. &&
244 ((!invert) == ((initialValue - to) > 0));
245
246 if (hasReversed) {
247 switch (reversingMode) {
248 default:
251 break;
256 trackVelocity = 0;
257 stop();
258 return;
260 initialVelocity = 0;
261 break;
262 }
263 }
264
266
267 invert = (to < initialValue);
268
269 if (!recalc()) {
273 stop();
274 return;
275 }
276}
277
279{
280 d << "SmoothedAnimationJob(" << Qt::hex << (const void *) this << Qt::dec << ")" << "duration:" << userDuration
281 << "velocity:" << velocity << "target:" << target.object() << "property:" << target.name()
282 << "to:" << to << "current velocity:" << trackVelocity;
283}
284
335{
336}
337
339 : anim(new QSmoothedAnimation)
340{
341}
342
344{
345 typedef QHash<QQmlProperty, QSmoothedAnimation* >::iterator ActiveAnimationsHashIt;
346
347 delete anim;
348 for (ActiveAnimationsHashIt it = activeAnimations.begin(), end = activeAnimations.end(); it != end; ++it)
349 it.value()->clearTemplate();
350}
351
353{
354 for (QSmoothedAnimation *ease : std::as_const(activeAnimations)) {
355 ease->maximumEasingTime = anim->maximumEasingTime;
356 ease->reversingMode = anim->reversingMode;
357 ease->velocity = anim->velocity;
358 ease->userDuration = anim->userDuration;
359 ease->init();
360 }
361}
362
364 QQmlProperties &modified,
366 QObject *defaultTarget)
367{
370
371 const QQuickStateActions dataActions = QQuickPropertyAnimation::createTransitionActions(actions, modified, defaultTarget);
372
374
375 if (!dataActions.isEmpty()) {
377 for (int i = 0; i < dataActions.size(); i++) {
378 QSmoothedAnimation *ease;
379 bool isActive;
380 if (!d->activeAnimations.contains(dataActions[i].property)) {
381 ease = new QSmoothedAnimation(d);
382 d->activeAnimations.insert(dataActions[i].property, ease);
383 ease->target = dataActions[i].property;
384 isActive = false;
385 } else {
386 ease = d->activeAnimations.value(dataActions[i].property);
387 isActive = true;
388 }
389 wrapperGroup->appendAnimation(initInstance(ease));
390
391 ease->to = dataActions[i].toValue.toReal();
392
393 // copying public members from main value holder animation
394 ease->maximumEasingTime = d->anim->maximumEasingTime;
395 ease->reversingMode = d->anim->reversingMode;
396 ease->velocity = d->anim->velocity;
397 ease->userDuration = d->anim->userDuration;
398
399 ease->initialVelocity = ease->trackVelocity;
400
401 if (isActive)
402 ease->prepareForRestart();
403 anims.insert(ease);
404 }
405
406 const auto copy = d->activeAnimations;
407 for (QSmoothedAnimation *ease : copy) {
408 if (!anims.contains(ease)) {
409 ease->clearTemplate();
410 d->activeAnimations.remove(ease->target);
411 }
412 }
413 }
414 return wrapperGroup;
415}
416
432{
433 Q_D(const QQuickSmoothedAnimation);
434 return (QQuickSmoothedAnimation::ReversingMode) d->anim->reversingMode;
435}
436
438{
440 if (d->anim->reversingMode == m)
441 return;
442
443 d->anim->reversingMode = m;
445 d->updateRunningAnimations();
446}
447
459{
460 Q_D(const QQuickSmoothedAnimation);
461 return d->anim->userDuration;
462}
463
465{
467 if (duration != -1)
469 if(duration == d->anim->userDuration)
470 return;
471 d->anim->userDuration = duration;
472 d->updateRunningAnimations();
473}
474
476{
477 Q_D(const QQuickSmoothedAnimation);
478 return d->anim->velocity;
479}
480
494{
496 if (d->anim->velocity == v)
497 return;
498
499 d->anim->velocity = v;
501 d->updateRunningAnimations();
502}
503
515{
516 Q_D(const QQuickSmoothedAnimation);
517 return d->anim->maximumEasingTime;
518}
519
521{
523 if(v == d->anim->maximumEasingTime)
524 return;
525 d->anim->maximumEasingTime = v;
527 d->updateRunningAnimations();
528}
529
531
532#include "moc_qquicksmoothedanimation_p_p.cpp"
533
534#include "moc_qquicksmoothedanimation_p.cpp"
bool isActive
void appendAnimation(QAbstractAnimationJob *animation)
\inmodule QtCore
\inmodule QtCore
Definition qhash.h:1093
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1258
iterator erase(const_iterator it)
Definition qhash.h:1223
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool write(QObject *, const QQmlPropertyData &, const QVariant &, const QQmlRefPointer< QQmlContextData > &, QQmlPropertyData::WriteFlags flags={})
QAbstractAnimationJob * initInstance(QAbstractAnimationJob *animation)
virtual void setDuration(int)
QQuickStateActions createTransitionActions(QQuickStateActions &actions, QQmlProperties &modified, QObject *defaultTarget=nullptr)
QHash< QQmlProperty, QSmoothedAnimation * > activeAnimations
int duration() const override
\qmlproperty int QtQuick::SmoothedAnimation::duration
QAbstractAnimationJob * transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, QObject *defaultTarget=nullptr) override
QQuickSmoothedAnimation(QObject *parent=nullptr)
\qmltype SmoothedAnimation \instantiates QQuickSmoothedAnimation \inqmlmodule QtQuick\inherits Number...
void setVelocity(qreal)
\qmlproperty real QtQuick::SmoothedAnimation::velocity
Definition qset.h:18
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
QSmoothedAnimationTimer(QSmoothedAnimation *animation, QObject *parent=nullptr)
void updateState(QAbstractAnimationJob::State, QAbstractAnimationJob::State) override
void updateCurrentTime(int) override
void debugAnimation(QDebug d) const override
QQuickSmoothedAnimation::ReversingMode reversingMode
QSmoothedAnimation(QQuickSmoothedAnimationPrivate *=nullptr)
int duration() const override
\inmodule QtCore
Definition qtimer.h:20
void setSingleShot(bool singleShot)
Definition qtimer.cpp:580
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:208
void setInterval(int msec)
Definition qtimer.cpp:607
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
Definition qtimer.cpp:156
void stop()
Stops the timer.
Definition qtimer.cpp:226
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
direction
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
static jboolean copy(JNIEnv *, jobject)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
int qCeil(T v)
Definition qmath.h:36
static const QMetaObjectPrivate * priv(const uint *data)
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLuint end
GLenum target
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean invert
Definition qopenglext.h:226
#define DELAY_STOP_TIMER_INTERVAL
#define a1
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
MyCustomStruct c2
QPropertyAnimation animation
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent