source: trunk/src/declarative/util/qdeclarativetimeline.cpp@ 986

Last change on this file since 986 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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