1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativetimeline_p_p.h"
47 #include <QWaitCondition>
49 #include <QCoreApplication>
50 #include <QEasingCurve>
56 Update(QDeclarativeTimeLineValue *_g, qreal _v)
58 Update(const QDeclarativeTimeLineCallback &_e)
59 : g(0), v(0), e(_e) {}
61 QDeclarativeTimeLineValue *g;
63 QDeclarativeTimeLineCallback e;
66 struct QDeclarativeTimeLinePrivate
68 QDeclarativeTimeLinePrivate(QDeclarativeTimeLine *);
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),
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;
101 QDeclarativeTimeLineCallback event;
106 TimeLine() : length(0), consumedOpLength(0), base(0.) {}
109 int consumedOpLength;
115 typedef QHash<QDeclarativeTimeLineObject *, TimeLine> Ops;
117 QDeclarativeTimeLine *q;
119 void add(QDeclarativeTimeLineObject &, const Op &);
120 qreal value(const Op &op, int time, qreal base, bool *) const;
129 QDeclarativeTimeLine::SyncMode syncMode;
131 QList<QPair<int, Update> > *updateQueue;
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)
139 void QDeclarativeTimeLinePrivate::add(QDeclarativeTimeLineObject &g, const Op &o)
141 if (g._t && g._t != q) {
142 qWarning() << "QDeclarativeTimeLine: Cannot modify a QDeclarativeTimeLineValue owned by"
143 << "another timeline.";
148 Ops::Iterator iter = ops.find(&g);
149 if (iter == ops.end()) {
150 iter = ops.insert(&g, TimeLine());
152 q->pause(g, syncPoint);
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;
161 iter->length += o.length;
164 if (iter->length > length)
165 length = iter->length;
172 if (syncMode == QDeclarativeTimeLine::LocalSync) {
179 if (syncMode == QDeclarativeTimeLine::LocalSync) {
188 qreal QDeclarativeTimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const
191 Q_ASSERT(time <= op.length);
203 } else if (time == (op.length)) {
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;
211 return base + delta * op.easing.valueForProgress(pTime);
216 } else if (time == (op.length)) {
217 return base + op.value;
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;
224 return base + delta * op.easing.valueForProgress(pTime);
230 qreal t = (qreal)(time) / 1000.0f;
231 qreal delta = op.value * t + 0.5f * op.value2 * t * t;
234 case Op::AccelDistance:
237 } else if (time == (op.length)) {
238 return base + op.value2;
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;
247 op.event.d0(op.event.d1);
257 \class QDeclarativeTimeLine
258 \brief The QDeclarativeTimeLine class provides a timeline for controlling animations.
260 QDeclarativeTimeLine is similar to QTimeLine except:
262 \i It updates QDeclarativeTimeLineValue instances directly, rather than maintaining a single
265 For example, the following animates a simple value over 200 milliseconds:
267 QDeclarativeTimeLineValue v(<starting value>);
268 QDeclarativeTimeLine tl;
269 tl.move(v, 100., 200);
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.
277 \i Supports multiple QDeclarativeTimeLineValue, arbitrary start and end values and allows
278 animations to be strung together for more complex effects.
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
286 QDeclarativeTimeLineValue x(<starting value>);
287 QDeclarativeTimeLineValue y(<starting value>);
289 QDeclarativeTimeLine tl;
292 tl.move(x, 100., 50);
293 tl.move(y, 100., 50);
294 tl.move(y, 200., 50);
297 \i All QDeclarativeTimeLine instances share a single, synchronized clock.
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.
306 Currently easing functions are not supported.
311 Construct a new QDeclarativeTimeLine with the specified \a parent.
313 QDeclarativeTimeLine::QDeclarativeTimeLine(QObject *parent)
314 : QAbstractAnimation(parent)
316 d = new QDeclarativeTimeLinePrivate(this);
320 Destroys the time line. Any inprogress animations are canceled, but not
323 QDeclarativeTimeLine::~QDeclarativeTimeLine()
325 for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
326 iter != d->ops.end();
334 \enum QDeclarativeTimeLine::SyncMode
338 Return the timeline's synchronization mode.
340 QDeclarativeTimeLine::SyncMode QDeclarativeTimeLine::syncMode() const
346 Set the timeline's synchronization mode to \a syncMode.
348 void QDeclarativeTimeLine::setSyncMode(SyncMode syncMode)
350 d->syncMode = syncMode;
354 Pause \a obj for \a time milliseconds.
356 void QDeclarativeTimeLine::pause(QDeclarativeTimeLineObject &obj, int time)
358 if (time <= 0) return;
359 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
364 Execute the \a event.
366 void QDeclarativeTimeLine::callback(const QDeclarativeTimeLineCallback &callback)
368 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, callback);
369 d->add(*callback.callbackObject(), op);
373 Set the \a value of \a timeLineValue.
375 void QDeclarativeTimeLine::set(QDeclarativeTimeLineValue &timeLineValue, qreal value)
377 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Set, 0, value, 0., d->order++);
378 d->add(timeLineValue, op);
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.
387 int QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
389 if (acceleration == 0.0f)
392 if ((velocity > 0.0f) == (acceleration > 0.0f))
393 acceleration = acceleration * -1.0f;
395 int time = static_cast<int>(-1000 * velocity / acceleration);
397 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
398 d->add(timeLineValue, op);
406 Decelerate \a timeLineValue from the starting \a velocity to zero at the
407 given \a acceleration rate over a maximum distance of maxDistance.
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.
413 int QDeclarativeTimeLine::accel(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
415 if (maxDistance == 0.0f || acceleration == 0.0f)
418 Q_ASSERT(acceleration > 0.0f && maxDistance > 0.0f);
420 qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance);
421 if (maxAccel > acceleration)
422 acceleration = maxAccel;
424 if ((velocity > 0.0f) == (acceleration > 0.0f))
425 acceleration = acceleration * -1.0f;
427 int time = static_cast<int>(-1000 * velocity / acceleration);
429 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
430 d->add(timeLineValue, op);
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
440 \a distance should be positive.
442 int QDeclarativeTimeLine::accelDistance(QDeclarativeTimeLineValue &timeLineValue, qreal velocity, qreal distance)
444 if (distance == 0.0f || velocity == 0.0f)
447 Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f));
449 int time = static_cast<int>(1000 * (2.0f * distance) / velocity);
451 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++);
452 d->add(timeLineValue, op);
458 Linearly change the \a timeLineValue from its current value to the given
459 \a destination value over \a time milliseconds.
461 void QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, int time)
463 if (time <= 0) return;
464 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++);
465 d->add(timeLineValue, op);
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.
472 void QDeclarativeTimeLine::move(QDeclarativeTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
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);
480 Linearly change the \a timeLineValue from its current value by the \a change amount
481 over \a time milliseconds.
483 void QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, int time)
485 if (time <= 0) return;
486 QDeclarativeTimeLinePrivate::Op op(QDeclarativeTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++);
487 d->add(timeLineValue, op);
491 Change the \a timeLineValue from its current value by the \a change amount over
492 \a time milliseconds using the \a easing curve.
494 void QDeclarativeTimeLine::moveBy(QDeclarativeTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
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);
502 Cancel (but don't complete) all scheduled actions for \a timeLineValue.
504 void QDeclarativeTimeLine::reset(QDeclarativeTimeLineValue &timeLineValue)
506 if (!timeLineValue._t)
508 if (timeLineValue._t != this) {
509 qWarning() << "QDeclarativeTimeLine: Cannot reset a QDeclarativeTimeLineValue owned by another timeline.";
512 remove(&timeLineValue);
513 timeLineValue._t = 0;
516 int QDeclarativeTimeLine::duration() const
522 Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo
523 within this timeline.
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:
529 QDeclarativeTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
532 void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue, QDeclarativeTimeLineValue &syncTo)
534 QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo);
535 if (iter == d->ops.end())
537 int length = iter->length;
539 iter = d->ops.find(&timeLineValue);
540 if (iter == d->ops.end()) {
541 pause(timeLineValue, length);
543 int glength = iter->length;
544 pause(timeLineValue, length - glength);
549 Synchronize the end point of \a timeLineValue to the endpoint of the longest
550 action cursrently scheduled in the timeline.
552 In pseudo-code, this is equivalent to:
554 QDeclarativeTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
557 void QDeclarativeTimeLine::sync(QDeclarativeTimeLineValue &timeLineValue)
559 QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue);
560 if (iter == d->ops.end()) {
561 pause(timeLineValue, d->length);
563 pause(timeLineValue, d->length - iter->length);
568 Synchronize all currently and future scheduled values in this timeline to
569 the longest action currently scheduled.
573 value1->setValue(0.);
574 value2->setValue(0.);
575 value3->setValue(0.);
576 QDeclarativeTimeLine tl;
578 tl.move(value1, 10, 200);
579 tl.move(value2, 10, 100);
581 tl.move(value2, 20, 100);
582 tl.move(value3, 20, 100);
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
595 /*void QDeclarativeTimeLine::sync()
597 for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
598 iter != d->ops.end();
600 pause(*iter.key(), d->length - iter->length);
601 d->syncPoint = d->length;
609 void QDeclarativeTimeLine::setSyncPoint(int sp)
619 int QDeclarativeTimeLine::syncPoint() const
625 Returns true if the timeline is active. An active timeline is one where
626 QDeclarativeTimeLineValue actions are still pending.
628 bool QDeclarativeTimeLine::isActive() const
630 return !d->ops.isEmpty();
634 Completes the timeline. All queued actions are played to completion, and then discarded. For example,
636 QDeclarativeTimeLineValue v(0.);
637 QDeclarativeTimeLine tl;
638 tl.move(v, 100., 1000.);
645 void QDeclarativeTimeLine::complete()
647 d->advance(d->length);
651 Resets the timeline. All queued actions are discarded and QDeclarativeTimeLineValue's retain their current value. For example,
653 QDeclarativeTimeLineValue v(0.);
654 QDeclarativeTimeLine tl;
655 tl.move(v, 100., 1000.);
662 void QDeclarativeTimeLine::clear()
664 for (QDeclarativeTimeLinePrivate::Ops::ConstIterator iter = d->ops.begin(); iter != d->ops.end(); ++iter)
669 //XXX need stop here?
672 int QDeclarativeTimeLine::time() const
678 \fn void QDeclarativeTimeLine::updated()
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.
684 void QDeclarativeTimeLine::updateCurrentTime(int v)
686 if (d->syncAdj == -1)
690 int timeChanged = v - d->prevTime;
696 d->advance(timeChanged);
699 // Do we need to stop the clock?
700 if (d->ops.isEmpty()) {
703 d->clockRunning = false;
705 } /*else if (pauseTime > 0) {
706 GfxClock::cancelClock();
708 GfxClock::pauseFor(pauseTime);
710 d->clockRunning = false;
711 }*/ else if (/*!GfxClock::isActive()*/ state() != Running) {
714 d->clockRunning = true;
720 bool operator<(const QPair<int, Update> &lhs,
721 const QPair<int, Update> &rhs)
723 return lhs.first < rhs.first;
726 int QDeclarativeTimeLinePrivate::advance(int t)
730 // XXX - surely there is a more efficient way?
733 // Minimal advance time
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;
740 if (length < advanceTime) {
741 advanceTime = length;
742 if (advanceTime == 0)
748 // Process until then. A zero length advance time will only process
750 QList<QPair<int, Update> > updates;
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());
758 Op &op = tl.ops.first();
759 if (advanceTime == 0 && op.length != 0)
762 if (tl.consumedOpLength == 0 &&
763 op.type != Op::Pause &&
764 op.type != Op::Execute)
765 tl.base = v->value();
767 if ((tl.consumedOpLength + advanceTime) == op.length) {
768 if (op.type == Op::Execute) {
769 updates << qMakePair(op.order, Update(op.event));
771 bool changed = false;
772 qreal val = value(op, op.length, tl.base, &changed);
774 updates << qMakePair(op.order, Update(v, val));
776 tl.length -= qMin(advanceTime, tl.length);
777 tl.consumedOpLength = 0;
778 tl.ops.removeFirst();
780 tl.consumedOpLength += advanceTime;
781 bool changed = false;
782 qreal val = value(op, tl.consumedOpLength, tl.base, &changed);
784 updates << qMakePair(op.order, Update(v, val));
785 tl.length -= qMin(advanceTime, tl.length);
789 } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0);
792 if (tl.ops.isEmpty()) {
793 iter = ops.erase(iter);
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;
807 length -= qMin(length, advanceTime);
808 syncPoint -= advanceTime;
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;
826 void QDeclarativeTimeLine::remove(QDeclarativeTimeLineObject *v)
828 QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.find(v);
829 Q_ASSERT(iter != d->ops.end());
831 int len = iter->length;
833 if (len == d->length) {
834 // We need to recalculate the length
836 for (QDeclarativeTimeLinePrivate::Ops::Iterator iter = d->ops.begin();
837 iter != d->ops.end();
840 if (iter->length > d->length)
841 d->length = iter->length;
845 if (d->ops.isEmpty()) {
847 d->clockRunning = false;
848 } else if (/*!GfxClock::isActive()*/ state() != Running) {
851 d->clockRunning = true;
853 if (d->syncMode == QDeclarativeTimeLine::LocalSync) {
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);
876 \class QDeclarativeTimeLineValue
877 \brief The QDeclarativeTimeLineValue class provides a value that can be modified by QDeclarativeTimeLine.
881 \fn QDeclarativeTimeLineValue::QDeclarativeTimeLineValue(qreal value = 0)
883 Construct a new QDeclarativeTimeLineValue with an initial \a value.
887 \fn qreal QDeclarativeTimeLineValue::value() const
889 Return the current value.
893 \fn void QDeclarativeTimeLineValue::setValue(qreal value)
895 Set the current \a value.
899 \fn QDeclarativeTimeLine *QDeclarativeTimeLineValue::timeLine() const
901 If a QDeclarativeTimeLine is operating on this value, return a pointer to it,
902 otherwise return null.
906 QDeclarativeTimeLineObject::QDeclarativeTimeLineObject()
911 QDeclarativeTimeLineObject::~QDeclarativeTimeLineObject()
919 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback()
920 : d0(0), d1(0), d2(0)
924 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(QDeclarativeTimeLineObject *b, Callback f, void *d)
925 : d0(f), d1(d), d2(b)
929 QDeclarativeTimeLineCallback::QDeclarativeTimeLineCallback(const QDeclarativeTimeLineCallback &o)
930 : d0(o.d0), d1(o.d1), d2(o.d2)
934 QDeclarativeTimeLineCallback &QDeclarativeTimeLineCallback::operator=(const QDeclarativeTimeLineCallback &o)
942 QDeclarativeTimeLineObject *QDeclarativeTimeLineCallback::callbackObject() const