166void QQmlAnimationTimer::stopTimer()
168 stopTimerPending =
false;
169 bool pendingStart = startAnimationPending && animationsToStart.size() > 0;
170 if (animations.isEmpty() && !pendingStart) {
171 QUnifiedTimer::resumeAnimationTimer(
this);
172 QUnifiedTimer::stopAnimationTimer(
this);
178void QQmlAnimationTimer::registerAnimation(QAbstractAnimationJob *animation,
bool isTopLevel)
180 if (animation->userControlDisabled())
183 registerRunningAnimation(animation);
185 Q_ASSERT(!animation->m_hasRegisteredTimer);
186 animation->m_hasRegisteredTimer =
true;
187 animationsToStart << animation;
188 if (!startAnimationPending) {
189 startAnimationPending =
true;
190 QMetaObject::invokeMethod(
this,
"startAnimations", Qt::QueuedConnection);
195void QQmlAnimationTimer::unregisterAnimation(QAbstractAnimationJob *animation)
197 unregisterRunningAnimation(animation);
199 if (!animation->m_hasRegisteredTimer)
202 int idx = animations.indexOf(animation);
204 animations.removeAt(idx);
206 if (idx <= currentAnimationIdx)
207 --currentAnimationIdx;
209 if (animations.isEmpty() && !stopTimerPending) {
210 stopTimerPending =
true;
211 QMetaObject::invokeMethod(
this,
"stopTimer", Qt::QueuedConnection);
214 animationsToStart.removeOne(animation);
216 animation->m_hasRegisteredTimer =
false;
267QAbstractAnimationJob::QAbstractAnimationJob()
270 , m_direction(QAbstractAnimationJob::Forward)
271 , m_state(QAbstractAnimationJob::Stopped)
272 , m_totalCurrentTime(0)
275 , m_uncontrolledFinishTime(-1)
276 , m_currentLoopStartTime(0)
277 , m_hasRegisteredTimer(
false)
280 , m_disableUserControl(
false)
281 , m_hasCurrentTimeChangeListeners(
false)
282 , m_isRenderThreadJob(
false)
283 , m_isRenderThreadProxy(
false)
288QAbstractAnimationJob::~QAbstractAnimationJob()
291 if (m_state != Stopped) {
292 State oldState = m_state;
294 stateChanged(oldState, m_state);
296 Q_ASSERT(m_state == Stopped);
297 if (oldState == Running) {
299 Q_ASSERT(QQmlAnimationTimer::instance(
false) == m_timer);
300 m_timer->unregisterAnimation(
this);
303 Q_ASSERT(!m_hasRegisteredTimer);
307 m_group->removeAnimation(
this);
318void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState)
320 if (m_state == newState)
323 if (m_loopCount == 0)
327 m_timer = QQmlAnimationTimer::instance(newState != Stopped);
328 Q_ASSERT(m_timer || newState == Stopped);
330 State oldState = m_state;
331 int oldCurrentTime = m_currentTime;
332 int oldCurrentLoop = m_currentLoop;
333 Direction oldDirection = m_direction;
336 if ((newState == Paused || newState == Running) && oldState == Stopped) {
340 m_totalCurrentTime = m_currentTime = (m_direction == Forward) ?
341 0 : (m_loopCount == -1 ? duration() : totalDuration());
344 m_uncontrolledFinishTime = -1;
346 m_currentLoopStartTime = m_totalCurrentTime;
352 bool isTopLevel = !m_group || m_group->isStopped();
353 if (oldState == Running) {
354 if (newState == Paused && m_hasRegisteredTimer)
355 m_timer->ensureTimerUpdate();
358 m_timer->unregisterAnimation(
this);
359 }
else if (newState == Running) {
360 m_timer->registerAnimation(
this, isTopLevel);
364 if (newState == Running && oldState == Stopped && !m_group)
365 fireTopLevelAnimationLoopChanged();
367 RETURN_IF_DELETED(updateState(newState, oldState));
369 if (newState != m_state)
373 RETURN_IF_DELETED(stateChanged(newState, oldState));
374 if (newState != m_state)
383 if (oldState == Stopped) {
387 RETURN_IF_DELETED(m_timer->ensureTimerUpdate());
388 RETURN_IF_DELETED(setCurrentTime(m_totalCurrentTime));
395 int dura = duration();
397 if (dura == -1 || m_loopCount < 0
398 || (oldDirection == Forward
399 && qint64(oldCurrentTime) * (oldCurrentLoop + 1) == qint64(dura) * m_loopCount)
400 || (oldDirection == Backward && oldCurrentTime == 0)) {
407void QAbstractAnimationJob::setDirection(Direction direction)
409 if (m_direction == direction)
412 if (m_state == Stopped) {
413 if (m_direction == Backward) {
414 m_currentTime = duration();
415 m_currentLoop = m_loopCount - 1;
424 if (m_hasRegisteredTimer)
425 m_timer->ensureTimerUpdate();
427 m_direction = direction;
428 updateDirection(direction);
430 if (m_hasRegisteredTimer)
432 m_timer->updateAnimationTimer();
454void QAbstractAnimationJob::setCurrentTime(
int msecs)
456 msecs = qMax(msecs, 0);
458 int dura = duration();
460 int oldLoop = m_currentLoop;
462 if (dura < 0 && m_direction == Forward) {
464 if (m_uncontrolledFinishTime >= 0 && msecs >= m_uncontrolledFinishTime) {
465 msecs = m_uncontrolledFinishTime;
466 if (m_currentLoop == m_loopCount - 1) {
467 totalDura = m_uncontrolledFinishTime;
470 m_currentLoopStartTime = msecs;
471 m_uncontrolledFinishTime = -1;
474 m_totalCurrentTime = msecs;
475 m_currentTime = msecs - m_currentLoopStartTime;
477 totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : mulSaturating(dura, m_loopCount));
479 msecs = qMin(totalDura, msecs);
480 m_totalCurrentTime = msecs;
483 m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
484 if (m_currentLoop == m_loopCount) {
486 m_currentTime = qMax(0, dura);
487 m_currentLoop = qMax(0, m_loopCount - 1);
489 if (m_direction == Forward) {
490 m_currentTime = (dura <= 0) ? msecs : (msecs % dura);
492 m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
493 if (m_currentTime == dura)
500 if (m_currentLoop != oldLoop && !m_group)
501 fireTopLevelAnimationLoopChanged();
503 RETURN_IF_DELETED(updateCurrentTime(m_currentTime));
505 if (m_currentLoop != oldLoop) {
508 RETURN_IF_DELETED(currentLoopChanged());
514 if ((m_direction == Forward && m_totalCurrentTime == totalDura)
515 || (m_direction == Backward && m_totalCurrentTime == 0)) {
516 RETURN_IF_DELETED(stop());
519 if (m_hasCurrentTimeChangeListeners)
520 currentTimeChanged(m_currentTime);
604void QAbstractAnimationJob::finished()
607 for (
const auto &change : changeListeners) {
608 if (change.types & QAbstractAnimationJob::Completion) {
609 RETURN_IF_DELETED(change.listener->animationFinished(
this));
613 if (m_group && (duration() == -1 || loopCount() < 0)) {
615 m_group->uncontrolledAnimationFinished(
this);
619void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState)
621 for (
const auto &change : changeListeners) {
622 if (change.types & QAbstractAnimationJob::StateChange) {
623 RETURN_IF_DELETED(change.listener->animationStateChanged(
this, newState, oldState));
637void QAbstractAnimationJob::currentTimeChanged(
int currentTime)
639 Q_ASSERT(m_hasCurrentTimeChangeListeners);
641 for (
const auto &change : changeListeners) {
642 if (change.types & QAbstractAnimationJob::CurrentTime) {
643 RETURN_IF_DELETED(change.listener->animationCurrentTimeChanged(
this, currentTime));
648void QAbstractAnimationJob::addAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
650 if (changes & QAbstractAnimationJob::CurrentTime)
651 m_hasCurrentTimeChangeListeners =
true;
653 changeListeners.push_back(ChangeListener(listener, changes));
656void QAbstractAnimationJob::removeAnimationChangeListener(QAnimationJobChangeListener *listener, QAbstractAnimationJob::ChangeTypes changes)
658 m_hasCurrentTimeChangeListeners =
false;
660 const auto it = std::find(changeListeners.begin(), changeListeners.end(), ChangeListener(listener, changes));
661 if (it != changeListeners.end())
662 changeListeners.erase(it);
664 for (
const auto &change: changeListeners) {
665 if (change.types & QAbstractAnimationJob::CurrentTime) {
666 m_hasCurrentTimeChangeListeners =
true;