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