160void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation,
bool isTopLevel)
162 if (animation->userControlDisabled())
165 registerRunningAnimation(animation);
167 Q_ASSERT(!animation->m_hasRegisteredTimer);
168 animation->m_hasRegisteredTimer =
true;
169 animationsToStart << animation;
170 if (!startAnimationPending) {
171 startAnimationPending =
true;
172 QMetaObject::invokeMethod(
this,
"startAnimations", Qt::QueuedConnection);
177void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
179 unregisterRunningAnimation(animation);
181 if (!animation->m_hasRegisteredTimer)
184 int idx = animations.indexOf(animation);
186 animations.removeAt(idx);
188 if (idx <= currentAnimationIdx)
189 --currentAnimationIdx;
191 if (animations.isEmpty() && !stopTimerPending) {
192 stopTimerPending =
true;
193 QMetaObject::invokeMethod(
this,
"stopTimer", Qt::QueuedConnection);
196 animationsToStart.removeOne(animation);
198 animation->m_hasRegisteredTimer =
false;
249QAbstractAnimationJob::QAbstractAnimationJob()
252 , m_direction(QAbstractAnimationJob::Forward)
253 , m_state(QAbstractAnimationJob::Stopped)
254 , m_totalCurrentTime(0)
257 , m_uncontrolledFinishTime(-1)
258 , m_currentLoopStartTime(0)
259 , m_hasRegisteredTimer(
false)
262 , m_disableUserControl(
false)
263 , m_hasCurrentTimeChangeListeners(
false)
264 , m_isRenderThreadJob(
false)
265 , m_isRenderThreadProxy(
false)
270QAbstractAnimationJob::~QAbstractAnimationJob()
273 if (m_state != Stopped) {
274 State oldState = m_state;
276 stateChanged(oldState, m_state);
278 Q_ASSERT(m_state == Stopped);
279 if (oldState == Running) {
281 Q_ASSERT(QQmlAnimationTimer::instance(
false) == m_timer);
282 m_timer->unregisterAnimation(
this);
285 Q_ASSERT(!m_hasRegisteredTimer);
289 m_group->removeAnimation(
this);
300void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
302 if (m_state == newState)
305 if (m_loopCount == 0)
309 m_timer = QQmlAnimationTimer::instance(newState != Stopped);
310 Q_ASSERT(m_timer || newState == Stopped);
312 State oldState = m_state;
313 int oldCurrentTime = m_currentTime;
314 int oldCurrentLoop = m_currentLoop;
315 Direction oldDirection = m_direction;
318 if ((newState == Paused || newState == Running) && oldState == Stopped) {
322 m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
323 0 : (m_loopCount == -1 ? duration() : totalDuration());
326 m_uncontrolledFinishTime = -1;
328 m_currentLoopStartTime = m_totalCurrentTime;
334 bool isTopLevel = !m_group || m_group->isStopped();
335 if (oldState == Running) {
336 if (newState == Paused && m_hasRegisteredTimer)
337 m_timer->ensureTimerUpdate();
340 m_timer->unregisterAnimation(
this);
341 }
else if (newState == Running) {
342 m_timer->registerAnimation(
this, isTopLevel);
346 if (newState == Running && oldState == Stopped && !m_group)
347 fireTopLevelAnimationLoopChanged();
349 RETURN_IF_DELETED(updateState(newState, oldState));
351 if (newState != m_state)
355 RETURN_IF_DELETED(stateChanged(newState, oldState));
356 if (newState != m_state)
365 if (oldState == Stopped) {
369 RETURN_IF_DELETED(m_timer->ensureTimerUpdate());
370 RETURN_IF_DELETED(setCurrentTime(m_totalCurrentTime));
377 int dura = duration();
379 if (dura == -1 || m_loopCount < 0
380 || (oldDirection == Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * m_loopCount))
381 || (oldDirection == Backward && oldCurrentTime == 0)) {
388void QAbstractAnimationJob::setDirection(Direction direction)
390 if (m_direction == direction)
393 if (m_state == Stopped) {
394 if (m_direction == Backward) {
395 m_currentTime = duration();
396 m_currentLoop = m_loopCount - 1;
405 if (m_hasRegisteredTimer)
406 m_timer->ensureTimerUpdate();
408 m_direction = direction;
409 updateDirection(direction);
411 if (m_hasRegisteredTimer)
413 m_timer->updateAnimationTimer();
435void QAbstractAnimationJob::setCurrentTime(
int msecs)
437 msecs = qMax(msecs, 0);
439 int dura = duration();
441 int oldLoop = m_currentLoop;
443 if (dura < 0 && m_direction == Forward) {
445 if (m_uncontrolledFinishTime >= 0 && msecs >= m_uncontrolledFinishTime) {
446 msecs = m_uncontrolledFinishTime;
447 if (m_currentLoop == m_loopCount - 1) {
448 totalDura = m_uncontrolledFinishTime;
451 m_currentLoopStartTime = msecs;
452 m_uncontrolledFinishTime = -1;
455 m_totalCurrentTime = msecs;
456 m_currentTime = msecs - m_currentLoopStartTime;
458 totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
460 msecs = qMin(totalDura, msecs);
461 m_totalCurrentTime = msecs;
464 m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
465 if (m_currentLoop == m_loopCount) {
467 m_currentTime = qMax(0, dura);
468 m_currentLoop = qMax(0, m_loopCount - 1);
470 if (m_direction == Forward) {
471 m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
473 m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
474 if (m_currentTime == dura)
481 if (m_currentLoop != oldLoop && !m_group)
482 fireTopLevelAnimationLoopChanged();
484 RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
486 if (m_currentLoop != oldLoop) {
489 RETURN_IF_DELETED(currentLoopChanged());
495 if ((m_direction == Forward && m_totalCurrentTime == totalDura)
496 || (m_direction == Backward && m_totalCurrentTime == 0)) {
497 RETURN_IF_DELETED(stop());
500 if (m_hasCurrentTimeChangeListeners)
501 currentTimeChanged(m_currentTime);
585void QAbstractAnimationJob::finished()
588 for (
const auto &change : changeListeners) {
589 if (change.types & QAbstractAnimationJob::Completion) {
590 RETURN_IF_DELETED(change.listener->animationFinished(
this));
594 if (m_group && (duration() == -1 || loopCount() < 0)) {
596 m_group->uncontrolledAnimationFinished(
this);
600void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
602 for (
const auto &change : changeListeners) {
603 if (change.types & QAbstractAnimationJob::StateChange) {
604 RETURN_IF_DELETED(change.listener->animationStateChanged(
this, newState, oldState));
618void QAbstractAnimationJob::currentTimeChanged(
int currentTime)
620 Q_ASSERT(m_hasCurrentTimeChangeListeners);
622 for (
const auto &change : changeListeners) {
623 if (change.types & QAbstractAnimationJob::CurrentTime) {
624 RETURN_IF_DELETED(change.listener->animationCurrentTimeChanged(
this, currentTime));
629void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
631 if (changes & QAbstractAnimationJob::CurrentTime)
632 m_hasCurrentTimeChangeListeners =
true;
634 changeListeners.push_back(ChangeListener(listener, changes));
637void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
639 m_hasCurrentTimeChangeListeners =
false;
641 const auto it = std::find(changeListeners.begin(), changeListeners.end(), ChangeListener(listener, changes));
642 if (it != changeListeners.end())
643 changeListeners.erase(it);
645 for (
const auto &change: changeListeners) {
646 if (change.types & QAbstractAnimationJob::CurrentTime) {
647 m_hasCurrentTimeChangeListeners =
true;