1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativetimeline_p_p.h"
47 #include <QWaitCondition>
49 #include <QCoreApplication>
50 #include <QEasingCurve>
58 Update(QDeclarative1TimeLineValue *_g, qreal _v)
60 Update(const QDeclarative1TimeLineCallback &_e)
61 : g(0), v(0), e(_e) {}
63 QDeclarative1TimeLineValue *g;
65 QDeclarative1TimeLineCallback e;
68 struct QDeclarative1TimeLinePrivate
70 QDeclarative1TimeLinePrivate(QDeclarative1TimeLine *);
83 Op(Type t, int l, qreal v, qreal v2, int o,
84 const QDeclarative1TimeLineCallback &ev = QDeclarative1TimeLineCallback(), const QEasingCurve &es = QEasingCurve())
85 : type(t), length(l), value(v), value2(v2), order(o), event(ev),
88 : type(o.type), length(o.length), value(o.value), value2(o.value2),
89 order(o.order), event(o.event), easing(o.easing) {}
90 Op &operator=(const Op &o) {
91 type = o.type; length = o.length; value = o.value;
92 value2 = o.value2; order = o.order; event = o.event;
103 QDeclarative1TimeLineCallback event;
108 TimeLine() : length(0), consumedOpLength(0), base(0.) {}
111 int consumedOpLength;
117 typedef QHash<QDeclarative1TimeLineObject *, TimeLine> Ops;
119 QDeclarative1TimeLine *q;
121 void add(QDeclarative1TimeLineObject &, const Op &);
122 qreal value(const Op &op, int time, qreal base, bool *) const;
131 QDeclarative1TimeLine::SyncMode syncMode;
133 QList<QPair<int, Update> > *updateQueue;
136 QDeclarative1TimeLinePrivate::QDeclarative1TimeLinePrivate(QDeclarative1TimeLine *parent)
137 : length(0), syncPoint(0), q(parent), clockRunning(false), prevTime(0), order(0), syncMode(QDeclarative1TimeLine::LocalSync), syncAdj(0), updateQueue(0)
141 void QDeclarative1TimeLinePrivate::add(QDeclarative1TimeLineObject &g, const Op &o)
143 if (g._t && g._t != q) {
144 qWarning() << "QDeclarative1TimeLine: Cannot modify a QDeclarative1TimeLineValue owned by"
145 << "another timeline.";
150 Ops::Iterator iter = ops.find(&g);
151 if (iter == ops.end()) {
152 iter = ops.insert(&g, TimeLine());
154 q->pause(g, syncPoint);
156 if (!iter->ops.isEmpty() &&
157 o.type == Op::Pause &&
158 iter->ops.last().type == Op::Pause) {
159 iter->ops.last().length += o.length;
160 iter->length += o.length;
163 iter->length += o.length;
166 if (iter->length > length)
167 length = iter->length;
174 if (syncMode == QDeclarative1TimeLine::LocalSync) {
181 if (syncMode == QDeclarative1TimeLine::LocalSync) {
190 qreal QDeclarative1TimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const
193 Q_ASSERT(time <= op.length);
205 } else if (time == (op.length)) {
208 qreal delta = op.value - base;
209 qreal pTime = (qreal)(time) / (qreal)op.length;
210 if (op.easing.type() == QEasingCurve::Linear)
211 return base + delta * pTime;
213 return base + delta * op.easing.valueForProgress(pTime);
218 } else if (time == (op.length)) {
219 return base + op.value;
221 qreal delta = op.value;
222 qreal pTime = (qreal)(time) / (qreal)op.length;
223 if (op.easing.type() == QEasingCurve::Linear)
224 return base + delta * pTime;
226 return base + delta * op.easing.valueForProgress(pTime);
232 qreal t = (qreal)(time) / 1000.0f;
233 qreal delta = op.value * t + 0.5f * op.value2 * t * t;
236 case Op::AccelDistance:
239 } else if (time == (op.length)) {
240 return base + op.value2;
242 qreal t = (qreal)(time) / 1000.0f;
243 qreal accel = -1.0f * 1000.0f * op.value / (qreal)op.length;
244 qreal delta = op.value * t + 0.5f * accel * t * t;
249 op.event.d0(op.event.d1);
259 \class QDeclarative1TimeLine
260 \brief The QDeclarative1TimeLine class provides a timeline for controlling animations.
262 QDeclarative1TimeLine is similar to QTimeLine except:
264 \i It updates QDeclarative1TimeLineValue instances directly, rather than maintaining a single
267 For example, the following animates a simple value over 200 milliseconds:
269 QDeclarative1TimeLineValue v(<starting value>);
270 QDeclarative1TimeLine tl;
271 tl.move(v, 100., 200);
275 If your program needs to know when values are changed, it can either
276 connect to the QDeclarative1TimeLine's updated() signal, or inherit from QDeclarative1TimeLineValue
277 and reimplement the QDeclarative1TimeLineValue::setValue() method.
279 \i Supports multiple QDeclarative1TimeLineValue, arbitrary start and end values and allows
280 animations to be strung together for more complex effects.
282 For example, the following animation moves the x and y coordinates of
283 an object from wherever they are to the position (100, 100) in 50
284 milliseconds and then further animates them to (100, 200) in 50
288 QDeclarative1TimeLineValue x(<starting value>);
289 QDeclarative1TimeLineValue y(<starting value>);
291 QDeclarative1TimeLine tl;
294 tl.move(x, 100., 50);
295 tl.move(y, 100., 50);
296 tl.move(y, 200., 50);
299 \i All QDeclarative1TimeLine instances share a single, synchronized clock.
301 Actions scheduled within the same event loop tick are scheduled
302 synchronously against each other, regardless of the wall time between the
303 scheduling. Synchronized scheduling applies both to within the same
304 QDeclarative1TimeLine and across separate QDeclarative1TimeLine's within the same process.
308 Currently easing functions are not supported.
313 Construct a new QDeclarative1TimeLine with the specified \a parent.
315 QDeclarative1TimeLine::QDeclarative1TimeLine(QObject *parent)
316 : QAbstractAnimation(parent)
318 d = new QDeclarative1TimeLinePrivate(this);
322 Destroys the time line. Any inprogress animations are canceled, but not
325 QDeclarative1TimeLine::~QDeclarative1TimeLine()
327 for (QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.begin();
328 iter != d->ops.end();
336 \enum QDeclarative1TimeLine::SyncMode
340 Return the timeline's synchronization mode.
342 QDeclarative1TimeLine::SyncMode QDeclarative1TimeLine::syncMode() const
348 Set the timeline's synchronization mode to \a syncMode.
350 void QDeclarative1TimeLine::setSyncMode(SyncMode syncMode)
352 d->syncMode = syncMode;
356 Pause \a obj for \a time milliseconds.
358 void QDeclarative1TimeLine::pause(QDeclarative1TimeLineObject &obj, int time)
360 if (time <= 0) return;
361 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Pause, time, 0., 0., d->order++);
366 Execute the \a event.
368 void QDeclarative1TimeLine::callback(const QDeclarative1TimeLineCallback &callback)
370 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, callback);
371 d->add(*callback.callbackObject(), op);
375 Set the \a value of \a timeLineValue.
377 void QDeclarative1TimeLine::set(QDeclarative1TimeLineValue &timeLineValue, qreal value)
379 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Set, 0, value, 0., d->order++);
380 d->add(timeLineValue, op);
384 Decelerate \a timeLineValue from the starting \a velocity to zero at the
385 given \a acceleration rate. Although the \a acceleration is technically
386 a deceleration, it should always be positive. The QDeclarative1TimeLine will ensure
387 that the deceleration is in the opposite direction to the initial velocity.
389 int QDeclarative1TimeLine::accel(QDeclarative1TimeLineValue &timeLineValue, qreal velocity, qreal acceleration)
391 if (acceleration == 0.0f)
394 if ((velocity > 0.0f) == (acceleration > 0.0f))
395 acceleration = acceleration * -1.0f;
397 int time = static_cast<int>(-1000 * velocity / acceleration);
399 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
400 d->add(timeLineValue, op);
408 Decelerate \a timeLineValue from the starting \a velocity to zero at the
409 given \a acceleration rate over a maximum distance of maxDistance.
411 If necessary, QDeclarative1TimeLine will reduce the acceleration to ensure that the
412 entire operation does not require a move of more than \a maxDistance.
413 \a maxDistance should always be positive.
415 int QDeclarative1TimeLine::accel(QDeclarative1TimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance)
417 if (maxDistance == 0.0f || acceleration == 0.0f)
420 Q_ASSERT(acceleration > 0.0f && maxDistance > 0.0f);
422 qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance);
423 if (maxAccel > acceleration)
424 acceleration = maxAccel;
426 if ((velocity > 0.0f) == (acceleration > 0.0f))
427 acceleration = acceleration * -1.0f;
429 int time = static_cast<int>(-1000 * velocity / acceleration);
431 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++);
432 d->add(timeLineValue, op);
438 Decelerate \a timeLineValue from the starting \a velocity to zero over the given
439 \a distance. This is like accel(), but the QDeclarative1TimeLine calculates the exact
442 \a distance should be positive.
444 int QDeclarative1TimeLine::accelDistance(QDeclarative1TimeLineValue &timeLineValue, qreal velocity, qreal distance)
446 if (distance == 0.0f || velocity == 0.0f)
449 Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f));
451 int time = static_cast<int>(1000 * (2.0f * distance) / velocity);
453 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++);
454 d->add(timeLineValue, op);
460 Linearly change the \a timeLineValue from its current value to the given
461 \a destination value over \a time milliseconds.
463 void QDeclarative1TimeLine::move(QDeclarative1TimeLineValue &timeLineValue, qreal destination, int time)
465 if (time <= 0) return;
466 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++);
467 d->add(timeLineValue, op);
471 Change the \a timeLineValue from its current value to the given \a destination
472 value over \a time milliseconds using the \a easing curve.
474 void QDeclarative1TimeLine::move(QDeclarative1TimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time)
476 if (time <= 0) return;
477 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QDeclarative1TimeLineCallback(), easing);
478 d->add(timeLineValue, op);
482 Linearly change the \a timeLineValue from its current value by the \a change amount
483 over \a time milliseconds.
485 void QDeclarative1TimeLine::moveBy(QDeclarative1TimeLineValue &timeLineValue, qreal change, int time)
487 if (time <= 0) return;
488 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++);
489 d->add(timeLineValue, op);
493 Change the \a timeLineValue from its current value by the \a change amount over
494 \a time milliseconds using the \a easing curve.
496 void QDeclarative1TimeLine::moveBy(QDeclarative1TimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time)
498 if (time <= 0) return;
499 QDeclarative1TimeLinePrivate::Op op(QDeclarative1TimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QDeclarative1TimeLineCallback(), easing);
500 d->add(timeLineValue, op);
504 Cancel (but don't complete) all scheduled actions for \a timeLineValue.
506 void QDeclarative1TimeLine::reset(QDeclarative1TimeLineValue &timeLineValue)
508 if (!timeLineValue._t)
510 if (timeLineValue._t != this) {
511 qWarning() << "QDeclarative1TimeLine: Cannot reset a QDeclarative1TimeLineValue owned by another timeline.";
514 remove(&timeLineValue);
515 timeLineValue._t = 0;
518 int QDeclarative1TimeLine::duration() const
524 Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo
525 within this timeline.
527 Following operations on \a timeLineValue in this timeline will be scheduled after
528 all the currently scheduled actions on \a syncTo are complete. In
529 pseudo-code this is equivalent to:
531 QDeclarative1TimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue)))
534 void QDeclarative1TimeLine::sync(QDeclarative1TimeLineValue &timeLineValue, QDeclarative1TimeLineValue &syncTo)
536 QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo);
537 if (iter == d->ops.end())
539 int length = iter->length;
541 iter = d->ops.find(&timeLineValue);
542 if (iter == d->ops.end()) {
543 pause(timeLineValue, length);
545 int glength = iter->length;
546 pause(timeLineValue, length - glength);
551 Synchronize the end point of \a timeLineValue to the endpoint of the longest
552 action cursrently scheduled in the timeline.
554 In pseudo-code, this is equivalent to:
556 QDeclarative1TimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue))
559 void QDeclarative1TimeLine::sync(QDeclarative1TimeLineValue &timeLineValue)
561 QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue);
562 if (iter == d->ops.end()) {
563 pause(timeLineValue, d->length);
565 pause(timeLineValue, d->length - iter->length);
570 Synchronize all currently and future scheduled values in this timeline to
571 the longest action currently scheduled.
575 value1->setValue(0.);
576 value2->setValue(0.);
577 value3->setValue(0.);
578 QDeclarative1TimeLine tl;
580 tl.move(value1, 10, 200);
581 tl.move(value2, 10, 100);
583 tl.move(value2, 20, 100);
584 tl.move(value3, 20, 100);
590 \header \o \o 0ms \o 50ms \o 100ms \o 150ms \o 200ms \o 250ms \o 300ms
591 \row \o value1 \o 0 \o 2.5 \o 5.0 \o 7.5 \o 10 \o 10 \o 10
592 \row \o value2 \o 0 \o 5.0 \o 10.0 \o 10.0 \o 10.0 \o 15.0 \o 20.0
593 \row \o value2 \o 0 \o 0 \o 0 \o 0 \o 0 \o 10.0 \o 20.0
597 /*void QDeclarative1TimeLine::sync()
599 for (QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.begin();
600 iter != d->ops.end();
602 pause(*iter.key(), d->length - iter->length);
603 d->syncPoint = d->length;
611 void QDeclarative1TimeLine::setSyncPoint(int sp)
621 int QDeclarative1TimeLine::syncPoint() const
627 Returns true if the timeline is active. An active timeline is one where
628 QDeclarative1TimeLineValue actions are still pending.
630 bool QDeclarative1TimeLine::isActive() const
632 return !d->ops.isEmpty();
636 Completes the timeline. All queued actions are played to completion, and then discarded. For example,
638 QDeclarative1TimeLineValue v(0.);
639 QDeclarative1TimeLine tl;
640 tl.move(v, 100., 1000.);
647 void QDeclarative1TimeLine::complete()
649 d->advance(d->length);
653 Resets the timeline. All queued actions are discarded and QDeclarative1TimeLineValue's retain their current value. For example,
655 QDeclarative1TimeLineValue v(0.);
656 QDeclarative1TimeLine tl;
657 tl.move(v, 100., 1000.);
664 void QDeclarative1TimeLine::clear()
666 for (QDeclarative1TimeLinePrivate::Ops::ConstIterator iter = d->ops.begin(); iter != d->ops.end(); ++iter)
671 //XXX need stop here?
674 int QDeclarative1TimeLine::time() const
680 \fn void QDeclarative1TimeLine::updated()
682 Emitted each time the timeline modifies QDeclarative1TimeLineValues. Even if multiple
683 QDeclarative1TimeLineValues are changed, this signal is only emitted once for each clock tick.
686 void QDeclarative1TimeLine::updateCurrentTime(int v)
688 if (d->syncAdj == -1)
692 int timeChanged = v - d->prevTime;
698 d->advance(timeChanged);
701 // Do we need to stop the clock?
702 if (d->ops.isEmpty()) {
705 d->clockRunning = false;
707 } /*else if (pauseTime > 0) {
708 GfxClock::cancelClock();
710 GfxClock::pauseFor(pauseTime);
712 d->clockRunning = false;
713 }*/ else if (/*!GfxClock::isActive()*/ state() != Running) {
716 d->clockRunning = true;
722 bool operator<(const QPair<int, Update> &lhs,
723 const QPair<int, Update> &rhs)
725 return lhs.first < rhs.first;
728 int QDeclarative1TimeLinePrivate::advance(int t)
732 // XXX - surely there is a more efficient way?
735 // Minimal advance time
737 for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ++iter) {
738 TimeLine &tl = *iter;
739 Op &op = tl.ops.first();
740 int length = op.length - tl.consumedOpLength;
742 if (length < advanceTime) {
743 advanceTime = length;
744 if (advanceTime == 0)
750 // Process until then. A zero length advance time will only process
752 QList<QPair<int, Update> > updates;
754 for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ) {
755 QDeclarative1TimeLineValue *v = static_cast<QDeclarative1TimeLineValue *>(iter.key());
756 TimeLine &tl = *iter;
757 Q_ASSERT(!tl.ops.isEmpty());
760 Op &op = tl.ops.first();
761 if (advanceTime == 0 && op.length != 0)
764 if (tl.consumedOpLength == 0 &&
765 op.type != Op::Pause &&
766 op.type != Op::Execute)
767 tl.base = v->value();
769 if ((tl.consumedOpLength + advanceTime) == op.length) {
770 if (op.type == Op::Execute) {
771 updates << qMakePair(op.order, Update(op.event));
773 bool changed = false;
774 qreal val = value(op, op.length, tl.base, &changed);
776 updates << qMakePair(op.order, Update(v, val));
778 tl.length -= qMin(advanceTime, tl.length);
779 tl.consumedOpLength = 0;
780 tl.ops.removeFirst();
782 tl.consumedOpLength += advanceTime;
783 bool changed = false;
784 qreal val = value(op, tl.consumedOpLength, tl.base, &changed);
786 updates << qMakePair(op.order, Update(v, val));
787 tl.length -= qMin(advanceTime, tl.length);
791 } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0);
794 if (tl.ops.isEmpty()) {
795 iter = ops.erase(iter);
798 if (tl.ops.first().type == Op::Pause && pauseTime != 0) {
799 int opPauseTime = tl.ops.first().length - tl.consumedOpLength;
800 if (pauseTime == -1 || opPauseTime < pauseTime)
801 pauseTime = opPauseTime;
809 length -= qMin(length, advanceTime);
810 syncPoint -= advanceTime;
812 qSort(updates.begin(), updates.end());
813 updateQueue = &updates;
814 for (int ii = 0; ii < updates.count(); ++ii) {
815 const Update &v = updates.at(ii).second;
828 void QDeclarative1TimeLine::remove(QDeclarative1TimeLineObject *v)
830 QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.find(v);
831 Q_ASSERT(iter != d->ops.end());
833 int len = iter->length;
835 if (len == d->length) {
836 // We need to recalculate the length
838 for (QDeclarative1TimeLinePrivate::Ops::Iterator iter = d->ops.begin();
839 iter != d->ops.end();
842 if (iter->length > d->length)
843 d->length = iter->length;
847 if (d->ops.isEmpty()) {
849 d->clockRunning = false;
850 } else if (/*!GfxClock::isActive()*/ state() != Running) {
853 d->clockRunning = true;
855 if (d->syncMode == QDeclarative1TimeLine::LocalSync) {
863 if (d->updateQueue) {
864 for (int ii = 0; ii < d->updateQueue->count(); ++ii) {
865 if (d->updateQueue->at(ii).second.g == v ||
866 d->updateQueue->at(ii).second.e.callbackObject() == v) {
867 d->updateQueue->removeAt(ii);
878 \class QDeclarative1TimeLineValue
879 \brief The QDeclarative1TimeLineValue class provides a value that can be modified by QDeclarative1TimeLine.
883 \fn QDeclarative1TimeLineValue::QDeclarative1TimeLineValue(qreal value = 0)
885 Construct a new QDeclarative1TimeLineValue with an initial \a value.
889 \fn qreal QDeclarative1TimeLineValue::value() const
891 Return the current value.
895 \fn void QDeclarative1TimeLineValue::setValue(qreal value)
897 Set the current \a value.
901 \fn QDeclarative1TimeLine *QDeclarative1TimeLineValue::timeLine() const
903 If a QDeclarative1TimeLine is operating on this value, return a pointer to it,
904 otherwise return null.
908 QDeclarative1TimeLineObject::QDeclarative1TimeLineObject()
913 QDeclarative1TimeLineObject::~QDeclarative1TimeLineObject()
921 QDeclarative1TimeLineCallback::QDeclarative1TimeLineCallback()
922 : d0(0), d1(0), d2(0)
926 QDeclarative1TimeLineCallback::QDeclarative1TimeLineCallback(QDeclarative1TimeLineObject *b, Callback f, void *d)
927 : d0(f), d1(d), d2(b)
931 QDeclarative1TimeLineCallback::QDeclarative1TimeLineCallback(const QDeclarative1TimeLineCallback &o)
932 : d0(o.d0), d1(o.d1), d2(o.d2)
936 QDeclarative1TimeLineCallback &QDeclarative1TimeLineCallback::operator=(const QDeclarative1TimeLineCallback &o)
944 QDeclarative1TimeLineObject *QDeclarative1TimeLineCallback::callbackObject() const