Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qvariantanimation.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
4#include "qvariantanimation.h"
6
7#include <QtCore/qrect.h>
8#include <QtCore/qline.h>
9#include <QtCore/qmutex.h>
10#include <QtCore/private/qlocking_p.h>
11
12#include <algorithm>
13
15
111
113{
114 return p1.first < p2.first;
115}
116
117static QVariant defaultInterpolator(const void *, const void *, qreal)
118{
119 return QVariant();
120}
121
122template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress)
123{
124 QRect ret;
125 ret.setCoords(_q_interpolate(f.left(), t.left(), progress),
126 _q_interpolate(f.top(), t.top(), progress),
127 _q_interpolate(f.right(), t.right(), progress),
128 _q_interpolate(f.bottom(), t.bottom(), progress));
129 return ret;
130}
131
132template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress)
133{
134 qreal x1, y1, w1, h1;
135 f.getRect(&x1, &y1, &w1, &h1);
136 qreal x2, y2, w2, h2;
137 t.getRect(&x2, &y2, &w2, &h2);
138 return QRectF(_q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress),
139 _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress));
140}
141
142template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress)
143{
144 return QLine( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
145}
146
147template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress)
148{
149 return QLineF( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress));
150}
151
153{ }
154
156{
157 auto type = QMetaType(t);
158 //this ensures that all the keyValues are of type t
159 for (int i = 0; i < keyValues.size(); ++i) {
160 QVariantAnimation::KeyValue &pair = keyValues[i];
161 pair.second.convert(type);
162 }
163 //we also need update to the current interval if needed
164 currentInterval.start.second.convert(type);
165 currentInterval.end.second.convert(type);
166
167 //... and the interpolator
169}
170
172{
173 int type = currentInterval.start.second.userType();
174 if (type == currentInterval.end.second.userType())
176 else
177 interpolator = nullptr;
178
179 //we make sure that the interpolator is always set to something
180 if (!interpolator)
182}
183
191{
192 // can't interpolate if we don't have at least 2 values
193 if ((keyValues.size() + (defaultStartEndValue.isValid() ? 1 : 0)) < 2)
194 return;
195
196 const qreal endProgress = (direction == QAbstractAnimation::Forward) ? qreal(1) : qreal(0);
197 const qreal progress = easing.value().valueForProgress(
198 duration == 0 ? endProgress : qreal(currentTime) / qreal(duration));
199
200 //0 and 1 are still the boundaries
201 if (force || (currentInterval.start.first > 0 && progress < currentInterval.start.first)
202 || (currentInterval.end.first < 1 && progress > currentInterval.end.first)) {
203 //let's update currentInterval
204 QVariantAnimation::KeyValues::const_iterator it = std::lower_bound(keyValues.constBegin(),
205 keyValues.constEnd(),
206 qMakePair(progress, QVariant()),
208 if (it == keyValues.constBegin()) {
209 //the item pointed to by it is the start element in the range
210 if (it->first == 0 && keyValues.size() > 1) {
211 currentInterval.start = *it;
212 currentInterval.end = *(it+1);
213 } else {
215 currentInterval.end = *it;
216 }
217 } else if (it == keyValues.constEnd()) {
218 --it; //position the iterator on the last item
219 if (it->first == 1 && keyValues.size() > 1) {
220 //we have an end value (item with progress = 1)
221 currentInterval.start = *(it-1);
222 currentInterval.end = *it;
223 } else {
224 //we use the default end value here
225 currentInterval.start = *it;
227 }
228 } else {
229 currentInterval.start = *(it-1);
230 currentInterval.end = *it;
231 }
232
233 // update all the values of the currentInterval
235 }
237}
238
240{
242
243 const qreal startProgress = currentInterval.start.first;
244 const qreal endProgress = currentInterval.end.first;
245 const qreal localProgress =
246 qIsNull(progress - startProgress) ? 0.0 // avoid 0/0 below
247 /* else */ : (progress - startProgress) / (endProgress - startProgress);
248
249 QVariant ret = q->interpolated(currentInterval.start.second,
250 currentInterval.end.second,
251 localProgress);
253 q->updateCurrentValue(currentValue);
254 Q_CONSTINIT static QBasicAtomicInt changedSignalIndex = Q_BASIC_ATOMIC_INITIALIZER(0);
255 if (!changedSignalIndex.loadRelaxed()) {
256 //we keep the mask so that we emit valueChanged only when needed (for performance reasons)
257 changedSignalIndex.testAndSetRelaxed(0, signalIndex("valueChanged(QVariant)"));
258 }
259 if (isSignalConnected(changedSignalIndex.loadRelaxed()) && currentValue != ret) {
260 //the value has changed
261 emit q->valueChanged(currentValue);
262 }
263}
264
266{
268 std::lower_bound(keyValues.constBegin(), keyValues.constEnd(), qMakePair(step, QVariant()), animationValueLessThan);
269 if (result != keyValues.constEnd() && !animationValueLessThan(qMakePair(step, QVariant()), *result))
270 return result->second;
271
272 return QVariant();
273}
274
276{
277 if (step < qreal(0.0) || step > qreal(1.0)) {
278 qWarning("QVariantAnimation::setValueAt: invalid step = %f", step);
279 return;
280 }
281
283
284 QVariantAnimation::KeyValues::iterator result = std::lower_bound(keyValues.begin(), keyValues.end(), pair, animationValueLessThan);
285 if (result == keyValues.end() || result->first != step) {
286 keyValues.insert(result, pair);
287 } else {
288 if (value.isValid())
289 result->second = value; // replaces the previous value
290 else
291 keyValues.erase(result); // removes the previous value
292 }
293
294 recalculateCurrentInterval(/*force=*/true);
295}
296
298{
300 recalculateCurrentInterval(/*force=*/true);
301}
302
308{
309}
310
315{
316}
317
322{
323}
324
348{
349 Q_D(const QVariantAnimation);
350 return d->easing;
351}
352
354{
356 const bool valueChanged = easing != d->easing;
357 d->easing = easing;
358 d->recalculateCurrentInterval();
359 if (valueChanged)
360 d->easing.notify();
361}
362
364{
366 return &d->easing;
367}
368
370Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators)
372
399void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType)
400{
401 // will override any existing interpolators
402 QInterpolatorVector *interpolators = registeredInterpolators();
403 // When built on solaris with GCC, the destructors can be called
404 // in such an order that we get here with interpolators == NULL,
405 // to continue causes the app to crash on exit with a SEGV
406 if (interpolators) {
407 const auto locker = qt_scoped_lock(registeredInterpolatorsMutex);
408 if (interpolationType >= interpolators->size())
409 interpolators->resize(interpolationType + 1);
410 interpolators->replace(interpolationType, func);
411 }
412}
413
414
415template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
416{
417 return reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void(*)()>(func));
418}
419
421{
422 {
423 QInterpolatorVector *interpolators = registeredInterpolators();
424 const auto locker = qt_scoped_lock(registeredInterpolatorsMutex);
426 if (interpolationType < interpolators->size()) {
427 ret = interpolators->at(interpolationType);
428 if (ret) return ret;
429 }
430 }
431
432 switch(interpolationType)
433 {
434 case QMetaType::Int:
435 return castToInterpolator(_q_interpolateVariant<int>);
436 case QMetaType::UInt:
437 return castToInterpolator(_q_interpolateVariant<uint>);
438 case QMetaType::Double:
439 return castToInterpolator(_q_interpolateVariant<double>);
440 case QMetaType::Float:
441 return castToInterpolator(_q_interpolateVariant<float>);
442 case QMetaType::QLine:
443 return castToInterpolator(_q_interpolateVariant<QLine>);
444 case QMetaType::QLineF:
445 return castToInterpolator(_q_interpolateVariant<QLineF>);
446 case QMetaType::QPoint:
447 return castToInterpolator(_q_interpolateVariant<QPoint>);
448 case QMetaType::QPointF:
449 return castToInterpolator(_q_interpolateVariant<QPointF>);
450 case QMetaType::QSize:
451 return castToInterpolator(_q_interpolateVariant<QSize>);
452 case QMetaType::QSizeF:
453 return castToInterpolator(_q_interpolateVariant<QSizeF>);
454 case QMetaType::QRect:
455 return castToInterpolator(_q_interpolateVariant<QRect>);
456 case QMetaType::QRectF:
457 return castToInterpolator(_q_interpolateVariant<QRectF>);
458 default:
459 return nullptr; //this type is not handled
460 }
461}
462
473{
474 Q_D(const QVariantAnimation);
475 return d->duration;
476}
477
479{
481 if (msecs < 0) {
482 qWarning("QVariantAnimation::setDuration: cannot set a negative duration");
483 return;
484 }
485 if (d->duration == msecs) {
486 d->duration.removeBindingUnlessInWrapper();
487 return;
488 }
489 d->duration = msecs;
490 d->recalculateCurrentInterval();
491 d->duration.notify();
492}
493
495{
497 return &d->duration;
498}
499
512{
513 return keyValueAt(0);
514}
515
517{
519}
520
530{
531 return keyValueAt(1);
532}
533
535{
537}
538
539
548{
549 return d_func()->valueAt(step);
550}
551
570{
571 d_func()->setValueAt(step, value);
572}
573
580{
581 return d_func()->keyValues;
582}
583
591{
593 d->keyValues = keyValues;
594 std::sort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan);
595 d->recalculateCurrentInterval(/*force=*/true);
596}
597
617{
618 Q_D(const QVariantAnimation);
619 if (!d->currentValue.isValid())
620 const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval();
621 return d->currentValue;
622}
623
628{
630}
631
637{
638 Q_UNUSED(oldState);
640}
641
662QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
663{
664 return d_func()->interpolator(from.constData(), to.constData(), progress);
665}
666
671{
672 d_func()->recalculateCurrentInterval();
673}
674
676
677#include "moc_qvariantanimation.cpp"
State
This enum describes the state of the animation.
bool event(QEvent *event) override
\reimp
\inmodule QtCore
Definition qproperty.h:809
\inmodule QtCore
qreal valueForProgress(qreal progress) const
Return the effective progress for the easing curve at progress.
\inmodule QtCore
Definition qcoreevent.h:45
\inmodule QtCore
Definition qline.h:182
\inmodule QtCore
Definition qline.h:18
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void replace(qsizetype i, parameter_type t)
Definition qlist.h:526
void resize(qsizetype size)
Definition qlist.h:392
\inmodule QtCore
Definition qmetatype.h:320
\inmodule QtCore
Definition qmutex.h:285
bool isSignalConnected(uint signalIdx, bool checkDeclarative=true) const
Definition qobject.cpp:450
\inmodule QtCore
Definition qobject.h:90
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtCore\reentrant
Definition qrect.h:30
qsizetype size() const
Definition qset.h:50
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
void setCurrentValueForProgress(const qreal progress)
void recalculateCurrentInterval(bool force=false)
Q_OBJECT_COMPAT_PROPERTY(QVariantAnimationPrivate, int, duration, &QVariantAnimationPrivate::setDuration) QVariantAnimation QVariantAnimation::Interpolator interpolator
void setValueAt(qreal, const QVariant &)
struct QVariantAnimationPrivate::@3 currentInterval
QVariant valueAt(qreal step) const
void setDefaultStartEndValue(const QVariant &value)
static Q_CORE_EXPORT QVariantAnimation::Interpolator getInterpolator(int interpolationType)
\inmodule QtCore
int duration
the duration of the animation
KeyValues keyValues() const
Returns the key frames of this animation.
void setStartValue(const QVariant &value)
void setEasingCurve(const QEasingCurve &easing)
void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override
\reimp
QVariant(* Interpolator)(const void *from, const void *to, qreal progress)
QEasingCurve easingCurve
the easing curve of the animation
QVariant currentValue
the current value of the animation.
virtual void updateCurrentValue(const QVariant &value)
This virtual function is called every time the animation's current value changes.
QVariant keyValueAt(qreal step) const
Returns the key frame value for the given step.
void setKeyValues(const KeyValues &values)
Replaces the current set of key frames with the given keyValues.
QPair< qreal, QVariant > KeyValue
This is a typedef for QPair<qreal, QVariant>.
void valueChanged(const QVariant &value)
QVariantAnimation emits this signal whenever the current value changes.
QVariantAnimation(QObject *parent=nullptr)
Construct a QVariantAnimation object.
QVariant startValue
the optional start value of the animation
QBindable< int > bindableDuration()
void updateCurrentTime(int) override
\reimp
void setDuration(int msecs)
virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const
This virtual function returns the linear interpolation between variants from and to,...
QVariant endValue
the end value of the animation
bool event(QEvent *event) override
\reimp
void setKeyValueAt(qreal step, const QVariant &value)
Creates a key frame at the given step with the given value.
QBindable< QEasingCurve > bindableEasingCurve()
~QVariantAnimation()
Destroys the animation.
void setEndValue(const QVariant &value)
\inmodule QtCore
Definition qvariant.h:64
bool isValid() const
Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns fal...
Definition qvariant.h:707
const void * constData() const
Definition qvariant.h:446
QPixmap p2
QPixmap p1
[0]
qSwap(pi, e)
QSet< QString >::iterator it
auto signalIndex
direction
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
Combined button and popup list for selecting options.
#define Q_BASIC_ATOMIC_INITIALIZER(a)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qIsNull(qfloat16 f) noexcept
Definition qfloat16.h:308
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:162
return ret
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLfloat GLfloat GLfloat x1
GLfloat GLfloat f
GLenum type
struct _cl_event * event
GLenum func
Definition qopenglext.h:663
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
static double currentTime()
Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress)
static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2)
static QVariant defaultInterpolator(const void *, const void *, qreal)
static Q_CONSTINIT QBasicMutex registeredInterpolatorsMutex
static QVariantAnimation::Interpolator castToInterpolator(QVariant(*func)(const T &from, const T &to, qreal progress))
QList< QVariantAnimation::Interpolator > QInterpolatorVector
QEasingCurve easing(QEasingCurve::InOutQuad)
[typedef]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent