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
50QT_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*/
146void QVariantAnimation::updateCurrentValue(const QVariant &) {}
147
148static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2)
149{
150 return p1.first < p2.first;
151}
152
153static QVariant defaultInterpolator(const void *, const void *, qreal)
154{
155 return QVariant();
156}
157
158template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress)
159{
160 QRect ret;
161 ret.setCoords(xp1: _q_interpolate(f: f.left(), t: t.left(), progress),
162 yp1: _q_interpolate(f: f.top(), t: t.top(), progress),
163 xp2: _q_interpolate(f: f.right(), t: t.right(), progress),
164 yp2: _q_interpolate(f: f.bottom(), t: t.bottom(), progress));
165 return ret;
166}
167
168template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress)
169{
170 qreal x1, y1, w1, h1;
171 f.getRect(ax: &x1, ay: &y1, aaw: &w1, aah: &h1);
172 qreal x2, y2, w2, h2;
173 t.getRect(ax: &x2, ay: &y2, aaw: &w2, aah: &h2);
174 return QRectF(_q_interpolate(f: x1, t: x2, progress), _q_interpolate(f: y1, t: y2, progress),
175 _q_interpolate(f: w1, t: w2, progress), _q_interpolate(f: h1, t: h2, progress));
176}
177
178template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress)
179{
180 return QLine( _q_interpolate(f: f.p1(), t: t.p1(), progress), _q_interpolate(f: f.p2(), t: t.p2(), progress));
181}
182
183template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress)
184{
185 return QLineF( _q_interpolate(f: f.p1(), t: t.p1(), progress), _q_interpolate(f: f.p2(), t: t.p2(), progress));
186}
187
188QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), interpolator(&defaultInterpolator)
189{ }
190
191void 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(targetTypeId: t);
197 }
198 //we also need update to the current interval if needed
199 currentInterval.start.second.convert(targetTypeId: t);
200 currentInterval.end.second.convert(targetTypeId: t);
201
202 //... and the interpolator
203 updateInterpolator();
204}
205
206void QVariantAnimationPrivate::updateInterpolator()
207{
208 int type = currentInterval.start.second.userType();
209 if (type == currentInterval.end.second.userType())
210 interpolator = getInterpolator(interpolationType: 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*/
225void 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(progress: ((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(first: keyValues.constBegin(),
239 last: keyValues.constEnd(),
240 val: qMakePair(x: progress, y: QVariant()),
241 comp: 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(x: qreal(0), y: 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(x: qreal(1), y: 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
273void 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 =
280 qIsNull(d: progress - startProgress) ? 0.0 // avoid 0/0 below
281 /* else */ : (progress - startProgress) / (endProgress - startProgress);
282
283 QVariant ret = q->interpolated(from: currentInterval.start.second,
284 to: currentInterval.end.second,
285 progress: localProgress);
286 qSwap(value1&: currentValue, value2&: ret);
287 q->updateCurrentValue(currentValue);
288 static QBasicAtomicInt changedSignalIndex = Q_BASIC_ATOMIC_INITIALIZER(0);
289 if (!changedSignalIndex.loadRelaxed()) {
290 //we keep the mask so that we emit valueChanged only when needed (for performance reasons)
291 changedSignalIndex.testAndSetRelaxed(expectedValue: 0, newValue: signalIndex(signalName: "valueChanged(QVariant)"));
292 }
293 if (isSignalConnected(signalIdx: changedSignalIndex.loadRelaxed()) && currentValue != ret) {
294 //the value has changed
295 emit q->valueChanged(value: currentValue);
296 }
297}
298
299QVariant QVariantAnimationPrivate::valueAt(qreal step) const
300{
301 QVariantAnimation::KeyValues::const_iterator result =
302 std::lower_bound(first: keyValues.constBegin(), last: keyValues.constEnd(), val: qMakePair(x: step, y: QVariant()), comp: animationValueLessThan);
303 if (result != keyValues.constEnd() && !animationValueLessThan(p1: qMakePair(x: step, y: QVariant()), p2: *result))
304 return result->second;
305
306 return QVariant();
307}
308
309void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value)
310{
311 if (step < qreal(0.0) || step > qreal(1.0)) {
312 qWarning(msg: "QVariantAnimation::setValueAt: invalid step = %f", step);
313 return;
314 }
315
316 QVariantAnimation::KeyValue pair(step, value);
317
318 QVariantAnimation::KeyValues::iterator result = std::lower_bound(first: keyValues.begin(), last: keyValues.end(), val: pair, comp: animationValueLessThan);
319 if (result == keyValues.end() || result->first != step) {
320 keyValues.insert(before: result, x: pair);
321 } else {
322 if (value.isValid())
323 result->second = value; // replaces the previous value
324 else
325 keyValues.erase(pos: result); // removes the previous value
326 }
327
328 recalculateCurrentInterval(/*force=*/true);
329}
330
331void QVariantAnimationPrivate::setDefaultStartEndValue(const QVariant &value)
332{
333 defaultStartEndValue = value;
334 recalculateCurrentInterval(/*force=*/true);
335}
336
337/*!
338 Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's
339 constructor.
340*/
341QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent)
342{
343}
344
345/*!
346 \internal
347*/
348QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent)
349{
350}
351
352/*!
353 Destroys the animation.
354*/
355QVariantAnimation::~QVariantAnimation()
356{
357}
358
359/*!
360 \property QVariantAnimation::easingCurve
361 \brief the easing curve of the animation
362
363 This property defines the easing curve of the animation. By
364 default, a linear easing curve is used, resulting in linear
365 interpolation. Other curves are provided, for instance,
366 QEasingCurve::InCirc, which provides a circular entry curve.
367 Another example is QEasingCurve::InOutElastic, which provides an
368 elastic effect on the values of the interpolated variant.
369
370 QVariantAnimation will use the QEasingCurve::valueForProgress() to
371 transform the "normalized progress" (currentTime / totalDuration)
372 of the animation into the effective progress actually
373 used by the animation. It is this effective progress that will be
374 the progress when interpolated() is called. Also, the steps in the
375 keyValues are referring to this effective progress.
376
377 The easing curve is used with the interpolator, the interpolated()
378 virtual function, and the animation's duration to control how the
379 current value changes as the animation progresses.
380*/
381QEasingCurve QVariantAnimation::easingCurve() const
382{
383 Q_D(const QVariantAnimation);
384 return d->easing;
385}
386
387void QVariantAnimation::setEasingCurve(const QEasingCurve &easing)
388{
389 Q_D(QVariantAnimation);
390 d->easing = easing;
391 d->recalculateCurrentInterval();
392}
393
394typedef QVector<QVariantAnimation::Interpolator> QInterpolatorVector;
395Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators)
396static QBasicMutex registeredInterpolatorsMutex;
397
398/*!
399 \fn template <typename T> void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
400 \relates QVariantAnimation
401 \threadsafe
402
403 Registers a custom interpolator \a func for the template type \c{T}.
404 The interpolator has to be registered before the animation is constructed.
405 To unregister (and use the default interpolator) set \a func to \nullptr.
406 */
407
408/*!
409 \internal
410 \typedef QVariantAnimation::Interpolator
411
412 This is a typedef for a pointer to a function with the following
413 signature:
414 \snippet code/src_corelib_animation_qvariantanimation.cpp 1
415
416*/
417
418/*!
419 * \internal
420 * Registers a custom interpolator \a func for the specific \a interpolationType.
421 * The interpolator has to be registered before the animation is constructed.
422 * To unregister (and use the default interpolator) set \a func to \nullptr.
423 */
424void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType)
425{
426 // will override any existing interpolators
427 QInterpolatorVector *interpolators = registeredInterpolators();
428 // When built on solaris with GCC, the destructors can be called
429 // in such an order that we get here with interpolators == NULL,
430 // to continue causes the app to crash on exit with a SEGV
431 if (interpolators) {
432 const auto locker = qt_scoped_lock(mutex&: registeredInterpolatorsMutex);
433 if (int(interpolationType) >= interpolators->count())
434 interpolators->resize(size: int(interpolationType) + 1);
435 interpolators->replace(i: interpolationType, t: func);
436 }
437}
438
439
440template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
441{
442 return reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void(*)()>(func));
443}
444
445QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType)
446{
447 {
448 QInterpolatorVector *interpolators = registeredInterpolators();
449 const auto locker = qt_scoped_lock(mutex&: registeredInterpolatorsMutex);
450 QVariantAnimation::Interpolator ret = nullptr;
451 if (interpolationType < interpolators->count()) {
452 ret = interpolators->at(i: interpolationType);
453 if (ret) return ret;
454 }
455 }
456
457 switch(interpolationType)
458 {
459 case QMetaType::Int:
460 return castToInterpolator(func: _q_interpolateVariant<int>);
461 case QMetaType::UInt:
462 return castToInterpolator(func: _q_interpolateVariant<uint>);
463 case QMetaType::Double:
464 return castToInterpolator(func: _q_interpolateVariant<double>);
465 case QMetaType::Float:
466 return castToInterpolator(func: _q_interpolateVariant<float>);
467 case QMetaType::QLine:
468 return castToInterpolator(func: _q_interpolateVariant<QLine>);
469 case QMetaType::QLineF:
470 return castToInterpolator(func: _q_interpolateVariant<QLineF>);
471 case QMetaType::QPoint:
472 return castToInterpolator(func: _q_interpolateVariant<QPoint>);
473 case QMetaType::QPointF:
474 return castToInterpolator(func: _q_interpolateVariant<QPointF>);
475 case QMetaType::QSize:
476 return castToInterpolator(func: _q_interpolateVariant<QSize>);
477 case QMetaType::QSizeF:
478 return castToInterpolator(func: _q_interpolateVariant<QSizeF>);
479 case QMetaType::QRect:
480 return castToInterpolator(func: _q_interpolateVariant<QRect>);
481 case QMetaType::QRectF:
482 return castToInterpolator(func: _q_interpolateVariant<QRectF>);
483 default:
484 return nullptr; //this type is not handled
485 }
486}
487
488/*!
489 \property QVariantAnimation::duration
490 \brief the duration of the animation
491
492 This property describes the duration in milliseconds of the
493 animation. The default duration is 250 milliseconds.
494
495 \sa QAbstractAnimation::duration()
496 */
497int QVariantAnimation::duration() const
498{
499 Q_D(const QVariantAnimation);
500 return d->duration;
501}
502
503void QVariantAnimation::setDuration(int msecs)
504{
505 Q_D(QVariantAnimation);
506 if (msecs < 0) {
507 qWarning(msg: "QVariantAnimation::setDuration: cannot set a negative duration");
508 return;
509 }
510 if (d->duration == msecs)
511 return;
512 d->duration = msecs;
513 d->recalculateCurrentInterval();
514}
515
516/*!
517 \property QVariantAnimation::startValue
518 \brief the optional start value of the animation
519
520 This property describes the optional start value of the animation. If
521 omitted, or if a null QVariant is assigned as the start value, the
522 animation will use the current position of the end when the animation
523 is started.
524
525 \sa endValue
526*/
527QVariant QVariantAnimation::startValue() const
528{
529 return keyValueAt(step: 0);
530}
531
532void QVariantAnimation::setStartValue(const QVariant &value)
533{
534 setKeyValueAt(step: 0, value);
535}
536
537/*!
538 \property QVariantAnimation::endValue
539 \brief the end value of the animation
540
541 This property describes the end value of the animation.
542
543 \sa startValue
544 */
545QVariant QVariantAnimation::endValue() const
546{
547 return keyValueAt(step: 1);
548}
549
550void QVariantAnimation::setEndValue(const QVariant &value)
551{
552 setKeyValueAt(step: 1, value);
553}
554
555
556/*!
557 Returns the key frame value for the given \a step. The given \a step
558 must be in the range 0 to 1. If there is no KeyValue for \a step,
559 it returns an invalid QVariant.
560
561 \sa keyValues(), setKeyValueAt()
562*/
563QVariant QVariantAnimation::keyValueAt(qreal step) const
564{
565 return d_func()->valueAt(step);
566}
567
568/*!
569 \typedef QVariantAnimation::KeyValue
570
571 This is a typedef for QPair<qreal, QVariant>.
572*/
573/*!
574 \typedef QVariantAnimation::KeyValues
575
576 This is a typedef for QVector<KeyValue>
577*/
578
579/*!
580 Creates a key frame at the given \a step with the given \a value.
581 The given \a step must be in the range 0 to 1.
582
583 \sa setKeyValues(), keyValueAt()
584*/
585void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value)
586{
587 d_func()->setValueAt(step, value);
588}
589
590/*!
591 Returns the key frames of this animation.
592
593 \sa keyValueAt(), setKeyValues()
594*/
595QVariantAnimation::KeyValues QVariantAnimation::keyValues() const
596{
597 return d_func()->keyValues;
598}
599
600/*!
601 Replaces the current set of key frames with the given \a keyValues.
602 the step of the key frames must be in the range 0 to 1.
603
604 \sa keyValues(), keyValueAt()
605*/
606void QVariantAnimation::setKeyValues(const KeyValues &keyValues)
607{
608 Q_D(QVariantAnimation);
609 d->keyValues = keyValues;
610 std::sort(first: d->keyValues.begin(), last: d->keyValues.end(), comp: animationValueLessThan);
611 d->recalculateCurrentInterval(/*force=*/true);
612}
613
614/*!
615 \property QVariantAnimation::currentValue
616 \brief the current value of the animation.
617
618 This property describes the current value; an interpolated value
619 between the \l{startValue}{start value} and the \l{endValue}{end
620 value}, using the current time for progress. The value itself is
621 obtained from interpolated(), which is called repeatedly as the
622 animation is running.
623
624 QVariantAnimation calls the virtual updateCurrentValue() function
625 when the current value changes. This is particularly useful for
626 subclasses that need to track updates. For example,
627 QPropertyAnimation uses this function to animate Qt \l{Qt's
628 Property System}{properties}.
629
630 \sa startValue, endValue
631*/
632QVariant QVariantAnimation::currentValue() const
633{
634 Q_D(const QVariantAnimation);
635 if (!d->currentValue.isValid())
636 const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval();
637 return d->currentValue;
638}
639
640/*!
641 \reimp
642 */
643bool QVariantAnimation::event(QEvent *event)
644{
645 return QAbstractAnimation::event(event);
646}
647
648/*!
649 \reimp
650*/
651void QVariantAnimation::updateState(QAbstractAnimation::State newState,
652 QAbstractAnimation::State oldState)
653{
654 Q_UNUSED(oldState);
655 Q_UNUSED(newState);
656}
657
658/*!
659
660 This virtual function returns the linear interpolation between
661 variants \a from and \a to, at \a progress, usually a value
662 between 0 and 1. You can reimplement this function in a subclass
663 of QVariantAnimation to provide your own interpolation algorithm.
664
665 Note that in order for the interpolation to work with a
666 QEasingCurve that return a value smaller than 0 or larger than 1
667 (such as QEasingCurve::InBack) you should make sure that it can
668 extrapolate. If the semantic of the datatype does not allow
669 extrapolation this function should handle that gracefully.
670
671 You should call the QVariantAnimation implementation of this
672 function if you want your class to handle the types already
673 supported by Qt (see class QVariantAnimation description for a
674 list of supported types).
675
676 \sa QEasingCurve
677 */
678QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
679{
680 return d_func()->interpolator(from.constData(), to.constData(), progress);
681}
682
683/*!
684 \reimp
685 */
686void QVariantAnimation::updateCurrentTime(int)
687{
688 d_func()->recalculateCurrentInterval();
689}
690
691QT_END_NAMESPACE
692
693#include "moc_qvariantanimation.cpp"
694

source code of qtbase/src/corelib/animation/qvariantanimation.cpp