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