void QAbstractAnimationJob::stateChanged(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) { for (int i = 0; i < changeListeners.count(); ++i) { const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i); if (change.types & QAbstractAnimationJob::StateChange) { RETURN_IF_DELETED(change.listener->animationStateChanged(this, newState, oldState)); } } }
void QAbstractAnimationJob::currentLoopChanged() { for (int i = 0; i < changeListeners.count(); ++i) { const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i); if (change.types & QAbstractAnimationJob::CurrentLoop) { RETURN_IF_DELETED(change.listener->animationCurrentLoopChanged(this)); } } }
void QContinuingAnimationGroupJob::updateCurrentTime(int /*currentTime*/) { Q_ASSERT(firstChild()); for (QAbstractAnimationJob *animation = firstChild(); animation; animation = animation->nextSibling()) { if (animation->state() == state()) { RETURN_IF_DELETED(animation->setCurrentTime(m_currentTime)); } } }
void QAbstractAnimationJob::currentTimeChanged(int currentTime) { Q_ASSERT(m_hasCurrentTimeChangeListeners); for (int i = 0; i < changeListeners.count(); ++i) { const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i); if (change.types & QAbstractAnimationJob::CurrentTime) { RETURN_IF_DELETED(change.listener->animationCurrentTimeChanged(this, currentTime)); } } }
void QSequentialAnimationGroupJob::updateCurrentTime(int currentTime) { if (!m_currentAnimation) return; const QSequentialAnimationGroupJob::AnimationIndex newAnimationIndex = indexForCurrentTime(); // newAnimationIndex.index is the new current animation if (m_previousLoop < m_currentLoop || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && newAnimationIndex.afterCurrent)) { // advancing with forward direction is the same as rewinding with backwards direction RETURN_IF_DELETED(advanceForwards(newAnimationIndex)); } else if (m_previousLoop > m_currentLoop || (m_previousLoop == m_currentLoop && m_currentAnimation != newAnimationIndex.animation && !newAnimationIndex.afterCurrent)) { // rewinding with forward direction is the same as advancing with backwards direction RETURN_IF_DELETED(rewindForwards(newAnimationIndex)); } setCurrentAnimation(newAnimationIndex.animation); const int newCurrentTime = currentTime - newAnimationIndex.timeOffset; if (m_currentAnimation) { RETURN_IF_DELETED(m_currentAnimation->setCurrentTime(newCurrentTime)); if (atEnd()) { //we make sure that we don't exceed the duration here m_currentTime += m_currentAnimation->currentTime() - newCurrentTime; stop(); } } else { //the only case where currentAnimation could be null //is when all animations have been removed Q_ASSERT(!firstChild()); m_currentTime = 0; stop(); } m_previousLoop = m_currentLoop; }
void QSequentialAnimationGroupJob::advanceForwards(const AnimationIndex &newAnimationIndex) { if (m_previousLoop < m_currentLoop) { // we need to fast forward to the end for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->nextSibling()) { setCurrentAnimation(anim, true); RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim))); } // this will make sure the current animation is reset to the beginning if (firstChild() && !firstChild()->nextSibling()) //count == 1 // we need to force activation because setCurrentAnimation will have no effect activateCurrentAnimation(); else setCurrentAnimation(firstChild(), true); } // and now we need to fast forward from the current position to for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->nextSibling()) { //### WRONG, setCurrentAnimation(anim, true); RETURN_IF_DELETED(anim->setCurrentTime(animationActualTotalDuration(anim))); } // setting the new current animation will happen later }
void QAbstractAnimationJob::finished() { //TODO: update this code so it is valid to delete the animation in animationFinished for (int i = 0; i < changeListeners.count(); ++i) { const QAbstractAnimationJob::ChangeListener &change = changeListeners.at(i); if (change.types & QAbstractAnimationJob::Completion) { RETURN_IF_DELETED(change.listener->animationFinished(this)); } } if (m_group && (duration() == -1 || loopCount() < 0)) { //this is an uncontrolled animation, need to notify the group animation we are finished m_group->uncontrolledAnimationFinished(this); } }
void QSequentialAnimationGroupJob::rewindForwards(const AnimationIndex &newAnimationIndex) { if (m_previousLoop > m_currentLoop) { // we need to fast rewind to the beginning for (QAbstractAnimationJob *anim = m_currentAnimation; anim; anim = anim->previousSibling()) { setCurrentAnimation(anim, true); RETURN_IF_DELETED(anim->setCurrentTime(0)); } // this will make sure the current animation is reset to the end if (lastChild() && !lastChild()->previousSibling()) //count == 1 // we need to force activation because setCurrentAnimation will have no effect activateCurrentAnimation(); else { setCurrentAnimation(lastChild(), true); } } // and now we need to fast rewind from the current position to for (QAbstractAnimationJob *anim = m_currentAnimation; anim && anim != newAnimationIndex.animation; anim = anim->previousSibling()) { setCurrentAnimation(anim, true); RETURN_IF_DELETED(anim->setCurrentTime(0)); } // setting the new current animation will happen later }
void QSequentialAnimationGroupJob::activateCurrentAnimation(bool intermediate) { if (!m_currentAnimation || isStopped()) return; m_currentAnimation->stop(); // we ensure the direction is consistent with the group's direction m_currentAnimation->setDirection(m_direction); // reset the finish time of the animation if it is uncontrolled if (m_currentAnimation->totalDuration() == -1) resetUncontrolledAnimationFinishTime(m_currentAnimation); RETURN_IF_DELETED(m_currentAnimation->start()); if (!intermediate && isPaused()) m_currentAnimation->pause(); }
void QAbstractAnimationJob::setCurrentTime(int msecs) { msecs = qMax(msecs, 0); // Calculate new time and loop. int dura = duration(); int totalDura; int oldLoop = m_currentLoop; if (dura < 0 && m_direction == Forward) { totalDura = -1; if (m_uncontrolledFinishTime >= 0 && msecs >= m_uncontrolledFinishTime) { msecs = m_uncontrolledFinishTime; if (m_currentLoop == m_loopCount - 1) { totalDura = m_uncontrolledFinishTime; } else { ++m_currentLoop; m_currentLoopStartTime = msecs; m_uncontrolledFinishTime = -1; } } m_totalCurrentTime = msecs; m_currentTime = msecs - m_currentLoopStartTime; } else { totalDura = dura <= 0 ? dura : ((m_loopCount < 0) ? -1 : dura * m_loopCount); if (totalDura != -1) msecs = qMin(totalDura, msecs); m_totalCurrentTime = msecs; // Update new values. m_currentLoop = ((dura <= 0) ? 0 : (msecs / dura)); if (m_currentLoop == m_loopCount) { //we're at the end m_currentTime = qMax(0, dura); m_currentLoop = qMax(0, m_loopCount - 1); } else { if (m_direction == Forward) { m_currentTime = (dura <= 0) ? msecs : (msecs % dura); } else { m_currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1; if (m_currentTime == dura) --m_currentLoop; } } } if (m_currentLoop != oldLoop && !m_group) //### verify Running as well? fireTopLevelAnimationLoopChanged(); RETURN_IF_DELETED(updateCurrentTime(m_currentTime)); if (m_currentLoop != oldLoop) currentLoopChanged(); // All animations are responsible for stopping the animation when their // own end state is reached; in this case the animation is time driven, // and has reached the end. if ((m_direction == Forward && m_totalCurrentTime == totalDura) || (m_direction == Backward && m_totalCurrentTime == 0)) { RETURN_IF_DELETED(stop()); } if (m_hasCurrentTimeChangeListeners) currentTimeChanged(m_currentTime); }
void QAbstractAnimationJob::setState(QAbstractAnimationJob::State newState) { if (m_state == newState) return; if (m_loopCount == 0) return; State oldState = m_state; int oldCurrentTime = m_currentTime; int oldCurrentLoop = m_currentLoop; Direction oldDirection = m_direction; // check if we should Rewind if ((newState == Paused || newState == Running) && oldState == Stopped) { //here we reset the time if needed //we don't call setCurrentTime because this might change the way the animation //behaves: changing the state or changing the current value m_totalCurrentTime = m_currentTime = (m_direction == Forward) ? 0 : (m_loopCount == -1 ? duration() : totalDuration()); // Reset uncontrolled finish time and currentLoopStartTime for this run. m_uncontrolledFinishTime = -1; if (!m_group) m_currentLoopStartTime = m_totalCurrentTime; } m_state = newState; //(un)registration of the animation must always happen before calls to //virtual function (updateState) to ensure a correct state of the timer bool isTopLevel = !m_group || m_group->isStopped(); if (oldState == Running) { if (newState == Paused && m_hasRegisteredTimer) QQmlAnimationTimer::ensureTimerUpdate(); //the animation, is not running any more QQmlAnimationTimer::unregisterAnimation(this); } else if (newState == Running) { QQmlAnimationTimer::registerAnimation(this, isTopLevel); } //starting an animation qualifies as a top level loop change if (newState == Running && oldState == Stopped && !m_group) fireTopLevelAnimationLoopChanged(); RETURN_IF_DELETED(updateState(newState, oldState)); if (newState != m_state) //this is to be safe if updateState changes the state return; // Notify state change RETURN_IF_DELETED(stateChanged(newState, oldState)); if (newState != m_state) //this is to be safe if updateState changes the state return; switch (m_state) { case Paused: break; case Running: { // this ensures that the value is updated now that the animation is running if (oldState == Stopped) { m_currentLoop = 0; if (isTopLevel) { // currentTime needs to be updated if pauseTimer is active RETURN_IF_DELETED(QQmlAnimationTimer::ensureTimerUpdate()); RETURN_IF_DELETED(setCurrentTime(m_totalCurrentTime)); } } } break; case Stopped: // Leave running state. int dura = duration(); if (dura == -1 || m_loopCount < 0 || (oldDirection == Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * m_loopCount)) || (oldDirection == Backward && oldCurrentTime == 0)) { finished(); } break; } }