1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qtimeline.h"
43 
44 #include <private/qobject_p.h>
45 #include <QtCore/qcoreevent.h>
46 #include <QtCore/qmath.h>
47 #include <QtCore/qelapsedtimer.h>
48 
49 QT_BEGIN_NAMESPACE
50 
51 class QTimeLinePrivate : public QObjectPrivate
52 {
53     Q_DECLARE_PUBLIC(QTimeLine)
54 public:
QTimeLinePrivate()55     inline QTimeLinePrivate()
56         : startTime(0), duration(1000), startFrame(0), endFrame(0),
57           updateInterval(1000 / 25),
58           totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
59           direction(QTimeLine::Forward), easingCurve(QEasingCurve::InOutSine),
60           state(QTimeLine::NotRunning)
61     { }
62 
63     int startTime;
64     int duration;
65     int startFrame;
66     int endFrame;
67     int updateInterval;
68     int totalLoopCount;
69     int currentLoopCount;
70 
71     int currentTime;
72     int timerId;
73     QElapsedTimer timer;
74 
75     QTimeLine::Direction direction;
76     QEasingCurve easingCurve;
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);
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());
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);
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);
157     }
158     if (finished && state == QTimeLine::Running) {
159         q->stop();
160         emit q->finished();
161     }
162 }
163 
164 /*!
165     \class QTimeLine
166     \brief The QTimeLine class provides a timeline for controlling animations.
167     \since 4.2
168     \ingroup animation
169 
170     It's most commonly used to animate a GUI control by calling a slot
171     periodically. You can construct a timeline by passing its duration in
172     milliseconds to QTimeLine's constructor. The timeline's duration describes
173     for how long the animation will run. Then you set a suitable frame range
174     by calling setFrameRange(). Finally connect the frameChanged() signal to a
175     suitable slot in the widget you wish to animate (e.g., setValue() in
176     QProgressBar). When you proceed to calling start(), QTimeLine will enter
177     Running state, and start emitting frameChanged() at regular intervals,
178     causing your widget's connected property's value to grow from the lower
179     end to the upper and of your frame range, at a steady rate. You can
180     specify the update interval by calling setUpdateInterval(). When done,
181     QTimeLine enters NotRunning state, and emits finished().
182 
183     Example:
184 
185     \snippet doc/src/snippets/code/src_corelib_tools_qtimeline.cpp 0
186 
187     You can also use QTimeLine with the
188     \l{Graphics View}{Graphics View framework} for
189     animations. The QGraphicsItemAnimation class implements animation
190     of \l{QGraphicsItem}{QGraphicsItems} with a timeline.
191 
192     By default the timeline runs once, from the beginning and towards the end,
193     upon which you must call start() again to restart from the beginning. To
194     make the timeline loop, you can call setLoopCount(), passing the number of
195     times the timeline should run before finishing. The direction can also be
196     changed, causing the timeline to run backward, by calling
197     setDirection(). You can also pause and unpause the timeline while it's
198     running by calling setPaused(). For interactive control, the
199     setCurrentTime() function is provided, which sets the time position of the
200     time line directly. Although most useful in NotRunning state, (e.g.,
201     connected to a valueChanged() signal in a QSlider,) this function can be
202     called at any time.
203 
204     The frame interface is useful for standard widgets, but QTimeLine can be
205     used to control any type of animation. The heart of QTimeLine lies in the
206     valueForTime() function, which generates a \e value between 0 and 1 for a
207     given time. This value is typically used to describe the steps of an
208     animation, where 0 is the first step of an animation, and 1 is the last
209     step. When running, QTimeLine generates values between 0 and 1 by calling
210     valueForTime() and emitting valueChanged(). By default, valueForTime()
211     applies an interpolation algorithm to generate these value. You can choose
212     from a set of predefined timeline algorithms by calling
213     setCurveShape().
214 
215     Note that by default, QTimeLine uses the EaseInOut curve shape,
216     which provides a value that grows slowly, then grows steadily, and
217     finally grows slowly. For a custom timeline, you can reimplement
218     valueForTime(), in which case QTimeLine's curveShape property is ignored.
219 
220     \sa QProgressBar, QProgressDialog, QGraphicsItemAnimation
221 */
222 
223 /*!
224     \enum QTimeLine::State
225 
226     This enum describes the state of the timeline.
227 
228     \value NotRunning The timeline is not running. This is the initial state
229     of QTimeLine, and the state QTimeLine reenters when finished. The current
230     time, frame and value remain unchanged until either setCurrentTime() is
231     called, or the timeline is started by calling start().
232 
233     \value Paused The timeline is paused (i.e., temporarily
234     suspended). Calling setPaused(false) will resume timeline activity.
235 
236     \value Running The timeline is running. While control is in the event
237     loop, QTimeLine will update its current time at regular intervals,
238     emitting valueChanged() and frameChanged() when appropriate.
239 
240     \sa state(), stateChanged()
241 */
242 
243 /*!
244     \enum QTimeLine::Direction
245 
246     This enum describes the direction of the timeline when in \l Running state.
247 
248     \value Forward The current time of the timeline increases with time (i.e.,
249     moves from 0 and towards the end / duration).
250 
251     \value Backward The current time of the timeline decreases with time (i.e.,
252     moves from the end / duration and towards 0).
253 
254     \sa setDirection()
255 */
256 
257 /*!
258     \enum QTimeLine::CurveShape
259 
260     This enum describes the default shape of QTimeLine's value curve. The
261     default, shape is EaseInOutCurve. The curve defines the relation
262     between the value and the timeline.
263 
264     \value EaseInCurve The value starts growing slowly, then increases in speed.
265     \value EaseOutCurve The value starts growing steadily, then ends slowly.
266     \value EaseInOutCurve The value starts growing slowly, then runs steadily, then grows slowly again.
267     \value LinearCurve The value grows linearly (e.g., if the duration is 1000 ms,
268            the value at time 500 ms is 0.5).
269     \value SineCurve The value grows sinusoidally.
270     \value CosineCurve The value grows cosinusoidally.
271 
272     \sa setCurveShape()
273 */
274 
275 /*!
276     \fn QTimeLine::valueChanged(qreal value)
277 
278     QTimeLine emits this signal at regular intervals when in \l Running state,
279     but only if the current value changes. \a value is the current value. \a value is
280     a number between 0.0 and 1.0
281 
282     \sa QTimeLine::setDuration(), QTimeLine::valueForTime(), QTimeLine::updateInterval
283 */
284 
285 /*!
286     \fn QTimeLine::frameChanged(int frame)
287 
288     QTimeLine emits this signal at regular intervals when in \l Running state,
289     but only if the current frame changes. \a frame is the current frame number.
290 
291     \sa QTimeLine::setFrameRange(), QTimeLine::updateInterval
292 */
293 
294 /*!
295     \fn QTimeLine::stateChanged(QTimeLine::State newState)
296 
297     This signal is emitted whenever QTimeLine's state changes. The new state
298     is \a newState.
299 */
300 
301 /*!
302     \fn QTimeLine::finished()
303 
304     This signal is emitted when QTimeLine finishes (i.e., reaches the end of
305     its time line), and does not loop.
306 */
307 
308 /*!
309     Constructs a timeline with a duration of \a duration milliseconds. \a
310     parent is passed to QObject's constructor. The default duration is 1000
311     milliseconds.
312  */
QTimeLine(int duration,QObject * parent)313 QTimeLine::QTimeLine(int duration, QObject *parent)
314     : QObject(*new QTimeLinePrivate, parent)
315 {
316     setDuration(duration);
317 }
318 
319 /*!
320     Destroys the timeline.
321  */
~QTimeLine()322 QTimeLine::~QTimeLine()
323 {
324     Q_D(QTimeLine);
325 
326     if (d->state == Running)
327         stop();
328 }
329 
330 /*!
331     Returns the state of the timeline.
332 
333     \sa start(), setPaused(), stop()
334 */
state() const335 QTimeLine::State QTimeLine::state() const
336 {
337     Q_D(const QTimeLine);
338     return d->state;
339 }
340 
341 /*!
342     \property QTimeLine::loopCount
343     \brief the number of times the timeline should loop before it's finished.
344 
345     A loop count of of 0 means that the timeline will loop forever.
346 
347     By default, this property contains a value of 1.
348 */
loopCount() const349 int QTimeLine::loopCount() const
350 {
351     Q_D(const QTimeLine);
352     return d->totalLoopCount;
353 }
setLoopCount(int count)354 void QTimeLine::setLoopCount(int count)
355 {
356     Q_D(QTimeLine);
357     d->totalLoopCount = count;
358 }
359 
360 /*!
361     \property QTimeLine::direction
362     \brief the direction of the timeline when QTimeLine is in \l Running
363     state.
364 
365     This direction indicates whether the time moves from 0 towards the
366     timeline duration, or from the value of the duration and towards 0 after
367     start() has been called.
368 
369     By default, this property is set to \l Forward.
370 */
direction() const371 QTimeLine::Direction QTimeLine::direction() const
372 {
373     Q_D(const QTimeLine);
374     return d->direction;
375 }
setDirection(Direction direction)376 void QTimeLine::setDirection(Direction direction)
377 {
378     Q_D(QTimeLine);
379     d->direction = direction;
380     d->startTime = d->currentTime;
381     d->timer.start();
382 }
383 
384 /*!
385     \property QTimeLine::duration
386     \brief the total duration of the timeline in milliseconds.
387 
388     By default, this value is 1000 (i.e., 1 second), but you can change this
389     by either passing a duration to QTimeLine's constructor, or by calling
390     setDuration(). The duration must be larger than 0.
391 
392     \note Changing the duration does not cause the current time to be reset
393     to zero or the new duration. You also need to call setCurrentTime() with
394     the desired value.
395 */
duration() const396 int QTimeLine::duration() const
397 {
398     Q_D(const QTimeLine);
399     return d->duration;
400 }
setDuration(int duration)401 void QTimeLine::setDuration(int duration)
402 {
403     Q_D(QTimeLine);
404     if (duration <= 0) {
405         qWarning("QTimeLine::setDuration: cannot set duration <= 0");
406         return;
407     }
408     d->duration = duration;
409 }
410 
411 /*!
412     Returns the start frame, which is the frame corresponding to the start of
413     the timeline (i.e., the frame for which the current value is 0).
414 
415     \sa setStartFrame(), setFrameRange()
416 */
startFrame() const417 int QTimeLine::startFrame() const
418 {
419     Q_D(const QTimeLine);
420     return d->startFrame;
421 }
422 
423 /*!
424     Sets the start frame, which is the frame corresponding to the start of the
425     timeline (i.e., the frame for which the current value is 0), to \a frame.
426 
427     \sa startFrame(), endFrame(), setFrameRange()
428 */
setStartFrame(int frame)429 void QTimeLine::setStartFrame(int frame)
430 {
431     Q_D(QTimeLine);
432     d->startFrame = frame;
433 }
434 
435 /*!
436     Returns the end frame, which is the frame corresponding to the end of the
437     timeline (i.e., the frame for which the current value is 1).
438 
439     \sa setEndFrame(), setFrameRange()
440 */
endFrame() const441 int QTimeLine::endFrame() const
442 {
443     Q_D(const QTimeLine);
444     return d->endFrame;
445 }
446 
447 /*!
448     Sets the end frame, which is the frame corresponding to the end of the
449     timeline (i.e., the frame for which the current value is 1), to \a frame.
450 
451     \sa endFrame(), startFrame(), setFrameRange()
452 */
setEndFrame(int frame)453 void QTimeLine::setEndFrame(int frame)
454 {
455     Q_D(QTimeLine);
456     d->endFrame = frame;
457 }
458 
459 /*!
460     Sets the timeline's frame counter to start at \a startFrame, and end and
461     \a endFrame. For each time value, QTimeLine will find the corresponding
462     frame when you call currentFrame() or frameForTime() by interpolating,
463     using the return value of valueForTime().
464 
465     When in Running state, QTimeLine also emits the frameChanged() signal when
466     the frame changes.
467 
468     \sa startFrame(), endFrame(), start(), currentFrame()
469 */
setFrameRange(int startFrame,int endFrame)470 void QTimeLine::setFrameRange(int startFrame, int endFrame)
471 {
472     Q_D(QTimeLine);
473     d->startFrame = startFrame;
474     d->endFrame = endFrame;
475 }
476 
477 /*!
478     \property QTimeLine::updateInterval
479     \brief the time in milliseconds between each time QTimeLine updates its
480     current time.
481 
482     When updating the current time, QTimeLine will emit valueChanged() if the
483     current value changed, and frameChanged() if the frame changed.
484 
485     By default, the interval is 40 ms, which corresponds to a rate of 25
486     updates per second.
487 */
updateInterval() const488 int QTimeLine::updateInterval() const
489 {
490     Q_D(const QTimeLine);
491     return d->updateInterval;
492 }
setUpdateInterval(int interval)493 void QTimeLine::setUpdateInterval(int interval)
494 {
495     Q_D(QTimeLine);
496     d->updateInterval = interval;
497 }
498 
499 /*!
500     \property QTimeLine::curveShape
501     \brief the shape of the timeline curve.
502 
503     The curve shape describes the relation between the time and value for the
504     base implementation of valueForTime().
505 
506     If you have reimplemented valueForTime(), this value is ignored.
507 
508     By default, this property is set to \l EaseInOutCurve.
509 
510     \sa valueForTime()
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 
setCurveShape(CurveShape shape)533 void QTimeLine::setCurveShape(CurveShape shape)
534 {
535     switch (shape) {
536     default:
537     case EaseInOutCurve:
538         setEasingCurve(QEasingCurve(QEasingCurve::InOutSine));
539         break;
540     case EaseInCurve:
541         setEasingCurve(QEasingCurve(QEasingCurve::InCurve));
542         break;
543     case EaseOutCurve:
544         setEasingCurve(QEasingCurve(QEasingCurve::OutCurve));
545         break;
546     case LinearCurve:
547         setEasingCurve(QEasingCurve(QEasingCurve::Linear));
548         break;
549     case SineCurve:
550         setEasingCurve(QEasingCurve(QEasingCurve::SineCurve));
551         break;
552     case CosineCurve:
553         setEasingCurve(QEasingCurve(QEasingCurve::CosineCurve));
554         break;
555     }
556 }
557 
558 /*!
559     \property QTimeLine::easingCurve
560 
561     \since 4.6
562 
563     Specifies the easing curve that the timeline will use.
564     If both easing curve and curveShape are set, the last set property will
565     override the previous one. (If valueForTime() is reimplemented it will
566     override both)
567 */
568 
easingCurve() const569 QEasingCurve QTimeLine::easingCurve() const
570 {
571     Q_D(const QTimeLine);
572     return d->easingCurve;
573 }
574 
setEasingCurve(const QEasingCurve & curve)575 void QTimeLine::setEasingCurve(const QEasingCurve& curve)
576 {
577     Q_D(QTimeLine);
578     d->easingCurve = curve;
579 }
580 
581 /*!
582     \property QTimeLine::currentTime
583     \brief the current time of the time line.
584 
585     When QTimeLine is in Running state, this value is updated continuously as
586     a function of the duration and direction of the timeline. Otherwise, it is
587     value that was current when stop() was called last, or the value set by
588     setCurrentTime().
589 
590     By default, this property contains a value of 0.
591 */
currentTime() const592 int QTimeLine::currentTime() const
593 {
594     Q_D(const QTimeLine);
595     return d->currentTime;
596 }
setCurrentTime(int msec)597 void QTimeLine::setCurrentTime(int msec)
598 {
599     Q_D(QTimeLine);
600     d->startTime = 0;
601     d->currentLoopCount = 0;
602     d->timer.restart();
603     d->setCurrentTime(msec);
604 }
605 
606 /*!
607     Returns the frame corresponding to the current time.
608 
609     \sa currentTime(), frameForTime(), setFrameRange()
610 */
currentFrame() const611 int QTimeLine::currentFrame() const
612 {
613     Q_D(const QTimeLine);
614     return frameForTime(d->currentTime);
615 }
616 
617 /*!
618     Returns the value corresponding to the current time.
619 
620     \sa valueForTime(), currentFrame()
621 */
currentValue() const622 qreal QTimeLine::currentValue() const
623 {
624     Q_D(const QTimeLine);
625     return valueForTime(d->currentTime);
626 }
627 
628 /*!
629     Returns the frame corresponding to the time \a msec. This value is
630     calculated using a linear interpolation of the start and end frame, based
631     on the value returned by valueForTime().
632 
633     \sa valueForTime(), setFrameRange()
634 */
frameForTime(int msec) const635 int QTimeLine::frameForTime(int msec) const
636 {
637     Q_D(const QTimeLine);
638     if (d->direction == Forward)
639         return d->startFrame + int((d->endFrame - d->startFrame) * valueForTime(msec));
640     return d->startFrame + qCeil((d->endFrame - d->startFrame) * valueForTime(msec));
641 }
642 
643 /*!
644     Returns the timeline value for the time \a msec. The returned value, which
645     varies depending on the curve shape, is always between 0 and 1. If \a msec
646     is 0, the default implementation always returns 0.
647 
648     Reimplement this function to provide a custom curve shape for your
649     timeline.
650 
651     \sa CurveShape, frameForTime()
652 */
valueForTime(int msec) const653 qreal QTimeLine::valueForTime(int msec) const
654 {
655     Q_D(const QTimeLine);
656     msec = qMin(qMax(msec, 0), d->duration);
657 
658     qreal value = msec / qreal(d->duration);
659     return d->easingCurve.valueForProgress(value);
660 }
661 
662 /*!
663     Starts the timeline. QTimeLine will enter Running state, and once it
664     enters the event loop, it will update its current time, frame and value at
665     regular intervals. The default interval is 40 ms (i.e., 25 times per
666     second). You can change the update interval by calling
667     setUpdateInterval().
668 
669     The timeline will start from position 0, or the end if going backward.
670     If you want to resume a stopped timeline without restarting, you can call
671     resume() instead.
672 
673     \sa resume(), updateInterval(), frameChanged(), valueChanged()
674 */
start()675 void QTimeLine::start()
676 {
677     Q_D(QTimeLine);
678     if (d->timerId) {
679         qWarning("QTimeLine::start: already running");
680         return;
681     }
682     int curTime = 0;
683     if (d->direction == Backward)
684         curTime = d->duration;
685     d->timerId = startTimer(d->updateInterval);
686     d->startTime = curTime;
687     d->currentLoopCount = 0;
688     d->timer.start();
689     d->setState(Running);
690     d->setCurrentTime(curTime);
691 }
692 
693 /*!
694     Resumes the timeline from the current time. QTimeLine will reenter Running
695     state, and once it enters the event loop, it will update its current time,
696     frame and value at regular intervals.
697 
698     In contrast to start(), this function does not restart the timeline before
699     it resumes.
700 
701     \sa start(), updateInterval(), frameChanged(), valueChanged()
702 */
resume()703 void QTimeLine::resume()
704 {
705     Q_D(QTimeLine);
706     if (d->timerId) {
707         qWarning("QTimeLine::resume: already running");
708         return;
709     }
710     d->timerId = startTimer(d->updateInterval);
711     d->startTime = d->currentTime;
712     d->timer.start();
713     d->setState(Running);
714 }
715 
716 /*!
717     Stops the timeline, causing QTimeLine to enter NotRunning state.
718 
719     \sa start()
720 */
stop()721 void QTimeLine::stop()
722 {
723     Q_D(QTimeLine);
724     if (d->timerId)
725         killTimer(d->timerId);
726     d->setState(NotRunning);
727     d->timerId = 0;
728 }
729 
730 /*!
731     If \a paused is true, the timeline is paused, causing QTimeLine to enter
732     Paused state. No updates will be signaled until either start() or
733     setPaused(false) is called. If \a paused is false, the timeline is resumed
734     and continues where it left.
735 
736     \sa state(), start()
737 */
setPaused(bool paused)738 void QTimeLine::setPaused(bool paused)
739 {
740     Q_D(QTimeLine);
741     if (d->state == NotRunning) {
742         qWarning("QTimeLine::setPaused: Not running");
743         return;
744     }
745     if (paused && d->state != Paused) {
746         d->startTime = d->currentTime;
747         killTimer(d->timerId);
748         d->timerId = 0;
749         d->setState(Paused);
750     } else if (!paused && d->state == Paused) {
751         // Same as resume()
752         d->timerId = startTimer(d->updateInterval);
753         d->startTime = d->currentTime;
754         d->timer.start();
755         d->setState(Running);
756     }
757 }
758 
759 /*!
760     Toggles the direction of the timeline. If the direction was Forward, it
761     becomes Backward, and vice verca.
762 
763     \sa setDirection()
764 */
toggleDirection()765 void QTimeLine::toggleDirection()
766 {
767     Q_D(QTimeLine);
768     setDirection(d->direction == Forward ? Backward : Forward);
769 }
770 
771 /*!
772     \reimp
773 */
timerEvent(QTimerEvent * event)774 void QTimeLine::timerEvent(QTimerEvent *event)
775 {
776     Q_D(QTimeLine);
777     if (event->timerId() != d->timerId) {
778         event->ignore();
779         return;
780     }
781     event->accept();
782 
783     if (d->direction == Forward) {
784         d->setCurrentTime(d->startTime + d->timer.elapsed());
785     } else {
786         d->setCurrentTime(d->startTime - d->timer.elapsed());
787     }
788 }
789 
790 QT_END_NAMESPACE
791