18class QTimeLinePrivate :
public QObjectPrivate
20 Q_DECLARE_PUBLIC(QTimeLine)
23 QBasicTimer basicTimer;
24 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, QEasingCurve, easingCurve,
25 QEasingCurve::InOutSine)
28 void setDuration(
int duration) { q_func()->setDuration(duration); }
29 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, duration,
30 &QTimeLinePrivate::setDuration, 1000)
33 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, updateInterval, 1000 / 25)
34 Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, loopCount, 1)
35 int currentLoopCount = 0;
37 void setCurrentTimeForwardToQ(
int time) { q_func()->setCurrentTime(time); }
38 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate,
int, currentTime,
39 &QTimeLinePrivate::setCurrentTimeForwardToQ, 0)
41 void setDirection(QTimeLine::Direction direction) { q_func()->setDirection(direction); }
42 Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, QTimeLine::Direction, direction,
43 &QTimeLinePrivate::setDirection, QTimeLine::Forward)
44 QTimeLine::State state = QTimeLine::NotRunning;
45 inline void setState(QTimeLine::State newState)
48 if (newState != state)
49 emit q->stateChanged(state = newState, QTimeLine::QPrivateSignal());
52 void setCurrentTime(
int msecs);
58void QTimeLinePrivate::setCurrentTime(
int msecs)
61 currentTime.removeBindingUnlessInWrapper();
62 const auto previousCurrentTime = currentTime.valueBypassingBindings();
64 const qreal lastValue = q->valueForTime(previousCurrentTime);
65 const int lastFrame = q->frameForTime(previousCurrentTime);
68 const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
69 const int loopCountNow = elapsed / duration;
71 const bool looping = (loopCountNow != currentLoopCount);
73 qDebug() <<
"QTimeLinePrivate::setCurrentTime:" << msecs << duration <<
"with loopCountNow"
74 << loopCountNow <<
"currentLoopCount" << currentLoopCount <<
"looping" << looping;
77 currentLoopCount = loopCountNow;
80 currentTime.setValueBypassingBindings(elapsed % duration);
81 if (direction.value() == QTimeLine::Backward)
82 currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
85 bool finished =
false;
86 if (loopCount && currentLoopCount >= loopCount) {
88 currentTime.setValueBypassingBindings((direction == QTimeLine::Backward) ? 0 : duration);
89 currentLoopCount = loopCount - 1;
92 const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
94 qDebug() <<
"QTimeLinePrivate::setCurrentTime: frameForTime"
95 << currentTime.valueBypassingBindings() << currentFrame;
97 const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
98 if (!qFuzzyCompare(lastValue, currentValue))
99 emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
100 if (lastFrame != currentFrame) {
101 const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
102 if (looping && !finished && transitionframe != currentFrame) {
103#ifdef QTIMELINE_DEBUG
104 qDebug(
"QTimeLinePrivate::setCurrentTime: transitionframe");
106 emit q->frameChanged(transitionframe, QTimeLine::QPrivateSignal());
108#ifdef QTIMELINE_DEBUG
112 reason +=
" not looping";
114 if (!reason.isEmpty())
116 reason +=
" finished";
118 if (transitionframe == currentFrame) {
119 if (!reason.isEmpty())
121 reason +=
" transitionframe is equal to currentFrame: " + QByteArray::number(currentFrame);
123 qDebug(
"QTimeLinePrivate::setCurrentTime: not transitionframe because %s", reason.constData());
126 emit q->frameChanged(currentFrame, QTimeLine::QPrivateSignal());
128 if (finished && state == QTimeLine::Running) {
130 emit q->finished(QTimeLine::QPrivateSignal());
132 if (currentTime.valueBypassingBindings() != previousCurrentTime)
133 currentTime.notify();
340void QTimeLine::setDirection(Direction direction)
343 d->direction.removeBindingUnlessInWrapper();
344 const auto previousDirection = d->direction.valueBypassingBindings();
345 d->direction.setValueBypassingBindings(direction);
346 d->startTime = d->currentTime;
348 if (previousDirection != d->direction.valueBypassingBindings())
349 d->direction.notify();
593qreal QTimeLine::valueForTime(
int msec)
const
595 Q_D(
const QTimeLine);
596 msec = qBound(0, msec, d->duration.value());
598 qreal value = msec / qreal(d->duration.value());
599 return d->easingCurve.value().valueForProgress(value);
615void QTimeLine::start()
618 if (d->basicTimer.isActive()) {
619 qWarning(
"QTimeLine::start: already running");
623 if (d->direction == Backward)
624 curTime = d->duration;
625 d->basicTimer.start(d->updateInterval * 1ms,
this);
626 d->startTime = curTime;
627 d->currentLoopCount = 0;
629 d->setState(Running);
630 d->setCurrentTime(curTime);
676void QTimeLine::setPaused(
bool paused)
679 if (d->state == NotRunning) {
680 qWarning(
"QTimeLine::setPaused: Not running");
683 if (paused && d->state != Paused) {
684 d->startTime = d->currentTime;
685 d->basicTimer.stop();
687 }
else if (!paused && d->state == Paused) {
689 d->basicTimer.start(d->updateInterval * 1ms,
this);
690 d->startTime = d->currentTime;
692 d->setState(Running);
713void QTimeLine::timerEvent(QTimerEvent *event)
716 if (event->id() != d->basicTimer.id()) {
722 if (d->direction == Forward) {
723 d->setCurrentTime(d->startTime + d->timer.elapsed());
725 d->setCurrentTime(d->startTime - d->timer.elapsed());