0
|
1 |
/****************************************************************************
|
|
2 |
**
|
18
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
0
|
4 |
** All rights reserved.
|
|
5 |
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
6 |
**
|
|
7 |
** This file is part of the QtCore module of the Qt Toolkit.
|
|
8 |
**
|
|
9 |
** $QT_BEGIN_LICENSE:LGPL$
|
|
10 |
** No Commercial Usage
|
|
11 |
** This file contains pre-release code and may not be distributed.
|
|
12 |
** You may use this file in accordance with the terms and conditions
|
|
13 |
** contained in the Technology Preview License Agreement accompanying
|
|
14 |
** this package.
|
|
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 |
** If you have questions regarding the use of this file, please contact
|
|
29 |
** Nokia at qt-info@nokia.com.
|
|
30 |
**
|
|
31 |
**
|
|
32 |
**
|
|
33 |
**
|
|
34 |
**
|
|
35 |
**
|
|
36 |
**
|
|
37 |
**
|
|
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}
|
3
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
107 |
\o \l{QMetaType::}{QPointF}
|
0
|
108 |
\o \l{QMetaType::}{QSize}
|
|
109 |
\o \l{QMetaType::}{QSizeF}
|
|
110 |
\o \l{QMetaType::}{QRect}
|
|
111 |
\o \l{QMetaType::}{QRectF}
|
3
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
112 |
\o \l{QMetaType::}{QColor}
|
0
|
113 |
\endlist
|
|
114 |
|
|
115 |
If you need to interpolate other variant types, including custom
|
|
116 |
types, you have to implement interpolation for these yourself.
|
3
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
117 |
To do this, you can register an interpolator function for a given
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
118 |
type. This function takes 3 parameters: the start value, the end value
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
119 |
and the current progress.
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
120 |
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
121 |
Example:
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
122 |
\code
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
123 |
QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress)
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
124 |
{
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
125 |
...
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
126 |
return QColor(...);
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
127 |
}
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
128 |
...
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
129 |
qRegisterAnimationInterpolator<QColor>(myColorInterpolator);
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
130 |
\endcode
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
131 |
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
132 |
Another option is to reimplement interpolated(), which returns
|
0
|
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 |
|
3
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
376 |
QVariantAnimation will use the QEasingCurve::valueForProgress() to
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
377 |
transform the "normalized progress" (currentTime / totalDuration)
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
378 |
of the animation into the effective progress actually
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
379 |
used by the animation. It is this effective progress that will be
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
380 |
the progress when interpolated() is called. Also, the steps in the
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
381 |
keyValues are referring to this effective progress.
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
382 |
|
0
|
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();
|
30
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
434 |
#ifndef QT_NO_THREAD
|
0
|
435 |
QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators));
|
30
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
436 |
#endif
|
0
|
437 |
if (int(interpolationType) >= interpolators->count())
|
|
438 |
interpolators->resize(int(interpolationType) + 1);
|
|
439 |
interpolators->replace(interpolationType, func);
|
|
440 |
}
|
|
441 |
|
|
442 |
|
|
443 |
template<typename T> static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress))
|
|
444 |
{
|
|
445 |
return reinterpret_cast<QVariantAnimation::Interpolator>(func);
|
|
446 |
}
|
|
447 |
|
|
448 |
QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType)
|
|
449 |
{
|
|
450 |
QInterpolatorVector *interpolators = registeredInterpolators();
|
30
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
451 |
#ifndef QT_NO_THREAD
|
0
|
452 |
QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators));
|
30
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
453 |
#endif
|
0
|
454 |
QVariantAnimation::Interpolator ret = 0;
|
|
455 |
if (interpolationType < interpolators->count()) {
|
|
456 |
ret = interpolators->at(interpolationType);
|
|
457 |
if (ret) return ret;
|
|
458 |
}
|
|
459 |
|
|
460 |
switch(interpolationType)
|
|
461 |
{
|
|
462 |
case QMetaType::Int:
|
|
463 |
return castToInterpolator(_q_interpolateVariant<int>);
|
|
464 |
case QMetaType::Double:
|
|
465 |
return castToInterpolator(_q_interpolateVariant<double>);
|
|
466 |
case QMetaType::Float:
|
|
467 |
return castToInterpolator(_q_interpolateVariant<float>);
|
|
468 |
case QMetaType::QLine:
|
|
469 |
return castToInterpolator(_q_interpolateVariant<QLine>);
|
|
470 |
case QMetaType::QLineF:
|
|
471 |
return castToInterpolator(_q_interpolateVariant<QLineF>);
|
|
472 |
case QMetaType::QPoint:
|
|
473 |
return castToInterpolator(_q_interpolateVariant<QPoint>);
|
|
474 |
case QMetaType::QPointF:
|
|
475 |
return castToInterpolator(_q_interpolateVariant<QPointF>);
|
|
476 |
case QMetaType::QSize:
|
|
477 |
return castToInterpolator(_q_interpolateVariant<QSize>);
|
|
478 |
case QMetaType::QSizeF:
|
|
479 |
return castToInterpolator(_q_interpolateVariant<QSizeF>);
|
|
480 |
case QMetaType::QRect:
|
|
481 |
return castToInterpolator(_q_interpolateVariant<QRect>);
|
|
482 |
case QMetaType::QRectF:
|
|
483 |
return castToInterpolator(_q_interpolateVariant<QRectF>);
|
|
484 |
default:
|
|
485 |
return 0; //this type is not handled
|
|
486 |
}
|
|
487 |
}
|
|
488 |
|
|
489 |
/*!
|
|
490 |
\property QVariantAnimation::duration
|
|
491 |
\brief the duration of the animation
|
|
492 |
|
|
493 |
This property describes the duration in milliseconds of the
|
|
494 |
animation. The default duration is 250 milliseconds.
|
|
495 |
|
|
496 |
\sa QAbstractAnimation::duration()
|
|
497 |
*/
|
|
498 |
int QVariantAnimation::duration() const
|
|
499 |
{
|
|
500 |
Q_D(const QVariantAnimation);
|
|
501 |
return d->duration;
|
|
502 |
}
|
|
503 |
|
|
504 |
void QVariantAnimation::setDuration(int msecs)
|
|
505 |
{
|
|
506 |
Q_D(QVariantAnimation);
|
|
507 |
if (msecs < 0) {
|
|
508 |
qWarning("QVariantAnimation::setDuration: cannot set a negative duration");
|
|
509 |
return;
|
|
510 |
}
|
|
511 |
if (d->duration == msecs)
|
|
512 |
return;
|
|
513 |
d->duration = msecs;
|
|
514 |
d->recalculateCurrentInterval();
|
|
515 |
}
|
|
516 |
|
|
517 |
/*!
|
|
518 |
\property QVariantAnimation::startValue
|
|
519 |
\brief the optional start value of the animation
|
|
520 |
|
|
521 |
This property describes the optional start value of the animation. If
|
|
522 |
omitted, or if a null QVariant is assigned as the start value, the
|
|
523 |
animation will use the current position of the end when the animation
|
|
524 |
is started.
|
|
525 |
|
|
526 |
\sa endValue
|
|
527 |
*/
|
|
528 |
QVariant QVariantAnimation::startValue() const
|
|
529 |
{
|
|
530 |
return keyValueAt(0);
|
|
531 |
}
|
|
532 |
|
|
533 |
void QVariantAnimation::setStartValue(const QVariant &value)
|
|
534 |
{
|
|
535 |
setKeyValueAt(0, value);
|
|
536 |
}
|
|
537 |
|
|
538 |
/*!
|
|
539 |
\property QVariantAnimation::endValue
|
|
540 |
\brief the end value of the animation
|
|
541 |
|
|
542 |
This property describes the end value of the animation.
|
|
543 |
|
|
544 |
\sa startValue
|
|
545 |
*/
|
|
546 |
QVariant QVariantAnimation::endValue() const
|
|
547 |
{
|
|
548 |
return keyValueAt(1);
|
|
549 |
}
|
|
550 |
|
|
551 |
void QVariantAnimation::setEndValue(const QVariant &value)
|
|
552 |
{
|
|
553 |
setKeyValueAt(1, value);
|
|
554 |
}
|
|
555 |
|
|
556 |
|
|
557 |
/*!
|
|
558 |
Returns the key frame value for the given \a step. The given \a step
|
|
559 |
must be in the range 0 to 1. If there is no KeyValue for \a step,
|
|
560 |
it returns an invalid QVariant.
|
|
561 |
|
|
562 |
\sa keyValues(), setKeyValueAt()
|
|
563 |
*/
|
|
564 |
QVariant QVariantAnimation::keyValueAt(qreal step) const
|
|
565 |
{
|
|
566 |
return d_func()->valueAt(step);
|
|
567 |
}
|
|
568 |
|
|
569 |
/*!
|
|
570 |
\typedef QVariantAnimation::KeyValue
|
|
571 |
|
|
572 |
This is a typedef for QPair<qreal, QVariant>.
|
|
573 |
*/
|
|
574 |
/*!
|
|
575 |
\typedef QVariantAnimation::KeyValues
|
|
576 |
|
|
577 |
This is a typedef for QVector<KeyValue>
|
|
578 |
*/
|
|
579 |
|
|
580 |
/*!
|
|
581 |
Creates a key frame at the given \a step with the given \a value.
|
|
582 |
The given \a step must be in the range 0 to 1.
|
|
583 |
|
|
584 |
\sa setKeyValues(), keyValueAt()
|
|
585 |
*/
|
|
586 |
void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value)
|
|
587 |
{
|
|
588 |
d_func()->setValueAt(step, value);
|
|
589 |
}
|
|
590 |
|
|
591 |
/*!
|
|
592 |
Returns the key frames of this animation.
|
|
593 |
|
|
594 |
\sa keyValueAt(), setKeyValues()
|
|
595 |
*/
|
|
596 |
QVariantAnimation::KeyValues QVariantAnimation::keyValues() const
|
|
597 |
{
|
|
598 |
return d_func()->keyValues;
|
|
599 |
}
|
|
600 |
|
|
601 |
/*!
|
|
602 |
Replaces the current set of key frames with the given \a keyValues.
|
|
603 |
the step of the key frames must be in the range 0 to 1.
|
|
604 |
|
|
605 |
\sa keyValues(), keyValueAt()
|
|
606 |
*/
|
|
607 |
void QVariantAnimation::setKeyValues(const KeyValues &keyValues)
|
|
608 |
{
|
|
609 |
Q_D(QVariantAnimation);
|
|
610 |
d->keyValues = keyValues;
|
|
611 |
qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan);
|
|
612 |
d->recalculateCurrentInterval(/*force=*/true);
|
|
613 |
}
|
|
614 |
|
|
615 |
/*!
|
|
616 |
\property QVariantAnimation::currentValue
|
|
617 |
\brief the current value of the animation.
|
|
618 |
|
|
619 |
This property describes the current value; an interpolated value
|
|
620 |
between the \l{startValue}{start value} and the \l{endValue}{end
|
|
621 |
value}, using the current time for progress. The value itself is
|
|
622 |
obtained from interpolated(), which is called repeatedly as the
|
|
623 |
animation is running.
|
|
624 |
|
|
625 |
QVariantAnimation calls the virtual updateCurrentValue() function
|
|
626 |
when the current value changes. This is particularly useful for
|
|
627 |
subclasses that need to track updates. For example,
|
|
628 |
QPropertyAnimation uses this function to animate Qt \l{Qt's
|
|
629 |
Property System}{properties}.
|
|
630 |
|
|
631 |
\sa startValue, endValue
|
|
632 |
*/
|
|
633 |
QVariant QVariantAnimation::currentValue() const
|
|
634 |
{
|
|
635 |
Q_D(const QVariantAnimation);
|
|
636 |
if (!d->currentValue.isValid())
|
|
637 |
const_cast<QVariantAnimationPrivate*>(d)->recalculateCurrentInterval();
|
|
638 |
return d->currentValue;
|
|
639 |
}
|
|
640 |
|
|
641 |
/*!
|
|
642 |
\reimp
|
|
643 |
*/
|
|
644 |
bool QVariantAnimation::event(QEvent *event)
|
|
645 |
{
|
|
646 |
return QAbstractAnimation::event(event);
|
|
647 |
}
|
|
648 |
|
|
649 |
/*!
|
|
650 |
\reimp
|
|
651 |
*/
|
3
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
652 |
void QVariantAnimation::updateState(QAbstractAnimation::State newState,
|
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
diff
changeset
|
653 |
QAbstractAnimation::State oldState)
|
0
|
654 |
{
|
|
655 |
Q_UNUSED(oldState);
|
|
656 |
Q_UNUSED(newState);
|
|
657 |
}
|
|
658 |
|
|
659 |
/*!
|
|
660 |
|
|
661 |
This virtual function returns the linear interpolation between
|
|
662 |
variants \a from and \a to, at \a progress, usually a value
|
|
663 |
between 0 and 1. You can reimplement this function in a subclass
|
|
664 |
of QVariantAnimation to provide your own interpolation algorithm.
|
|
665 |
|
|
666 |
Note that in order for the interpolation to work with a
|
|
667 |
QEasingCurve that return a value smaller than 0 or larger than 1
|
|
668 |
(such as QEasingCurve::InBack) you should make sure that it can
|
|
669 |
extrapolate. If the semantic of the datatype does not allow
|
|
670 |
extrapolation this function should handle that gracefully.
|
|
671 |
|
|
672 |
You should call the QVariantAnimation implementation of this
|
|
673 |
function if you want your class to handle the types already
|
|
674 |
supported by Qt (see class QVariantAnimation description for a
|
|
675 |
list of supported types).
|
|
676 |
|
|
677 |
\sa QEasingCurve
|
|
678 |
*/
|
|
679 |
QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const
|
|
680 |
{
|
|
681 |
return d_func()->interpolator(from.constData(), to.constData(), progress);
|
|
682 |
}
|
|
683 |
|
|
684 |
/*!
|
|
685 |
\reimp
|
|
686 |
*/
|
|
687 |
void QVariantAnimation::updateCurrentTime(int)
|
|
688 |
{
|
|
689 |
d_func()->recalculateCurrentInterval();
|
|
690 |
}
|
|
691 |
|
|
692 |
QT_END_NAMESPACE
|
|
693 |
|
|
694 |
#include "moc_qvariantanimation.cpp"
|
|
695 |
|
|
696 |
#endif //QT_NO_ANIMATION
|