src/declarative/util/qdeclarativetimeline.cpp
changeset 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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     psuedo-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 psuedo-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