source: trunk/src/gui/graphicsview/qgraphicsitemanimation.cpp@ 116

Last change on this file since 116 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 17.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QGraphicsItemAnimation
44 \brief The QGraphicsItemAnimation class provides simple animation
45 support for QGraphicsItem.
46 \since 4.2
47 \ingroup multimedia
48 \ingroup graphicsview-api
49
50 The QGraphicsItemAnimation class animates a QGraphicsItem. You can
51 schedule changes to the item's transformation matrix at
52 specified steps. The QGraphicsItemAnimation class has a
53 current step value. When this value changes the transformations
54 scheduled at that step are performed. The current step of the
55 animation is set with the \c setStep() function.
56
57 QGraphicsItemAnimation will do a simple linear interpolation
58 between the nearest adjacent scheduled changes to calculate the
59 matrix. For instance, if you set the position of an item at values
60 0.0 and 1.0, the animation will show the item moving in a straight
61 line between these positions. The same is true for scaling and
62 rotation.
63
64 It is usual to use the class with a QTimeLine. The timeline's
65 \l{QTimeLine::}{valueChanged()} signal is then connected to the
66 \c setStep() slot. For example, you can set up an item for rotation
67 by calling \c setRotationAt() for different step values.
68 The animations timeline is set with the setTimeLine() function.
69
70 An example animation with a timeline follows:
71
72 \snippet doc/src/snippets/timeline/main.cpp 0
73
74 Note that steps lie between 0.0 and 1.0. It may be necessary to use
75 \l{QTimeLine::}{setUpdateInterval()}. The default update interval
76 is 40 ms. A scheduled transformation cannot be removed when set,
77 so scheduling several transformations of the same kind (e.g.,
78 rotations) at the same step is not recommended.
79
80 \sa QTimeLine, {The Graphics View Framework}
81*/
82
83#include "qgraphicsitemanimation.h"
84
85#ifndef QT_NO_GRAPHICSVIEW
86
87#include "qgraphicsitem.h"
88
89#include <QtCore/qtimeline.h>
90#include <QtCore/qpoint.h>
91#include <QtCore/qpointer.h>
92#include <QtCore/qpair.h>
93#include <QtGui/qmatrix.h>
94
95QT_BEGIN_NAMESPACE
96
97class QGraphicsItemAnimationPrivate
98{
99public:
100 inline QGraphicsItemAnimationPrivate()
101 : q(0), timeLine(0), item(0), step(0)
102 { }
103
104 QGraphicsItemAnimation *q;
105
106 QPointer<QTimeLine> timeLine;
107 QGraphicsItem *item;
108
109 QPointF startPos;
110 QMatrix startMatrix;
111
112 qreal step;
113
114 struct Pair {
115 Pair(qreal a, qreal b) : step(a), value(b) {}
116 bool operator <(const Pair &other) const
117 { return step < other.step; }
118 bool operator==(const Pair &other) const
119 { return step == other.step; }
120 qreal step;
121 qreal value;
122 };
123 QList<Pair> xPosition;
124 QList<Pair> yPosition;
125 QList<Pair> rotation;
126 QList<Pair> verticalScale;
127 QList<Pair> horizontalScale;
128 QList<Pair> verticalShear;
129 QList<Pair> horizontalShear;
130 QList<Pair> xTranslation;
131 QList<Pair> yTranslation;
132
133 qreal linearValueForStep(qreal step, QList<Pair> *source, qreal defaultValue = 0);
134 void insertUniquePair(qreal step, qreal value, QList<Pair> *binList, const char* method);
135};
136
137qreal QGraphicsItemAnimationPrivate::linearValueForStep(qreal step, QList<Pair> *source, qreal defaultValue)
138{
139 if (source->isEmpty())
140 return defaultValue;
141 step = qMin<qreal>(qMax<qreal>(step, 0), 1);
142
143 if (step == 1)
144 return source->last().value;
145
146 qreal stepBefore = 0;
147 qreal stepAfter = 1;
148 qreal valueBefore = source->first().step == 0 ? source->first().value : defaultValue;
149 qreal valueAfter = source->last().value;
150
151 // Find the closest step and value before the given step.
152 for (int i = 0; i < source->size() && step >= source->at(i).step; ++i) {
153 stepBefore = source->at(i).step;
154 valueBefore = source->at(i).value;
155 }
156
157 // Find the closest step and value after the given step.
158 for (int j = source->size() - 1; j >= 0 && step < source->at(j).step; --j) {
159 stepAfter = source->at(j).step;
160 valueAfter = source->at(j).value;
161 }
162
163 // Do a simple linear interpolation.
164 return valueBefore + (valueAfter - valueBefore) * ((step - stepBefore) / (stepAfter - stepBefore));
165}
166
167void QGraphicsItemAnimationPrivate::insertUniquePair(qreal step, qreal value, QList<Pair> *binList, const char* method)
168{
169 if (step < 0.0 || step > 1.0) {
170 qWarning("QGraphicsItemAnimation::%s: invalid step = %f", method, step);
171 return;
172 }
173
174 Pair pair(step, value);
175
176 QList<Pair>::iterator result = qBinaryFind(binList->begin(), binList->end(), pair);
177 if (result != binList->end())
178 result->value = value;
179 else {
180 *binList << pair;
181 qSort(binList->begin(), binList->end());
182 }
183}
184
185/*!
186 Constructs an animation object with the given \a parent.
187*/
188QGraphicsItemAnimation::QGraphicsItemAnimation(QObject *parent)
189 : QObject(parent), d(new QGraphicsItemAnimationPrivate)
190{
191 d->q = this;
192}
193
194/*!
195 Destroys the animation object.
196*/
197QGraphicsItemAnimation::~QGraphicsItemAnimation()
198{
199 delete d;
200}
201
202/*!
203 Returns the item on which the animation object operates.
204
205 \sa setItem()
206*/
207QGraphicsItem *QGraphicsItemAnimation::item() const
208{
209 return d->item;
210}
211
212/*!
213 Sets the specified \a item to be used in the animation.
214
215 \sa item()
216*/
217void QGraphicsItemAnimation::setItem(QGraphicsItem *item)
218{
219 d->item = item;
220 d->startPos = d->item->pos();
221}
222
223/*!
224 Returns the timeline object used to control the rate at which the animation
225 occurs.
226
227 \sa setTimeLine()
228*/
229QTimeLine *QGraphicsItemAnimation::timeLine() const
230{
231 return d->timeLine;
232}
233
234/*!
235 Sets the timeline object used to control the rate of animation to the \a timeLine
236 specified.
237
238 \sa timeLine()
239*/
240void QGraphicsItemAnimation::setTimeLine(QTimeLine *timeLine)
241{
242 if (d->timeLine == timeLine)
243 return;
244 if (d->timeLine)
245 delete d->timeLine;
246 if (!timeLine)
247 return;
248 d->timeLine = timeLine;
249 connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(setStep(qreal)));
250}
251
252/*!
253 Returns the position of the item at the given \a step value.
254
255 \sa setPosAt()
256*/
257QPointF QGraphicsItemAnimation::posAt(qreal step) const
258{
259 if (step < 0.0 || step > 1.0)
260 qWarning("QGraphicsItemAnimation::posAt: invalid step = %f", step);
261
262 return QPointF(d->linearValueForStep(step, &d->xPosition, d->startPos.x()),
263 d->linearValueForStep(step, &d->yPosition, d->startPos.y()));
264}
265
266/*!
267 \fn void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &point)
268
269 Sets the position of the item at the given \a step value to the \a point specified.
270
271 \sa posAt()
272*/
273void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &pos)
274{
275 d->insertUniquePair(step, pos.x(), &d->xPosition, "setPosAt");
276 d->insertUniquePair(step, pos.y(), &d->yPosition, "setPosAt");
277}
278
279/*!
280 Returns all explicitly inserted positions.
281
282 \sa posAt(), setPosAt()
283*/
284QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::posList() const
285{
286 QList<QPair<qreal, QPointF> > list;
287 for (int i = 0; i < d->xPosition.size(); ++i)
288 list << QPair<qreal, QPointF>(d->xPosition.at(i).step, QPointF(d->xPosition.at(i).value, d->yPosition.at(i).value));
289
290 return list;
291}
292
293/*!
294 Returns the matrix used to transform the item at the specified \a step value.
295*/
296QMatrix QGraphicsItemAnimation::matrixAt(qreal step) const
297{
298 if (step < 0.0 || step > 1.0)
299 qWarning("QGraphicsItemAnimation::matrixAt: invalid step = %f", step);
300
301 QMatrix matrix;
302 if (!d->rotation.isEmpty())
303 matrix.rotate(rotationAt(step));
304 if (!d->verticalScale.isEmpty())
305 matrix.scale(horizontalScaleAt(step), verticalScaleAt(step));
306 if (!d->verticalShear.isEmpty())
307 matrix.shear(horizontalShearAt(step), verticalShearAt(step));
308 if (!d->xTranslation.isEmpty())
309 matrix.translate(xTranslationAt(step), yTranslationAt(step));
310 return matrix;
311}
312
313/*!
314 Returns the angle at which the item is rotated at the specified \a step value.
315
316 \sa setRotationAt()
317*/
318qreal QGraphicsItemAnimation::rotationAt(qreal step) const
319{
320 if (step < 0.0 || step > 1.0)
321 qWarning("QGraphicsItemAnimation::rotationAt: invalid step = %f", step);
322
323 return d->linearValueForStep(step, &d->rotation);
324}
325
326/*!
327 Sets the rotation of the item at the given \a step value to the \a angle specified.
328
329 \sa rotationAt()
330*/
331void QGraphicsItemAnimation::setRotationAt(qreal step, qreal angle)
332{
333 d->insertUniquePair(step, angle, &d->rotation, "setRotationAt");
334}
335
336/*!
337 Returns all explicitly inserted rotations.
338
339 \sa rotationAt(), setRotationAt()
340*/
341QList<QPair<qreal, qreal> > QGraphicsItemAnimation::rotationList() const
342{
343 QList<QPair<qreal, qreal> > list;
344 for (int i = 0; i < d->rotation.size(); ++i)
345 list << QPair<qreal, qreal>(d->rotation.at(i).step, d->rotation.at(i).value);
346
347 return list;
348}
349
350/*!
351 Returns the horizontal translation of the item at the specified \a step value.
352
353 \sa setTranslationAt()
354*/
355qreal QGraphicsItemAnimation::xTranslationAt(qreal step) const
356{
357 if (step < 0.0 || step > 1.0)
358 qWarning("QGraphicsItemAnimation::xTranslationAt: invalid step = %f", step);
359
360 return d->linearValueForStep(step, &d->xTranslation);
361}
362
363/*!
364 Returns the vertical translation of the item at the specified \a step value.
365
366 \sa setTranslationAt()
367*/
368qreal QGraphicsItemAnimation::yTranslationAt(qreal step) const
369{
370 if (step < 0.0 || step > 1.0)
371 qWarning("QGraphicsItemAnimation::yTranslationAt: invalid step = %f", step);
372
373 return d->linearValueForStep(step, &d->yTranslation);
374}
375
376/*!
377 Sets the translation of the item at the given \a step value using the horizontal
378 and vertical coordinates specified by \a dx and \a dy.
379
380 \sa xTranslationAt(), yTranslationAt()
381*/
382void QGraphicsItemAnimation::setTranslationAt(qreal step, qreal dx, qreal dy)
383{
384 d->insertUniquePair(step, dx, &d->xTranslation, "setTranslationAt");
385 d->insertUniquePair(step, dy, &d->yTranslation, "setTranslationAt");
386}
387
388/*!
389 Returns all explicitly inserted translations.
390
391 \sa xTranslationAt(), yTranslationAt(), setTranslationAt()
392*/
393QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::translationList() const
394{
395 QList<QPair<qreal, QPointF> > list;
396 for (int i = 0; i < d->xTranslation.size(); ++i)
397 list << QPair<qreal, QPointF>(d->xTranslation.at(i).step, QPointF(d->xTranslation.at(i).value, d->yTranslation.at(i).value));
398
399 return list;
400}
401
402/*!
403 Returns the vertical scale for the item at the specified \a step value.
404
405 \sa setScaleAt()
406*/
407qreal QGraphicsItemAnimation::verticalScaleAt(qreal step) const
408{
409 if (step < 0.0 || step > 1.0)
410 qWarning("QGraphicsItemAnimation::verticalScaleAt: invalid step = %f", step);
411
412 return d->linearValueForStep(step, &d->verticalScale, 1);
413}
414
415/*!
416 Returns the horizontal scale for the item at the specified \a step value.
417
418 \sa setScaleAt()
419*/
420qreal QGraphicsItemAnimation::horizontalScaleAt(qreal step) const
421{
422 if (step < 0.0 || step > 1.0)
423 qWarning("QGraphicsItemAnimation::horizontalScaleAt: invalid step = %f", step);
424
425 return d->linearValueForStep(step, &d->horizontalScale, 1);
426}
427
428/*!
429 Sets the scale of the item at the given \a step value using the horizontal and
430 vertical scale factors specified by \a sx and \a sy.
431
432 \sa verticalScaleAt(), horizontalScaleAt()
433*/
434void QGraphicsItemAnimation::setScaleAt(qreal step, qreal sx, qreal sy)
435{
436 d->insertUniquePair(step, sx, &d->horizontalScale, "setScaleAt");
437 d->insertUniquePair(step, sy, &d->verticalScale, "setScaleAt");
438}
439
440/*!
441 Returns all explicitly inserted scales.
442
443 \sa verticalScaleAt(), horizontalScaleAt(), setScaleAt()
444*/
445QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::scaleList() const
446{
447 QList<QPair<qreal, QPointF> > list;
448 for (int i = 0; i < d->horizontalScale.size(); ++i)
449 list << QPair<qreal, QPointF>(d->horizontalScale.at(i).step, QPointF(d->horizontalScale.at(i).value, d->verticalScale.at(i).value));
450
451 return list;
452}
453
454/*!
455 Returns the vertical shear for the item at the specified \a step value.
456
457 \sa setShearAt()
458*/
459qreal QGraphicsItemAnimation::verticalShearAt(qreal step) const
460{
461 if (step < 0.0 || step > 1.0)
462 qWarning("QGraphicsItemAnimation::verticalShearAt: invalid step = %f", step);
463
464 return d->linearValueForStep(step, &d->verticalShear, 0);
465}
466
467/*!
468 Returns the horizontal shear for the item at the specified \a step value.
469
470 \sa setShearAt()
471*/
472qreal QGraphicsItemAnimation::horizontalShearAt(qreal step) const
473{
474 if (step < 0.0 || step > 1.0)
475 qWarning("QGraphicsItemAnimation::horizontalShearAt: invalid step = %f", step);
476
477 return d->linearValueForStep(step, &d->horizontalShear, 0);
478}
479
480/*!
481 Sets the shear of the item at the given \a step value using the horizontal and
482 vertical shear factors specified by \a sh and \a sv.
483
484 \sa verticalShearAt(), horizontalShearAt()
485*/
486void QGraphicsItemAnimation::setShearAt(qreal step, qreal sh, qreal sv)
487{
488 d->insertUniquePair(step, sh, &d->horizontalShear, "setShearAt");
489 d->insertUniquePair(step, sv, &d->verticalShear, "setShearAt");
490}
491
492/*!
493 Returns all explicitly inserted shears.
494
495 \sa verticalShearAt(), horizontalShearAt(), setShearAt()
496*/
497QList<QPair<qreal, QPointF> > QGraphicsItemAnimation::shearList() const
498{
499 QList<QPair<qreal, QPointF> > list;
500 for (int i = 0; i < d->horizontalShear.size(); ++i)
501 list << QPair<qreal, QPointF>(d->horizontalShear.at(i).step, QPointF(d->horizontalShear.at(i).value, d->verticalShear.at(i).value));
502
503 return list;
504}
505
506/*!
507 Clears the scheduled transformations used for the animation, but
508 retains the item and timeline.
509*/
510void QGraphicsItemAnimation::clear()
511{
512 d->xPosition.clear();
513 d->yPosition.clear();
514 d->rotation.clear();
515 d->verticalScale.clear();
516 d->horizontalScale.clear();
517 d->verticalShear.clear();
518 d->horizontalShear.clear();
519 d->xTranslation.clear();
520 d->yTranslation.clear();
521}
522
523/*!
524 \fn void QGraphicsItemAnimation::setStep(qreal step)
525
526 Sets the current \a step value for the animation, causing the
527 transformations scheduled at this step to be performed.
528*/
529void QGraphicsItemAnimation::setStep(qreal x)
530{
531 if (x < 0.0 || x > 1.0) {
532 qWarning("QGraphicsItemAnimation::setStep: invalid step = %f", x);
533 return;
534 }
535
536 beforeAnimationStep(x);
537
538 d->step = x;
539 if (d->item) {
540 if (!d->xPosition.isEmpty() || !d->yPosition.isEmpty())
541 d->item->setPos(posAt(x));
542 if (!d->rotation.isEmpty()
543 || !d->verticalScale.isEmpty()
544 || !d->horizontalScale.isEmpty()
545 || !d->verticalShear.isEmpty()
546 || !d->horizontalShear.isEmpty()
547 || !d->xTranslation.isEmpty()
548 || !d->yTranslation.isEmpty()) {
549 d->item->setMatrix(d->startMatrix * matrixAt(x));
550 }
551 }
552
553 afterAnimationStep(x);
554}
555
556/*!
557 Resets the item to its starting position and transformation.
558
559 \obsolete
560
561 You can call setStep(0) instead.
562*/
563void QGraphicsItemAnimation::reset()
564{
565 if (!d->item)
566 return;
567 d->startPos = d->item->pos();
568 d->startMatrix = d->item->matrix();
569}
570
571/*!
572 \fn void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
573
574 This method is meant to be overridden by subclassed that needs to
575 execute additional code before a new step takes place. The
576 animation \a step is provided for use in cases where the action
577 depends on its value.
578*/
579void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
580{
581 Q_UNUSED(step);
582}
583
584/*!
585 \fn void QGraphicsItemAnimation::afterAnimationStep(qreal step)
586
587 This method is meant to be overridden in subclasses that need to
588 execute additional code after a new step has taken place. The
589 animation \a step is provided for use in cases where the action
590 depends on its value.
591*/
592void QGraphicsItemAnimation::afterAnimationStep(qreal step)
593{
594 Q_UNUSED(step);
595}
596
597QT_END_NAMESPACE
598
599#endif // QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.