Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgraphicsitemanimation.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5/*!
6 \class QGraphicsItemAnimation
7 \brief The QGraphicsItemAnimation class provides simple animation
8 support for QGraphicsItem.
9 \since 4.2
10 \ingroup graphicsview-api
11 \inmodule QtWidgets
12 \deprecated
13
14 The QGraphicsItemAnimation class animates a QGraphicsItem. You can
15 schedule changes to the item's transformation matrix at
16 specified steps. The QGraphicsItemAnimation class has a
17 current step value. When this value changes the transformations
18 scheduled at that step are performed. The current step of the
19 animation is set with the \c setStep() function.
20
21 QGraphicsItemAnimation will do a simple linear interpolation
22 between the nearest adjacent scheduled changes to calculate the
23 matrix. For instance, if you set the position of an item at values
24 0.0 and 1.0, the animation will show the item moving in a straight
25 line between these positions. The same is true for scaling and
26 rotation.
27
28 It is usual to use the class with a QTimeLine. The timeline's
29 \l{QTimeLine::}{valueChanged()} signal is then connected to the
30 \c setStep() slot. For example, you can set up an item for rotation
31 by calling \c setRotationAt() for different step values.
32 The animations timeline is set with the setTimeLine() function.
33
34 An example animation with a timeline follows:
35
36 \snippet timeline/main.cpp 0
37
38 Note that steps lie between 0.0 and 1.0. It may be necessary to use
39 \l{QTimeLine::}{setUpdateInterval()}. The default update interval
40 is 40 ms. A scheduled transformation cannot be removed when set,
41 so scheduling several transformations of the same kind (e.g.,
42 rotations) at the same step is not recommended.
43
44 \sa QTimeLine, {Graphics View Framework}
45*/
46
48
49#include "qgraphicsitem.h"
50
51#include <QtCore/qtimeline.h>
52#include <QtCore/qpoint.h>
53#include <QtCore/qpointer.h>
54
55#include <algorithm>
56
58
59static inline bool check_step_valid(qreal step, const char *method)
60{
61 if (!(step >= 0 && step <= 1)) {
62 qWarning("QGraphicsItemAnimation::%s: invalid step = %f", method, step);
63 return false;
64 }
65 return true;
66}
67
69{
70public:
72 : q(nullptr), timeLine(nullptr), item(nullptr), step(0)
73 { }
74
76
78 QGraphicsItem *item;
79
81 QTransform startTransform;
82
84
85 struct Pair {
86 bool operator <(const Pair &other) const
87 { return step < other.step; }
88 bool operator==(const Pair &other) const
89 { return step == other.step; }
92 };
102
103 qreal linearValueForStep(qreal step, const QList<Pair> &source, qreal defaultValue = 0);
104 void insertUniquePair(qreal step, qreal value, QList<Pair> *binList, const char *method);
105};
107
108qreal QGraphicsItemAnimationPrivate::linearValueForStep(qreal step, const QList<Pair> &source,
109 qreal defaultValue)
110{
111 if (source.isEmpty())
112 return defaultValue;
113 step = qMin<qreal>(qMax<qreal>(step, 0), 1);
114
115 if (step == 1)
116 return source.back().value;
117
118 qreal stepBefore = 0;
119 qreal stepAfter = 1;
120 qreal valueBefore = source.front().step == 0 ? source.front().value : defaultValue;
121 qreal valueAfter = source.back().value;
122
123 // Find the closest step and value before the given step.
124 for (int i = 0; i < source.size() && step >= source[i].step; ++i) {
125 stepBefore = source[i].step;
126 valueBefore = source[i].value;
127 }
128
129 // Find the closest step and value after the given step.
130 for (int i = source.size() - 1; i >= 0 && step < source[i].step; --i) {
131 stepAfter = source[i].step;
132 valueAfter = source[i].value;
133 }
134
135 // Do a simple linear interpolation.
136 return valueBefore + (valueAfter - valueBefore) * ((step - stepBefore) / (stepAfter - stepBefore));
137}
138
139void QGraphicsItemAnimationPrivate::insertUniquePair(qreal step, qreal value, QList<Pair> *binList,
140 const char *method)
141{
142 if (!check_step_valid(step, method))
143 return;
144
145 const Pair pair = { step, value };
146
147 const QList<Pair>::iterator result = std::lower_bound(binList->begin(), binList->end(), pair);
148 if (result == binList->end() || pair < *result)
149 binList->insert(result, pair);
150 else
151 result->value = value;
152}
153
154/*!
155 Constructs an animation object with the given \a parent.
156*/
157QGraphicsItemAnimation::QGraphicsItemAnimation(QObject *parent)
158 : QObject(parent), d(new QGraphicsItemAnimationPrivate)
159{
160 d->q = this;
161}
162
163/*!
164 Destroys the animation object.
165*/
166QGraphicsItemAnimation::~QGraphicsItemAnimation()
167{
168 delete d;
169}
170
171/*!
172 Returns the item on which the animation object operates.
173
174 \sa setItem()
175*/
176QGraphicsItem *QGraphicsItemAnimation::item() const
177{
178 return d->item;
179}
180
181/*!
182 Sets the specified \a item to be used in the animation.
183
184 \sa item()
185*/
186void QGraphicsItemAnimation::setItem(QGraphicsItem *item)
187{
188 d->item = item;
189 d->startPos = d->item->pos();
190}
191
192/*!
193 Returns the timeline object used to control the rate at which the animation
194 occurs.
195
196 \sa setTimeLine()
197*/
198QTimeLine *QGraphicsItemAnimation::timeLine() const
199{
200 return d->timeLine;
201}
202
203/*!
204 Sets the timeline object used to control the rate of animation to the \a timeLine
205 specified.
206
207 \sa timeLine()
208*/
209void QGraphicsItemAnimation::setTimeLine(QTimeLine *timeLine)
210{
211 if (d->timeLine == timeLine)
212 return;
213 if (d->timeLine)
214 delete d->timeLine;
215 if (!timeLine)
216 return;
217 d->timeLine = timeLine;
218 connect(timeLine, SIGNAL(valueChanged(qreal)), this, SLOT(setStep(qreal)));
219}
220
221/*!
222 Returns the position of the item at the given \a step value.
223
224 \sa setPosAt()
225*/
226QPointF QGraphicsItemAnimation::posAt(qreal step) const
227{
228 check_step_valid(step, "posAt");
229 return QPointF(d->linearValueForStep(step, d->xPosition, d->startPos.x()),
230 d->linearValueForStep(step, d->yPosition, d->startPos.y()));
231}
232
233/*!
234 \fn void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &point)
235
236 Sets the position of the item at the given \a step value to the \a point specified.
237
238 \sa posAt()
239*/
240void QGraphicsItemAnimation::setPosAt(qreal step, const QPointF &pos)
241{
242 d->insertUniquePair(step, pos.x(), &d->xPosition, "setPosAt");
243 d->insertUniquePair(step, pos.y(), &d->yPosition, "setPosAt");
244}
245
246/*!
247 Returns all explicitly inserted positions.
248
249 \sa posAt(), setPosAt()
250*/
251QList<std::pair<qreal, QPointF> > QGraphicsItemAnimation::posList() const
252{
253 QList<std::pair<qreal, QPointF>> list;
254 const int xPosCount = d->xPosition.size();
255 list.reserve(xPosCount);
256 for (int i = 0; i < xPosCount; ++i)
257 list.emplace_back(d->xPosition.at(i).step,
258 QPointF(d->xPosition.at(i).value, d->yPosition.at(i).value));
259
260 return list;
261}
262
263/*!
264 Returns the transform used for the item at the specified \a step value.
265
266 \since 5.14
267*/
268QTransform QGraphicsItemAnimation::transformAt(qreal step) const
269{
270 check_step_valid(step, "transformAt");
271
272 QTransform transform;
273 if (!d->rotation.isEmpty())
274 transform.rotate(rotationAt(step));
275 if (!d->verticalScale.isEmpty())
276 transform.scale(horizontalScaleAt(step), verticalScaleAt(step));
277 if (!d->verticalShear.isEmpty())
278 transform.shear(horizontalShearAt(step), verticalShearAt(step));
279 if (!d->xTranslation.isEmpty())
280 transform.translate(xTranslationAt(step), yTranslationAt(step));
281 return transform;
282}
283
284/*!
285 Returns the angle at which the item is rotated at the specified \a step value.
286
287 \sa setRotationAt()
288*/
289qreal QGraphicsItemAnimation::rotationAt(qreal step) const
290{
291 check_step_valid(step, "rotationAt");
292 return d->linearValueForStep(step, d->rotation);
293}
294
295/*!
296 Sets the rotation of the item at the given \a step value to the \a angle specified.
297
298 \sa rotationAt()
299*/
300void QGraphicsItemAnimation::setRotationAt(qreal step, qreal angle)
301{
302 d->insertUniquePair(step, angle, &d->rotation, "setRotationAt");
303}
304
305/*!
306 Returns all explicitly inserted rotations.
307
308 \sa rotationAt(), setRotationAt()
309*/
310QList<std::pair<qreal, qreal> > QGraphicsItemAnimation::rotationList() const
311{
312 QList<std::pair<qreal, qreal>> list;
313 const int numRotations = d->rotation.size();
314 list.reserve(numRotations);
315 for (int i = 0; i < numRotations; ++i)
316 list.emplace_back(d->rotation.at(i).step, d->rotation.at(i).value);
317
318 return list;
319}
320
321/*!
322 Returns the horizontal translation of the item at the specified \a step value.
323
324 \sa setTranslationAt()
325*/
326qreal QGraphicsItemAnimation::xTranslationAt(qreal step) const
327{
328 check_step_valid(step, "xTranslationAt");
329 return d->linearValueForStep(step, d->xTranslation);
330}
331
332/*!
333 Returns the vertical translation of the item at the specified \a step value.
334
335 \sa setTranslationAt()
336*/
337qreal QGraphicsItemAnimation::yTranslationAt(qreal step) const
338{
339 check_step_valid(step, "yTranslationAt");
340 return d->linearValueForStep(step, d->yTranslation);
341}
342
343/*!
344 Sets the translation of the item at the given \a step value using the horizontal
345 and vertical coordinates specified by \a dx and \a dy.
346
347 \sa xTranslationAt(), yTranslationAt()
348*/
349void QGraphicsItemAnimation::setTranslationAt(qreal step, qreal dx, qreal dy)
350{
351 d->insertUniquePair(step, dx, &d->xTranslation, "setTranslationAt");
352 d->insertUniquePair(step, dy, &d->yTranslation, "setTranslationAt");
353}
354
355/*!
356 Returns all explicitly inserted translations.
357
358 \sa xTranslationAt(), yTranslationAt(), setTranslationAt()
359*/
360QList<std::pair<qreal, QPointF> > QGraphicsItemAnimation::translationList() const
361{
362 QList<std::pair<qreal, QPointF>> list;
363 const int numTranslations = d->xTranslation.size();
364 list.reserve(numTranslations);
365 for (int i = 0; i < numTranslations; ++i)
366 list.emplace_back(d->xTranslation.at(i).step,
367 QPointF(d->xTranslation.at(i).value, d->yTranslation.at(i).value));
368
369 return list;
370}
371
372/*!
373 Returns the vertical scale for the item at the specified \a step value.
374
375 \sa setScaleAt()
376*/
377qreal QGraphicsItemAnimation::verticalScaleAt(qreal step) const
378{
379 check_step_valid(step, "verticalScaleAt");
380
381 return d->linearValueForStep(step, d->verticalScale, 1);
382}
383
384/*!
385 Returns the horizontal scale for the item at the specified \a step value.
386
387 \sa setScaleAt()
388*/
389qreal QGraphicsItemAnimation::horizontalScaleAt(qreal step) const
390{
391 check_step_valid(step, "horizontalScaleAt");
392 return d->linearValueForStep(step, d->horizontalScale, 1);
393}
394
395/*!
396 Sets the scale of the item at the given \a step value using the horizontal and
397 vertical scale factors specified by \a sx and \a sy.
398
399 \sa verticalScaleAt(), horizontalScaleAt()
400*/
401void QGraphicsItemAnimation::setScaleAt(qreal step, qreal sx, qreal sy)
402{
403 d->insertUniquePair(step, sx, &d->horizontalScale, "setScaleAt");
404 d->insertUniquePair(step, sy, &d->verticalScale, "setScaleAt");
405}
406
407/*!
408 Returns all explicitly inserted scales.
409
410 \sa verticalScaleAt(), horizontalScaleAt(), setScaleAt()
411*/
412QList<std::pair<qreal, QPointF> > QGraphicsItemAnimation::scaleList() const
413{
414 QList<std::pair<qreal, QPointF>> list;
415 const int numScales = d->horizontalScale.size();
416 list.reserve(numScales);
417 for (int i = 0; i < numScales; ++i)
418 list.emplace_back(d->horizontalScale.at(i).step,
419 QPointF(d->horizontalScale.at(i).value,
420 d->verticalScale.at(i).value));
421
422 return list;
423}
424
425/*!
426 Returns the vertical shear for the item at the specified \a step value.
427
428 \sa setShearAt()
429*/
430qreal QGraphicsItemAnimation::verticalShearAt(qreal step) const
431{
432 check_step_valid(step, "verticalShearAt");
433 return d->linearValueForStep(step, d->verticalShear, 0);
434}
435
436/*!
437 Returns the horizontal shear for the item at the specified \a step value.
438
439 \sa setShearAt()
440*/
441qreal QGraphicsItemAnimation::horizontalShearAt(qreal step) const
442{
443 check_step_valid(step, "horizontalShearAt");
444 return d->linearValueForStep(step, d->horizontalShear, 0);
445}
446
447/*!
448 Sets the shear of the item at the given \a step value using the horizontal and
449 vertical shear factors specified by \a sh and \a sv.
450
451 \sa verticalShearAt(), horizontalShearAt()
452*/
453void QGraphicsItemAnimation::setShearAt(qreal step, qreal sh, qreal sv)
454{
455 d->insertUniquePair(step, sh, &d->horizontalShear, "setShearAt");
456 d->insertUniquePair(step, sv, &d->verticalShear, "setShearAt");
457}
458
459/*!
460 Returns all explicitly inserted shears.
461
462 \sa verticalShearAt(), horizontalShearAt(), setShearAt()
463*/
464QList<std::pair<qreal, QPointF> > QGraphicsItemAnimation::shearList() const
465{
466 QList<std::pair<qreal, QPointF>> list;
467 const int numShears = d->horizontalShear.size();
468 list.reserve(numShears);
469 for (int i = 0; i < numShears; ++i)
470 list.emplace_back(d->horizontalShear.at(i).step,
471 QPointF(d->horizontalShear.at(i).value,
472 d->verticalShear.at(i).value));
473
474 return list;
475}
476
477/*!
478 Clears the scheduled transformations used for the animation, but
479 retains the item and timeline.
480*/
481void QGraphicsItemAnimation::clear()
482{
483 d->xPosition.clear();
484 d->yPosition.clear();
485 d->rotation.clear();
486 d->verticalScale.clear();
487 d->horizontalScale.clear();
488 d->verticalShear.clear();
489 d->horizontalShear.clear();
490 d->xTranslation.clear();
491 d->yTranslation.clear();
492}
493
494/*!
495 \fn void QGraphicsItemAnimation::setStep(qreal step)
496
497 Sets the current \a step value for the animation, causing the
498 transformations scheduled at this step to be performed.
499*/
500void QGraphicsItemAnimation::setStep(qreal step)
501{
502 if (!check_step_valid(step, "setStep"))
503 return;
504
505 beforeAnimationStep(step);
506
507 d->step = step;
508 if (d->item) {
509 if (!d->xPosition.isEmpty() || !d->yPosition.isEmpty())
510 d->item->setPos(posAt(step));
511 if (!d->rotation.isEmpty()
512 || !d->verticalScale.isEmpty()
513 || !d->horizontalScale.isEmpty()
514 || !d->verticalShear.isEmpty()
515 || !d->horizontalShear.isEmpty()
516 || !d->xTranslation.isEmpty()
517 || !d->yTranslation.isEmpty()) {
518 d->item->setTransform(d->startTransform * transformAt(step));
519 }
520 }
521
522 afterAnimationStep(step);
523}
524
525/*!
526 \fn void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
527
528 This method is meant to be overridden by subclassed that needs to
529 execute additional code before a new step takes place. The
530 animation \a step is provided for use in cases where the action
531 depends on its value.
532*/
533void QGraphicsItemAnimation::beforeAnimationStep(qreal step)
534{
535 Q_UNUSED(step);
536}
537
538/*!
539 \fn void QGraphicsItemAnimation::afterAnimationStep(qreal step)
540
541 This method is meant to be overridden in subclasses that need to
542 execute additional code after a new step has taken place. The
543 animation \a step is provided for use in cases where the action
544 depends on its value.
545*/
546void QGraphicsItemAnimation::afterAnimationStep(qreal step)
547{
548 Q_UNUSED(step);
549}
550
551QT_END_NAMESPACE
552
553#include "moc_qgraphicsitemanimation.cpp"
void insertUniquePair(qreal step, qreal value, QList< Pair > *binList, const char *method)
qreal linearValueForStep(qreal step, const QList< Pair > &source, qreal defaultValue=0)
\inmodule QtCore\reentrant
Definition qpoint.h:231
static QT_BEGIN_NAMESPACE bool check_step_valid(qreal step, const char *method)
Q_DECLARE_TYPEINFO(QGraphicsItemAnimationPrivate::Pair, Q_PRIMITIVE_TYPE)
bool operator==(const Pair &other) const
bool operator<(const Pair &other) const