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" |
5 | #include "qvariantanimation_p.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 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | /*! |
17 | \class QVariantAnimation |
18 | \inmodule QtCore |
19 | \ingroup animation |
20 | \brief The QVariantAnimation class provides a base class for animations. |
21 | \since 4.6 |
22 | |
23 | This class is part of \l{The Animation Framework}. It serves as a |
24 | base class for property and item animations, with functions for |
25 | shared functionality. |
26 | |
27 | The class performs interpolation over |
28 | \l{QVariant}s, but leaves using the interpolated values to its |
29 | subclasses. Currently, Qt provides QPropertyAnimation, which |
30 | animates Qt \l{Qt's Property System}{properties}. See the |
31 | QPropertyAnimation class description if you wish to animate such |
32 | properties. |
33 | |
34 | You can then set start and end values for the property by calling |
35 | setStartValue() and setEndValue(), and finally call start() to |
36 | start the animation. QVariantAnimation will interpolate the |
37 | property of the target object and emit valueChanged(). To react to |
38 | a change in the current value you have to reimplement the |
39 | updateCurrentValue() virtual function or connect to said signal. |
40 | |
41 | It is also possible to set values at specified steps situated |
42 | between the start and end value. The interpolation will then |
43 | touch these points at the specified steps. Note that the start and |
44 | end values are defined as the key values at 0.0 and 1.0. |
45 | |
46 | There are two ways to affect how QVariantAnimation interpolates |
47 | the values. You can set an easing curve by calling |
48 | setEasingCurve(), and configure the duration by calling |
49 | setDuration(). You can change how the \l{QVariant}s are interpolated |
50 | by creating a subclass of QVariantAnimation, and reimplementing |
51 | the virtual interpolated() function. |
52 | |
53 | Subclassing QVariantAnimation can be an alternative if you have |
54 | \l{QVariant}s that you do not wish to declare as Qt properties. |
55 | Note, however, that you in most cases will be better off declaring |
56 | your QVariant as a property. |
57 | |
58 | Not all QVariant types are supported. Below is a list of currently |
59 | supported QVariant types: |
60 | |
61 | \list |
62 | \li \l{QMetaType::}{Int} |
63 | \li \l{QMetaType::}{UInt} |
64 | \li \l{QMetaType::}{Double} |
65 | \li \l{QMetaType::}{Float} |
66 | \li \l{QMetaType::}{QLine} |
67 | \li \l{QMetaType::}{QLineF} |
68 | \li \l{QMetaType::}{QPoint} |
69 | \li \l{QMetaType::}{QPointF} |
70 | \li \l{QMetaType::}{QSize} |
71 | \li \l{QMetaType::}{QSizeF} |
72 | \li \l{QMetaType::}{QRect} |
73 | \li \l{QMetaType::}{QRectF} |
74 | \li \l{QMetaType::}{QColor} |
75 | \endlist |
76 | |
77 | If you need to interpolate other variant types, including custom |
78 | types, you have to implement interpolation for these yourself. |
79 | To do this, you can register an interpolator function for a given |
80 | type. This function takes 3 parameters: the start value, the end value, |
81 | and the current progress. |
82 | |
83 | Example: |
84 | \snippet code/src_corelib_animation_qvariantanimation.cpp 0 |
85 | |
86 | Another option is to reimplement interpolated(), which returns |
87 | interpolation values for the value being interpolated. |
88 | |
89 | \omit We need some snippets around here. \endomit |
90 | |
91 | \sa QPropertyAnimation, QAbstractAnimation, {The Animation Framework} |
92 | */ |
93 | |
94 | /*! |
95 | \fn void QVariantAnimation::valueChanged(const QVariant &value) |
96 | |
97 | QVariantAnimation emits this signal whenever the current \a value changes. |
98 | |
99 | \sa currentValue, startValue, endValue |
100 | */ |
101 | |
102 | /*! |
103 | This virtual function is called every time the animation's current |
104 | value changes. The \a value argument is the new current value. |
105 | |
106 | The base class implementation does nothing. |
107 | |
108 | \sa currentValue |
109 | */ |
110 | void QVariantAnimation::updateCurrentValue(const QVariant &) {} |
111 | |
112 | static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2) |
113 | { |
114 | return p1.first < p2.first; |
115 | } |
116 | |
117 | static QVariant defaultInterpolator(const void *, const void *, qreal) |
118 | { |
119 | return QVariant(); |
120 | } |
121 | |
122 | template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress) |
123 | { |
124 | QRect ret; |
125 | ret.setCoords(xp1: _q_interpolate(f: f.left(), t: t.left(), progress), |
126 | yp1: _q_interpolate(f: f.top(), t: t.top(), progress), |
127 | xp2: _q_interpolate(f: f.right(), t: t.right(), progress), |
128 | yp2: _q_interpolate(f: f.bottom(), t: t.bottom(), progress)); |
129 | return ret; |
130 | } |
131 | |
132 | template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress) |
133 | { |
134 | qreal x1, y1, w1, h1; |
135 | f.getRect(ax: &x1, ay: &y1, aaw: &w1, aah: &h1); |
136 | qreal x2, y2, w2, h2; |
137 | t.getRect(ax: &x2, ay: &y2, aaw: &w2, aah: &h2); |
138 | return QRectF(_q_interpolate(f: x1, t: x2, progress), _q_interpolate(f: y1, t: y2, progress), |
139 | _q_interpolate(f: w1, t: w2, progress), _q_interpolate(f: h1, t: h2, progress)); |
140 | } |
141 | |
142 | template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress) |
143 | { |
144 | return QLine( _q_interpolate(f: f.p1(), t: t.p1(), progress), _q_interpolate(f: f.p2(), t: t.p2(), progress)); |
145 | } |
146 | |
147 | template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress) |
148 | { |
149 | return QLineF( _q_interpolate(f: f.p1(), t: t.p1(), progress), _q_interpolate(f: f.p2(), t: t.p2(), progress)); |
150 | } |
151 | |
152 | QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), interpolator(&defaultInterpolator) |
153 | { } |
154 | |
155 | void QVariantAnimationPrivate::convertValues(int t) |
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 |
168 | updateInterpolator(); |
169 | } |
170 | |
171 | void QVariantAnimationPrivate::updateInterpolator() |
172 | { |
173 | int type = currentInterval.start.second.userType(); |
174 | if (type == currentInterval.end.second.userType()) |
175 | interpolator = getInterpolator(interpolationType: type); |
176 | else |
177 | interpolator = nullptr; |
178 | |
179 | //we make sure that the interpolator is always set to something |
180 | if (!interpolator) |
181 | interpolator = &defaultInterpolator; |
182 | } |
183 | |
184 | /*! |
185 | \internal |
186 | The goal of this function is to update the currentInterval member. As a consequence, we also |
187 | need to update the currentValue. |
188 | Set \a force to true to always recalculate the interval. |
189 | */ |
190 | void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/) |
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 | progress: 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(first: keyValues.constBegin(), |
205 | last: keyValues.constEnd(), |
206 | val: qMakePair(value1: progress, value2: QVariant()), |
207 | comp: animationValueLessThan); |
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 { |
214 | currentInterval.start = qMakePair(value1: qreal(0), value2&: defaultStartEndValue); |
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; |
226 | currentInterval.end = qMakePair(value1: qreal(1), value2&: defaultStartEndValue); |
227 | } |
228 | } else { |
229 | currentInterval.start = *(it-1); |
230 | currentInterval.end = *it; |
231 | } |
232 | |
233 | // update all the values of the currentInterval |
234 | updateInterpolator(); |
235 | } |
236 | setCurrentValueForProgress(progress); |
237 | } |
238 | |
239 | void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress) |
240 | { |
241 | Q_Q(QVariantAnimation); |
242 | |
243 | const qreal startProgress = currentInterval.start.first; |
244 | const qreal endProgress = currentInterval.end.first; |
245 | const qreal localProgress = |
246 | qIsNull(d: progress - startProgress) ? 0.0 // avoid 0/0 below |
247 | /* else */ : (progress - startProgress) / (endProgress - startProgress); |
248 | |
249 | QVariant ret = q->interpolated(from: currentInterval.start.second, |
250 | to: currentInterval.end.second, |
251 | progress: localProgress); |
252 | qSwap(value1&: currentValue, value2&: ret); |
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(expectedValue: 0, newValue: signalIndex(signalName: "valueChanged(QVariant)" )); |
258 | } |
259 | if (isSignalConnected(signalIdx: changedSignalIndex.loadRelaxed()) && currentValue != ret) { |
260 | //the value has changed |
261 | emit q->valueChanged(value: currentValue); |
262 | } |
263 | } |
264 | |
265 | QVariant QVariantAnimationPrivate::valueAt(qreal step) const |
266 | { |
267 | QVariantAnimation::KeyValues::const_iterator result = |
268 | std::lower_bound(first: keyValues.constBegin(), last: keyValues.constEnd(), val: qMakePair(value1&: step, value2: QVariant()), comp: animationValueLessThan); |
269 | if (result != keyValues.constEnd() && !animationValueLessThan(p1: qMakePair(value1&: step, value2: QVariant()), p2: *result)) |
270 | return result->second; |
271 | |
272 | return QVariant(); |
273 | } |
274 | |
275 | void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value) |
276 | { |
277 | if (step < qreal(0.0) || step > qreal(1.0)) { |
278 | qWarning(msg: "QVariantAnimation::setValueAt: invalid step = %f" , step); |
279 | return; |
280 | } |
281 | |
282 | QVariantAnimation::KeyValue pair(step, value); |
283 | |
284 | QVariantAnimation::KeyValues::iterator result = std::lower_bound(first: keyValues.begin(), last: keyValues.end(), val: pair, comp: animationValueLessThan); |
285 | if (result == keyValues.end() || result->first != step) { |
286 | keyValues.insert(before: result, t: pair); |
287 | } else { |
288 | if (value.isValid()) |
289 | result->second = value; // replaces the previous value |
290 | else |
291 | keyValues.erase(pos: result); // removes the previous value |
292 | } |
293 | |
294 | recalculateCurrentInterval(/*force=*/true); |
295 | } |
296 | |
297 | void QVariantAnimationPrivate::setDefaultStartEndValue(const QVariant &value) |
298 | { |
299 | defaultStartEndValue = value; |
300 | recalculateCurrentInterval(/*force=*/true); |
301 | } |
302 | |
303 | /*! |
304 | Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's |
305 | constructor. |
306 | */ |
307 | QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent) |
308 | { |
309 | } |
310 | |
311 | /*! |
312 | \internal |
313 | */ |
314 | QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent) |
315 | { |
316 | } |
317 | |
318 | /*! |
319 | Destroys the animation. |
320 | */ |
321 | QVariantAnimation::~QVariantAnimation() |
322 | { |
323 | } |
324 | |
325 | /*! |
326 | \property QVariantAnimation::easingCurve |
327 | \brief the easing curve of the animation |
328 | |
329 | This property defines the easing curve of the animation. By |
330 | default, a linear easing curve is used, resulting in linear |
331 | interpolation. Other curves are provided, for instance, |
332 | QEasingCurve::InCirc, which provides a circular entry curve. |
333 | Another example is QEasingCurve::InOutElastic, which provides an |
334 | elastic effect on the values of the interpolated variant. |
335 | |
336 | QVariantAnimation will use the QEasingCurve::valueForProgress() to |
337 | transform the "normalized progress" (currentTime / totalDuration) |
338 | of the animation into the effective progress actually |
339 | used by the animation. It is this effective progress that will be |
340 | the progress when interpolated() is called. Also, the steps in the |
341 | keyValues are referring to this effective progress. |
342 | |
343 | The easing curve is used with the interpolator, the interpolated() |
344 | virtual function, and the animation's duration to control how the |
345 | current value changes as the animation progresses. |
346 | */ |
347 | QEasingCurve QVariantAnimation::easingCurve() const |
348 | { |
349 | Q_D(const QVariantAnimation); |
350 | return d->easing; |
351 | } |
352 | |
353 | void QVariantAnimation::setEasingCurve(const QEasingCurve &easing) |
354 | { |
355 | Q_D(QVariantAnimation); |
356 | d->easing.removeBindingUnlessInWrapper(); |
357 | const bool valueChanged = easing != d->easing.valueBypassingBindings(); |
358 | d->easing.setValueBypassingBindings(easing); |
359 | d->recalculateCurrentInterval(); |
360 | if (valueChanged) |
361 | d->easing.notify(); |
362 | } |
363 | |
364 | QBindable<QEasingCurve> QVariantAnimation::bindableEasingCurve() |
365 | { |
366 | Q_D(QVariantAnimation); |
367 | return &d->easing; |
368 | } |
369 | |
370 | typedef QList<QVariantAnimation::Interpolator> QInterpolatorVector; |
371 | Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators) |
372 | Q_CONSTINIT static QBasicMutex registeredInterpolatorsMutex; |
373 | |
374 | /*! |
375 | \fn template <typename T> void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) |
376 | \relates QVariantAnimation |
377 | \threadsafe |
378 | |
379 | Registers a custom interpolator \a func for the template type \c{T}. |
380 | The interpolator has to be registered before the animation is constructed. |
381 | To unregister (and use the default interpolator) set \a func to \nullptr. |
382 | */ |
383 | |
384 | /*! |
385 | \internal |
386 | \typedef QVariantAnimation::Interpolator |
387 | |
388 | This is a typedef for a pointer to a function with the following |
389 | signature: |
390 | \snippet code/src_corelib_animation_qvariantanimation.cpp 1 |
391 | |
392 | */ |
393 | |
394 | /*! |
395 | * \internal |
396 | * Registers a custom interpolator \a func for the specific \a interpolationType. |
397 | * The interpolator has to be registered before the animation is constructed. |
398 | * To unregister (and use the default interpolator) set \a func to \nullptr. |
399 | */ |
400 | void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType) |
401 | { |
402 | // will override any existing interpolators |
403 | QInterpolatorVector *interpolators = registeredInterpolators(); |
404 | // When built on solaris with GCC, the destructors can be called |
405 | // in such an order that we get here with interpolators == NULL, |
406 | // to continue causes the app to crash on exit with a SEGV |
407 | if (interpolators) { |
408 | const auto locker = qt_scoped_lock(mutex&: registeredInterpolatorsMutex); |
409 | if (interpolationType >= interpolators->size()) |
410 | interpolators->resize(size: interpolationType + 1); |
411 | interpolators->replace(i: interpolationType, t: func); |
412 | } |
413 | } |
414 | |
415 | |
416 | template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) |
417 | { |
418 | return reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void(*)()>(func)); |
419 | } |
420 | |
421 | QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType) |
422 | { |
423 | { |
424 | QInterpolatorVector *interpolators = registeredInterpolators(); |
425 | const auto locker = qt_scoped_lock(mutex&: registeredInterpolatorsMutex); |
426 | QVariantAnimation::Interpolator ret = nullptr; |
427 | if (interpolationType < interpolators->size()) { |
428 | ret = interpolators->at(i: interpolationType); |
429 | if (ret) return ret; |
430 | } |
431 | } |
432 | |
433 | switch(interpolationType) |
434 | { |
435 | case QMetaType::Int: |
436 | return castToInterpolator(func: _q_interpolateVariant<int>); |
437 | case QMetaType::UInt: |
438 | return castToInterpolator(func: _q_interpolateVariant<uint>); |
439 | case QMetaType::Double: |
440 | return castToInterpolator(func: _q_interpolateVariant<double>); |
441 | case QMetaType::Float: |
442 | return castToInterpolator(func: _q_interpolateVariant<float>); |
443 | case QMetaType::QLine: |
444 | return castToInterpolator(func: _q_interpolateVariant<QLine>); |
445 | case QMetaType::QLineF: |
446 | return castToInterpolator(func: _q_interpolateVariant<QLineF>); |
447 | case QMetaType::QPoint: |
448 | return castToInterpolator(func: _q_interpolateVariant<QPoint>); |
449 | case QMetaType::QPointF: |
450 | return castToInterpolator(func: _q_interpolateVariant<QPointF>); |
451 | case QMetaType::QSize: |
452 | return castToInterpolator(func: _q_interpolateVariant<QSize>); |
453 | case QMetaType::QSizeF: |
454 | return castToInterpolator(func: _q_interpolateVariant<QSizeF>); |
455 | case QMetaType::QRect: |
456 | return castToInterpolator(func: _q_interpolateVariant<QRect>); |
457 | case QMetaType::QRectF: |
458 | return castToInterpolator(func: _q_interpolateVariant<QRectF>); |
459 | default: |
460 | return nullptr; //this type is not handled |
461 | } |
462 | } |
463 | |
464 | /*! |
465 | \property QVariantAnimation::duration |
466 | \brief the duration of the animation |
467 | |
468 | This property describes the duration in milliseconds of the |
469 | animation. The default duration is 250 milliseconds. |
470 | |
471 | \sa QAbstractAnimation::duration() |
472 | */ |
473 | int QVariantAnimation::duration() const |
474 | { |
475 | Q_D(const QVariantAnimation); |
476 | return d->duration; |
477 | } |
478 | |
479 | void QVariantAnimation::setDuration(int msecs) |
480 | { |
481 | Q_D(QVariantAnimation); |
482 | if (msecs < 0) { |
483 | qWarning(msg: "QVariantAnimation::setDuration: cannot set a negative duration" ); |
484 | return; |
485 | } |
486 | d->duration.removeBindingUnlessInWrapper(); |
487 | if (d->duration.valueBypassingBindings() != msecs) { |
488 | d->duration.setValueBypassingBindings(msecs); |
489 | d->recalculateCurrentInterval(); |
490 | d->duration.notify(); |
491 | } |
492 | } |
493 | |
494 | QBindable<int> QVariantAnimation::bindableDuration() |
495 | { |
496 | Q_D(QVariantAnimation); |
497 | return &d->duration; |
498 | } |
499 | |
500 | /*! |
501 | \property QVariantAnimation::startValue |
502 | \brief the optional start value of the animation |
503 | |
504 | This property describes the optional start value of the animation. If |
505 | omitted, or if a null QVariant is assigned as the start value, the |
506 | animation will use the current position of the end when the animation |
507 | is started. |
508 | |
509 | \sa endValue |
510 | */ |
511 | QVariant QVariantAnimation::startValue() const |
512 | { |
513 | return keyValueAt(step: 0); |
514 | } |
515 | |
516 | void QVariantAnimation::setStartValue(const QVariant &value) |
517 | { |
518 | setKeyValueAt(step: 0, value); |
519 | } |
520 | |
521 | /*! |
522 | \property QVariantAnimation::endValue |
523 | \brief the end value of the animation |
524 | |
525 | This property describes the end value of the animation. |
526 | |
527 | \sa startValue |
528 | */ |
529 | QVariant QVariantAnimation::endValue() const |
530 | { |
531 | return keyValueAt(step: 1); |
532 | } |
533 | |
534 | void QVariantAnimation::setEndValue(const QVariant &value) |
535 | { |
536 | setKeyValueAt(step: 1, value); |
537 | } |
538 | |
539 | |
540 | /*! |
541 | Returns the key frame value for the given \a step. The given \a step |
542 | must be in the range 0 to 1. If there is no KeyValue for \a step, |
543 | it returns an invalid QVariant. |
544 | |
545 | \sa keyValues(), setKeyValueAt() |
546 | */ |
547 | QVariant QVariantAnimation::keyValueAt(qreal step) const |
548 | { |
549 | return d_func()->valueAt(step); |
550 | } |
551 | |
552 | /*! |
553 | \typedef QVariantAnimation::KeyValue |
554 | |
555 | This is a typedef for QPair<qreal, QVariant>. |
556 | */ |
557 | /*! |
558 | \typedef QVariantAnimation::KeyValues |
559 | |
560 | This is a typedef for QList<KeyValue> |
561 | */ |
562 | |
563 | /*! |
564 | Creates a key frame at the given \a step with the given \a value. |
565 | The given \a step must be in the range 0 to 1. |
566 | |
567 | \sa setKeyValues(), keyValueAt() |
568 | */ |
569 | void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value) |
570 | { |
571 | d_func()->setValueAt(step, value); |
572 | } |
573 | |
574 | /*! |
575 | Returns the key frames of this animation. |
576 | |
577 | \sa keyValueAt(), setKeyValues() |
578 | */ |
579 | QVariantAnimation::KeyValues QVariantAnimation::keyValues() const |
580 | { |
581 | return d_func()->keyValues; |
582 | } |
583 | |
584 | /*! |
585 | Replaces the current set of key frames with the given \a keyValues. |
586 | the step of the key frames must be in the range 0 to 1. |
587 | |
588 | \sa keyValues(), keyValueAt() |
589 | */ |
590 | void QVariantAnimation::setKeyValues(const KeyValues &keyValues) |
591 | { |
592 | Q_D(QVariantAnimation); |
593 | d->keyValues = keyValues; |
594 | std::sort(first: d->keyValues.begin(), last: d->keyValues.end(), comp: animationValueLessThan); |
595 | d->recalculateCurrentInterval(/*force=*/true); |
596 | } |
597 | |
598 | /*! |
599 | \property QVariantAnimation::currentValue |
600 | \brief the current value of the animation. |
601 | |
602 | This property describes the current value; an interpolated value |
603 | between the \l{startValue}{start value} and the \l{endValue}{end |
604 | value}, using the current time for progress. The value itself is |
605 | obtained from interpolated(), which is called repeatedly as the |
606 | animation is running. |
607 | |
608 | QVariantAnimation calls the virtual updateCurrentValue() function |
609 | when the current value changes. This is particularly useful for |
610 | subclasses that need to track updates. For example, |
611 | QPropertyAnimation uses this function to animate Qt \l{Qt's |
612 | Property System}{properties}. |
613 | |
614 | \sa startValue, endValue |
615 | */ |
616 | QVariant QVariantAnimation::currentValue() const |
617 | { |
618 | Q_D(const QVariantAnimation); |
619 | if (!d->currentValue.isValid()) |
620 | const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval(); |
621 | return d->currentValue; |
622 | } |
623 | |
624 | /*! |
625 | \reimp |
626 | */ |
627 | bool QVariantAnimation::event(QEvent *event) |
628 | { |
629 | return QAbstractAnimation::event(event); |
630 | } |
631 | |
632 | /*! |
633 | \reimp |
634 | */ |
635 | void QVariantAnimation::updateState(QAbstractAnimation::State newState, |
636 | QAbstractAnimation::State oldState) |
637 | { |
638 | Q_UNUSED(oldState); |
639 | Q_UNUSED(newState); |
640 | } |
641 | |
642 | /*! |
643 | |
644 | This virtual function returns the linear interpolation between |
645 | variants \a from and \a to, at \a progress, usually a value |
646 | between 0 and 1. You can reimplement this function in a subclass |
647 | of QVariantAnimation to provide your own interpolation algorithm. |
648 | |
649 | Note that in order for the interpolation to work with a |
650 | QEasingCurve that return a value smaller than 0 or larger than 1 |
651 | (such as QEasingCurve::InBack) you should make sure that it can |
652 | extrapolate. If the semantic of the datatype does not allow |
653 | extrapolation this function should handle that gracefully. |
654 | |
655 | You should call the QVariantAnimation implementation of this |
656 | function if you want your class to handle the types already |
657 | supported by Qt (see class QVariantAnimation description for a |
658 | list of supported types). |
659 | |
660 | \sa QEasingCurve |
661 | */ |
662 | QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const |
663 | { |
664 | return d_func()->interpolator(from.constData(), to.constData(), progress); |
665 | } |
666 | |
667 | /*! |
668 | \reimp |
669 | */ |
670 | void QVariantAnimation::updateCurrentTime(int) |
671 | { |
672 | d_func()->recalculateCurrentInterval(); |
673 | } |
674 | |
675 | QT_END_NAMESPACE |
676 | |
677 | #include "moc_qvariantanimation.cpp" |
678 | |