diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
commit | 2366667fc97eb6a56203b2dd7dac776ff4164abd (patch) | |
tree | b2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/timeline | |
parent | 2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff) | |
download | Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2 |
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/timeline')
-rw-r--r-- | src/declarative/timeline/gfxeasing.cpp | 846 | ||||
-rw-r--r-- | src/declarative/timeline/gfxeasing.h | 107 | ||||
-rw-r--r-- | src/declarative/timeline/gfxtimeline.cpp | 946 | ||||
-rw-r--r-- | src/declarative/timeline/gfxtimeline.h | 190 | ||||
-rw-r--r-- | src/declarative/timeline/gfxvalueproxy.h | 83 | ||||
-rw-r--r-- | src/declarative/timeline/timeline.pri | 9 |
6 files changed, 2181 insertions, 0 deletions
diff --git a/src/declarative/timeline/gfxeasing.cpp b/src/declarative/timeline/gfxeasing.cpp new file mode 100644 index 0000000..c89ba88 --- /dev/null +++ b/src/declarative/timeline/gfxeasing.cpp @@ -0,0 +1,846 @@ +/**************************************************************************** +** +** 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 "gfxeasing.h" +#include <math.h> +#include <QHash> +#include <QPainter> +#include <QVariant> +#include <QDebug> +#include <QStringList> +#include <QMouseEvent> +#include "gfxtimeline.h" + + +QT_BEGIN_NAMESPACE +typedef QHash<QString, qreal> GfxEasingProperties; +class GfxEasingFunction +{ +public: + virtual ~GfxEasingFunction() {} + virtual float value(float t, float b, float c, float d) = 0; + virtual GfxEasingFunction *copy() const = 0; +}; + +#include "../3rdparty/easing.cpp" + +struct ElasticEase : public GfxEasingFunction +{ + enum Type { In, Out }; + ElasticEase(Type t) : _t(t), _p(0.0f), _a(0.0f) {} + + Type _t; + qreal _p; + qreal _a; + + GfxEasingFunction *copy() const + { + ElasticEase *rv = new ElasticEase(_t); + rv->_p = _p; + rv->_a = _a; + return rv; + } + + float value(float t, float b, float c, float d) + { + if (t==0) return b; + float t_adj = (float)t / (float)d; + if (t_adj==1) return b+c; + + qreal p = _p?_p:(d * 0.3f); + + qreal a; + qreal s; + + if(!_a || _a < ::fabs(c)) { + a = c; + s = p / 4.0f; + } else { + a = _a; + s = p / (2 * M_PI) * ::asin(c / a); + } + + if(_t == In) + t_adj -= 1.0f; + + return (a*::pow(2,-10*t_adj) * ::sin( (t_adj*d-s)*(2*M_PI)/p ) + c + b); + } +}; + +struct BounceEase : public GfxEasingFunction +{ + enum Type { In, Out }; + BounceEase(Type t) : _t(t), _a(-1.0) {} + + Type _t; + qreal _a; + + GfxEasingFunction *copy() const + { + BounceEase *rv = new BounceEase(_t); + rv->_t = _t; + rv->_a = _a; + return rv; + } + + float value(float t, float b, float c, float d) + { + if(In == _t) + return c - bounce(d - t, 0, c, d) + b; + else + return bounce(t, b, c, d); + } + + float bounce(float t, float b, float c, float d) + { + float t_adj = (float)t / (float)d; + float amp = (_a == -1.0)?c:_a; + if ((t_adj) < (1/2.75)) { + if(c == 0. && _a != -1.0) { + t_adj -= (0.5f/2.75f); + return -amp * (1. - (30.25*t_adj*t_adj)) + b; + } else { + return c*(7.5625*t_adj*t_adj) + b; + } + } else if (t_adj < (2/2.75)) { + t_adj -= (1.5f/2.75f); + return -amp * (1. - (7.5625*t_adj*t_adj + .75)) + (b + c); + } else if (t_adj < (2.5/2.75)) { + t_adj -= (2.25f/2.75f); + return -amp * (1. - (7.5625*t_adj*t_adj + .9375)) + (b + c); + } else { + t_adj -= (2.65f/2.75f); + return -amp * (1. - (7.5625*t_adj*t_adj + .984375)) + (b + c); + } + } +}; + +static GfxEasingFunction *easeInElasticC(const GfxEasingProperties &p) +{ + ElasticEase *rv = new ElasticEase(ElasticEase::In); + rv->_p = p[QLatin1String("period")]; + rv->_a = p[QLatin1String("amplitude")]; + return rv; +} + + +static GfxEasingFunction *easeOutElasticC(const GfxEasingProperties &p) +{ + ElasticEase *rv = new ElasticEase(ElasticEase::Out); + rv->_p = p[QLatin1String("period")]; + rv->_a = p[QLatin1String("amplitude")]; + return rv; +} + +static GfxEasingFunction *easeOutBounceC(const GfxEasingProperties &p) +{ + BounceEase *rv = new BounceEase(BounceEase::Out); + rv->_a = p[QLatin1String("amplitude")]; + return rv; +} + +static GfxEasingFunction *easeInBounceC(const GfxEasingProperties &p) +{ + BounceEase *rv = new BounceEase(BounceEase::Out); + rv->_a = p[QLatin1String("amplitude")]; + return rv; +} + + +struct SimpleConfig : public GfxEasingFunction +{ + GfxEasing::Function func; + + float value(float t, float b, float c, float d) + { + return func(t, b, c, d); + } + + GfxEasingFunction *copy() const + { + SimpleConfig *rv = new SimpleConfig; + rv->func = func; + return rv; + } +}; + +GfxEasing::Function curveToFunc(GfxEasing::Curve curve) +{ + switch(curve) + { + case GfxEasing::None: + return &easeNone; + case GfxEasing::InQuad: + return &easeInQuad; + case GfxEasing::OutQuad: + return &easeOutQuad; + case GfxEasing::InOutQuad: + return &easeInOutQuad; + case GfxEasing::OutInQuad: + return &easeOutInQuad; + case GfxEasing::InCubic: + return &easeInCubic; + case GfxEasing::OutCubic: + return &easeOutCubic; + case GfxEasing::InOutCubic: + return &easeInOutCubic; + case GfxEasing::OutInCubic: + return &easeOutInCubic; + case GfxEasing::InQuart: + return &easeInQuart; + case GfxEasing::OutQuart: + return &easeOutQuart; + case GfxEasing::InOutQuart: + return &easeInOutQuart; + case GfxEasing::OutInQuart: + return &easeOutInQuart; + case GfxEasing::InQuint: + return &easeInQuint; + case GfxEasing::OutQuint: + return &easeOutQuint; + case GfxEasing::InOutQuint: + return &easeInOutQuint; + case GfxEasing::OutInQuint: + return &easeOutInQuint; + case GfxEasing::InSine: + return &easeInSine; + case GfxEasing::OutSine: + return &easeOutSine; + case GfxEasing::InOutSine: + return &easeInOutSine; + case GfxEasing::OutInSine: + return &easeOutInSine; + case GfxEasing::InExpo: + return &easeInExpo; + case GfxEasing::OutExpo: + return &easeOutExpo; + case GfxEasing::InOutExpo: + return &easeInOutExpo; + case GfxEasing::OutInExpo: + return &easeOutInExpo; + case GfxEasing::InCirc: + return &easeInCirc; + case GfxEasing::OutCirc: + return &easeOutCirc; + case GfxEasing::InOutCirc: + return &easeInOutCirc; + case GfxEasing::OutInCirc: + return &easeOutInCirc; + case GfxEasing::InElastic: + return &easeInElastic; + case GfxEasing::OutElastic: + return &easeOutElastic; + case GfxEasing::InOutElastic: + return &easeInOutElastic; + case GfxEasing::OutInElastic: + return &easeOutInElastic; + case GfxEasing::InBack: + return &easeInBack; + case GfxEasing::OutBack: + return &easeOutBack; + case GfxEasing::InOutBack: + return &easeInOutBack; + case GfxEasing::OutInBack: + return &easeOutInBack; + case GfxEasing::InBounce: + return &easeInBounce; + case GfxEasing::OutBounce: + return &easeOutBounce; + case GfxEasing::InOutBounce: + return &easeInOutBounce; + case GfxEasing::OutInBounce: + return &easeOutInBounce; + default: + return 0; + }; +} + +struct NameFunctionMap : public QHash<QString, GfxEasing::Function> +{ + NameFunctionMap() + { + insert(QLatin1String("easeNone"), easeNone); + insert(QLatin1String("easeInQuad"), easeInQuad); + insert(QLatin1String("easeOutQuad"), easeOutQuad); + insert(QLatin1String("easeInOutQuad"), easeInOutQuad); + insert(QLatin1String("easeOutInQuad"), easeOutInQuad); + insert(QLatin1String("easeInCubic"), easeInCubic); + insert(QLatin1String("easeOutCubic"), easeOutCubic); + insert(QLatin1String("easeInOutCubic"), easeInOutCubic); + insert(QLatin1String("easeOutInCubic"), easeOutInCubic); + insert(QLatin1String("easeInQuart"), easeInQuart); + insert(QLatin1String("easeOutQuart"), easeOutQuart); + insert(QLatin1String("easeInOutQuart"), easeInOutQuart); + insert(QLatin1String("easeOutInQuart"), easeOutInQuart); + insert(QLatin1String("easeInQuint"), easeInQuint); + insert(QLatin1String("easeOutQuint"), easeOutQuint); + insert(QLatin1String("easeInOutQuint"), easeInOutQuint); + insert(QLatin1String("easeOutInQuint"), easeOutInQuint); + insert(QLatin1String("easeInSine"), easeInSine); + insert(QLatin1String("easeOutSine"), easeOutSine); + insert(QLatin1String("easeInOutSine"), easeInOutSine); + insert(QLatin1String("easeOutInSine"), easeOutInSine); + insert(QLatin1String("easeInExpo"), easeInExpo); + insert(QLatin1String("easeOutExpo"), easeOutExpo); + insert(QLatin1String("easeInOutExpo"), easeInOutExpo); + insert(QLatin1String("easeOutInExpo"), easeOutInExpo); + insert(QLatin1String("easeInCirc"), easeInCirc); + insert(QLatin1String("easeOutCirc"), easeOutCirc); + insert(QLatin1String("easeInOutCirc"), easeInOutCirc); + insert(QLatin1String("easeOutInCirc"), easeOutInCirc); + insert(QLatin1String("easeInElastic"), easeInElastic); + insert(QLatin1String("easeOutElastic"), easeOutElastic); + insert(QLatin1String("easeInOutElastic"), easeInOutElastic); + insert(QLatin1String("easeOutInElastic"), easeOutInElastic); + insert(QLatin1String("easeInBack"), easeInBack); + insert(QLatin1String("easeOutBack"), easeOutBack); + insert(QLatin1String("easeInOutBack"), easeInOutBack); + insert(QLatin1String("easeOutInBack"), easeOutInBack); + insert(QLatin1String("easeInBounce"), easeInBounce); + insert(QLatin1String("easeOutBounce"), easeOutBounce); + insert(QLatin1String("easeInOutBounce"), easeInOutBounce); + insert(QLatin1String("easeOutInBounce"), easeOutInBounce); + } +}; +Q_GLOBAL_STATIC(NameFunctionMap, nameFunctionMap); + +typedef GfxEasingFunction *(*ConfigurableFunction)(const GfxEasingProperties &); +struct ConfigFunctionMap : public QHash<QString, ConfigurableFunction> +{ + ConfigFunctionMap() + { + insert(QLatin1String("easeInElastic"), easeInElasticC); + insert(QLatin1String("easeOutElastic"), easeOutElasticC); + insert(QLatin1String("easeInBounce"), easeInBounceC); + insert(QLatin1String("easeOutBounce"), easeOutBounceC); + } +}; +Q_GLOBAL_STATIC(ConfigFunctionMap, configFunctionMap); + +/*! + \class GfxEasing + \ingroup animation + \brief The GfxEasing class provides easing curves for controlling animation. + + Easing curves describe a function that controls how a value changes over + time. Easing curves allow transitions from one value to another to appear + more natural than a simple linear motion would allow. The GfxEasing class + is usually used in conjunction with the GfxTimeLine class, but can be used + on its own. + + To calculate the value at a given time, the easing curve function requires + the starting value, the final value and the total time to change from the + starting to the final value. When using the GfxEasing class with + GfxTimeLine, these values are supplied by the GfxTimeLine. When using + the GfxEasing class on its own, the programmer must specify them using + the GfxEasing::setFrom(), GfxEasing::setTo() and GfxEasing::setLength() + methods, or by passing them explicitly to the GfxEasing::valueAt() method. + + For example, + \code + GfxEasing easing(GfxEasing::InOutQuad); + easing.setFrom(0); + easing.setTo(1000); + easing.setLength(1000); + + for(int milliseconds = 0; milliseconds < 1000; ++milliseconds) + qWarning() << "Value at" << milliseconds << "milliseconds is + << easing.valueAt(milliseconds); + \endcode + will print the value at each millisecond for an InOutQuad transition from + 0 to 1000 over 1 second. + + When using a GfxTimeLine, the values are communicated implicitly. + \code + GfxTimeLine timeline; + GfxValue value(0); + + timeline.move(value, 1000, GfxEasing(GfxEasing::InOutQuad), 1000); + \endcode + In this case, any values set using the previous setter methods would be + ignored. + */ + +/*! + \qmlproperty string NumericAnimation::easing + \brief the easing curve used for the transition. + + Available values are: + + \list + \i \e easeNone - Easing equation function for a simple linear tweening, with no easing. + \i \e easeInQuad - Easing equation function for a quadratic (t^2) easing in: accelerating from zero velocity. + \i \e easeOutQuad - Easing equation function for a quadratic (t^2) easing out: decelerating to zero velocity. + \i \e easeInOutQuad - Easing equation function for a quadratic (t^2) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInQuad - Easing equation function for a quadratic (t^2) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInCubic - Easing equation function for a cubic (t^3) easing in: accelerating from zero velocity. + \i \e easeOutCubic - Easing equation function for a cubic (t^3) easing out: decelerating from zero velocity. + \i \e easeInOutCubic - Easing equation function for a cubic (t^3) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInCubic - Easing equation function for a cubic (t^3) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInQuart - Easing equation function for a quartic (t^4) easing in: accelerating from zero velocity. + \i \e easeOutQuart - Easing equation function for a quartic (t^4) easing out: decelerating from zero velocity. + \i \e easeInOutQuart - Easing equation function for a quartic (t^4) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInQuart - Easing equation function for a quartic (t^4) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInQuint - Easing equation function for a quintic (t^5) easing in: accelerating from zero velocity. + \i \e easeOutQuint - Easing equation function for a quintic (t^5) easing out: decelerating from zero velocity. + \i \e easeInOutQuint - Easing equation function for a quintic (t^5) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInQuint - Easing equation function for a quintic (t^5) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInSine - Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity. + \i \e easeOutSine - Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity. + \i \e easeInOutSine - Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInSine - Easing equation function for a sinusoidal (sin(t)) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInExpo - Easing equation function for an exponential (2^t) easing in: accelerating from zero velocity. + \i \e easeOutExpo - Easing equation function for an exponential (2^t) easing out: decelerating from zero velocity. + \i \e easeInOutExpo - Easing equation function for an exponential (2^t) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInExpo - Easing equation function for an exponential (2^t) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInCirc - Easing equation function for a circular (sqrt(1-t^2)) easing in: accelerating from zero velocity. + \i \e easeOutCirc - Easing equation function for a circular (sqrt(1-t^2)) easing out: decelerating from zero velocity. + \i \e easeInOutCirc - Easing equation function for a circular (sqrt(1-t^2)) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInCirc - Easing equation function for a circular (sqrt(1-t^2)) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInElastic - Easing equation function for an elastic (exponentially decaying sine wave) easing in: accelerating from zero velocity. The peak amplitude can be set with the \i amplitude parameter, and the period of decay by the \i period parameter. + \i \e easeOutElastic - Easing equation function for an elastic (exponentially decaying sine wave) easing out: decelerating from zero velocity. The peak amplitude can be set with the \i amplitude parameter, and the period of decay by the \i period parameter. + \i \e easeInOutElastic - Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInElastic - Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: deceleration until halfway, then acceleration. + \i \e easeInBack - Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity. + \i \e easeOutBack - Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out: decelerating from zero velocity. + \i \e easeInOutBack - Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInBack - Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration. + \i \e easeOutBounce - Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity. + \i \e easeInBounce - Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity. + \i \e easeInOutBounce - Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration. + \i \e easeOutInBounce - Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: deceleration until halfway, then acceleration. + \endlist +*/ + +/*! + \enum GfxEasing::Curve + + The type of easing curve. +*/ +/*! + \var GfxEasing::Curve GfxEasing::None + Easing equation function for a simple linear tweening, with no easing. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InQuad + Easing equation function for a quadratic (t^2) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutQuad + Easing equation function for a quadratic (t^2) easing out: decelerating to zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutQuad + Easing equation function for a quadratic (t^2) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInQuad + Easing equation function for a quadratic (t^2) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InCubic + Easing equation function for a cubic (t^3) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutCubic + Easing equation function for a cubic (t^3) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutCubic + Easing equation function for a cubic (t^3) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInCubic + Easing equation function for a cubic (t^3) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InQuart + Easing equation function for a quartic (t^4) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutQuart + Easing equation function for a quartic (t^4) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutQuart + Easing equation function for a quartic (t^4) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInQuart + Easing equation function for a quartic (t^4) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InQuint + Easing equation function for a quintic (t^5) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutQuint + Easing equation function for a quintic (t^5) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutQuint + Easing equation function for a quintic (t^5) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInQuint + Easing equation function for a quintic (t^5) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InSine + Easing equation function for a sinusoidal (sin(t)) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutSine + Easing equation function for a sinusoidal (sin(t)) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutSine + Easing equation function for a sinusoidal (sin(t)) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInSine + Easing equation function for a sinusoidal (sin(t)) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InExpo + Easing equation function for an exponential (2^t) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutExpo + Easing equation function for an exponential (2^t) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutExpo + Easing equation function for an exponential (2^t) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInExpo + Easing equation function for an exponential (2^t) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InCirc + Easing equation function for a circular (sqrt(1-t^2)) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutCirc + Easing equation function for a circular (sqrt(1-t^2)) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutCirc + Easing equation function for a circular (sqrt(1-t^2)) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInCirc + Easing equation function for a circular (sqrt(1-t^2)) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InElastic + Easing equation function for an elastic (exponentially decaying sine wave) easing in: accelerating from zero velocity. The peak amplitude can be set with the \i amplitude parameter, and the period of decay by the \i period parameter. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutElastic + Easing equation function for an elastic (exponentially decaying sine wave) easing out: decelerating from zero velocity. The peak amplitude can be set with the \i amplitude parameter, and the period of decay by the \i period parameter. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutElastic + Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInElastic + Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InBack + Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutBack + Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutBack + Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInBack + Easing equation function for a back (overshooting cubic easing: (s+1)*t^3 - s*t^2) easing out/in: deceleration until halfway, then acceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutBounce + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InBounce + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity. +*/ +/*! + \var GfxEasing::Curve GfxEasing::InOutBounce + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration. +*/ +/*! + \var GfxEasing::Curve GfxEasing::OutInBounce + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: deceleration until halfway, then acceleration. +*/ + +/*! + Construct a linear easing object. This is equivalent to \c {GfxEasing(GfxEasing::None)}. + */ +GfxEasing::GfxEasing() +: _config(0), _func(&easeNone), _b(0.), _c(1.), _d(1.) +{ +} + +/*! + Construct an easing object with the given \a curve. + */ +GfxEasing::GfxEasing(Curve curve) +: _config(0), _func(0), _b(0.), _c(1.), _d(1.) +{ + _func = curveToFunc(curve); + if(!_func) { + qWarning("GfxEasing: Invalid curve type %d", curve); + _func = &easeNone; + } +} + +/*! + Construct an easing object with the given \a curve. If \a curve does not + describe a legal curve, a linear easing object is constructed. + + Curve names have the form + \c {ease<CurveName>[(<arg>: <arg value>[, <arg2>: <arg value>])]}. The + \i CurveName is equivalent to the GfxEasing::Curve enum name. Some more + advanced curves can take arguments to further refine their behaviour. Where + applicable, these parameters are described in the corresponding + GfxEasing::Curve value documentation. + + For example, + \code + GfxEasing easing("easeInOutQuad"); + GfxEasing easing2("easeInElastic(period: 5, amplitude: 100)"); + \endcode + */ +GfxEasing::GfxEasing(const QString &curve) +: _config(0), _func(&easeNone), _b(0.), _c(1.), _d(1.) +{ + if(curve.contains(QLatin1Char('('))) { + QString easeName = curve.trimmed(); + GfxEasingProperties prop; + if(!easeName.endsWith(QLatin1Char(')'))) { + qWarning("GfxEasing: Unmatched perenthesis in easing function '%s'", + curve.toLatin1().constData()); + return; + } + + int idx = easeName.indexOf(QLatin1Char('(')); + QString prop_str = + easeName.mid(idx + 1, easeName.length() - 1 - idx - 1); + easeName = easeName.left(idx); + + QStringList props = prop_str.split(QLatin1Char(',')); + foreach(QString str, props) { + int sep = str.indexOf(QLatin1Char(':')); + + if(sep == -1) { + qWarning("GfxEasing: Improperly specified property in easing function '%s'", + curve.toLatin1().constData()); + return; + } + + QString propName = str.left(sep).trimmed(); + bool isOk; + qreal propValue = str.mid(sep + 1).trimmed().toDouble(&isOk); + + if(propName.isEmpty() || !isOk) { + qWarning("GfxEasing: Improperly specified property in easing function '%s'", + curve.toLatin1().constData()); + return; + } + + prop.insert(propName, propValue); + } + + QHash<QString, ConfigurableFunction>::Iterator iter = + configFunctionMap()->find(easeName); + + if(iter != configFunctionMap()->end()) + _config = (*iter)(prop); + } else { + if(nameFunctionMap()->contains(curve)) + _func = *(nameFunctionMap()->find(curve)); + } + + if(!_func && !_config) { + qWarning("GfxEasing: Unknown easing curve '%s'", + curve.toLatin1().constData()); + _func = &easeNone; + } +} + +/*! + Construct a copy of \a other. + */ +GfxEasing::GfxEasing(const GfxEasing &other) +: _config(0), _func(other._func), _b(other._b), _c(other._c), _d(other._d) +{ + if(other._config) _config = other._config->copy(); +} + +/*! + Copy \a other. + */ +GfxEasing &GfxEasing::operator=(const GfxEasing &other) +{ + if(_config) { delete _config; _config = 0; } + if(other._config) _config = other._config->copy(); + + _func = other._func; + _b = other._b; + _c = other._c; + _d = other._d; + + return *this; +} + +/*! + Returns true if this is a linear easing object. + */ +bool GfxEasing::isLinear() const +{ + return !_config && _func == &easeNone; +} + +/*! + Return the starting value for the easing curve. By default this is 0. + */ +qreal GfxEasing::from() const +{ + return _b; +} + +/*! + Set the starting value for the easing curve to \a from. + */ +void GfxEasing::setFrom(qreal from) +{ + _b = from; +} + +/*! + Return the final value for the easing curve. By default this is 0. + */ +qreal GfxEasing::to() const +{ + return _c; +} + +/*! + Set the final value for the easing curve to \a to. + */ +void GfxEasing::setTo(qreal to) +{ + _c = to; +} + +/*! + Return the length of the easing curve, in milliseconds. By default this + is 1. + */ +qreal GfxEasing::length() const +{ + return _d; +} + +/*! + Set the \a length of the easing curve, in milliseconds. + */ +void GfxEasing::setLength(qreal length) +{ + Q_ASSERT(length > 0); + _d = length; +} + +/*! + Return the value for the easing curve at time \a t milliseconds, based on + the parameters returned by GfxEasing::from(), GfxEasing::to() and + GfxEasing::length(). + + \a t is clamped to (0, GfxEasing::length()). + */ +qreal GfxEasing::valueAt(qreal t) const +{ + if(t < 0) t = 0; + else if(t > length()) t = length(); + + if(_config) + return _config->value(t, _b, _c - _b, _d); + else + return _func(t, _b, _c - _b, _d); +} + +/* + Return the value for the easing curve at time \a t milliseconds, based on + the provided parameters \a from, \a to and \a length. The values returned + from the object's GfxEasing::from(), GfxEasing::to() and GfxEasing::length() + methods are ignored. + + \a t is clamped to (0, \a length). + */ +qreal GfxEasing::valueAt(qreal t, qreal from, qreal to, qreal length) const +{ + if(t < 0) t = 0; + else if(t > length) t = length; + + if(_config) + return _config->value(t, from, to - from, length); + else + return _func(t, from, to - from, length); +} + +/*! + \internal + */ +QStringList GfxEasing::curves() +{ + return nameFunctionMap()->keys(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/timeline/gfxeasing.h b/src/declarative/timeline/gfxeasing.h new file mode 100644 index 0000000..c15aadc --- /dev/null +++ b/src/declarative/timeline/gfxeasing.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 GFXEASING_H +#define GFXEASING_H + +#include <qfxglobal.h> +#include <QList> +#include <QPair> +#include <QWidget> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class GfxEasingFunction; +class Q_DECLARATIVE_EXPORT GfxEasing +{ +public: + enum Curve { + None, + InQuad, OutQuad, InOutQuad, OutInQuad, + InCubic, OutCubic, InOutCubic, OutInCubic, + InQuart, OutQuart, InOutQuart, OutInQuart, + InQuint, OutQuint, InOutQuint, OutInQuint, + InSine, OutSine, InOutSine, OutInSine, + InExpo, OutExpo, InOutExpo, OutInExpo, + InCirc, OutCirc, InOutCirc, OutInCirc, + InElastic, OutElastic, InOutElastic, OutInElastic, + InBack, OutBack, InOutBack, OutInBack, + InBounce, OutBounce, InOutBounce, OutInBounce + }; + + GfxEasing(); + GfxEasing(Curve); + GfxEasing(const QString &); + GfxEasing(const GfxEasing &); + GfxEasing &operator=(const GfxEasing &); + + bool isLinear() const; + + qreal from() const; + void setFrom(qreal); + qreal to() const; + void setTo(qreal); + qreal length() const; + void setLength(qreal); + + qreal valueAt(qreal t) const; + qreal valueAt(qreal t, qreal from, qreal to, qreal length) const; + + static QStringList curves(); + + typedef float (*Function)(float t, float b, float c, float d); +private: + GfxEasingFunction *_config; + Function _func; + + qreal _b, _c, _d; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/timeline/gfxtimeline.cpp b/src/declarative/timeline/gfxtimeline.cpp new file mode 100644 index 0000000..36b18d0 --- /dev/null +++ b/src/declarative/timeline/gfxtimeline.cpp @@ -0,0 +1,946 @@ +/**************************************************************************** +** +** 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 "gfxtimeline.h" +#include <QDebug> +#include <QMutex> +#include <QThread> +#include <QWaitCondition> +#include <QEvent> +#include <QCoreApplication> +#include "gfxeasing.h" +#include <QTime> + +QT_BEGIN_NAMESPACE + +#define TIMETICK 5 + +// +// Timeline stuff +// + +struct Update { + Update(GfxValue *_g, qreal _v) + : g(_g), v(_v) {} + Update(const GfxEvent &_e) + : g(0), v(0), e(_e) {} + + GfxValue *g; + qreal v; + GfxEvent 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 GfxEvent &ev = GfxEvent(), const GfxEasing &es = GfxEasing()) + : 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; + GfxEvent event; + GfxEasing 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 GfxValue 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 { + if(op.easing.isLinear()) { + qreal delta = op.value - base; + qreal pTime = (qreal)(time) / (qreal)op.length; + return base + delta * pTime; + } else { + return op.easing.valueAt(time, base, op.value, op.length); + } + } + case Op::MoveBy: + if(time == 0) { + return base; + } else if(time == (op.length)) { + return base + op.value; + } else { + if(op.easing.isLinear()) { + qreal delta = op.value; + qreal pTime = (qreal)(time) / (qreal)op.length; + return base + delta * pTime; + } else { + return op.easing.valueAt(time, base, base + op.value, op.length); + } + } + 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; +} + +/*! + \class QmlTimeLine + \ingroup animation + \brief The QmlTimeLine class provides a timeline for controlling animations. + + QmlTimeLine is similar to QTimeLine except: + \list + \i It updates GfxValue instances directly, rather than maintaining a single + current value. + + For example, the following animates a simple value over 200 milliseconds: + \code + GfxValue 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 GfxValue + and reimplement the GfxValue::setValue() method. + + \i Supports multiple GfxValue, 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 + GfxValue x(<starting value>); + GfxValue 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 gfxValue 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 GfxEvent &event) +{ + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Execute, 0, 0, 0., d->order++, event); + d->add(*event.eventObject(), op); +} + +/*! + Set the \a value of \a gfxValue. +*/ +void QmlTimeLine::set(GfxValue &gfxValue, qreal value) +{ + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Set, 0, value, 0., d->order++); + d->add(gfxValue, op); +} + +/*! + Decelerate \a gfxValue 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(GfxValue &gfxValue, 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(gfxValue, op); + + return time; +} + +/*! + \overload + + Decelerate \a gfxValue 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(GfxValue &gfxValue, 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(gfxValue, op); + + return time; +} + +/*! + Decelerate \a gfxValue 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(GfxValue &gfxValue, 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(gfxValue, op); + + return time; +} + +/*! + Linearly change the \a gfxValue from its current value to the given + \a destination value over \a time milliseconds. +*/ +void QmlTimeLine::move(GfxValue &gfxValue, qreal destination, int time) +{ + if(time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++); + d->add(gfxValue, op); +} + +/*! + Change the \a gfxValue from its current value to the given \a destination + value over \a time milliseconds using the \a easing curve. + */ +void QmlTimeLine::move(GfxValue &gfxValue, qreal destination, const GfxEasing &easing, int time) +{ + if(time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::Move, time, destination, 0.0f, d->order++, GfxEvent(), easing); + d->add(gfxValue, op); +} + +/*! + Linearly change the \a gfxValue from its current value by the \a change amount + over \a time milliseconds. +*/ +void QmlTimeLine::moveBy(GfxValue &gfxValue, qreal change, int time) +{ + if(time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++); + d->add(gfxValue, op); +} + +/*! + Change the \a gfxValue from its current value by the \a change amount over + \a time milliseconds using the \a easing curve. + */ +void QmlTimeLine::moveBy(GfxValue &gfxValue, qreal change, const GfxEasing &easing, int time) +{ + if(time <= 0) return; + QmlTimeLinePrivate::Op op(QmlTimeLinePrivate::Op::MoveBy, time, change, 0.0f, d->order++, GfxEvent(), easing); + d->add(gfxValue, op); +} + +/*! + Cancel (but don't complete) all scheduled actions for \a gfxValue. +*/ +void QmlTimeLine::reset(GfxValue &gfxValue) +{ + if(!gfxValue._t) + return; + if(gfxValue._t != this) { + qWarning() << "QmlTimeLine: Cannot reset a GfxValue owned by another timeline."; + return; + } + remove(&gfxValue); + gfxValue._t = 0; +} + +int QmlTimeLine::duration() const +{ + return -1; +} + +/*! + Synchronize the end point of \a gfxValue to the endpoint of \a syncTo + within this timeline. + + Following operations on \a gfxValue 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(gfxValue, min(0, length_of(syncTo) - length_of(gfxValue))) + \endcode +*/ +void QmlTimeLine::sync(GfxValue &gfxValue, GfxValue &syncTo) +{ + QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&syncTo); + if(iter == d->ops.end()) + return; + int length = iter->length; + + iter = d->ops.find(&gfxValue); + if(iter == d->ops.end()) { + pause(gfxValue, length); + } else { + int glength = iter->length; + pause(gfxValue, length - glength); + } +} + +/*! + Synchronize the end point of \a gfxValue to the endpoint of the longest + action currently scheduled in the timeline. + + In psuedo-code, this is equivalent to: + \code + QmlTimeLine::pause(gfxValue, length_of(timeline) - length_of(gfxValue)) + \endcode +*/ +void QmlTimeLine::sync(GfxValue &gfxValue) +{ + QmlTimeLinePrivate::Ops::Iterator iter = d->ops.find(&gfxValue); + if(iter == d->ops.end()) { + pause(gfxValue, d->length); + } else { + pause(gfxValue, 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 + GfxValue 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 + GfxValue 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 GfxValue's retain their current value. For example, + \code + GfxValue 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 GfxValues. Even if multiple + GfxValues 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(); ) { + GfxValue *v = static_cast<GfxValue *>(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; + } + } + } + + +} + +/*! + \class GfxValue + \ingroup animation + \brief The GfxValue class is modified by QmlTimeLine. +*/ + +/*! + \fn GfxValue::GfxValue(qreal value = 0) + + Construct a new GfxValue with an initial \a value. +*/ + +/*! + \fn qreal GfxValue::value() const + + Return the current value. +*/ + +/*! + \fn void GfxValue::setValue(qreal value) + + Set the current \a value. +*/ + +/*! + \fn QmlTimeLine *GfxValue::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; + } +} + +GfxEvent::GfxEvent() +: d0(0), d1(0), d2(0) +{ +} + +GfxEvent::GfxEvent(const GfxEvent &o) +: d0(o.d0), d1(o.d1), d2(o.d2) +{ +} + +GfxEvent &GfxEvent::operator=(const GfxEvent &o) +{ + d0 = o.d0; + d1 = o.d1; + d2 = o.d2; + return *this; +} + +void GfxEvent::execute() const +{ + d0(d1); +} + +QmlTimeLineObject *GfxEvent::eventObject() const +{ + return d2; +} + +QT_END_NAMESPACE diff --git a/src/declarative/timeline/gfxtimeline.h b/src/declarative/timeline/gfxtimeline.h new file mode 100644 index 0000000..0bdddaf --- /dev/null +++ b/src/declarative/timeline/gfxtimeline.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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 GFXTIMELINE_H +#define GFXTIMELINE_H + +#include <QObject> +#include <qfxglobal.h> +#include <QAbstractAnimation> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class GfxEasing; +class GfxValue; +class GfxEvent; +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 GfxEvent &); + void set(GfxValue &, qreal); + + int accel(GfxValue &, qreal velocity, qreal accel); + int accel(GfxValue &, qreal velocity, qreal accel, qreal maxDistance); + int accelDistance(GfxValue &, qreal velocity, qreal distance); + + void move(GfxValue &, qreal destination, int time = 500); + void move(GfxValue &, qreal destination, const GfxEasing &, int time = 500); + void moveBy(GfxValue &, qreal change, int time = 500); + void moveBy(GfxValue &, qreal change, const GfxEasing &, int time = 500); + + void sync(); + void setSyncPoint(int); + int syncPoint() const; + + void sync(GfxValue &); + void sync(GfxValue &, GfxValue &); + + void reset(GfxValue &); + + 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 GfxValue : public QmlTimeLineObject +{ +public: + GfxValue(qreal v = 0.) : _v(v) {} + + qreal value() const { return _v; } + virtual void setValue(qreal v) { _v = v; } + + QmlTimeLine *timeLine() const { return _t; } + + operator qreal() const { return _v; } + GfxValue &operator=(qreal v) { setValue(v); return *this; } +private: + friend class QmlTimeLine; + friend struct QmlTimeLinePrivate; + qreal _v; +}; + +class Q_DECLARATIVE_EXPORT GfxEvent +{ +public: + GfxEvent(); + GfxEvent(const GfxEvent &o); + + template<class T, void (T::*method)()> + GfxEvent(QmlTimeLineObject *b, T *c) + { + d0 = &callFunc<T, method>; + d1 = (void *)c; + d2 = b; + } + + template<class T, void (T::*method)()> + static GfxEvent gfxEvent(QmlTimeLineObject *b, T *c) + { + GfxEvent rv; + rv.d0 = &callFunc<T, method>; + rv.d1 = (void *)c; + rv.d2 = b; + return rv; + } + + GfxEvent &operator=(const GfxEvent &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; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/declarative/timeline/gfxvalueproxy.h b/src/declarative/timeline/gfxvalueproxy.h new file mode 100644 index 0000000..1eaf44e --- /dev/null +++ b/src/declarative/timeline/gfxvalueproxy.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 GFXVALUEPROXY_H +#define GFXVALUEPROXY_H +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +template<class T> +class GfxValueProxy : public GfxValue +{ +public: + GfxValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.) + : GfxValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0) + { + Q_ASSERT(_class); + } + + GfxValueProxy(T *cls, void (T::*func)(int), qreal v = 0.) + : GfxValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func) + { + Q_ASSERT(_class); + } + + virtual void setValue(qreal v) + { + GfxValue::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 + +QT_END_HEADER + +#endif//GFXVALUEPROXY diff --git a/src/declarative/timeline/timeline.pri b/src/declarative/timeline/timeline.pri new file mode 100644 index 0000000..8994c78 --- /dev/null +++ b/src/declarative/timeline/timeline.pri @@ -0,0 +1,9 @@ +SOURCES += \ + timeline/gfxeasing.cpp \ + timeline/gfxtimeline.cpp \ + +HEADERS += \ + timeline/gfxeasing.h \ + timeline/gfxtimeline.h \ + timeline/gfxvalueproxy.h \ + |