159void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation,
bool isTopLevel)
161 if (animation->userControlDisabled())
164 registerRunningAnimation(animation);
166 Q_ASSERT(!animation->m_hasRegisteredTimer);
167 animation->m_hasRegisteredTimer =
true;
168 animationsToStart << animation;
169 if (!startAnimationPending) {
170 startAnimationPending =
true;
171 QMetaObject::invokeMethod(
this,
"startAnimations", Qt::QueuedConnection);
176void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
178 unregisterRunningAnimation(animation);
180 if (!animation->m_hasRegisteredTimer)
183 int idx = animations.indexOf(animation);
185 animations.removeAt(idx);
187 if (idx <= currentAnimationIdx)
188 --currentAnimationIdx;
190 if (animations.isEmpty() && !stopTimerPending) {
191 stopTimerPending =
true;
192 QMetaObject::invokeMethod(
this,
"stopTimer", Qt::QueuedConnection);
195 animationsToStart.removeOne(animation);
197 animation->m_hasRegisteredTimer =
false;
248QAbstractAnimationJob::QAbstractAnimationJob()
251 , m_direction(QAbstractAnimationJob::Forward)
252 , m_state(QAbstractAnimationJob::Stopped)
253 , m_totalCurrentTime(0)
256 , m_uncontrolledFinishTime(-1)
257 , m_currentLoopStartTime(0)
258 , m_hasRegisteredTimer(
false)
261 , m_disableUserControl(
false)
262 , m_hasCurrentTimeChangeListeners(
false)
263 , m_isRenderThreadJob(
false)
264 , m_isRenderThreadProxy(
false)
269QAbstractAnimationJob::~QAbstractAnimationJob()
272 if (m_state != Stopped) {
273 State oldState = m_state;
275 stateChanged(oldState, m_state);
277 Q_ASSERT(m_state == Stopped);
278 if (oldState == Running) {
280 Q_ASSERT(QQmlAnimationTimer::instance(
false) == m_timer);
281 m_timer->unregisterAnimation(
this);
284 Q_ASSERT(!m_hasRegisteredTimer);
288 m_group->removeAnimation(
this);
299void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
301 if (m_state == newState)
304 if (m_loopCount == 0)
308 m_timer = QQmlAnimationTimer::instance(newState != Stopped);
309 Q_ASSERT(m_timer || newState == Stopped);
311 State oldState = m_state;
312 int oldCurrentTime = m_currentTime;
313 int oldCurrentLoop = m_currentLoop;
314 Direction oldDirection = m_direction;
317 if ((newState == Paused || newState == Running) && oldState == Stopped) {
321 m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
322 0 : (m_loopCount == -1 ? duration() : totalDuration());
325 m_uncontrolledFinishTime = -1;
327 m_currentLoopStartTime = m_totalCurrentTime;
333 bool isTopLevel = !m_group || m_group->isStopped();
334 if (oldState == Running) {
335 if (newState == Paused && m_hasRegisteredTimer)
336 m_timer->ensureTimerUpdate();
339 m_timer->unregisterAnimation(
this);
340 }
else if (newState == Running) {
341 m_timer->registerAnimation(
this, isTopLevel);
345 if (newState == Running && oldState == Stopped && !m_group)
346 fireTopLevelAnimationLoopChanged();
348 RETURN_IF_DELETED(updateState(newState, oldState));
350 if (newState != m_state)
354 RETURN_IF_DELETED(stateChanged(newState, oldState));
355 if (newState != m_state)
364 if (oldState == Stopped) {
368 RETURN_IF_DELETED(m_timer->ensureTimerUpdate());
369 RETURN_IF_DELETED(setCurrentTime(m_totalCurrentTime));
376 int dura = duration();
378 if (dura == -1 || m_loopCount < 0
379 || (oldDirection == Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * m_loopCount))
380 || (oldDirection == Backward && oldCurrentTime == 0)) {
387void QAbstractAnimationJob::setDirection(Direction direction)
389 if (m_direction == direction)
392 if (m_state == Stopped) {
393 if (m_direction == Backward) {
394 m_currentTime = duration();
395 m_currentLoop = m_loopCount - 1;
404 if (m_hasRegisteredTimer)
405 m_timer->ensureTimerUpdate();
407 m_direction = direction;
408 updateDirection(direction);
410 if (m_hasRegisteredTimer)
412 m_timer->updateAnimationTimer();
434void QAbstractAnimationJob::setCurrentTime(
int msecs)
436 msecs = qMax(msecs, 0);
438 int dura = duration();
440 int oldLoop = m_currentLoop;
442 if (dura < 0 && m_direction == Forward) {
444 if (m_uncontrolledFinishTime >= 0 && msecs >= m_uncontrolledFinishTime) {
445 msecs = m_uncontrolledFinishTime;
446 if (m_currentLoop == m_loopCount - 1) {
447 totalDura = m_uncontrolledFinishTime;
450 m_currentLoopStartTime = msecs;
451 m_uncontrolledFinishTime = -1;
454 m_totalCurrentTime = msecs;
455 m_currentTime = msecs - m_currentLoopStartTime;
457 totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount);
459 msecs = qMin(totalDura, msecs);
460 m_totalCurrentTime = msecs;
463 m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
464 if (m_currentLoop == m_loopCount) {
466 m_currentTime = qMax(0, dura);
467 m_currentLoop = qMax(0, m_loopCount - 1);
469 if (m_direction == Forward) {
470 m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
472 m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
473 if (m_currentTime == dura)
480 if (m_currentLoop != oldLoop && !m_group)
481 fireTopLevelAnimationLoopChanged();
483 RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
485 if (m_currentLoop != oldLoop) {
488 RETURN_IF_DELETED(currentLoopChanged());
494 if ((m_direction == Forward && m_totalCurrentTime == totalDura)
495 || (m_direction == Backward && m_totalCurrentTime == 0)) {
496 RETURN_IF_DELETED(stop());
499 if (m_hasCurrentTimeChangeListeners)
500 currentTimeChanged(m_currentTime);
584void QAbstractAnimationJob::finished()
587 for (
const auto &change : changeListeners) {
588 if (change.types & QAbstractAnimationJob::Completion) {
589 RETURN_IF_DELETED(change.listener->animationFinished(
this));
593 if (m_group && (duration() == -1 || loopCount() < 0)) {
595 m_group->uncontrolledAnimationFinished(
this);
599void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
601 for (
const auto &change : changeListeners) {
602 if (change.types & QAbstractAnimationJob::StateChange) {
603 RETURN_IF_DELETED(change.listener->animationStateChanged(
this, newState, oldState));
617void QAbstractAnimationJob::currentTimeChanged(
int currentTime)
619 Q_ASSERT(m_hasCurrentTimeChangeListeners);
621 for (
const auto &change : changeListeners) {
622 if (change.types & QAbstractAnimationJob::CurrentTime) {
623 RETURN_IF_DELETED(change.listener->animationCurrentTimeChanged(
this, currentTime));
628void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
630 if (changes & QAbstractAnimationJob::CurrentTime)
631 m_hasCurrentTimeChangeListeners =
true;
633 changeListeners.push_back(ChangeListener(listener, changes));
636void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
638 m_hasCurrentTimeChangeListeners =
false;
640 const auto it = std::find(changeListeners.begin(), changeListeners.end(), ChangeListener(listener, changes));
641 if (it != changeListeners.end())
642 changeListeners.erase(it);
644 for (
const auto &change: changeListeners) {
645 if (change.types & QAbstractAnimationJob::CurrentTime) {
646 m_hasCurrentTimeChangeListeners =
true;