6#include "QskAnimator.h"
8#include <qelapsedtimer.h>
9#include <qglobalstatic.h>
11#include <qquickwindow.h>
16#ifndef QT_NO_DEBUG_STREAM
30#ifndef QT_NO_DEBUG_STREAM
31 void debugStatistics( QDebug debug )
33 QDebugStateSaver saver( debug );
36 debug <<
"created: " << created
37 <<
", destroyed: " << destroyed
38 <<
", current: " << current
39 <<
", maximum: " << maximum;
46 created = destroyed = current = maximum = 0;
49 inline void increment()
54 if ( current > maximum )
58 inline void decrement()
78 class AnimatorDriver final :
public QObject
88 qint64 referenceTime()
const;
91 void advanced( QQuickWindow* );
92 void terminated( QQuickWindow* );
95 void advanceAnimators( QQuickWindow* );
96 void removeWindow( QQuickWindow* );
97 void scheduleUpdate( QQuickWindow* );
99 QElapsedTimer m_referenceTime;
102 QVector< QskAnimator* > m_animators;
109 QVector< QQuickWindow* > m_windows;
110 mutable int m_index = -1;
114AnimatorDriver::AnimatorDriver()
116 m_referenceTime.start();
119inline qint64 AnimatorDriver::referenceTime()
const
121 return m_referenceTime.elapsed();
124void AnimatorDriver::registerAnimator(
QskAnimator* animator )
126 Q_ASSERT( animator->window() );
130 auto it = std::lower_bound( m_animators.begin(), m_animators.end(), animator );
131 if ( it != m_animators.end() && *it == animator )
136 if ( it - m_animators.begin() < m_index )
140 m_animators.insert( it, animator );
142 if (
auto window = animator->window() )
144 if ( !m_windows.contains( window ) )
148 connect( window, &QQuickWindow::afterAnimating,
149 this, [
this, window ]() { advanceAnimators( window ); } );
151 connect( window, &QQuickWindow::frameSwapped,
152 this, [
this, window ]() { scheduleUpdate( window ); } );
154 connect( window, &QWindow::visibleChanged,
155 this, [
this, window ](
bool on ) {
if ( !on ) removeWindow( window ); } );
157 connect( window, &QObject::destroyed,
158 this, [
this, window ]( QObject* ) { removeWindow( window ); } );
165void AnimatorDriver::scheduleUpdate( QQuickWindow* window )
167 if ( m_windows.contains( window ) )
171void AnimatorDriver::removeWindow( QQuickWindow* window )
173 window->disconnect(
this );
174 m_windows.removeOne( window );
176 for (
auto it = m_animators.begin(); it != m_animators.end(); )
178 if ( ( *it )->window() == window )
179 it = m_animators.erase( it );
185void AnimatorDriver::unregisterAnimator(
QskAnimator* animator )
187 auto it = std::find( m_animators.begin(), m_animators.end(), animator );
188 if ( it != m_animators.end() )
190 if ( it - m_animators.begin() < m_index )
193 m_animators.erase( it );
197void AnimatorDriver::advanceAnimators( QQuickWindow* window )
199 bool hasAnimators =
false;
200 bool hasTerminations =
false;
202 for ( m_index = m_animators.size() - 1; m_index >= 0; m_index-- )
207 auto animator = m_animators[ m_index ];
208 if ( animator->window() == window )
212 if ( animator->isRunning() )
216 if ( !animator->isRunning() )
217 hasTerminations =
true;
226 window->disconnect(
this );
227 m_windows.removeOne(
const_cast< QQuickWindow*
>( window ) );
230 Q_EMIT advanced( window );
232 if ( hasTerminations )
233 Q_EMIT terminated( window );
236Q_GLOBAL_STATIC( AnimatorDriver, qskAnimatorDriver )
237Q_GLOBAL_STATIC( Statistics, qskStatistics )
239QskAnimator::QskAnimator()
240 : m_window( nullptr )
245 qskStatistics->increment();
248QskAnimator::~QskAnimator()
250 if ( qskAnimatorDriver )
251 qskAnimatorDriver->unregisterAnimator(
this );
254 qskStatistics->decrement();
257QQuickWindow* QskAnimator::window()
const
262void QskAnimator::setWindow( QQuickWindow* window )
264 if ( window != m_window )
271void QskAnimator::setAutoRepeat(
bool on )
276void QskAnimator::setDuration(
int ms )
281void QskAnimator::setEasingCurve( QEasingCurve::Type type )
283 if ( type >= 0 && type < QEasingCurve::Custom )
288 static QEasingCurve curveTable[ QEasingCurve::Custom ];
289 if ( curveTable[ type ].type() != type )
290 curveTable[ type ].setType( type );
292 m_easingCurve = curveTable[ type ];
296 m_easingCurve.setType( type );
300void QskAnimator::setEasingCurve(
const QEasingCurve& easingCurve )
302 m_easingCurve = easingCurve;
305const QEasingCurve& QskAnimator::easingCurve()
const
307 return m_easingCurve;
310qint64 QskAnimator::elapsed()
const
315 const qint64 driverTime = qskAnimatorDriver->referenceTime();
316 return driverTime - m_startTime;
319void QskAnimator::start()
324 if (
auto driver = qskAnimatorDriver )
326 driver->registerAnimator(
this );
327 m_startTime = driver->referenceTime();
333void QskAnimator::stop()
338 if (
auto driver = qskAnimatorDriver )
339 driver->unregisterAnimator(
this );
345void QskAnimator::update()
350 const qint64 driverTime = qskAnimatorDriver->referenceTime();
354 double progress = std::fmod( driverTime - m_startTime, m_duration );
355 progress /= m_duration;
357 advance( m_easingCurve.valueForProgress( progress ) );
361 double progress = ( driverTime - m_startTime ) /
double( m_duration );
363 if ( progress > 1.0 )
366 advance( m_easingCurve.valueForProgress( progress ) );
368 if ( progress >= 1.0 )
373void QskAnimator::setup()
378void QskAnimator::done()
387QMetaObject::Connection QskAnimator::addCleanupHandler(
388 QObject* receiver,
const char* method, Qt::ConnectionType type )
390 return QObject::connect( qskAnimatorDriver,
391 SIGNAL(terminated(QQuickWindow*)), receiver, method, type );
394QMetaObject::Connection QskAnimator::addAdvanceHandler(
395 QObject* receiver,
const char* method, Qt::ConnectionType type )
397 return QObject::connect( qskAnimatorDriver,
398 SIGNAL(advanced(QQuickWindow*)), receiver, method, type );
401#ifndef QT_NO_DEBUG_STREAM
403void QskAnimator::debugStatistics( QDebug debug )
406 qskStatistics->debugStatistics( debug );
411#include "QskAnimator.moc"