1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qtimeline.h"
41 
42 #include <private/qobject_p.h>
43 #include <QtCore/qcoreevent.h>
44 #include <QtCore/qmath.h>
45 #include <QtCore/qelapsedtimer.h>
46 
47 QT_BEGIN_NAMESPACE
48 
49 class QTimeLinePrivate : public QObjectPrivate
50 {
51     Q_DECLARE_PUBLIC(QTimeLine)
52 public:
QTimeLinePrivate()53     inline QTimeLinePrivate()
54         : easingCurve(QEasingCurve::InOutSine),
55           startTime(0), duration(1000), startFrame(0), endFrame(0),
56           updateInterval(1000 / 25),
57           totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
58           direction(QTimeLine::Forward),
59           state(QTimeLine::NotRunning)
60     { }
61 
62     QElapsedTimer timer;
63     QEasingCurve easingCurve;
64 
65     int startTime;
66     int duration;
67     int startFrame;
68     int endFrame;
69     int updateInterval;
70     int totalLoopCount;
71     int currentLoopCount;
72 
73     int currentTime;
74     int timerId;
75 
76     QTimeLine::Direction direction;
77     QTimeLine::State state;
setState(QTimeLine::State newState)78     inline void setState(QTimeLine::State newState)
79     {
80         Q_Q(QTimeLine);
81         if (newState != state)
82             emit q->stateChanged(state = newState, QTimeLine::QPrivateSignal());
83     }
84 
85     void setCurrentTime(int msecs);
86 };
87 
88 /*!
89     \internal
90 */
setCurrentTime(int msecs)91 void QTimeLinePrivate::setCurrentTime(int msecs)
92 {
93     Q_Q(QTimeLine);
94 
95     qreal lastValue = q->currentValue();
96     int lastFrame = q->currentFrame();
97 
98     // Determine if we are looping.
99     int elapsed = (direction == QTimeLine::Backward) ? (-msecs +  duration) : msecs;
100     int loopCount = elapsed / duration;
101 
102     bool looping = (loopCount != currentLoopCount);
103 #ifdef QTIMELINE_DEBUG
104     qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCount" << loopCount
105              << "currentLoopCount" << currentLoopCount
106              << "looping" << looping;
107 #endif
108     if (looping)
109         currentLoopCount = loopCount;
110 
111     // Normalize msecs to be between 0 and duration, inclusive.
112     currentTime = elapsed % duration;
113     if (direction == QTimeLine::Backward)
114         currentTime = duration - currentTime;
115 
116     // Check if we have reached the end of loopcount.
117     bool finished = false;
118     if (totalLoopCount && currentLoopCount >= totalLoopCount) {
119         finished = true;
120         currentTime = (direction == QTimeLine::Backward) ? 0 : duration;
121         currentLoopCount = totalLoopCount - 1;
122     }
123 
124     int currentFrame = q->frameForTime(currentTime);
125 #ifdef QTIMELINE_DEBUG
126     qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime" << currentTime << currentFrame;
127 #endif
128     if (!qFuzzyCompare(lastValue, q->currentValue()))
129         emit q->valueChanged(q->currentValue(), QTimeLine::QPrivateSignal());
130     if (lastFrame != currentFrame) {
131         const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
132         if (looping && !finished && transitionframe != currentFrame) {
133 #ifdef QTIMELINE_DEBUG
134             qDebug("QTimeLinePrivate::setCurrentTime: transitionframe");
135 #endif
136             emit q->frameChanged(transitionframe, QTimeLine::QPrivateSignal());
137         }
138 #ifdef QTIMELINE_DEBUG
139         else {
140             QByteArray reason;
141             if (!looping)
142                 reason += " not looping";
143             if (finished) {
144                 if (!reason.isEmpty())
145                     reason += " and";
146                 reason += " finished";
147             }
148             if (transitionframe == currentFrame) {
149                 if (!reason.isEmpty())
150                     reason += " and";
151                 reason += " transitionframe is equal to currentFrame: " + QByteArray::number(currentFrame);
152             }
153             qDebug("QTimeLinePrivate::setCurrentTime: not transitionframe because %s",  reason.constData());
154         }
155 #endif
156         emit q->frameChanged(currentFrame, QTimeLine::QPrivateSignal());
157     }
158     if (finished && state == QTimeLine::Running) {
159         q->stop();
160         emit q->finished(QTimeLine::QPrivateSignal());
161     }
162 }
163 
164 /*!
165     \class QTimeLine
166     \inmodule QtCore
167     \brief The QTimeLine class provides a timeline for controlling animations.
168     \since 4.2
169     \ingroup animation
170 
171     It's most commonly used to animate a GUI control by calling a slot
172     periodically. You can construct a timeline by passing its duration in
173     milliseconds to QTimeLine's constructor. The timeline's duration describes
174     for how long the animation will run. Then you set a suitable frame range
175     by calling setFrameRange(). Finally connect the frameChanged() signal to a
176     suitable slot in the widget you wish to animate (for example, \l {QProgressBar::}{setValue()}
177     in QProgressBar). When you proceed to calling start(), QTimeLine will enter
178     Running state, and start emitting frameChanged() at regular intervals,
179     causing your widget's connected property's value to grow from the lower
180     end to the upper and of your frame range, at a steady rate. You can
181     specify the update interval by calling setUpdateInterval(). When done,
182     QTimeLine enters NotRunning state, and emits finished().
183 
184     Example:
185 
186     \snippet code/src_corelib_tools_qtimeline.cpp 0
187 
188     By default the timeline runs once, from its beginning to its end,
189     upon which you must call start() again to restart from the beginning. To
190     make the timeline loop, you can call setLoopCount(), passing the number of
191     times the timeline should run before finishing. The direction can also be
192     changed, causing the timeline to run backward, by calling
193     setDirection(). You can also pause and unpause the timeline while it's
194     running by calling setPaused(). For interactive control, the
195     setCurrentTime() function is provided, which sets the time position of the
196     time line directly. Although most useful in NotRunning state (e.g.,
197     connected to a valueChanged() signal in a QSlider), this function can be
198     called at any time.
199 
200     The frame interface is useful for standard widgets, but QTimeLine can be
201     used to control any type of animation. The heart of QTimeLine lies in the
202     valueForTime() function, which generates a \e value between 0 and 1 for a
203     given time. This value is typically used to describe the steps of an
204     animation, where 0 is the first step of an animation, and 1 is the last
205     step. When running, QTimeLine generates values between 0 and 1 by calling
206     valueForTime() and emitting valueChanged(). By default, valueForTime()
207     applies an interpolation algorithm to generate these value. You can choose
208     from a set of predefined timeline algorithms by calling setEasingCurve().
209 
210     Note that, by default, QTimeLine uses QEasingCurve::InOutSine, which
211     provides a value that grows slowly, then grows steadily, and finally grows
212     slowly. For a custom timeline, you can reimplement valueForTime(), in which
213     case QTimeLine's easingCurve property is ignored.
214 
215     \sa QProgressBar, QProgressDialog
216 */
217 
218 /*!
219     \enum QTimeLine::State
220 
221     This enum describes the state of the timeline.
222 
223     \value NotRunning The timeline is not running. This is the initial state
224     of QTimeLine, and the state QTimeLine reenters when finished. The current
225     time, frame and value remain unchanged until either setCurrentTime() is
226     called, or the timeline is started by calling start().
227 
228     \value Paused The timeline is paused (i.e., temporarily
229     suspended). Calling setPaused(false) will resume timeline activity.
230 
231     \value Running The timeline is running. While control is in the event
232     loop, QTimeLine will update its current time at regular intervals,
233     emitting valueChanged() and frameChanged() when appropriate.
234 
235     \sa state(), stateChanged()
236 */
237 
238 /*!
239     \enum QTimeLine::Direction
240 
241     This enum describes the direction of the timeline when in \l Running state.
242 
243     \value Forward The current time of the timeline increases with time (i.e.,
244     moves from 0 and towards the end / duration).
245 
246     \value Backward The current time of the timeline decreases with time (i.e.,
247     moves from the end / duration and towards 0).
248 
249     \sa setDirection()
250 */
251 
252 /*!
253     \enum QTimeLine::CurveShape
254     \obsolete use QEasingCurve instead
255 
256     This enum describes the shape of QTimeLine's value curve. The default shape
257     is EaseInOutCurve. The curve defines the relation between the value and the
258     timeline.
259 
260     \value EaseInCurve Obsolete equivalent of QEasingCurve::InCurve
261     \value EaseOutCurve Obsolete equivalent of QEasingCurve::OutCurve
262     \value EaseInOutCurve Obsolete equivalent of QEasingCurve::InOutSine
263     \value LinearCurve Obsolete equivalent of QEasingCurve::Linear
264     \value SineCurve Obsolete equivalent of QEasingCurve::SineCurve
265     \value CosineCurve Obsolete equivalent of QEasingCurve::CosineCurve
266 
267     \sa curveShape, setCurveShape(), easingCurve, QEasingCurve
268 */
269 
270 /*!
271     \fn void QTimeLine::valueChanged(qreal value)
272 
273     QTimeLine emits this signal at regular intervals when in \l Running state,
274     but only if the current value changes. \a value is the current value. \a value is
275     a number between 0.0 and 1.0
276 
277     \sa QTimeLine::setDuration(), QTimeLine::valueForTime(), QTimeLine::updateInterval
278 */
279 
280 /*!
281     \fn void QTimeLine::frameChanged(int frame)
282 
283     QTimeLine emits this signal at regular intervals when in \l Running state,
284     but only if the current frame changes. \a frame is the current frame number.
285 
286     \sa QTimeLine::setFrameRange(), QTimeLine::updateInterval
287 */
288 
289 /*!
290     \fn void QTimeLine::stateChanged(QTimeLine::State newState)
291 
292     This signal is emitted whenever QTimeLine's state changes. The new state
293     is \a newState.
294 */
295 
296 /*!
297     \fn void QTimeLine::finished()
298 
299     This signal is emitted when QTimeLine finishes (i.e., reaches the end of
300     its time line), and does not loop.
301 */
302 
303 /*!
304     Constructs a timeline with a duration of \a duration milliseconds. \a
305     parent is passed to QObject's constructor. The default duration is 1000
306     milliseconds.
307  */
QTimeLine(int duration,QObject * parent)308 QTimeLine::QTimeLine(int duration, QObject *parent)
309     : QObject(*new QTimeLinePrivate, parent)
310 {
311     setDuration(duration);
312 }
313 
314 /*!
315     Destroys the timeline.
316  */
~QTimeLine()317 QTimeLine::~QTimeLine()
318 {
319     Q_D(QTimeLine);
320 
321     if (d->state == Running)
322         stop();
323 }
324 
325 /*!
326     Returns the state of the timeline.
327 
328     \sa start(), setPaused(), stop()
329 */
state() const330 QTimeLine::State QTimeLine::state() const
331 {
332     Q_D(const QTimeLine);
333     return d->state;
334 }
335 
336 /*!
337     \property QTimeLine::loopCount
338     \brief the number of times the timeline should loop before it's finished.
339 
340     A loop count of of 0 means that the timeline will loop forever.
341 
342     By default, this property contains a value of 1.
343 */
loopCount() const344 int QTimeLine::loopCount() const
345 {
346     Q_D(const QTimeLine);
347     return d->totalLoopCount;
348 }
setLoopCount(int count)349 void QTimeLine::setLoopCount(int count)
350 {
351     Q_D(QTimeLine);
352     d->totalLoopCount = count;
353 }
354 
355 /*!
356     \property QTimeLine::direction
357     \brief the direction of the timeline when QTimeLine is in \l Running
358     state.
359 
360     This direction indicates whether the time moves from 0 towards the
361     timeline duration, or from the value of the duration and towards 0 after
362     start() has been called.
363 
364     By default, this property is set to \l Forward.
365 */
direction() const366 QTimeLine::Direction QTimeLine::direction() const
367 {
368     Q_D(const QTimeLine);
369     return d->direction;
370 }
setDirection(Direction direction)371 void QTimeLine::setDirection(Direction direction)
372 {
373     Q_D(QTimeLine);
374     d->direction = direction;
375     d->startTime = d->currentTime;
376     d->timer.start();
377 }
378 
379 /*!
380     \property QTimeLine::duration
381     \brief the total duration of the timeline in milliseconds.
382 
383     By default, this value is 1000 (i.e., 1 second), but you can change this
384     by either passing a duration to QTimeLine's constructor, or by calling
385     setDuration(). The duration must be larger than 0.
386 
387     \note Changing the duration does not cause the current time to be reset
388     to zero or the new duration. You also need to call setCurrentTime() with
389     the desired value.
390 */
duration() const391 int QTimeLine::duration() const
392 {
393     Q_D(const QTimeLine);
394     return d->duration;
395 }
setDuration(int duration)396 void QTimeLine::setDuration(int duration)
397 {
398     Q_D(QTimeLine);
399     if (duration <= 0) {
400         qWarning("QTimeLine::setDuration: cannot set duration <= 0");
401         return;
402     }
403     d->duration = duration;
404 }
405 
406 /*!
407     Returns the start frame, which is the frame corresponding to the start of
408     the timeline (i.e., the frame for which the current value is 0).
409 
410     \sa setStartFrame(), setFrameRange()
411 */
startFrame() const412 int QTimeLine::startFrame() const
413 {
414     Q_D(const QTimeLine);
415     return d->startFrame;
416 }
417 
418 /*!
419     Sets the start frame, which is the frame corresponding to the start of the
420     timeline (i.e., the frame for which the current value is 0), to \a frame.
421 
422     \sa startFrame(), endFrame(), setFrameRange()
423 */
setStartFrame(int frame)424 void QTimeLine::setStartFrame(int frame)
425 {
426     Q_D(QTimeLine);
427     d->startFrame = frame;
428 }
429 
430 /*!
431     Returns the end frame, which is the frame corresponding to the end of the
432     timeline (i.e., the frame for which the current value is 1).
433 
434     \sa setEndFrame(), setFrameRange()
435 */
endFrame() const436 int QTimeLine::endFrame() const
437 {
438     Q_D(const QTimeLine);
439     return d->endFrame;
440 }
441 
442 /*!
443     Sets the end frame, which is the frame corresponding to the end of the
444     timeline (i.e., the frame for which the current value is 1), to \a frame.
445 
446     \sa endFrame(), startFrame(), setFrameRange()
447 */
setEndFrame(int frame)448 void QTimeLine::setEndFrame(int frame)
449 {
450     Q_D(QTimeLine);
451     d->endFrame = frame;
452 }
453 
454 /*!
455     Sets the timeline's frame counter to start at \a startFrame, and end and
456     \a endFrame. For each time value, QTimeLine will find the corresponding
457     frame when you call currentFrame() or frameForTime() by interpolating,
458     using the return value of valueForTime().
459 
460     When in Running state, QTimeLine also emits the frameChanged() signal when
461     the frame changes.
462 
463     \sa startFrame(), endFrame(), start(), currentFrame()
464 */
setFrameRange(int startFrame,int endFrame)465 void QTimeLine::setFrameRange(int startFrame, int endFrame)
466 {
467     Q_D(QTimeLine);
468     d->startFrame = startFrame;
469     d->endFrame = endFrame;
470 }
471 
472 /*!
473     \property QTimeLine::updateInterval
474     \brief the time in milliseconds between each time QTimeLine updates its
475     current time.
476 
477     When updating the current time, QTimeLine will emit valueChanged() if the
478     current value changed, and frameChanged() if the frame changed.
479 
480     By default, the interval is 40 ms, which corresponds to a rate of 25
481     updates per second.
482 */
updateInterval() const483 int QTimeLine::updateInterval() const
484 {
485     Q_D(const QTimeLine);
486     return d->updateInterval;
487 }
setUpdateInterval(int interval)488 void QTimeLine::setUpdateInterval(int interval)
489 {
490     Q_D(QTimeLine);
491     d->updateInterval = interval;
492 }
493 
494 #if QT_DEPRECATED_SINCE(5, 15)
495 /*!
496     \property QTimeLine::curveShape
497     \brief the shape of the timeline curve.
498 
499     The curve shape describes the relation between the time and value for the
500     base implementation of valueForTime().
501 
502     This property is an indirect way to update the easingCurve property; if you
503     set both, the one set more recently overrides the other. (If valueForTime()
504     is reimplemented it will override both.)
505 
506     By default, this property is set to \l EaseInOutCurve.
507 
508     \obsolete Access \c easingCurve instead.
509 
510     \sa valueForTime(), easingCurve
511 */
curveShape() const512 QTimeLine::CurveShape QTimeLine::curveShape() const
513 {
514     Q_D(const QTimeLine);
515     switch (d->easingCurve.type()) {
516     default:
517     case QEasingCurve::InOutSine:
518         return EaseInOutCurve;
519     case QEasingCurve::InCurve:
520         return EaseInCurve;
521     case QEasingCurve::OutCurve:
522         return EaseOutCurve;
523     case QEasingCurve::Linear:
524         return LinearCurve;
525     case QEasingCurve::SineCurve:
526         return SineCurve;
527     case QEasingCurve::CosineCurve:
528         return CosineCurve;
529     }
530     return EaseInOutCurve;
531 }
532 
convert(QTimeLine::CurveShape shape)533 static QEasingCurve::Type convert(QTimeLine::CurveShape shape)
534 {
535     switch (shape) {
536 #define CASE(x, y) case QTimeLine::x: return QEasingCurve::y
537     CASE(EaseInOutCurve, InOutSine);
538     CASE(EaseInCurve,    InCurve);
539     CASE(EaseOutCurve,   OutCurve);
540     CASE(LinearCurve,    Linear);
541     CASE(SineCurve,      SineCurve);
542     CASE(CosineCurve,    CosineCurve);
543 #undef CASE
544     }
545     Q_UNREACHABLE();
546 }
547 
setCurveShape(CurveShape shape)548 void QTimeLine::setCurveShape(CurveShape shape)
549 {
550     setEasingCurve(convert(shape));
551 }
552 #endif // 5.15 deprecation
553 
554 /*!
555     \property QTimeLine::easingCurve
556 
557     \since 4.6
558 
559     Specifies the easing curve that the timeline will use.
560     If valueForTime() is reimplemented, this value is ignored.
561     If both easingCurve and curveShape are set, the last property set will
562     override the previous one.
563 
564     \sa valueForTime()
565 */
566 
easingCurve() const567 QEasingCurve QTimeLine::easingCurve() const
568 {
569     Q_D(const QTimeLine);
570     return d->easingCurve;
571 }
572 
setEasingCurve(const QEasingCurve & curve)573 void QTimeLine::setEasingCurve(const QEasingCurve& curve)
574 {
575     Q_D(QTimeLine);
576     d->easingCurve = curve;
577 }
578 
579 /*!
580     \property QTimeLine::currentTime
581     \brief the current time of the time line.
582 
583     When QTimeLine is in Running state, this value is updated continuously as
584     a function of the duration and direction of the timeline. Otherwise, it is
585     value that was current when stop() was called last, or the value set by
586     setCurrentTime().
587 
588     By default, this property contains a value of 0.
589 */
currentTime() const590 int QTimeLine::currentTime() const
591 {
592     Q_D(const QTimeLine);
593     return d->currentTime;
594 }
setCurrentTime(int msec)595 void QTimeLine::setCurrentTime(int msec)
596 {
597     Q_D(QTimeLine);
598     d->startTime = 0;
599     d->currentLoopCount = 0;
600     d->timer.restart();
601     d->setCurrentTime(msec);
602 }
603 
604 /*!
605     Returns the frame corresponding to the current time.
606 
607     \sa currentTime(), frameForTime(), setFrameRange()
608 */
currentFrame() const609 int QTimeLine::currentFrame() const
610 {
611     Q_D(const QTimeLine);
612     return frameForTime(d->currentTime);
613 }
614 
615 /*!
616     Returns the value corresponding to the current time.
617 
618     \sa valueForTime(), currentFrame()
619 */
currentValue() const620 qreal QTimeLine::currentValue() const
621 {
622     Q_D(const QTimeLine);
623     return valueForTime(d->currentTime);
624 }
625 
626 /*!
627     Returns the frame corresponding to the time \a msec. This value is
628     calculated using a linear interpolation of the start and end frame, based
629     on the value returned by valueForTime().
630 
631     \sa valueForTime(), setFrameRange()
632 */
frameForTime(int msec) const633 int QTimeLine::frameForTime(int msec) const
634 {
635     Q_D(const QTimeLine);
636     if (d->direction == Forward)
637         return d->startFrame + int((d->endFrame - d->startFrame) * valueForTime(msec));
638     return d->startFrame + qCeil((d->endFrame - d->startFrame) * valueForTime(msec));
639 }
640 
641 /*!
642     Returns the timeline value for the time \a msec. The returned value, which
643     varies depending on the curve shape, is always between 0 and 1. If \a msec
644     is 0, the default implementation always returns 0.
645 
646     Reimplement this function to provide a custom curve shape for your
647     timeline.
648 
649     \sa CurveShape, frameForTime()
650 */
valueForTime(int msec) const651 qreal QTimeLine::valueForTime(int msec) const
652 {
653     Q_D(const QTimeLine);
654     msec = qMin(qMax(msec, 0), d->duration);
655 
656     qreal value = msec / qreal(d->duration);
657     return d->easingCurve.valueForProgress(value);
658 }
659 
660 /*!
661     Starts the timeline. QTimeLine will enter Running state, and once it
662     enters the event loop, it will update its current time, frame and value at
663     regular intervals. The default interval is 40 ms (i.e., 25 times per
664     second). You can change the update interval by calling
665     setUpdateInterval().
666 
667     The timeline will start from position 0, or the end if going backward.
668     If you want to resume a stopped timeline without restarting, you can call
669     resume() instead.
670 
671     \sa resume(), updateInterval(), frameChanged(), valueChanged()
672 */
start()673 void QTimeLine::start()
674 {
675     Q_D(QTimeLine);
676     if (d->timerId) {
677         qWarning("QTimeLine::start: already running");
678         return;
679     }
680     int curTime = 0;
681     if (d->direction == Backward)
682         curTime = d->duration;
683     d->timerId = startTimer(d->updateInterval);
684     d->startTime = curTime;
685     d->currentLoopCount = 0;
686     d->timer.start();
687     d->setState(Running);
688     d->setCurrentTime(curTime);
689 }
690 
691 /*!
692     Resumes the timeline from the current time. QTimeLine will reenter Running
693     state, and once it enters the event loop, it will update its current time,
694     frame and value at regular intervals.
695 
696     In contrast to start(), this function does not restart the timeline before
697     it resumes.
698 
699     \sa start(), updateInterval(), frameChanged(), valueChanged()
700 */
resume()701 void QTimeLine::resume()
702 {
703     Q_D(QTimeLine);
704     if (d->timerId) {
705         qWarning("QTimeLine::resume: already running");
706         return;
707     }
708     d->timerId = startTimer(d->updateInterval);
709     d->startTime = d->currentTime;
710     d->timer.start();
711     d->setState(Running);
712 }
713 
714 /*!
715     Stops the timeline, causing QTimeLine to enter NotRunning state.
716 
717     \sa start()
718 */
stop()719 void QTimeLine::stop()
720 {
721     Q_D(QTimeLine);
722     if (d->timerId)
723         killTimer(d->timerId);
724     d->setState(NotRunning);
725     d->timerId = 0;
726 }
727 
728 /*!
729     If \a paused is true, the timeline is paused, causing QTimeLine to enter
730     Paused state. No updates will be signaled until either start() or
731     setPaused(false) is called. If \a paused is false, the timeline is resumed
732     and continues where it left.
733 
734     \sa state(), start()
735 */
setPaused(bool paused)736 void QTimeLine::setPaused(bool paused)
737 {
738     Q_D(QTimeLine);
739     if (d->state == NotRunning) {
740         qWarning("QTimeLine::setPaused: Not running");
741         return;
742     }
743     if (paused && d->state != Paused) {
744         d->startTime = d->currentTime;
745         killTimer(d->timerId);
746         d->timerId = 0;
747         d->setState(Paused);
748     } else if (!paused && d->state == Paused) {
749         // Same as resume()
750         d->timerId = startTimer(d->updateInterval);
751         d->startTime = d->currentTime;
752         d->timer.start();
753         d->setState(Running);
754     }
755 }
756 
757 /*!
758     Toggles the direction of the timeline. If the direction was Forward, it
759     becomes Backward, and vice verca.
760 
761     \sa setDirection()
762 */
toggleDirection()763 void QTimeLine::toggleDirection()
764 {
765     Q_D(QTimeLine);
766     setDirection(d->direction == Forward ? Backward : Forward);
767 }
768 
769 /*!
770     \reimp
771 */
timerEvent(QTimerEvent * event)772 void QTimeLine::timerEvent(QTimerEvent *event)
773 {
774     Q_D(QTimeLine);
775     if (event->timerId() != d->timerId) {
776         event->ignore();
777         return;
778     }
779     event->accept();
780 
781     if (d->direction == Forward) {
782         d->setCurrentTime(d->startTime + d->timer.elapsed());
783     } else {
784         d->setCurrentTime(d->startTime - d->timer.elapsed());
785     }
786 }
787 
788 QT_END_NAMESPACE
789 
790 #include "moc_qtimeline.cpp"
791