17class QTimeLinePrivate :
public QObjectPrivate
19 Q_DECLARE_PUBLIC(QTimeLine)
22 QBasicTimer basicTimer;
23 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, QEasingCurve, easingCurve,
24 QEasingCurve::InOutSine)
27 void setDuration(
int duration) { q_func()->setDuration(duration); }
28 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, duration,
29 &QTimeLinePrivate::setDuration, 1000)
32 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, updateInterval, 1000 / 25)
33 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, loopCount, 1)
34 int currentLoopCount = 0;
36 void setCurrentTimeForwardToQ(
int time) { q_func()->setCurrentTime(time); }
37 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, currentTime,
38 &QTimeLinePrivate::setCurrentTimeForwardToQ, 0)
40 void setDirection(QTimeLine::Direction direction) { q_func()->setDirection(direction); }
41 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, QTimeLine::Direction, direction,
42 &QTimeLinePrivate::setDirection, QTimeLine::Forward)
43 QTimeLine::State state = QTimeLine::NotRunning;
44 inline void setState(QTimeLine::State newState)
47 if (newState != state)
48 emit q->stateChanged(state = newState, QTimeLine::QPrivateSignal());
51 void setCurrentTime(
int msecs);
57void QTimeLinePrivate::setCurrentTime(
int msecs)
60 currentTime.removeBindingUnlessInWrapper();
61 const auto previousCurrentTime = currentTime.valueBypassingBindings();
63 const qreal lastValue = q->valueForTime(previousCurrentTime);
64 const int lastFrame = q->frameForTime(previousCurrentTime);
67 const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
68 const int loopCountNow = elapsed / duration;
70 const bool looping = (loopCountNow != currentLoopCount);
72 qDebug() <<
"QTimeLinePrivate::setCurrentTime:" << msecs << duration <<
"with loopCountNow"
73 << loopCountNow <<
"currentLoopCount" << currentLoopCount <<
"looping" << looping;
76 currentLoopCount = loopCountNow;
79 currentTime.setValueBypassingBindings(elapsed % duration);
80 if (direction.value() == QTimeLine::Backward)
81 currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
84 bool finished =
false;
85 if (loopCount && currentLoopCount >= loopCount) {
87 currentTime.setValueBypassingBindings((direction == QTimeLine::Backward) ? 0 : duration);
88 currentLoopCount = loopCount - 1;
91 const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
93 qDebug() <<
"QTimeLinePrivate::setCurrentTime: frameForTime"
94 << currentTime.valueBypassingBindings() << currentFrame;
96 const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
97 if (!qFuzzyCompare(lastValue, currentValue))
98 emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
99 if (lastFrame != currentFrame) {
100 const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
101 if (looping && !finished && transitionframe != currentFrame) {
102#ifdef QTIMELINE_DEBUG
103 qDebug(
"QTimeLinePrivate::setCurrentTime: transitionframe");
105 emit q->frameChanged(transitionframe, QTimeLine::QPrivateSignal());
107#ifdef QTIMELINE_DEBUG
111 reason +=
" not looping";
113 if (!reason.isEmpty())
115 reason +=
" finished";
117 if (transitionframe == currentFrame) {
118 if (!reason.isEmpty())
120 reason +=
" transitionframe is equal to currentFrame: " + QByteArray::number(currentFrame);
122 qDebug(
"QTimeLinePrivate::setCurrentTime: not transitionframe because %s", reason.constData());
125 emit q->frameChanged(currentFrame, QTimeLine::QPrivateSignal());
127 if (finished && state == QTimeLine::Running) {
129 emit q->finished(QTimeLine::QPrivateSignal());
131 if (currentTime.valueBypassingBindings() != previousCurrentTime)
132 currentTime.notify();
339void QTimeLine::setDirection(Direction direction)
342 d->direction.removeBindingUnlessInWrapper();
343 const auto previousDirection = d->direction.valueBypassingBindings();
344 d->direction.setValueBypassingBindings(direction);
345 d->startTime = d->currentTime;
347 if (previousDirection != d->direction.valueBypassingBindings())
348 d->direction.notify();
592qreal QTimeLine::valueForTime(
int msec)
const
594 Q_D(
const QTimeLine);
595 msec = qBound(0, msec, d->duration.value());
597 qreal value = msec / qreal(d->duration.value());
598 return d->easingCurve.value().valueForProgress(value);
614void QTimeLine::start()
617 if (d->basicTimer.isActive()) {
618 qWarning(
"QTimeLine::start: already running");
622 if (d->direction == Backward)
623 curTime = d->duration;
624 d->basicTimer.start(d->updateInterval * 1ms,
this);
625 d->startTime = curTime;
626 d->currentLoopCount = 0;
628 d->setState(Running);
629 d->setCurrentTime(curTime);
675void QTimeLine::setPaused(
bool paused)
678 if (d->state == NotRunning) {
679 qWarning(
"QTimeLine::setPaused: Not running");
682 if (paused && d->state != Paused) {
683 d->startTime = d->currentTime;
684 d->basicTimer.stop();
686 }
else if (!paused && d->state == Paused) {
688 d->basicTimer.start(d->updateInterval * 1ms,
this);
689 d->startTime = d->currentTime;
691 d->setState(Running);
712void QTimeLine::timerEvent(QTimerEvent *event)
715 if (event->id() != d->basicTimer.id()) {
721 if (d->direction == Forward) {
722 d->setCurrentTime(d->startTime + d->timer.elapsed());
724 d->setCurrentTime(d->startTime - d->timer.elapsed());