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 | */ |
146 | void QVariantAnimation::updateCurrentValue(const QVariant &) {} |
147 | |
148 | static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2) |
149 | { |
150 | return p1.first < p2.first; |
151 | } |
152 | |
153 | static QVariant defaultInterpolator(const void *, const void *, qreal) |
154 | { |
155 | return QVariant(); |
156 | } |
157 | |
158 | template<> 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 | |
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(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 | |
178 | template<> 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 | |
183 | template<> 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 | |
188 | QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), interpolator(&defaultInterpolator) |
189 | { } |
190 | |
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(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 | |
206 | void 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 | */ |
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(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 | |
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 = |
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 | |
299 | QVariant 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 | |
309 | void 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 | |
331 | void 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 | */ |
341 | QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent) |
342 | { |
343 | } |
344 | |
345 | /*! |
346 | \internal |
347 | */ |
348 | QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent) |
349 | { |
350 | } |
351 | |
352 | /*! |
353 | Destroys the animation. |
354 | */ |
355 | QVariantAnimation::~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 | */ |
381 | QEasingCurve QVariantAnimation::easingCurve() const |
382 | { |
383 | Q_D(const QVariantAnimation); |
384 | return d->easing; |
385 | } |
386 | |
387 | void QVariantAnimation::setEasingCurve(const QEasingCurve &easing) |
388 | { |
389 | Q_D(QVariantAnimation); |
390 | d->easing = easing; |
391 | d->recalculateCurrentInterval(); |
392 | } |
393 | |
394 | typedef QVector<QVariantAnimation::Interpolator> QInterpolatorVector; |
395 | Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators) |
396 | static 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 | */ |
424 | void 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 | |
440 | template<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 | |
445 | QVariantAnimation::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 | */ |
497 | int QVariantAnimation::duration() const |
498 | { |
499 | Q_D(const QVariantAnimation); |
500 | return d->duration; |
501 | } |
502 | |
503 | void 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 | */ |
527 | QVariant QVariantAnimation::startValue() const |
528 | { |
529 | return keyValueAt(step: 0); |
530 | } |
531 | |
532 | void 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 | */ |
545 | QVariant QVariantAnimation::endValue() const |
546 | { |
547 | return keyValueAt(step: 1); |
548 | } |
549 | |
550 | void 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 | */ |
563 | QVariant 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 | */ |
585 | void 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 | */ |
595 | QVariantAnimation::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 | */ |
606 | void 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 | */ |
632 | QVariant 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 | */ |
643 | bool QVariantAnimation::event(QEvent *event) |
644 | { |
645 | return QAbstractAnimation::event(event); |
646 | } |
647 | |
648 | /*! |
649 | \reimp |
650 | */ |
651 | void 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 | */ |
678 | QVariant 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 | */ |
686 | void QVariantAnimation::updateCurrentTime(int) |
687 | { |
688 | d_func()->recalculateCurrentInterval(); |
689 | } |
690 | |
691 | QT_END_NAMESPACE |
692 | |
693 | #include "moc_qvariantanimation.cpp" |
694 | |