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: |
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; |
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 | */ |
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 | \fn void QTimeLine::valueChanged(qreal value) |
254 | |
255 | QTimeLine emits this signal at regular intervals when in \l Running state, |
256 | but only if the current value changes. \a value is the current value. \a value is |
257 | a number between 0.0 and 1.0 |
258 | |
259 | \sa QTimeLine::setDuration(), QTimeLine::valueForTime(), QTimeLine::updateInterval |
260 | */ |
261 | |
262 | /*! |
263 | \fn void QTimeLine::frameChanged(int frame) |
264 | |
265 | QTimeLine emits this signal at regular intervals when in \l Running state, |
266 | but only if the current frame changes. \a frame is the current frame number. |
267 | |
268 | \sa QTimeLine::setFrameRange(), QTimeLine::updateInterval |
269 | */ |
270 | |
271 | /*! |
272 | \fn void QTimeLine::stateChanged(QTimeLine::State newState) |
273 | |
274 | This signal is emitted whenever QTimeLine's state changes. The new state |
275 | is \a newState. |
276 | */ |
277 | |
278 | /*! |
279 | \fn void QTimeLine::finished() |
280 | |
281 | This signal is emitted when QTimeLine finishes (i.e., reaches the end of |
282 | its time line), and does not loop. |
283 | */ |
284 | |
285 | /*! |
286 | Constructs a timeline with a duration of \a duration milliseconds. \a |
287 | parent is passed to QObject's constructor. The default duration is 1000 |
288 | milliseconds. |
289 | */ |
290 | QTimeLine::QTimeLine(int duration, QObject *parent) |
291 | : QObject(*new QTimeLinePrivate, parent) |
292 | { |
293 | setDuration(duration); |
294 | } |
295 | |
296 | /*! |
297 | Destroys the timeline. |
298 | */ |
299 | QTimeLine::~QTimeLine() |
300 | { |
301 | Q_D(QTimeLine); |
302 | |
303 | if (d->state == Running) |
304 | stop(); |
305 | } |
306 | |
307 | /*! |
308 | Returns the state of the timeline. |
309 | |
310 | \sa start(), setPaused(), stop() |
311 | */ |
312 | QTimeLine::State QTimeLine::state() const |
313 | { |
314 | Q_D(const QTimeLine); |
315 | return d->state; |
316 | } |
317 | |
318 | /*! |
319 | \property QTimeLine::loopCount |
320 | \brief the number of times the timeline should loop before it's finished. |
321 | |
322 | A loop count of of 0 means that the timeline will loop forever. |
323 | |
324 | By default, this property contains a value of 1. |
325 | */ |
326 | int QTimeLine::loopCount() const |
327 | { |
328 | Q_D(const QTimeLine); |
329 | return d->totalLoopCount; |
330 | } |
331 | void QTimeLine::setLoopCount(int count) |
332 | { |
333 | Q_D(QTimeLine); |
334 | d->totalLoopCount = count; |
335 | } |
336 | |
337 | /*! |
338 | \property QTimeLine::direction |
339 | \brief the direction of the timeline when QTimeLine is in \l Running |
340 | state. |
341 | |
342 | This direction indicates whether the time moves from 0 towards the |
343 | timeline duration, or from the value of the duration and towards 0 after |
344 | start() has been called. |
345 | |
346 | By default, this property is set to \l Forward. |
347 | */ |
348 | QTimeLine::Direction QTimeLine::direction() const |
349 | { |
350 | Q_D(const QTimeLine); |
351 | return d->direction; |
352 | } |
353 | void QTimeLine::setDirection(Direction direction) |
354 | { |
355 | Q_D(QTimeLine); |
356 | d->direction = direction; |
357 | d->startTime = d->currentTime; |
358 | d->timer.start(); |
359 | } |
360 | |
361 | /*! |
362 | \property QTimeLine::duration |
363 | \brief the total duration of the timeline in milliseconds. |
364 | |
365 | By default, this value is 1000 (i.e., 1 second), but you can change this |
366 | by either passing a duration to QTimeLine's constructor, or by calling |
367 | setDuration(). The duration must be larger than 0. |
368 | |
369 | \note Changing the duration does not cause the current time to be reset |
370 | to zero or the new duration. You also need to call setCurrentTime() with |
371 | the desired value. |
372 | */ |
373 | int QTimeLine::duration() const |
374 | { |
375 | Q_D(const QTimeLine); |
376 | return d->duration; |
377 | } |
378 | void QTimeLine::setDuration(int duration) |
379 | { |
380 | Q_D(QTimeLine); |
381 | if (duration <= 0) { |
382 | qWarning("QTimeLine::setDuration: cannot set duration <= 0" ); |
383 | return; |
384 | } |
385 | d->duration = duration; |
386 | } |
387 | |
388 | /*! |
389 | Returns the start frame, which is the frame corresponding to the start of |
390 | the timeline (i.e., the frame for which the current value is 0). |
391 | |
392 | \sa setStartFrame(), setFrameRange() |
393 | */ |
394 | int QTimeLine::startFrame() const |
395 | { |
396 | Q_D(const QTimeLine); |
397 | return d->startFrame; |
398 | } |
399 | |
400 | /*! |
401 | Sets the start frame, which is the frame corresponding to the start of the |
402 | timeline (i.e., the frame for which the current value is 0), to \a frame. |
403 | |
404 | \sa startFrame(), endFrame(), setFrameRange() |
405 | */ |
406 | void QTimeLine::setStartFrame(int frame) |
407 | { |
408 | Q_D(QTimeLine); |
409 | d->startFrame = frame; |
410 | } |
411 | |
412 | /*! |
413 | Returns the end frame, which is the frame corresponding to the end of the |
414 | timeline (i.e., the frame for which the current value is 1). |
415 | |
416 | \sa setEndFrame(), setFrameRange() |
417 | */ |
418 | int QTimeLine::endFrame() const |
419 | { |
420 | Q_D(const QTimeLine); |
421 | return d->endFrame; |
422 | } |
423 | |
424 | /*! |
425 | Sets the end frame, which is the frame corresponding to the end of the |
426 | timeline (i.e., the frame for which the current value is 1), to \a frame. |
427 | |
428 | \sa endFrame(), startFrame(), setFrameRange() |
429 | */ |
430 | void QTimeLine::setEndFrame(int frame) |
431 | { |
432 | Q_D(QTimeLine); |
433 | d->endFrame = frame; |
434 | } |
435 | |
436 | /*! |
437 | Sets the timeline's frame counter to start at \a startFrame, and end and |
438 | \a endFrame. For each time value, QTimeLine will find the corresponding |
439 | frame when you call currentFrame() or frameForTime() by interpolating, |
440 | using the return value of valueForTime(). |
441 | |
442 | When in Running state, QTimeLine also emits the frameChanged() signal when |
443 | the frame changes. |
444 | |
445 | \sa startFrame(), endFrame(), start(), currentFrame() |
446 | */ |
447 | void QTimeLine::setFrameRange(int startFrame, int endFrame) |
448 | { |
449 | Q_D(QTimeLine); |
450 | d->startFrame = startFrame; |
451 | d->endFrame = endFrame; |
452 | } |
453 | |
454 | /*! |
455 | \property QTimeLine::updateInterval |
456 | \brief the time in milliseconds between each time QTimeLine updates its |
457 | current time. |
458 | |
459 | When updating the current time, QTimeLine will emit valueChanged() if the |
460 | current value changed, and frameChanged() if the frame changed. |
461 | |
462 | By default, the interval is 40 ms, which corresponds to a rate of 25 |
463 | updates per second. |
464 | */ |
465 | int QTimeLine::updateInterval() const |
466 | { |
467 | Q_D(const QTimeLine); |
468 | return d->updateInterval; |
469 | } |
470 | void QTimeLine::setUpdateInterval(int interval) |
471 | { |
472 | Q_D(QTimeLine); |
473 | d->updateInterval = interval; |
474 | } |
475 | |
476 | /*! |
477 | \property QTimeLine::easingCurve |
478 | |
479 | \since 4.6 |
480 | |
481 | Specifies the easing curve that the timeline will use. |
482 | If valueForTime() is reimplemented, this value is ignored. |
483 | |
484 | \sa valueForTime() |
485 | */ |
486 | |
487 | QEasingCurve QTimeLine::easingCurve() const |
488 | { |
489 | Q_D(const QTimeLine); |
490 | return d->easingCurve; |
491 | } |
492 | |
493 | void QTimeLine::setEasingCurve(const QEasingCurve &curve) |
494 | { |
495 | Q_D(QTimeLine); |
496 | d->easingCurve = curve; |
497 | } |
498 | |
499 | /*! |
500 | \property QTimeLine::currentTime |
501 | \brief the current time of the time line. |
502 | |
503 | When QTimeLine is in Running state, this value is updated continuously as |
504 | a function of the duration and direction of the timeline. Otherwise, it is |
505 | value that was current when stop() was called last, or the value set by |
506 | setCurrentTime(). |
507 | |
508 | By default, this property contains a value of 0. |
509 | */ |
510 | int QTimeLine::currentTime() const |
511 | { |
512 | Q_D(const QTimeLine); |
513 | return d->currentTime; |
514 | } |
515 | void QTimeLine::setCurrentTime(int msec) |
516 | { |
517 | Q_D(QTimeLine); |
518 | d->startTime = 0; |
519 | d->currentLoopCount = 0; |
520 | d->timer.restart(); |
521 | d->setCurrentTime(msec); |
522 | } |
523 | |
524 | /*! |
525 | Returns the frame corresponding to the current time. |
526 | |
527 | \sa currentTime(), frameForTime(), setFrameRange() |
528 | */ |
529 | int QTimeLine::currentFrame() const |
530 | { |
531 | Q_D(const QTimeLine); |
532 | return frameForTime(d->currentTime); |
533 | } |
534 | |
535 | /*! |
536 | Returns the value corresponding to the current time. |
537 | |
538 | \sa valueForTime(), currentFrame() |
539 | */ |
540 | qreal QTimeLine::currentValue() const |
541 | { |
542 | Q_D(const QTimeLine); |
543 | return valueForTime(d->currentTime); |
544 | } |
545 | |
546 | /*! |
547 | Returns the frame corresponding to the time \a msec. This value is |
548 | calculated using a linear interpolation of the start and end frame, based |
549 | on the value returned by valueForTime(). |
550 | |
551 | \sa valueForTime(), setFrameRange() |
552 | */ |
553 | int QTimeLine::frameForTime(int msec) const |
554 | { |
555 | Q_D(const QTimeLine); |
556 | if (d->direction == Forward) |
557 | return d->startFrame + int((d->endFrame - d->startFrame) * valueForTime(msec)); |
558 | return d->startFrame + qCeil((d->endFrame - d->startFrame) * valueForTime(msec)); |
559 | } |
560 | |
561 | /*! |
562 | Returns the timeline value for the time \a msec. The returned value, which |
563 | varies depending on the curve shape, is always between 0 and 1. If \a msec |
564 | is 0, the default implementation always returns 0. |
565 | |
566 | Reimplement this function to provide a custom curve shape for your |
567 | timeline. |
568 | |
569 | \sa easingCurve, frameForTime() |
570 | */ |
571 | qreal QTimeLine::valueForTime(int msec) const |
572 | { |
573 | Q_D(const QTimeLine); |
574 | msec = qMin(qMax(msec, 0), d->duration); |
575 | |
576 | qreal value = msec / qreal(d->duration); |
577 | return d->easingCurve.valueForProgress(value); |
578 | } |
579 | |
580 | /*! |
581 | Starts the timeline. QTimeLine will enter Running state, and once it |
582 | enters the event loop, it will update its current time, frame and value at |
583 | regular intervals. The default interval is 40 ms (i.e., 25 times per |
584 | second). You can change the update interval by calling |
585 | setUpdateInterval(). |
586 | |
587 | The timeline will start from position 0, or the end if going backward. |
588 | If you want to resume a stopped timeline without restarting, you can call |
589 | resume() instead. |
590 | |
591 | \sa resume(), updateInterval(), frameChanged(), valueChanged() |
592 | */ |
593 | void QTimeLine::start() |
594 | { |
595 | Q_D(QTimeLine); |
596 | if (d->timerId) { |
597 | qWarning("QTimeLine::start: already running" ); |
598 | return; |
599 | } |
600 | int curTime = 0; |
601 | if (d->direction == Backward) |
602 | curTime = d->duration; |
603 | d->timerId = startTimer(d->updateInterval); |
604 | d->startTime = curTime; |
605 | d->currentLoopCount = 0; |
606 | d->timer.start(); |
607 | d->setState(Running); |
608 | d->setCurrentTime(curTime); |
609 | } |
610 | |
611 | /*! |
612 | Resumes the timeline from the current time. QTimeLine will reenter Running |
613 | state, and once it enters the event loop, it will update its current time, |
614 | frame and value at regular intervals. |
615 | |
616 | In contrast to start(), this function does not restart the timeline before |
617 | it resumes. |
618 | |
619 | \sa start(), updateInterval(), frameChanged(), valueChanged() |
620 | */ |
621 | void QTimeLine::resume() |
622 | { |
623 | Q_D(QTimeLine); |
624 | if (d->timerId) { |
625 | qWarning("QTimeLine::resume: already running" ); |
626 | return; |
627 | } |
628 | d->timerId = startTimer(d->updateInterval); |
629 | d->startTime = d->currentTime; |
630 | d->timer.start(); |
631 | d->setState(Running); |
632 | } |
633 | |
634 | /*! |
635 | Stops the timeline, causing QTimeLine to enter NotRunning state. |
636 | |
637 | \sa start() |
638 | */ |
639 | void QTimeLine::stop() |
640 | { |
641 | Q_D(QTimeLine); |
642 | if (d->timerId) |
643 | killTimer(d->timerId); |
644 | d->setState(NotRunning); |
645 | d->timerId = 0; |
646 | } |
647 | |
648 | /*! |
649 | If \a paused is true, the timeline is paused, causing QTimeLine to enter |
650 | Paused state. No updates will be signaled until either start() or |
651 | setPaused(false) is called. If \a paused is false, the timeline is resumed |
652 | and continues where it left. |
653 | |
654 | \sa state(), start() |
655 | */ |
656 | void QTimeLine::setPaused(bool paused) |
657 | { |
658 | Q_D(QTimeLine); |
659 | if (d->state == NotRunning) { |
660 | qWarning("QTimeLine::setPaused: Not running" ); |
661 | return; |
662 | } |
663 | if (paused && d->state != Paused) { |
664 | d->startTime = d->currentTime; |
665 | killTimer(d->timerId); |
666 | d->timerId = 0; |
667 | d->setState(Paused); |
668 | } else if (!paused && d->state == Paused) { |
669 | // Same as resume() |
670 | d->timerId = startTimer(d->updateInterval); |
671 | d->startTime = d->currentTime; |
672 | d->timer.start(); |
673 | d->setState(Running); |
674 | } |
675 | } |
676 | |
677 | /*! |
678 | Toggles the direction of the timeline. If the direction was Forward, it |
679 | becomes Backward, and vice verca. |
680 | |
681 | \sa setDirection() |
682 | */ |
683 | void QTimeLine::toggleDirection() |
684 | { |
685 | Q_D(QTimeLine); |
686 | setDirection(d->direction == Forward ? Backward : Forward); |
687 | } |
688 | |
689 | /*! |
690 | \reimp |
691 | */ |
692 | void QTimeLine::timerEvent(QTimerEvent *event) |
693 | { |
694 | Q_D(QTimeLine); |
695 | if (event->timerId() != d->timerId) { |
696 | event->ignore(); |
697 | return; |
698 | } |
699 | event->accept(); |
700 | |
701 | if (d->direction == Forward) { |
702 | d->setCurrentTime(d->startTime + d->timer.elapsed()); |
703 | } else { |
704 | d->setCurrentTime(d->startTime - d->timer.elapsed()); |
705 | } |
706 | } |
707 | |
708 | QT_END_NAMESPACE |
709 | |
710 | #include "moc_qtimeline.cpp" |
711 | |