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
qquicktimeline.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
6
7#include <QDebug>
8#include <QMutex>
9#include <QThread>
10#include <QWaitCondition>
11#include <QEvent>
12#include <QCoreApplication>
13#include <QEasingCurve>
14#include <QTime>
15#include <QtCore/private/qnumeric_p.h>
16#include <QHash>
17
18#include <algorithm>
19
21
22Q_STATIC_LOGGING_CATEGORY(lcTl, "qt.quick.timeline")
23
24struct Update {
25 Update(QQuickTimeLineValue *_g, qreal _v)
26 : g(_g), v(_v) {}
27 Update(const QQuickTimeLineCallback &_e)
28 : g(nullptr), v(0), e(_e) {}
29
30 QQuickTimeLineValue *g;
32 QQuickTimeLineCallback e;
33};
34
36{
37 QQuickTimeLinePrivate(QQuickTimeLine *);
38
39 struct Op {
40 enum Type {
41 Pause, // Pauses any value updates
42 Set, // Instantly changes the value to a target value
43 Move, // Moves towards a target value over time
44 MoveBy, // Same as Move, but target value is now an offset from the starting value
45 Accel, // Moves towards a target value over time with a constant acceleration
47 Execute // Calls back a function
48 };
49 Op() {}
50 Op(Type t, int l, qreal v, qreal v2, int o,
51 const QQuickTimeLineCallback &ev = QQuickTimeLineCallback(), const QEasingCurve &es = QEasingCurve())
52 : type(t), length(l), value(v), value2(v2), order(o), event(ev),
53 easing(es) {}
57 Op &operator=(const Op &o) {
58 type = o.type; length = o.length; value = o.value;
59 value2 = o.value2; order = o.order; event = o.event;
60 easing = o.easing;
61 return *this;
62 }
63
65 int length;
68
69 int order;
70 QQuickTimeLineCallback event;
71 QEasingCurve easing;
72 };
73 struct TimeLine
74 {
77 int length = 0;
79 qreal base = 0.;
80 };
81
82 int length;
87
88 void add(QQuickTimeLineObject &, const Op &);
89 qreal value(const Op &op, int time, qreal base, bool *) const;
90
91 int advance(int);
92
95
96 int order;
97
101};
102
105{
106}
107
108void QQuickTimeLinePrivate::add(QQuickTimeLineObject &g, const Op &o)
109{
110 if (g._t && g._t != q) {
111 qWarning() << "QQuickTimeLine: Cannot modify a QQuickTimeLineValue owned by"
112 << "another timeline.";
113 return;
114 }
115 g._t = q;
116
117 Ops::Iterator iter = ops.find(&g);
118 if (iter == ops.end()) {
119 iter = ops.insert(&g, TimeLine());
120 if (syncPoint > 0)
121 q->pause(g, syncPoint);
122 }
123 if (!iter->ops.isEmpty() &&
124 o.type == Op::Pause &&
125 iter->ops.constLast().type == Op::Pause) {
126 // If the last operation was a pause, and we're adding another, simply prolong it.
127 iter->ops.last().length += o.length;
128 iter->length += o.length;
129 } else {
130 // Add to the list of operations
131 iter->ops.append(o);
132 iter->length += o.length;
133 }
134
135 if (iter->length > length)
136 length = iter->length;
137
138 if (!clockRunning) {
139 q->stop();
140 prevTime = 0;
141 clockRunning = true;
142
143 if (syncMode == QQuickTimeLine::LocalSync) {
144 syncAdj = -1;
145 } else {
146 syncAdj = 0;
147 }
148 q->start();
149/* q->tick(0);
150 if (syncMode == QQuickTimeLine::LocalSync) {
151 syncAdj = -1;
152 } else {
153 syncAdj = 0;
154 }
155 */
156 }
157}
158
159qreal QQuickTimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const
160{
161 Q_ASSERT(time >= 0);
162 Q_ASSERT(time <= op.length);
163 *changed = true;
164
165 switch(op.type) {
166 case Op::Pause:
167 *changed = false;
168 return base;
169 case Op::Set:
170 return op.value;
171 case Op::Move:
172 if (time == 0) {
173 return base;
174 } else if (time == (op.length)) {
175 return op.value;
176 } else {
177 qreal delta = op.value - base;
178 qreal pTime = (qreal)(time) / (qreal)op.length;
179 if (op.easing.type() == QEasingCurve::Linear)
180 return base + delta * pTime;
181 else
182 return base + delta * op.easing.valueForProgress(pTime);
183 }
184 case Op::MoveBy:
185 if (time == 0) {
186 return base;
187 } else if (time == (op.length)) {
188 return base + op.value;
189 } else {
190 qreal delta = op.value;
191 qreal pTime = (qreal)(time) / (qreal)op.length;
192 if (op.easing.type() == QEasingCurve::Linear)
193 return base + delta * pTime;
194 else
195 return base + delta * op.easing.valueForProgress(pTime);
196 }
197 case Op::Accel:
198 if (time == 0) {
199 return base;
200 } else {
201 qreal t = (qreal)(time) / 1000.0f;
202 qreal delta = op.value * t + 0.5f * op.value2 * t * t;
203 return base + delta;
204 }
206 if (time == 0) {
207 return base;
208 } else if (time == (op.length)) {
209 return base + op.value2;
210 } else {
211 qreal t = (qreal)(time) / 1000.0f;
212 qreal accel = -1.0f * 1000.0f * op.value / (qreal)op.length;
213 qreal delta = op.value * t + 0.5f * accel * t * t;
214 return base + delta;
215
216 }
217 case Op::Execute:
218 op.event.d0(op.event.d1);
219 *changed = false;
220 return -1;
221 }
222
223 return base;
224}
225
226/*!
227 \internal
228 \class QQuickTimeLine
229 \brief The QQuickTimeLine class provides a timeline for controlling animations.
230
231 QQuickTimeLine is similar to QTimeLine except:
232 \list
233 \li It updates QQuickTimeLineValue instances directly, rather than maintaining a single
234 current value.
235
236 For example, the following animates a simple value over 200 milliseconds:
237 \code
238 QQuickTimeLineValue v(<starting value>);
239 QQuickTimeLine tl;
240 tl.move(v, 100., 200);
241 tl.start()
242 \endcode
243
244 If your program needs to know when values are changed, it can either
245 connect to the QQuickTimeLine's updated() signal, or inherit from QQuickTimeLineValue
246 and reimplement the QQuickTimeLineValue::setValue() method.
247
248 \li Supports multiple QQuickTimeLineValue, arbitrary start and end values and allows
249 animations to be strung together for more complex effects.
250
251 For example, the following animation moves the x and y coordinates of
252 an object from wherever they are to the position (100, 100) in 50
253 milliseconds and then further animates them to (100, 200) in 50
254 milliseconds:
255
256 \code
257 QQuickTimeLineValue x(<starting value>);
258 QQuickTimeLineValue y(<starting value>);
259
260 QQuickTimeLine tl;
261 tl.start();
262
263 tl.move(x, 100., 50);
264 tl.move(y, 100., 50);
265 tl.move(y, 200., 50);
266 \endcode
267
268 \li All QQuickTimeLine instances share a single, synchronized clock.
269
270 Actions scheduled within the same event loop tick are scheduled
271 synchronously against each other, regardless of the wall time between the
272 scheduling. Synchronized scheduling applies both to within the same
273 QQuickTimeLine and across separate QQuickTimeLine's within the same process.
274
275 \endlist
276
277 Currently easing functions are not supported.
278*/
279
280
281/*!
282 Construct a new QQuickTimeLine with the specified \a parent.
283*/
284QQuickTimeLine::QQuickTimeLine(QObject *parent)
285 : QObject(parent)
286{
287 d = new QQuickTimeLinePrivate(this);
288}
289
290/*!
291 Destroys the time line. Any inprogress animations are canceled, but not
292 completed.
293*/
294QQuickTimeLine::~QQuickTimeLine()
295{
296 for (QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
297 iter != d->ops.end();
298 ++iter)
299 iter.key()->_t = nullptr;
300
301 delete d; d = nullptr;
302}
303
304/*!
305 \enum QQuickTimeLine::SyncMode
306 */
307
308/*!
309 Return the timeline's synchronization mode.
310 */
311QQuickTimeLine::SyncMode QQuickTimeLine::syncMode() const
312{
313 return d->syncMode;
314}
315
316/*!
317 Set the timeline's synchronization mode to \a syncMode.
318 */
319void QQuickTimeLine::setSyncMode(SyncMode syncMode)
320{
321 d->syncMode = syncMode;
322}
323
324/*!
325 Pause \a obj for \a time milliseconds.
326*/
327void QQuickTimeLine::pause(QQuickTimeLineObject &obj, int time)
328{
329 if (time <= 0) return;
330 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
331 d->add(obj, op);
332}
333
334/*!
335 Execute the \a event.
336 */
337void QQuickTimeLine::callback(const QQuickTimeLineCallback &callback)
338{
339 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, callback);
340 d->add(*callback.callbackObject(), op);
341}
342
343/*!
344 Set the \a value of \a timeLineValue.
345*/
346void QQuickTimeLine::set(QQuickTimeLineValue &timeLineValue, qreal value)
347{
348 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Set, 0, value, 0., d->order++);
349 d->add(timeLineValue, op);
350}
351
352/*!
353 Decelerate \a timeLineValue from the starting \a velocity to zero at the
354 given \a acceleration rate. Although the \a acceleration is technically
355 a deceleration, it should always be positive. The QQuickTimeLine will ensure
356 that the deceleration is in the opposite direction to the initial velocity.
357*/
358int QQuickTimeLine::accel(QQuickTimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
359{
360 if (qFuzzyIsNull(acceleration) || qt_is_nan(acceleration))
361 return -1;
362
363 if ((velocity > 0.0f) == (acceleration > 0.0f))
364 acceleration = acceleration * -1.0f;
365
366 int time = static_cast<int>(-1000 * velocity / acceleration);
367 if (time <= 0) return -1;
368
369 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
370 d->add(timeLineValue, op);
371
372 return time;
373}
374
375/*!
376 \overload
377
378 Decelerate \a timeLineValue from the starting \a velocity to zero at the
379 given \a acceleration rate over a maximum distance of maxDistance.
380
381 If necessary, QQuickTimeLine will reduce the acceleration to ensure that the
382 entire operation does not require a move of more than \a maxDistance.
383 \a maxDistance should always be positive.
384*/
385int QQuickTimeLine::accel(QQuickTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
386{
387 if (qFuzzyIsNull(maxDistance) || qt_is_nan(maxDistance) || qFuzzyIsNull(acceleration) || qt_is_nan(acceleration))
388 return -1;
389
390 Q_ASSERT(acceleration > 0.0f && maxDistance > 0.0f);
391
392 qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance);
393 if (maxAccel > acceleration)
394 acceleration = maxAccel;
395
396 if ((velocity > 0.0f) == (acceleration > 0.0f))
397 acceleration = acceleration * -1.0f;
398
399 int time = static_cast<int>(-1000 * velocity / acceleration);
400 if (time <= 0) return -1;
401
402 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
403 d->add(timeLineValue, op);
404
405 return time;
406}
407
408/*!
409 Decelerate \a timeLineValue from the starting \a velocity to zero over the given
410 \a distance. This is like accel(), but the QQuickTimeLine calculates the exact
411 deceleration to use.
412
413 \a distance should be positive.
414*/
415int QQuickTimeLine::accelDistance(QQuickTimeLineValue &timeLineValue, qreal velocity, qreal distance)
416{
417 if (qFuzzyIsNull(distance) || qt_is_nan(distance) || qFuzzyIsNull(velocity) || qt_is_nan(velocity))
418 return -1;
419
420 Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f));
421
422 int time = static_cast<int>(1000 * (2.0f * distance) / velocity);
423 if (time <= 0) return -1;
424
425 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++);
426 d->add(timeLineValue, op);
427
428 return time;
429}
430
431/*!
432 Linearly change the \a timeLineValue from its current value to the given
433 \a destination value over \a time milliseconds.
434*/
435void QQuickTimeLine::move(QQuickTimeLineValue &timeLineValue, qreal destination, int time)
436{
437 if (time <= 0) return;
438 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++);
439 d->add(timeLineValue, op);
440}
441
442/*!
443 Change the \a timeLineValue from its current value to the given \a destination
444 value over \a time milliseconds using the \a easing curve.
445 */
446void QQuickTimeLine::move(QQuickTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
447{
448 if (time <= 0) return;
449 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QQuickTimeLineCallback(), easing);
450 d->add(timeLineValue, op);
451}
452
453/*!
454 Linearly change the \a timeLineValue from its current value by the \a change amount
455 over \a time milliseconds.
456*/
457void QQuickTimeLine::moveBy(QQuickTimeLineValue &timeLineValue, qreal change, int time)
458{
459 if (time <= 0) return;
460 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++);
461 d->add(timeLineValue, op);
462}
463
464/*!
465 Change the \a timeLineValue from its current value by the \a change amount over
466 \a time milliseconds using the \a easing curve.
467 */
468void QQuickTimeLine::moveBy(QQuickTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
469{
470 if (time <= 0) return;
471 QQuickTimeLinePrivate::Op op(QQuickTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QQuickTimeLineCallback(), easing);
472 d->add(timeLineValue, op);
473}
474
475/*!
476 Cancel (but don't complete) all scheduled actions for \a timeLineValue.
477*/
478void QQuickTimeLine::reset(QQuickTimeLineValue &timeLineValue)
479{
480 if (!timeLineValue._t)
481 return;
482 if (timeLineValue._t != this) {
483 qWarning() << "QQuickTimeLine: Cannot reset a QQuickTimeLineValue owned by another timeline.";
484 return;
485 }
486 qCDebug(lcTl) << static_cast<QObject*>(this) << timeLineValue.value();
487 remove(&timeLineValue);
488 timeLineValue._t = nullptr;
489}
490
491int QQuickTimeLine::duration() const
492{
493 return -1;
494}
495
496/*!
497 Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo
498 within this timeline.
499
500 Following operations on \a timeLineValue in this timeline will be scheduled after
501 all the currently scheduled actions on \a syncTo are complete. In
502 pseudo-code this is equivalent to:
503 \code
504 QQuickTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
505 \endcode
506*/
507void QQuickTimeLine::sync(QQuickTimeLineValue &timeLineValue, QQuickTimeLineValue &syncTo)
508{
509 QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo);
510 if (iter == d->ops.end())
511 return;
512 int length = iter->length;
513
514 iter = d->ops.find(&timeLineValue);
515 if (iter == d->ops.end()) {
516 pause(timeLineValue, length);
517 } else {
518 int glength = iter->length;
519 pause(timeLineValue, length - glength);
520 }
521}
522
523/*!
524 Synchronize the end point of \a timeLineValue to the endpoint of the longest
525 action cursrently scheduled in the timeline.
526
527 In pseudo-code, this is equivalent to:
528 \code
529 QQuickTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
530 \endcode
531*/
532void QQuickTimeLine::sync(QQuickTimeLineValue &timeLineValue)
533{
534 QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue);
535 if (iter == d->ops.end()) {
536 pause(timeLineValue, d->length);
537 } else {
538 pause(timeLineValue, d->length - iter->length);
539 }
540}
541
542/*
543 Synchronize all currently and future scheduled values in this timeline to
544 the longest action currently scheduled.
545
546 For example:
547 \code
548 value1->setValue(0.);
549 value2->setValue(0.);
550 value3->setValue(0.);
551 QQuickTimeLine tl;
552 ...
553 tl.move(value1, 10, 200);
554 tl.move(value2, 10, 100);
555 tl.sync();
556 tl.move(value2, 20, 100);
557 tl.move(value3, 20, 100);
558 \endcode
559
560 will result in:
561
562 \table
563 \header \li \li 0ms \li 50ms \li 100ms \li 150ms \li 200ms \li 250ms \li 300ms
564 \row \li value1 \li 0 \li 2.5 \li 5.0 \li 7.5 \li 10 \li 10 \li 10
565 \row \li value2 \li 0 \li 5.0 \li 10.0 \li 10.0 \li 10.0 \li 15.0 \li 20.0
566 \row \li value2 \li 0 \li 0 \li 0 \li 0 \li 0 \li 10.0 \li 20.0
567 \endtable
568*/
569
570/*void QQuickTimeLine::sync()
571{
572 for (QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
573 iter != d->ops.end();
574 ++iter)
575 pause(*iter.key(), d->length - iter->length);
576 d->syncPoint = d->length;
577}*/
578
579/*!
580 \internal
581
582 Temporary hack.
583 */
584void QQuickTimeLine::setSyncPoint(int sp)
585{
586 d->syncPoint = sp;
587}
588
589/*!
590 \internal
591
592 Temporary hack.
593 */
594int QQuickTimeLine::syncPoint() const
595{
596 return d->syncPoint;
597}
598
599/*!
600 Returns true if the timeline is active. An active timeline is one where
601 QQuickTimeLineValue actions are still pending.
602*/
603bool QQuickTimeLine::isActive() const
604{
605 return !d->ops.isEmpty();
606}
607
608/*!
609 Completes the timeline. All queued actions are played to completion, and then discarded. For example,
610 \code
611 QQuickTimeLineValue v(0.);
612 QQuickTimeLine tl;
613 tl.move(v, 100., 1000.);
614 // 500 ms passes
615 // v.value() == 50.
616 tl.complete();
617 // v.value() == 100.
618 \endcode
619*/
620void QQuickTimeLine::complete()
621{
622 d->advance(d->length);
623}
624
625/*!
626 Resets the timeline. All queued actions are discarded and QQuickTimeLineValue's retain their current value. For example,
627 \code
628 QQuickTimeLineValue v(0.);
629 QQuickTimeLine tl;
630 tl.move(v, 100., 1000.);
631 // 500 ms passes
632 // v.value() == 50.
633 tl.clear();
634 // v.value() == 50.
635 \endcode
636*/
637void QQuickTimeLine::clear()
638{
639 for (QQuickTimeLinePrivate::Ops::const_iterator iter = d->ops.cbegin(), cend = d->ops.cend(); iter != cend; ++iter)
640 iter.key()->_t = nullptr;
641 d->ops.clear();
642 d->length = 0;
643 d->syncPoint = 0;
644 //XXX need stop here?
645}
646
647int QQuickTimeLine::time() const
648{
649 return d->prevTime;
650}
651
652/*!
653 \fn void QQuickTimeLine::updated()
654
655 Emitted each time the timeline modifies QQuickTimeLineValues. Even if multiple
656 QQuickTimeLineValues are changed, this signal is only emitted once for each clock tick.
657*/
658
659void QQuickTimeLine::updateCurrentTime(int v)
660{
661 if (d->syncAdj == -1)
662 d->syncAdj = v;
663 v -= d->syncAdj;
664
665 int timeChanged = v - d->prevTime;
666#if 0
667 if (!timeChanged)
668 return;
669#endif
670 d->prevTime = v;
671 d->advance(timeChanged);
672 emit updated();
673
674 // Do we need to stop the clock?
675 if (d->ops.isEmpty()) {
676 stop();
677 d->prevTime = 0;
678 d->clockRunning = false;
679 emit completed();
680 } /*else if (pauseTime > 0) {
681 GfxClock::cancelClock();
682 d->prevTime = 0;
683 GfxClock::pauseFor(pauseTime);
684 d->syncAdj = 0;
685 d->clockRunning = false;
686 }*/elseif(/*!GfxClock::isActive()*/state()!=Running){
687 stop();
688 d->prevTime = 0;
689 d->clockRunning = true;
690 d->syncAdj = 0;
691 start();
692 }
693}
694
695void QQuickTimeLine::debugAnimation(QDebug d) const
696{
697 d << "QuickTimeLine(" << Qt::hex << (const void *) this << Qt::dec << ")";
698}
699
700bool operator<(const std::pair<int, Update> &lhs,
701 const std::pair<int, Update> &rhs)
702{
703 return lhs.first < rhs.first;
704}
705
707{
708 int pauseTime = -1;
709
710 // XXX - surely there is a more efficient way?
711 do {
712 pauseTime = -1;
713 // Minimal advance time
714 int advanceTime = t;
715 for (Ops::const_iterator iter = ops.constBegin(), cend = ops.constEnd(); iter != cend; ++iter) {
716 const TimeLine &tl = *iter;
717 const Op &op = tl.ops.first();
718 int length = op.length - tl.consumedOpLength;
719
720 if (length < advanceTime) {
721 advanceTime = length;
722 if (advanceTime == 0)
723 break;
724 }
725 }
726 t -= advanceTime;
727
728 // Process until then. A zero length advance time will only process
729 // sets.
730 QList<std::pair<int, Update> > updates;
731
732 for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ) {
733 QQuickTimeLineValue *v = static_cast<QQuickTimeLineValue *>(iter.key());
734 TimeLine &tl = *iter;
735 Q_ASSERT(!tl.ops.isEmpty());
736
737 do {
738 Op &op = tl.ops.first();
739 if (advanceTime == 0 && op.length != 0)
740 continue;
741
742 if (tl.consumedOpLength == 0 &&
743 op.type != Op::Pause &&
744 op.type != Op::Execute)
745 tl.base = v->value();
746
747 if ((tl.consumedOpLength + advanceTime) == op.length) {
748 // Finishing operation, the timeline value will be the operation's target value.
749 if (op.type == Op::Execute) {
750 updates << std::make_pair(op.order, Update(op.event));
751 } else {
752 bool changed = false;
753 qreal val = value(op, op.length, tl.base, &changed);
754 if (changed)
755 updates << std::make_pair(op.order, Update(v, val));
756 }
757 tl.length -= qMin(advanceTime, tl.length);
758 tl.consumedOpLength = 0;
759 tl.ops.removeFirst();
760 } else {
761 // Partially finished operation, the timeline value will be between the base
762 // value and the target value, depending on progress and type of operation.
763 tl.consumedOpLength += advanceTime;
764 bool changed = false;
765 qreal val = value(op, tl.consumedOpLength, tl.base, &changed);
766 if (changed)
767 updates << std::make_pair(op.order, Update(v, val));
768 tl.length -= qMin(advanceTime, tl.length);
769 break;
770 }
771
772 } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0);
773
774
775 if (tl.ops.isEmpty()) {
776 iter = ops.erase(iter);
777 v->_t = nullptr;
778 } else {
779 if (tl.ops.first().type == Op::Pause && pauseTime != 0) {
780 int opPauseTime = tl.ops.first().length - tl.consumedOpLength;
781 if (pauseTime == -1 || opPauseTime < pauseTime)
782 pauseTime = opPauseTime;
783 } else {
784 pauseTime = 0;
785 }
786 ++iter;
787 }
788 }
789
790 length -= qMin(length, advanceTime);
791 syncPoint -= advanceTime;
792
793 std::sort(updates.begin(), updates.end());
794 updateQueue = &updates;
795 for (int ii = 0; ii < updates.size(); ++ii) {
796 const Update &v = updates.at(ii).second;
797 if (v.g) {
798 v.g->setValue(v.v);
799 } else {
800 v.e.d0(v.e.d1);
801 }
802 }
803 updateQueue = nullptr;
804 } while(t);
805
806 return pauseTime;
807}
808
809void QQuickTimeLine::remove(QQuickTimeLineObject *v)
810{
811 QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.find(v);
812 Q_ASSERT(iter != d->ops.end());
813
814 int len = iter->length;
815 d->ops.erase(iter);
816 if (len == d->length) {
817 // We need to recalculate the length
818 d->length = 0;
819 for (QQuickTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
820 iter != d->ops.end();
821 ++iter) {
822
823 if (iter->length > d->length)
824 d->length = iter->length;
825
826 }
827 }
828 if (d->ops.isEmpty()) {
829 stop();
830 d->clockRunning = false;
831 } else if (state() != Running) { // was !GfxClock::isActive()
832 stop();
833 d->prevTime = 0;
834 d->clockRunning = true;
835
836 if (d->syncMode == QQuickTimeLine::LocalSync) {
837 d->syncAdj = -1;
838 } else {
839 d->syncAdj = 0;
840 }
841 start();
842 }
843
844 if (d->updateQueue) {
845 for (int ii = 0; ii < d->updateQueue->size(); ++ii) {
846 if (d->updateQueue->at(ii).second.g == v ||
847 d->updateQueue->at(ii).second.e.callbackObject() == v) {
848 d->updateQueue->removeAt(ii);
849 --ii;
850 }
851 }
852 }
853
854
855}
856
857/*!
858 \internal
859 \class QQuickTimeLineValue
860 \brief The QQuickTimeLineValue class provides a value that can be modified by QQuickTimeLine.
861*/
862
863/*!
864 \fn QQuickTimeLineValue::QQuickTimeLineValue(qreal value = 0)
865
866 Construct a new QQuickTimeLineValue with an initial \a value.
867*/
868
869/*!
870 \fn qreal QQuickTimeLineValue::value() const
871
872 Return the current value.
873*/
874
875/*!
876 \fn void QQuickTimeLineValue::setValue(qreal value)
877
878 Set the current \a value.
879*/
880
881/*!
882 \fn QQuickTimeLine *QQuickTimeLineValue::timeLine() const
883
884 If a QQuickTimeLine is operating on this value, return a pointer to it,
885 otherwise return null.
886*/
887
888
889QQuickTimeLineObject::QQuickTimeLineObject()
890: _t(nullptr)
891{
892}
893
894QQuickTimeLineObject::~QQuickTimeLineObject()
895{
896 if (_t) {
897 _t->remove(this);
898 _t = nullptr;
899 }
900}
901
902QQuickTimeLineCallback::QQuickTimeLineCallback()
903: d0(nullptr), d1(nullptr), d2(nullptr)
904{
905}
906
907QQuickTimeLineCallback::QQuickTimeLineCallback(QQuickTimeLineObject *b, Callback f, void *d)
908: d0(f), d1(d), d2(b)
909{
910}
911
912QQuickTimeLineCallback::QQuickTimeLineCallback(const QQuickTimeLineCallback &o)
913: d0(o.d0), d1(o.d1), d2(o.d2)
914{
915}
916
917QQuickTimeLineCallback &QQuickTimeLineCallback::operator=(const QQuickTimeLineCallback &o)
918{
919 d0 = o.d0;
920 d1 = o.d1;
921 d2 = o.d2;
922 return *this;
923}
924
925QQuickTimeLineObject *QQuickTimeLineCallback::callbackObject() const
926{
927 return d2;
928}
929
930QT_END_NAMESPACE
931
932#include "moc_qquicktimeline_p_p.cpp"
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
bool operator<(const std::pair< int, Update > &lhs, const std::pair< int, Update > &rhs)
Op & operator=(const Op &o)
Op(Type t, int l, qreal v, qreal v2, int o, const QQuickTimeLineCallback &ev=QQuickTimeLineCallback(), const QEasingCurve &es=QEasingCurve())
QQuickTimeLineCallback event
QList< std::pair< int, Update > > * updateQueue
qreal value(const Op &op, int time, qreal base, bool *) const
void add(QQuickTimeLineObject &, const Op &)
QQuickTimeLinePrivate(QQuickTimeLine *)
QHash< QQuickTimeLineObject *, TimeLine > Ops
QQuickTimeLineCallback e
QQuickTimeLineValue * g
Update(const QQuickTimeLineCallback &_e)
Update(QQuickTimeLineValue *_g, qreal _v)