diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2009-07-09 07:10:11 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2009-07-09 07:10:11 (GMT) |
commit | 5b56189c9a6c322fa595b716a9f17e39a35bcbc0 (patch) | |
tree | 2e8b4fc397d631207aa32a8c68c94100a54f0f61 /src/declarative/util | |
parent | 888f57107e698731c4a1dd2c46745c6293b2222e (diff) | |
parent | 7343bbb230161d563b0226011e4519f695fdc593 (diff) | |
download | Qt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.zip Qt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.tar.gz Qt-5b56189c9a6c322fa595b716a9f17e39a35bcbc0.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
Conflicts:
src/declarative/qml/qmlengine.cpp
Diffstat (limited to 'src/declarative/util')
-rw-r--r-- | src/declarative/util/qfxperf.cpp | 2 | ||||
-rw-r--r-- | src/declarative/util/qfxperf_p.h (renamed from src/declarative/util/qfxperf.h) | 13 | ||||
-rw-r--r-- | src/declarative/util/qfxview.cpp | 4 | ||||
-rw-r--r-- | src/declarative/util/qmlanimation.cpp | 70 | ||||
-rw-r--r-- | src/declarative/util/qmlanimation_p.h | 4 | ||||
-rw-r--r-- | src/declarative/util/qmlfollow.cpp | 57 | ||||
-rw-r--r-- | src/declarative/util/qmlfollow.h | 4 | ||||
-rw-r--r-- | src/declarative/util/qmlscript.cpp | 2 | ||||
-rw-r--r-- | src/declarative/util/qmltimeline.cpp | 940 | ||||
-rw-r--r-- | src/declarative/util/qmltimeline_p.h | 224 | ||||
-rw-r--r-- | src/declarative/util/qperformancelog.cpp | 2 | ||||
-rw-r--r-- | src/declarative/util/qperformancelog_p.h (renamed from src/declarative/util/qperformancelog.h) | 0 | ||||
-rw-r--r-- | src/declarative/util/util.pri | 6 |
13 files changed, 1273 insertions, 55 deletions
diff --git a/src/declarative/util/qfxperf.cpp b/src/declarative/util/qfxperf.cpp index 9ac9e8d..db56b37 100644 --- a/src/declarative/util/qfxperf.cpp +++ b/src/declarative/util/qfxperf.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qfxperf.h" +#include "private/qfxperf_p.h" QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qfxperf.h b/src/declarative/util/qfxperf_p.h index 0bc0cc9..a1e38b7 100644 --- a/src/declarative/util/qfxperf.h +++ b/src/declarative/util/qfxperf_p.h @@ -41,7 +41,18 @@ #ifndef QFXPERF_H #define QFXPERF_H -#include "qperformancelog.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qperformancelog_p.h" QT_BEGIN_HEADER diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index 0855224..0a3afda 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -54,8 +54,8 @@ #include "qmlbindablevalue.h" #include "qml.h" #include "qfxitem.h" -#include "qperformancelog.h" -#include "qfxperf.h" +#include "private/qperformancelog_p.h" +#include "private/qfxperf_p.h" #include "qfxview.h" #include <QtDeclarative/qmlengine.h> diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 6ad47f5..ff070c1 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -58,12 +58,6 @@ #include <private/qmlstringconverters_p.h> #include <private/qvariantanimation_p.h> -/* TODO: - Check for any memory leaks - easing should be a QEasingCurve-type property - All other XXXs and ###s -*/ - QT_BEGIN_NAMESPACE QEasingCurve stringToCurve(const QString &curve) @@ -1108,7 +1102,7 @@ void QmlParentChangeActionPrivate::init() void QmlParentChangeActionPrivate::doAction() { - //XXX property.write(value); + //### property.write(value); } void QmlParentChangeAction::prepare(QmlMetaProperty &p) @@ -1120,7 +1114,7 @@ void QmlParentChangeAction::prepare(QmlMetaProperty &p) else d->property = d->userProperty; - //XXX + //### } QAbstractAnimation *QmlParentChangeAction::qtAnimation() @@ -1239,7 +1233,7 @@ QmlNumberAnimation::~QmlNumberAnimation() qreal QmlNumberAnimation::from() const { Q_D(const QmlPropertyAnimation); - return d->from.toDouble(); //### toFloat? + return d->from.toDouble(); } void QmlNumberAnimation::setFrom(qreal f) @@ -1259,7 +1253,7 @@ void QmlNumberAnimation::setFrom(qreal f) qreal QmlNumberAnimation::to() const { Q_D(const QmlPropertyAnimation); - return d->to.toDouble(); //### toFloat? + return d->to.toDouble(); } void QmlNumberAnimation::setTo(qreal t) @@ -1346,7 +1340,7 @@ void QmlSequentialAnimation::transition(QmlStateActions &actions, from = d->animations.count() - 1; } - //### needed for Behavior + //needed for Behavior if (d->userProperty.isValid() && d->propertyName.isEmpty() && !target()) { for (int i = 0; i < d->animations.count(); ++i) d->animations.at(i)->setTarget(d->userProperty); @@ -1428,7 +1422,7 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, { Q_D(QmlAnimationGroup); - //### needed for Behavior + //needed for Behavior if (d->userProperty.isValid() && d->propertyName.isEmpty() && !target()) { for (int i = 0; i < d->animations.count(); ++i) d->animations.at(i)->setTarget(d->userProperty); @@ -1441,26 +1435,12 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, QML_DEFINE_TYPE(QmlParallelAnimation,ParallelAnimation) -//### profile and optimize -QVariant QmlPropertyAnimationPrivate::interpolateVariant(const QVariant &from, const QVariant &to, qreal progress) -{ - if (from.userType() != to.userType()) - return QVariant(); - - QVariantAnimation::Interpolator interpolator = QVariantAnimationPrivate::getInterpolator(from.userType()); - if (interpolator) - return interpolator(from.constData(), to.constData(), progress); - else - return QVariant(); -} - //convert a variant from string type to another animatable type -//### should use any registered string convertor -//### profile and optimize -void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Type type) +void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) { if (variant.type() != QVariant::String) { - variant.convert(type); + if ((uint)type < QVariant::UserType) + variant.convert((QVariant::Type)type); return; } @@ -1494,7 +1474,12 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Ty break; } default: - variant.convert(type); + if ((uint)type >= QVariant::UserType) { + QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); + if (converter) + variant = converter(variant.toString()); + } else + variant.convert((QVariant::Type)type); break; } } @@ -1742,7 +1727,8 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) if (!fromSourced) { if (!fromIsDefined) { from = property.read(); - convertVariant(from, (QVariant::Type)(interpolatorType ? interpolatorType : property.propertyType())); + convertVariant(from, interpolatorType ? interpolatorType : property.propertyType()); + //### check for invalid variant if using property type } fromSourced = true; } @@ -1752,8 +1738,6 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) } else { if (interpolator) property.write(interpolator(from.constData(), to.constData(), r)); - else - property.write(interpolateVariant(from, to, r)); //### optimize } } @@ -1771,9 +1755,15 @@ void QmlPropertyAnimation::prepare(QmlMetaProperty &p) else d->property = d->userProperty; - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : d->property.propertyType())); + int propType = d->property.propertyType(); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : propType); if (d->fromIsDefined) - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : d->property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : propType); + + if (!d->interpolatorType) { + //### check for invalid variants + d->interpolator = QVariantAnimationPrivate::getInterpolator(propType); + } d->fromSourced = false; d->value.QmlTimeLineValue::setValue(0.); @@ -1810,7 +1800,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (action.fromValue.isNull()) { action.fromValue = action.property.read(); if (interpolatorType) - QmlPropertyAnimationPrivate::convertVariant(action.fromValue, (QVariant::Type)interpolatorType); + QmlPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType); } if (!interpolatorType) { int propType = action.property.propertyType(); @@ -1871,8 +1861,8 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (d->toIsDefined) myAction.toValue = d->to; - d->convertVariant(myAction.fromValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); - d->convertVariant(myAction.toValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); + d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); modified << action.property; @@ -1890,10 +1880,10 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, continue; if (d->fromIsDefined) { - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.fromValue = d->from; } - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.toValue = d->to; data->actions << myAction; } diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index fce5eca..87d480f 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -63,7 +63,7 @@ #include <QtDeclarative/qmlanimation.h> #include <QtDeclarative/qml.h> #include <QtDeclarative/qmlcontext.h> -#include <QtDeclarative/qmltimelinevalueproxy.h> +#include <private/qmltimeline_p.h> QT_BEGIN_NAMESPACE @@ -346,7 +346,7 @@ public: QmlTimeLineValueProxy<QmlPropertyAnimationPrivate> value; static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); - static void convertVariant(QVariant &variant, QVariant::Type type); + static void convertVariant(QVariant &variant, int type); }; QT_END_NAMESPACE diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index c6d806a..b8e6685 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include <limits.h> +#include <math.h> #include <QtCore/qdebug.h> #include "private/qobject_p.h" #include "qmlfollow.h" @@ -55,7 +56,7 @@ class QmlFollowPrivate : public QObjectPrivate public: QmlFollowPrivate() : sourceValue(0), maxVelocity(0), lastTime(0) - , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), enabled(true), mode(Track), clock(this) {} + , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), modulus(0.0), enabled(true), mode(Track), clock(this) {} QmlMetaProperty property; qreal currentValue; @@ -68,6 +69,7 @@ public: qreal damping; qreal velocity; qreal epsilon; + qreal modulus; bool enabled; enum Mode { @@ -92,6 +94,11 @@ void QmlFollowPrivate::tick(int time) int elapsed = time - lastTime; if (!elapsed) return; + qreal srcVal = sourceValue; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + srcVal = fmod(srcVal, modulus); + } if (mode == Spring) { if (elapsed < 16) // capped at 62fps. return; @@ -99,7 +106,13 @@ void QmlFollowPrivate::tick(int time) // We'll do something much simpler which gives a result that looks fine. int count = (elapsed+8) / 16; for (int i = 0; i < count; ++i) { - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } velocity = velocity + spring * diff - damping * velocity; // The following line supports mass. Not sure its worth the extra divisions. // velocity = velocity + spring / mass * diff - damping / mass * velocity; @@ -111,24 +124,39 @@ void QmlFollowPrivate::tick(int time) velocity = -maxVelocity; } currentValue += velocity * 16.0 / 1000.0; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + if (currentValue < 0.0) + currentValue += modulus; + } } - if (qAbs(velocity) < epsilon && qAbs(sourceValue - currentValue) < epsilon) { + if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) { velocity = 0.0; - currentValue = sourceValue; + currentValue = srcVal; clock.stop(); } lastTime = time - (elapsed - count * 16); } else { qreal moveBy = elapsed * velocityms; - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } if (diff > 0) { currentValue += moveBy; + if (modulus != 0.0) + currentValue = fmod(currentValue, modulus); if (currentValue > sourceValue) { currentValue = sourceValue; clock.stop(); } } else { currentValue -= moveBy; + if (modulus != 0.0 && currentValue < 0.0) + currentValue = fmod(currentValue, modulus) + modulus; if (currentValue < sourceValue) { currentValue = sourceValue; clock.stop(); @@ -326,6 +354,25 @@ void QmlFollow::setEpsilon(qreal epsilon) } /*! + \qmlproperty qreal Follow::modulus + This property holds the modulus value. + + Setting a \a modulus forces the target value to "wrap around" at the modulus. + For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10. +*/ +qreal QmlFollow::modulus() const +{ + Q_D(const QmlFollow); + return d->modulus; +} + +void QmlFollow::setModulus(qreal modulus) +{ + Q_D(QmlFollow); + d->modulus = modulus; +} + +/*! \qmlproperty qreal Follow::followValue The current value. */ diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index 0953f2c..07e15e9 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -64,8 +64,10 @@ class Q_DECLARATIVE_EXPORT QmlFollow : public QmlPropertyValueSource, Q_PROPERTY(qreal spring READ spring WRITE setSpring) Q_PROPERTY(qreal damping READ damping WRITE setDamping) Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) Q_PROPERTY(qreal followValue READ value NOTIFY valueChanged) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged) public: QmlFollow(QObject *parent=0); @@ -83,6 +85,8 @@ public: void setDamping(qreal damping); qreal epsilon() const; void setEpsilon(qreal epsilon); + qreal modulus() const; + void setModulus(qreal modulus); bool enabled() const; void setEnabled(bool enabled); diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index f8cbf96..8d03804 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -55,7 +55,7 @@ #include <QNetworkReply> #include <QNetworkRequest> #include <QtDeclarative/qmlinfo.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qmltimeline.cpp b/src/declarative/util/qmltimeline.cpp new file mode 100644 index 0000000..5ba310d --- /dev/null +++ b/src/declarative/util/qmltimeline.cpp @@ -0,0 +1,940 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmltimeline_p.h" +#include <QDebug> +#include <QMutex> +#include <QThread> +#include <QWaitCondition> +#include <QEvent> +#include <QCoreApplication> +#include <QEasingCurve> +#include <QTime> + +QT_BEGIN_NAMESPACE + +struct Update { + Update(QmlTimeLineValue *_g, qreal _v) + : g(_g), v(_v) {} + Update(const QmlTimeLineEvent &_e) + : g(0), v(0), e(_e) {} + + QmlTimeLineValue *g; + qreal v; + QmlTimeLineEvent e; +}; + +struct QmlTimeLinePrivate +{ + QmlTimeLinePrivate(QmlTimeLine *); + + struct Op { + enum Type { + Pause, + Set, + Move, + MoveBy, + Accel, + AccelDistance, + Execute + }; + Op() {} + Op(Type t, int l, qreal v, qreal v2, int o, + const QmlTimeLineEvent &ev = QmlTimeLineEvent(), const QEasingCurve &es = QEasingCurve()) + : type(t), length(l), value(v), value2(v2), order(o), event(ev), + easing(es) {} + Op(const Op &o) + : type(o.type), length(o.length), value(o.value), value2(o.value2), + order(o.order), event(o.event), easing(o.easing) {} + Op &operator=(const Op &o) { + type = o.type; length = o.length; value = o.value; + value2 = o.value2; order = o.order; event = o.event; + easing = o.easing; + return *this; + } + + Type type; + int length; + qreal value; + qreal value2; + + int order; + QmlTimeLineEvent event; + QEasingCurve easing; + }; + struct TimeLine + { + TimeLine() : length(0), consumedOpLength(0), base(0.) {} + QList<Op> ops; + int length; + int consumedOpLength; + qreal base; + }; + + int length; + int syncPoint; + typedef QHash<QmlTimeLineObject *, TimeLine> Ops; + Ops ops; + QmlTimeLine *q; + + void add(QmlTimeLineObject &, const Op &); + qreal value(const Op &op, int time, qreal base, bool *) const; + + int advance(int); + + bool clockRunning; + int prevTime; + + int order; + + QmlTimeLine::SyncMode syncMode; + int syncAdj; + QList<QPair<int, Update> > *updateQueue; +}; + +QmlTimeLinePrivate::QmlTimeLinePrivate(QmlTimeLine *parent) +: length(0), syncPoint(0), q(parent), clockRunning(false), prevTime(0), order(0), syncMode(QmlTimeLine::LocalSync), syncAdj(0), updateQueue(0) +{ +} + +void QmlTimeLinePrivate::add(QmlTimeLineObject &g, const Op &o) +{ + if (g._t && g._t != q) { + qWarning() << "QmlTimeLine: Cannot modify a QmlTimeLineValue owned by" + << "another timeline."; + return; + } + g._t = q; + + Ops::Iterator iter = ops.find(&g); + if (iter == ops.end()) { + iter = ops.insert(&g, TimeLine()); + if (syncPoint > 0) + q->pause(g, syncPoint); + } + if (!iter->ops.isEmpty() && + o.type == Op::Pause && + iter->ops.last().type == Op::Pause) { + iter->ops.last().length += o.length; + iter->length += o.length; + } else { + iter->ops.append(o); + iter->length += o.length; + } + + if (iter->length > length) + length = iter->length; + + if (!clockRunning) { + q->stop(); + prevTime = 0; + clockRunning = true; + + if (syncMode == QmlTimeLine::LocalSync) { + syncAdj = -1; + } else { + syncAdj = 0; + } + q->start(); +/* q->tick(0); + if (syncMode == QmlTimeLine::LocalSync) { + syncAdj = -1; + } else { + syncAdj = 0; + } + */ + } +} + +qreal QmlTimeLinePrivate::value(const Op &op, int time, qreal base, bool *changed) const +{ + Q_ASSERT(time >= 0); + Q_ASSERT(time <= op.length); + *changed = true; + + switch(op.type) { + case Op::Pause: + *changed = false; + return base; + case Op::Set: + return op.value; + case Op::Move: + if (time == 0) { + return base; + } else if (time == (op.length)) { + return op.value; + } else { + qreal delta = op.value - base; + qreal pTime = (qreal)(time) / (qreal)op.length; + if (op.easing.type() == QEasingCurve::Linear) + return base + delta * pTime; + else + return base + delta * op.easing.valueForProgress(pTime); + } + case Op::MoveBy: + if (time == 0) { + return base; + } else if (time == (op.length)) { + return base + op.value; + } else { + qreal delta = op.value; + qreal pTime = (qreal)(time) / (qreal)op.length; + if (op.easing.type() == QEasingCurve::Linear) + return base + delta * pTime; + else + return base + delta * op.easing.valueForProgress(pTime); + } + case Op::Accel: + if (time == 0) { + return base; + } else { + qreal t = (qreal)(time) / 1000.0f; + qreal delta = op.value * t + 0.5f * op.value2 * t * t; + return base + delta; + } + case Op::AccelDistance: + if (time == 0) { + return base; + } else if (time == (op.length)) { + return base + op.value2; + } else { + qreal t = (qreal)(time) / 1000.0f; + qreal accel = -1.0f * 1000.0f * op.value / (qreal)op.length; + qreal delta = op.value * t + 0.5f * accel * t * t; + return base + delta; + + } + case Op::Execute: + op.event.execute(); + *changed = false; + return -1; + } + + return base; +} + +/*! + \internal + \class QmlTimeLine + \ingroup group_animation + \brief The QmlTimeLine class provides a timeline for controlling animations. + + QmlTimeLine is similar to QTimeLine except: + \list + \i It updates QmlTimeLineValue instances directly, rather than maintaining a single + current value. + + For example, the following animates a simple value over 200 milliseconds: + \code + QmlTimeLineValue v(<starting value>); + QmlTimeLine tl; + tl.move(v, 100., 200); + tl.start() + \endcode + + If your program needs to know when values are changed, it can either + connect to the QmlTimeLine's updated() signal, or inherit from QmlTimeLineValue + and reimplement the QmlTimeLineValue::setValue() method. + + \i Supports multiple QmlTimeLineValue, arbitrary start and end values and allows + animations to be strung together for more complex effects. + + For example, the following animation moves the x and y coordinates of + an object from wherever they are to the position (100, 100) in 50 + milliseconds and then further animates them to (100, 200) in 50 + milliseconds: + + \code + QmlTimeLineValue x(<starting value>); + QmlTimeLineValue y(<starting value>); + + QmlTimeLine tl; + tl.start(); + + tl.move(x, 100., 50); + tl.move(y, 100., 50); + tl.move(y, 200., 50); + \endcode + + \i All QmlTimeLine instances share a single, synchronized clock. + + Actions scheduled within the same event loop tick are scheduled + synchronously against each other, regardless of the wall time between the + scheduling. Synchronized scheduling applies both to within the same + QmlTimeLine and across separate QmlTimeLine's within the same process. + + \endlist + + Currently easing functions are not supported. +*/ + + +/*! + Construct a new QmlTimeLine with the specified \a parent. +*/ +QmlTimeLine::QmlTimeLine(QObject *parent) +: QAbstractAnimation(parent) +{ + d = new QmlTimeLinePrivate(this); +} + +/*! + Destroys the time line. Any inprogress animations are canceled, but not + completed. +*/ +QmlTimeLine::~QmlTimeLine() +{ + for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin(); + iter != d->ops.end(); + ++iter) + iter.key()->_t = 0; + + delete d; d = 0; +} + +/*! + \enum QmlTimeLine::SyncMode + */ + +/*! + Return the timeline's synchronization mode. + */ +QmlTimeLine::SyncMode QmlTimeLine::syncMode() const +{ + return d->syncMode; +} + +/*! + Set the timeline's synchronization mode to \a syncMode. + */ +void QmlTimeLine::setSyncMode(SyncMode syncMode) +{ + d->syncMode = syncMode; +} + +/*! + Pause \a obj for \a time milliseconds. +*/ +void QmlTimeLine::pause(QmlTimeLineObject &obj, int time) +{ + if (time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Pause, time, 0., 0., d->order++); + d->add(obj, op); +} + +/*! + Execute the \a event. + */ +void QmlTimeLine::execute(const QmlTimeLineEvent &event) +{ + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, event); + d->add(*event.eventObject(), op); +} + +/*! + Set the \a value of \a timeLineValue. +*/ +void QmlTimeLine::set(QmlTimeLineValue &timeLineValue, qreal value) +{ + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Set, 0, value, 0., d->order++); + d->add(timeLineValue, op); +} + +/*! + Decelerate \a timeLineValue from the starting \a velocity to zero at the + given \a acceleration rate. Although the \a acceleration is technically + a deceleration, it should always be positive. The QmlTimeLine will ensure + that the deceleration is in the opposite direction to the initial velocity. +*/ +int QmlTimeLine::accel(QmlTimeLineValue &timeLineValue, qreal velocity, qreal acceleration) +{ + if ((velocity > 0.0f) == (acceleration > 0.0f)) + acceleration = acceleration * -1.0f; + + int time = static_cast<int>(-1000 * velocity / acceleration); + + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++); + d->add(timeLineValue, op); + + return time; +} + +/*! + \overload + + Decelerate \a timeLineValue from the starting \a velocity to zero at the + given \a acceleration rate over a maximum distance of maxDistance. + + If necessary, QmlTimeLine will reduce the acceleration to ensure that the + entire operation does not require a move of more than \a maxDistance. + \a maxDistance should always be positive. +*/ +int QmlTimeLine::accel(QmlTimeLineValue &timeLineValue, qreal velocity, qreal acceleration, qreal maxDistance) +{ + Q_ASSERT(acceleration >= 0.0f && maxDistance >= 0.0f); + + qreal maxAccel = (velocity * velocity) / (2.0f * maxDistance); + if (maxAccel > acceleration) + acceleration = maxAccel; + + if ((velocity > 0.0f) == (acceleration > 0.0f)) + acceleration = acceleration * -1.0f; + + int time = static_cast<int>(-1000 * velocity / acceleration); + + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Accel, time, velocity, acceleration, d->order++); + d->add(timeLineValue, op); + + return time; +} + +/*! + Decelerate \a timeLineValue from the starting \a velocity to zero over the given + \a distance. This is like accel(), but the QmlTimeLine calculates the exact + deceleration to use. + + \a distance should be positive. +*/ +int QmlTimeLine::accelDistance(QmlTimeLineValue &timeLineValue, qreal velocity, qreal distance) +{ + if (distance == 0.0f || velocity == 0.0f) + return -1; + Q_ASSERT((distance >= 0.0f) == (velocity >= 0.0f)); + + int time = static_cast<int>(1000 * (2.0f * distance) / velocity); + + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::AccelDistance, time, velocity, distance, d->order++); + d->add(timeLineValue, op); + + return time; +} + +/*! + Linearly change the \a timeLineValue from its current value to the given + \a destination value over \a time milliseconds. +*/ +void QmlTimeLine::move(QmlTimeLineValue &timeLineValue, qreal destination, int time) +{ + if (time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++); + d->add(timeLineValue, op); +} + +/*! + Change the \a timeLineValue from its current value to the given \a destination + value over \a time milliseconds using the \a easing curve. + */ +void QmlTimeLine::move(QmlTimeLineValue &timeLineValue, qreal destination, const QEasingCurve &easing, int time) +{ + if (time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, QmlTimeLineEvent(), easing); + d->add(timeLineValue, op); +} + +/*! + Linearly change the \a timeLineValue from its current value by the \a change amount + over \a time milliseconds. +*/ +void QmlTimeLine::moveBy(QmlTimeLineValue &timeLineValue, qreal change, int time) +{ + if (time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++); + d->add(timeLineValue, op); +} + +/*! + Change the \a timeLineValue from its current value by the \a change amount over + \a time milliseconds using the \a easing curve. + */ +void QmlTimeLine::moveBy(QmlTimeLineValue &timeLineValue, qreal change, const QEasingCurve &easing, int time) +{ + if (time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, QmlTimeLineEvent(), easing); + d->add(timeLineValue, op); +} + +/*! + Cancel (but don't complete) all scheduled actions for \a timeLineValue. +*/ +void QmlTimeLine::reset(QmlTimeLineValue &timeLineValue) +{ + if (!timeLineValue._t) + return; + if (timeLineValue._t != this) { + qWarning() << "QmlTimeLine: Cannot reset a QmlTimeLineValue owned by another timeline."; + return; + } + remove(&timeLineValue); + timeLineValue._t = 0; +} + +int QmlTimeLine::duration() const +{ + return -1; +} + +/*! + Synchronize the end point of \a timeLineValue to the endpoint of \a syncTo + within this timeline. + + Following operations on \a timeLineValue in this timeline will be scheduled after + all the currently scheduled actions on \a syncTo are complete. In + psuedo-code this is equivalent to: + \code + QmlTimeLine::pause(timeLineValue, min(0, length_of(syncTo) - length_of(timeLineValue))) + \endcode +*/ +void QmlTimeLine::sync(QmlTimeLineValue &timeLineValue, QmlTimeLineValue &syncTo) +{ + QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo); + if (iter == d->ops.end()) + return; + int length = iter->length; + + iter = d->ops.find(&timeLineValue); + if (iter == d->ops.end()) { + pause(timeLineValue, length); + } else { + int glength = iter->length; + pause(timeLineValue, length - glength); + } +} + +/*! + Synchronize the end point of \a timeLineValue to the endpoint of the longest + action cursrently scheduled in the timeline. + + In psuedo-code, this is equivalent to: + \code + QmlTimeLine::pause(timeLineValue, length_of(timeline) - length_of(timeLineValue)) + \endcode +*/ +void QmlTimeLine::sync(QmlTimeLineValue &timeLineValue) +{ + QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&timeLineValue); + if (iter == d->ops.end()) { + pause(timeLineValue, d->length); + } else { + pause(timeLineValue, d->length - iter->length); + } +} + +/* + Synchronize all currently and future scheduled values in this timeline to + the longest action currently scheduled. + + For example: + \code + value1->setValue(0.); + value2->setValue(0.); + value3->setValue(0.); + QmlTimeLine tl; + ... + tl.move(value1, 10, 200); + tl.move(value2, 10, 100); + tl.sync(); + tl.move(value2, 20, 100); + tl.move(value3, 20, 100); + \endcode + + will result in: + + \table + \header \o \o 0ms \o 50ms \o 100ms \o 150ms \o 200ms \o 250ms \o 300ms + \row \o value1 \o 0 \o 2.5 \o 5.0 \o 7.5 \o 10 \o 10 \o 10 + \row \o value2 \o 0 \o 5.0 \o 10.0 \o 10.0 \o 10.0 \o 15.0 \o 20.0 + \row \o value2 \o 0 \o 0 \o 0 \o 0 \o 0 \o 10.0 \o 20.0 + \endtable +*/ + +/*void QmlTimeLine::sync() +{ + for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin(); + iter != d->ops.end(); + ++iter) + pause(*iter.key(), d->length - iter->length); + d->syncPoint = d->length; +}*/ + +/*! + \internal + + Temporary hack. + */ +void QmlTimeLine::setSyncPoint(int sp) +{ + d->syncPoint = sp; +} + +/*! + \internal + + Temporary hack. + */ +int QmlTimeLine::syncPoint() const +{ + return d->syncPoint; +} + +/*! + Returns true if the timeline is active. An active timeline is one where + QmlTimeLineValue actions are still pending. +*/ +bool QmlTimeLine::isActive() const +{ + return !d->ops.isEmpty(); +} + +/*! + Completes the timeline. All queued actions are played to completion, and then discarded. For example, + \code + QmlTimeLineValue v(0.); + QmlTimeLine tl; + tl.move(v, 100., 1000.); + // 500 ms passes + // v.value() == 50. + tl.complete(); + // v.value() == 100. + \endcode +*/ +void QmlTimeLine::complete() +{ + d->advance(d->length); +} + +/*! + Resets the timeline. All queued actions are discarded and QmlTimeLineValue's retain their current value. For example, + \code + QmlTimeLineValue v(0.); + QmlTimeLine tl; + tl.move(v, 100., 1000.); + // 500 ms passes + // v.value() == 50. + tl.clear(); + // v.value() == 50. + \endcode +*/ +void QmlTimeLine::clear() +{ + for (QmlTimeLinePrivate::Ops::ConstIterator iter = d->ops.begin(); iter != d->ops.end(); ++iter) + iter.key()->_t = 0; + d->ops.clear(); + d->length = 0; + d->syncPoint = 0; + //XXX need stop here? +} + +int QmlTimeLine::time() const +{ + return d->prevTime; +} + +/*! + \fn void QmlTimeLine::updated() + + Emitted each time the timeline modifies QmlTimeLineValues. Even if multiple + QmlTimeLineValues are changed, this signal is only emitted once for each clock tick. +*/ + +void QmlTimeLine::updateCurrentTime(int v) +{ + if (d->syncAdj == -1) + d->syncAdj = v; + v -= d->syncAdj; + + int timeChanged = v - d->prevTime; +#if 0 + if (!timeChanged) + return; +#endif + d->prevTime = v; + d->advance(timeChanged); + emit updated(); + + // Do we need to stop the clock? + if (d->ops.isEmpty()) { + stop(); + d->prevTime = 0; + d->clockRunning = false; + emit completed(); + } /*else if (pauseTime > 0) { + GfxClock::cancelClock(); + d->prevTime = 0; + GfxClock::pauseFor(pauseTime); + d->syncAdj = 0; + d->clockRunning = false; + }*/ else if (/*!GfxClock::isActive()*/ state() != Running) { + stop(); + d->prevTime = 0; + d->clockRunning = true; + d->syncAdj = 0; + start(); + } +} + +bool operator<(const QPair<int, Update> &lhs, + const QPair<int, Update> &rhs) +{ + return lhs.first < rhs.first; +} + +int QmlTimeLinePrivate::advance(int t) +{ + int pauseTime = -1; + + // XXX - surely there is a more efficient way? + do { + pauseTime = -1; + // Minimal advance time + int advanceTime = t; + for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ++iter) { + TimeLine &tl = *iter; + Op &op = tl.ops.first(); + int length = op.length - tl.consumedOpLength; + + if (length < advanceTime) { + advanceTime = length; + if (advanceTime == 0) + break; + } + } + t -= advanceTime; + + // Process until then. A zero length advance time will only process + // sets. + QList<QPair<int, Update> > updates; + + for (Ops::Iterator iter = ops.begin(); iter != ops.end(); ) { + QmlTimeLineValue *v = static_cast<QmlTimeLineValue *>(iter.key()); + TimeLine &tl = *iter; + Q_ASSERT(!tl.ops.isEmpty()); + + do { + Op &op = tl.ops.first(); + if (advanceTime == 0 && op.length != 0) + continue; + + if (tl.consumedOpLength == 0 && + op.type != Op::Pause && + op.type != Op::Execute) + tl.base = v->value(); + + if ((tl.consumedOpLength + advanceTime) == op.length) { + if (op.type == Op::Execute) { + updates << qMakePair(op.order, Update(op.event)); + } else { + bool changed = false; + qreal val = value(op, op.length, tl.base, &changed); + if (changed) + updates << qMakePair(op.order, Update(v, val)); + } + tl.length -= qMin(advanceTime, tl.length); + tl.consumedOpLength = 0; + tl.ops.removeFirst(); + } else { + tl.consumedOpLength += advanceTime; + bool changed = false; + qreal val = value(op, tl.consumedOpLength, tl.base, &changed); + if (changed) + updates << qMakePair(op.order, Update(v, val)); + tl.length -= qMin(advanceTime, tl.length); + break; + } + + } while(!tl.ops.isEmpty() && advanceTime == 0 && tl.ops.first().length == 0); + + + if (tl.ops.isEmpty()) { + iter = ops.erase(iter); + v->_t = 0; + } else { + if (tl.ops.first().type == Op::Pause && pauseTime != 0) { + int opPauseTime = tl.ops.first().length - tl.consumedOpLength; + if (pauseTime == -1 || opPauseTime < pauseTime) + pauseTime = opPauseTime; + } else { + pauseTime = 0; + } + ++iter; + } + } + + length -= qMin(length, advanceTime); + syncPoint -= advanceTime; + + qSort(updates.begin(), updates.end()); + updateQueue = &updates; + for (int ii = 0; ii < updates.count(); ++ii) { + const Update &v = updates.at(ii).second; + if (v.g) + v.g->setValue(v.v); + else + v.e.execute(); + } + updateQueue = 0; + } while(t); + + return pauseTime; +} + +void QmlTimeLine::remove(QmlTimeLineObject *v) +{ + QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(v); + Q_ASSERT(iter != d->ops.end()); + + int len = iter->length; + d->ops.erase(iter); + if (len == d->length) { + // We need to recalculate the length + d->length = 0; + for (QmlTimeLinePrivate::Ops::Iterator iter = d->ops.begin(); + iter != d->ops.end(); + ++iter) { + + if (iter->length > d->length) + d->length = iter->length; + + } + } + if (d->ops.isEmpty()) { + stop(); + d->clockRunning = false; + } else if (/*!GfxClock::isActive()*/ state() != Running) { + stop(); + d->prevTime = 0; + d->clockRunning = true; + + if (d->syncMode == QmlTimeLine::LocalSync) { + d->syncAdj = -1; + } else { + d->syncAdj = 0; + } + start(); + } + + if (d->updateQueue) { + for (int ii = 0; ii < d->updateQueue->count(); ++ii) { + if (d->updateQueue->at(ii).second.g == v || + d->updateQueue->at(ii).second.e.eventObject() == v) { + d->updateQueue->removeAt(ii); + --ii; + } + } + } + + +} + +/*! + \internal + \class QmlTimeLineValue + \ingroup group_animation + \brief The QmlTimeLineValue class provides a value that can be modified by QmlTimeLine. +*/ + +/*! + \fn QmlTimeLineValue::QmlTimeLineValue(qreal value = 0) + + Construct a new QmlTimeLineValue with an initial \a value. +*/ + +/*! + \fn qreal QmlTimeLineValue::value() const + + Return the current value. +*/ + +/*! + \fn void QmlTimeLineValue::setValue(qreal value) + + Set the current \a value. +*/ + +/*! + \fn QmlTimeLine *QmlTimeLineValue::timeLine() const + + If a QmlTimeLine is operating on this value, return a pointer to it, + otherwise return null. +*/ + + +QmlTimeLineObject::QmlTimeLineObject() +: _t(0) +{ +} + +QmlTimeLineObject::~QmlTimeLineObject() +{ + if (_t) { + _t->remove(this); + _t = 0; + } +} + +QmlTimeLineEvent::QmlTimeLineEvent() +: d0(0), d1(0), d2(0) +{ +} + +QmlTimeLineEvent::QmlTimeLineEvent(const QmlTimeLineEvent &o) +: d0(o.d0), d1(o.d1), d2(o.d2) +{ +} + +QmlTimeLineEvent &QmlTimeLineEvent::operator=(const QmlTimeLineEvent &o) +{ + d0 = o.d0; + d1 = o.d1; + d2 = o.d2; + return *this; +} + +void QmlTimeLineEvent::execute() const +{ + d0(d1); +} + +QmlTimeLineObject *QmlTimeLineEvent::eventObject() const +{ + return d2; +} + +QT_END_NAMESPACE diff --git a/src/declarative/util/qmltimeline_p.h b/src/declarative/util/qmltimeline_p.h new file mode 100644 index 0000000..abed80a --- /dev/null +++ b/src/declarative/util/qmltimeline_p.h @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLTIMELINE_H +#define QMLTIMELINE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QObject> +#include <QtCore/QAbstractAnimation> +#include <QtDeclarative/qfxglobal.h> + +QT_BEGIN_NAMESPACE + +class QEasingCurve; +class QmlTimeLineValue; +class QmlTimeLineEvent; +struct QmlTimeLinePrivate; +class QmlTimeLineObject; +class Q_DECLARATIVE_EXPORT QmlTimeLine : public QAbstractAnimation +{ +Q_OBJECT +public: + QmlTimeLine(QObject *parent = 0); + ~QmlTimeLine(); + + enum SyncMode { LocalSync, GlobalSync }; + SyncMode syncMode() const; + void setSyncMode(SyncMode); + + void pause(QmlTimeLineObject &, int); + void execute(const QmlTimeLineEvent &); + void set(QmlTimeLineValue &, qreal); + + int accel(QmlTimeLineValue &, qreal velocity, qreal accel); + int accel(QmlTimeLineValue &, qreal velocity, qreal accel, qreal maxDistance); + int accelDistance(QmlTimeLineValue &, qreal velocity, qreal distance); + + void move(QmlTimeLineValue &, qreal destination, int time = 500); + void move(QmlTimeLineValue &, qreal destination, const QEasingCurve &, int time = 500); + void moveBy(QmlTimeLineValue &, qreal change, int time = 500); + void moveBy(QmlTimeLineValue &, qreal change, const QEasingCurve &, int time = 500); + + void sync(); + void setSyncPoint(int); + int syncPoint() const; + + void sync(QmlTimeLineValue &); + void sync(QmlTimeLineValue &, QmlTimeLineValue &); + + void reset(QmlTimeLineValue &); + + void complete(); + void clear(); + bool isActive() const; + + int time() const; + + virtual int duration() const; +Q_SIGNALS: + void updated(); + void completed(); + +protected: + virtual void updateCurrentTime(int); + +private: + void remove(QmlTimeLineObject *); + friend class QmlTimeLineObject; + friend struct QmlTimeLinePrivate; + QmlTimeLinePrivate *d; +}; + +class Q_DECLARATIVE_EXPORT QmlTimeLineObject +{ +public: + QmlTimeLineObject(); + virtual ~QmlTimeLineObject(); + +protected: + friend class QmlTimeLine; + friend struct QmlTimeLinePrivate; + QmlTimeLine *_t; +}; + +class Q_DECLARATIVE_EXPORT QmlTimeLineValue : public QmlTimeLineObject +{ +public: + QmlTimeLineValue(qreal v = 0.) : _v(v) {} + + virtual qreal value() const { return _v; } + virtual void setValue(qreal v) { _v = v; } + + QmlTimeLine *timeLine() const { return _t; } + + operator qreal() const { return _v; } + QmlTimeLineValue &operator=(qreal v) { setValue(v); return *this; } +private: + friend class QmlTimeLine; + friend struct QmlTimeLinePrivate; + qreal _v; +}; + +class Q_DECLARATIVE_EXPORT QmlTimeLineEvent +{ +public: + QmlTimeLineEvent(); + QmlTimeLineEvent(const QmlTimeLineEvent &o); + + template<class T, void (T::*method)()> + QmlTimeLineEvent(QmlTimeLineObject *b, T *c) + { + d0 = &callFunc<T, method>; + d1 = (void *)c; + d2 = b; + } + + template<class T, void (T::*method)()> + static QmlTimeLineEvent timeLineEvent(QmlTimeLineObject *b, T *c) + { + QmlTimeLineEvent rv; + rv.d0 = &callFunc<T, method>; + rv.d1 = (void *)c; + rv.d2 = b; + return rv; + } + + QmlTimeLineEvent &operator=(const QmlTimeLineEvent &o); + void execute() const; + QmlTimeLineObject *eventObject() const; + +private: + typedef void (*CallFunc)(void *c); + + template <class T, void (T::*method)()> + static void callFunc(void *c) + { + T *cls = (T *)c; + (cls->*method)(); + } + CallFunc d0; + void *d1; + QmlTimeLineObject *d2; +}; + +template<class T> +class QmlTimeLineValueProxy : public QmlTimeLineValue +{ +public: + QmlTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.) + : QmlTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0) + { + Q_ASSERT(_class); + } + + QmlTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.) + : QmlTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func) + { + Q_ASSERT(_class); + } + + virtual void setValue(qreal v) + { + QmlTimeLineValue::setValue(v); + if (_setFunctionReal) (_class->*_setFunctionReal)(v); + else if (_setFunctionInt) (_class->*_setFunctionInt)((int)v); + } + +private: + T *_class; + void (T::*_setFunctionReal)(qreal); + void (T::*_setFunctionInt)(int); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/util/qperformancelog.cpp b/src/declarative/util/qperformancelog.cpp index 932e4b3..8e11997 100644 --- a/src/declarative/util/qperformancelog.cpp +++ b/src/declarative/util/qperformancelog.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qperformancelog.h" +#include "qperformancelog_p.h" #include <QHash> #include <QDebug> diff --git a/src/declarative/util/qperformancelog.h b/src/declarative/util/qperformancelog_p.h index 6655a8d..6655a8d 100644 --- a/src/declarative/util/qperformancelog.h +++ b/src/declarative/util/qperformancelog_p.h diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 0619a47..aae10af 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -17,13 +17,14 @@ SOURCES += \ util/qmllistmodel.cpp\ util/qmllistaccessor.cpp \ util/qmlopenmetaobject.cpp \ + util/qmltimeline.cpp \ util/qmlbind.cpp HEADERS += \ util/qfxview.h \ - util/qfxperf.h \ + util/qfxperf_p.h \ util/qfxglobal.h \ - util/qperformancelog.h \ + util/qperformancelog_p.h \ util/qmlconnection.h \ util/qmlpackage.h \ util/qmlscript.h \ @@ -42,4 +43,5 @@ HEADERS += \ util/qmllistaccessor.h \ util/qmlopenmetaobject.h \ util/qmlnullablevalue_p.h \ + util/qmltimeline_p.h \ util/qmlbind.h |