diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-11-11 14:21:18 (GMT) |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-11-12 13:55:50 (GMT) |
commit | 0d6451ec1f1042dbf8c8cd7f2759e2a385d29696 (patch) | |
tree | 7d8647ccec050f7b234220040464f99c7e4bd72b | |
parent | 215deeabaeba359a9b24681f33f99b80060c4fb1 (diff) | |
download | Qt-0d6451ec1f1042dbf8c8cd7f2759e2a385d29696.zip Qt-0d6451ec1f1042dbf8c8cd7f2759e2a385d29696.tar.gz Qt-0d6451ec1f1042dbf8c8cd7f2759e2a385d29696.tar.bz2 |
Introduced new class QAnimationDriver for plugging in what drives animations
We need such a concept in place in order to do animations that are driven
by vertical sync rather than QTimer, as vertical sync comes constantly at
16.66 ms. This means that animations do will not be jerking...
Reviewed-by: bnilsen
-rw-r--r-- | src/corelib/animation/qabstractanimation.cpp | 146 | ||||
-rw-r--r-- | src/corelib/animation/qabstractanimation.h | 31 | ||||
-rw-r--r-- | src/corelib/animation/qabstractanimation_p.h | 48 | ||||
-rw-r--r-- | tests/auto/qpauseanimation/tst_qpauseanimation.cpp | 5 |
4 files changed, 214 insertions, 16 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 641b42b..9add36e 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -166,11 +166,12 @@ Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) #endif QUnifiedTimer::QUnifiedTimer() : - QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), + QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), currentAnimationIdx(0), consistentTiming(false), slowMode(false), slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0) { time.invalidate(); + driver = &defaultDriver; } @@ -247,14 +248,27 @@ void QUnifiedTimer::restartAnimationTimer() qDebug() << runningPauseAnimations; qDebug() << closestPauseAnimationTimeToFinish(); } + driver->stop(); animationTimer.start(closestTimeToFinish, this); isPauseTimerActive = true; - } else if (!animationTimer.isActive() || isPauseTimerActive) { - animationTimer.start(timingInterval, this); + } else if (!driver->isRunning() || isPauseTimerActive) { + driver->start(); isPauseTimerActive = false; } } +void QUnifiedTimer::setTimingInterval(int interval) +{ + timingInterval = interval; + + if (driver->isRunning() && !isPauseTimerActive) { + //we changed the timing interval + driver->stop(); + driver->start(); + } +} + + void QUnifiedTimer::timerEvent(QTimerEvent *event) { //in the case of consistent timing we make sure the orders in which events come is always the same @@ -369,6 +383,129 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish() return closestTimeToFinish; } +void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d) +{ + if (driver->isRunning()) { + qWarning("QUnifiedTimer: Cannot change animation driver while animations are running"); + return; + } + + if (driver && driver != &defaultDriver) + delete driver; + + driver = d; +} + +/*! + \class QAnimationDriver + + \brief The QAnimationDriver class is used to exchange the mechanism that drives animations. + + The default animation system is driven by a timer that fires at regular intervals. + In some scenarios, it is better to drive the animation based on other synchronization + mechanisms, such as the vertical refresh rate of the screen. + */ + +QAnimationDriver::QAnimationDriver(QObject *parent) + : QObject(*(new QAnimationDriverPrivate), parent) +{ +} + +QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + + +/*! + Advances the animation based on the current time. This function should + be continuously called by the driver while the animation is running. + */ +void QAnimationDriver::advance() +{ + QUnifiedTimer *instance = QUnifiedTimer::instance(); + + // update current time on all top level animations + instance->updateAnimationsTime(); + instance->restartAnimationTimer(); +} + + +/*! + Installs this animation driver. The animation driver is thread local and + will only apply for the thread its installed in. + */ +void QAnimationDriver::install() +{ + QUnifiedTimer *timer = QUnifiedTimer::instance(true); + timer->installAnimationDriver(this); +} + +bool QAnimationDriver::isRunning() const +{ + return d_func()->running; +} + + +void QAnimationDriver::start() +{ + Q_D(QAnimationDriver); + if (!d->running) { + started(); + d->running = true; + } +} + + +void QAnimationDriver::stop() +{ + Q_D(QAnimationDriver); + if (d->running) { + stopped(); + d->running = false; + } +} + +/*! + \fn QAnimationDriver::started() + + This function is called by the animation framework to notify the driver + that it should start running. + */ + +/*! + \fn QAnimationDriver::stopped() + + This function is called by the animation framework to notify the driver + that it should stop running. + */ + +/*! + The default animation driver just spins the timer... + */ +QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer) + : QAnimationDriver(0), m_unified_timer(timer) +{ +} + +void QDefaultAnimationDriver::timerEvent(QTimerEvent *e) +{ + Q_ASSERT(e->timerId() == m_timer.timerId()); + advance(); +} + +void QDefaultAnimationDriver::started() +{ + m_timer.start(m_unified_timer->timingInterval, this); +} + +void QDefaultAnimationDriver::stopped() +{ + m_timer.stop(); +} + + + void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) { Q_Q(QAbstractAnimation); @@ -794,6 +931,9 @@ void QAbstractAnimation::stop() { Q_D(QAbstractAnimation); + if (d->state == Stopped) + return; + d->setState(Stopped); } diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index d3c0d0d..6abe8c1 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -54,6 +54,7 @@ QT_MODULE(Core) class QAnimationGroup; class QSequentialAnimationGroup; +class QAnimationDriver; class QAbstractAnimationPrivate; class Q_CORE_EXPORT QAbstractAnimation : public QObject @@ -132,6 +133,36 @@ private: Q_DECLARE_PRIVATE(QAbstractAnimation) }; +class QAnimationDriverPrivate; +class Q_CORE_EXPORT QAnimationDriver : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QAnimationDriver) + +public: + QAnimationDriver(QObject *parent); + + void advance(); + void install(); + + bool isRunning() const; + +protected: + virtual void started() = 0; + virtual void stopped() = 0; + + QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent = 0); + +private: + friend class QUnifiedTimer; + + void start(); + void stop(); +}; + + + + #endif //QT_NO_ANIMATION QT_END_NAMESPACE diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index d3d4098..bc3746d 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -58,6 +58,7 @@ #include <QtCore/qtimer.h> #include <QtCore/qelapsedtimer.h> #include <private/qobject_p.h> +#include <qabstractanimation.h> #ifdef Q_OS_WIN #include <qt_windows.h> @@ -114,6 +115,30 @@ private: Q_DECLARE_PUBLIC(QAbstractAnimation) }; + +class QUnifiedTimer; +class QDefaultAnimationDriver : public QAnimationDriver +{ + Q_OBJECT +public: + QDefaultAnimationDriver(QUnifiedTimer *timer); + void timerEvent(QTimerEvent *e); + + void started(); + void stopped(); + +private: + QBasicTimer m_timer; + QUnifiedTimer *m_unified_timer; +}; + +class Q_CORE_EXPORT QAnimationDriverPrivate : public QObjectPrivate +{ +public: + QAnimationDriverPrivate() : running(false) {} + bool running; +}; + typedef QElapsedTimer ElapsedTimer; class QUnifiedTimer : public QObject @@ -130,14 +155,7 @@ public: static void unregisterAnimation(QAbstractAnimation *animation); //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL - void setTimingInterval(int interval) - { - timingInterval = interval; - if (animationTimer.isActive() && !isPauseTimerActive) { - //we changed the timing interval - animationTimer.start(timingInterval, this); - } - } + void setTimingInterval(int interval); /* this allows to have a consistent timer interval at each tick from the timer @@ -161,11 +179,20 @@ public: */ static void updateAnimationTimer(); + void installAnimationDriver(QAnimationDriver *driver); + + void restartAnimationTimer(); + void updateAnimationsTime(); + protected: void timerEvent(QTimerEvent *); private: - // timer used for all active (running) animations + friend class QDefaultAnimationDriver; + + QAnimationDriver *driver; + QDefaultAnimationDriver defaultDriver; + QBasicTimer animationTimer; // timer used to delay the check if we should start/stop the animation timer QBasicTimer startStopAnimationTimer; @@ -195,9 +222,6 @@ private: void registerRunningAnimation(QAbstractAnimation *animation); void unregisterRunningAnimation(QAbstractAnimation *animation); - void restartAnimationTimer(); - - void updateAnimationsTime(); int closestPauseAnimationTimeToFinish(); }; diff --git a/tests/auto/qpauseanimation/tst_qpauseanimation.cpp b/tests/auto/qpauseanimation/tst_qpauseanimation.cpp index 605cee6..378eb1c 100644 --- a/tests/auto/qpauseanimation/tst_qpauseanimation.cpp +++ b/tests/auto/qpauseanimation/tst_qpauseanimation.cpp @@ -394,7 +394,10 @@ void tst_QPauseAnimation::multipleSequentialGroups() QVERIFY(subgroup3.state() == QAbstractAnimation::Running); QVERIFY(subgroup4.state() == QAbstractAnimation::Running); - QTest::qWait(group.totalDuration() + 100); + // This is a pretty long animation so it tends to get rather out of sync + // when using the consistent timer, so run for an extra half second for good + // measure... + QTest::qWait(group.totalDuration() + 500); #ifdef Q_OS_WIN if (group.state() != QAbstractAnimation::Stopped) |