Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / util / qdeclarativetimeline.cpp
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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
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
53 QT_BEGIN_NAMESPACE
54
55 struct 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
66 struct 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
134 QDeclarativeTimeLinePrivate::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
139 void 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
188 qreal 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 */
313 QDeclarativeTimeLine::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 */
323 QDeclarativeTimeLine::~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  */
340 QDeclarativeTimeLine::SyncMode QDeclarativeTimeLine::syncMode() const
341 {
342     return d->syncMode;
343 }
344
345 /*!
346     Set the timeline's synchronization mode to \a syncMode.
347  */
348 void QDeclarativeTimeLine::setSyncMode(SyncMode syncMode)
349 {
350     d->syncMode = syncMode;
351 }
352
353 /*!
354     Pause \a obj for \a time milliseconds.
355 */
356 void 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  */
366 void 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 */
375 void 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 */
387 int 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 */
413 int 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 */
442 int 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 */
461 void 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  */
472 void 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 */
483 void 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  */
494 void 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 */
504 void 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
516 int 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 */
532 void 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 */
557 void 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  */
609 void QDeclarativeTimeLine::setSyncPoint(int sp)
610 {
611     d->syncPoint = sp;
612 }
613
614 /*! 
615     \internal 
616  
617     Temporary hack.
618  */
619 int 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 */
628 bool 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 */
645 void 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 */
662 void 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
672 int 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
684 void 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
720 bool operator<(const QPair<int, Update> &lhs,
721                const QPair<int, Update> &rhs)
722 {
723     return lhs.first < rhs.first;
724 }
725
726 int 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
826 void 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
906 QDeclarativeTimeLineObject::QDeclarativeTimeLineObject()
907 : _t(0)
908 {
909 }
910
911 QDeclarativeTimeLineObject::~QDeclarativeTimeLineObject()
912 {
913     if (_t) {
914         _t->remove(this);
915         _t = 0;
916     }
917 }
918
919 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback()
920 : d0(0), d1(0), d2(0)
921 {
922 }
923
924 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback f, void *d)
925 : d0(f), d1(d), d2(b)
926 {
927 }
928
929 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o)
930 : d0(o.d0), d1(o.d1), d2(o.d2)
931 {
932 }
933
934 QDeclarativeTimeLineCallback &QDeclarativeTimeLineCallback::operator=(const QDeclarativeTimeLineCallback &o)
935 {
936     d0 = o.d0;
937     d1 = o.d1;
938     d2 = o.d2;
939     return *this;
940 }
941
942 QDeclarativeTimeLineObject *QDeclarativeTimeLineCallback::callbackObject() const
943 {
944     return d2;
945 }
946
947 QT_END_NAMESPACE