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