1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 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 the beginning and towards the 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 |
209 | setCurveShape(). |
210 | |
211 | Note that by default, QTimeLine uses the EaseInOut curve shape, |
212 | which provides a value that grows slowly, then grows steadily, and |
213 | finally grows slowly. For a custom timeline, you can reimplement |
214 | valueForTime(), in which case QTimeLine's curveShape property is ignored. |
215 | |
216 | \sa QProgressBar, QProgressDialog |
217 | */ |
218 | |
219 | /*! |
220 | \enum QTimeLine::State |
221 | |
222 | This enum describes the state of the timeline. |
223 | |
224 | \value NotRunning The timeline is not running. This is the initial state |
225 | of QTimeLine, and the state QTimeLine reenters when finished. The current |
226 | time, frame and value remain unchanged until either setCurrentTime() is |
227 | called, or the timeline is started by calling start(). |
228 | |
229 | \value Paused The timeline is paused (i.e., temporarily |
230 | suspended). Calling setPaused(false) will resume timeline activity. |
231 | |
232 | \value Running The timeline is running. While control is in the event |
233 | loop, QTimeLine will update its current time at regular intervals, |
234 | emitting valueChanged() and frameChanged() when appropriate. |
235 | |
236 | \sa state(), stateChanged() |
237 | */ |
238 | |
239 | /*! |
240 | \enum QTimeLine::Direction |
241 | |
242 | This enum describes the direction of the timeline when in \l Running state. |
243 | |
244 | \value Forward The current time of the timeline increases with time (i.e., |
245 | moves from 0 and towards the end / duration). |
246 | |
247 | \value Backward The current time of the timeline decreases with time (i.e., |
248 | moves from the end / duration and towards 0). |
249 | |
250 | \sa setDirection() |
251 | */ |
252 | |
253 | /*! |
254 | \enum QTimeLine::CurveShape |
255 | |
256 | This enum describes the default shape of QTimeLine's value curve. The |
257 | default, shape is EaseInOutCurve. The curve defines the relation |
258 | between the value and the timeline. |
259 | |
260 | \value EaseInCurve The value starts growing slowly, then increases in speed. |
261 | \value EaseOutCurve The value starts growing steadily, then ends slowly. |
262 | \value EaseInOutCurve The value starts growing slowly, then runs steadily, then grows slowly again. |
263 | \value LinearCurve The value grows linearly (e.g., if the duration is 1000 ms, |
264 | the value at time 500 ms is 0.5). |
265 | \value SineCurve The value grows sinusoidally. |
266 | \value CosineCurve The value grows cosinusoidally. |
267 | |
268 | \sa setCurveShape() |
269 | */ |
270 | |
271 | /*! |
272 | \fn void QTimeLine::valueChanged(qreal value) |
273 | |
274 | QTimeLine emits this signal at regular intervals when in \l Running state, |
275 | but only if the current value changes. \a value is the current value. \a value is |
276 | a number between 0.0 and 1.0 |
277 | |
278 | \sa QTimeLine::setDuration(), QTimeLine::valueForTime(), QTimeLine::updateInterval |
279 | */ |
280 | |
281 | /*! |
282 | \fn void QTimeLine::frameChanged(int frame) |
283 | |
284 | QTimeLine emits this signal at regular intervals when in \l Running state, |
285 | but only if the current frame changes. \a frame is the current frame number. |
286 | |
287 | \sa QTimeLine::setFrameRange(), QTimeLine::updateInterval |
288 | */ |
289 | |
290 | /*! |
291 | \fn void QTimeLine::stateChanged(QTimeLine::State newState) |
292 | |
293 | This signal is emitted whenever QTimeLine's state changes. The new state |
294 | is \a newState. |
295 | */ |
296 | |
297 | /*! |
298 | \fn void QTimeLine::finished() |
299 | |
300 | This signal is emitted when QTimeLine finishes (i.e., reaches the end of |
301 | its time line), and does not loop. |
302 | */ |
303 | |
304 | /*! |
305 | Constructs a timeline with a duration of \a duration milliseconds. \a |
306 | parent is passed to QObject's constructor. The default duration is 1000 |
307 | milliseconds. |
308 | */ |
309 | QTimeLine::QTimeLine(int duration, QObject *parent) |
310 | : QObject(*new QTimeLinePrivate, parent) |
311 | { |
312 | setDuration(duration); |
313 | } |
314 | |
315 | /*! |
316 | Destroys the timeline. |
317 | */ |
318 | QTimeLine::~QTimeLine() |
319 | { |
320 | Q_D(QTimeLine); |
321 | |
322 | if (d->state == Running) |
323 | stop(); |
324 | } |
325 | |
326 | /*! |
327 | Returns the state of the timeline. |
328 | |
329 | \sa start(), setPaused(), stop() |
330 | */ |
331 | QTimeLine::State QTimeLine::state() const |
332 | { |
333 | Q_D(const QTimeLine); |
334 | return d->state; |
335 | } |
336 | |
337 | /*! |
338 | \property QTimeLine::loopCount |
339 | \brief the number of times the timeline should loop before it's finished. |
340 | |
341 | A loop count of of 0 means that the timeline will loop forever. |
342 | |
343 | By default, this property contains a value of 1. |
344 | */ |
345 | int QTimeLine::loopCount() const |
346 | { |
347 | Q_D(const QTimeLine); |
348 | return d->totalLoopCount; |
349 | } |
350 | void QTimeLine::setLoopCount(int count) |
351 | { |
352 | Q_D(QTimeLine); |
353 | d->totalLoopCount = count; |
354 | } |
355 | |
356 | /*! |
357 | \property QTimeLine::direction |
358 | \brief the direction of the timeline when QTimeLine is in \l Running |
359 | state. |
360 | |
361 | This direction indicates whether the time moves from 0 towards the |
362 | timeline duration, or from the value of the duration and towards 0 after |
363 | start() has been called. |
364 | |
365 | By default, this property is set to \l Forward. |
366 | */ |
367 | QTimeLine::Direction QTimeLine::direction() const |
368 | { |
369 | Q_D(const QTimeLine); |
370 | return d->direction; |
371 | } |
372 | void QTimeLine::setDirection(Direction direction) |
373 | { |
374 | Q_D(QTimeLine); |
375 | d->direction = direction; |
376 | d->startTime = d->currentTime; |
377 | d->timer.start(); |
378 | } |
379 | |
380 | /*! |
381 | \property QTimeLine::duration |
382 | \brief the total duration of the timeline in milliseconds. |
383 | |
384 | By default, this value is 1000 (i.e., 1 second), but you can change this |
385 | by either passing a duration to QTimeLine's constructor, or by calling |
386 | setDuration(). The duration must be larger than 0. |
387 | |
388 | \note Changing the duration does not cause the current time to be reset |
389 | to zero or the new duration. You also need to call setCurrentTime() with |
390 | the desired value. |
391 | */ |
392 | int QTimeLine::duration() const |
393 | { |
394 | Q_D(const QTimeLine); |
395 | return d->duration; |
396 | } |
397 | void QTimeLine::setDuration(int duration) |
398 | { |
399 | Q_D(QTimeLine); |
400 | if (duration <= 0) { |
401 | qWarning("QTimeLine::setDuration: cannot set duration <= 0" ); |
402 | return; |
403 | } |
404 | d->duration = duration; |
405 | } |
406 | |
407 | /*! |
408 | Returns the start frame, which is the frame corresponding to the start of |
409 | the timeline (i.e., the frame for which the current value is 0). |
410 | |
411 | \sa setStartFrame(), setFrameRange() |
412 | */ |
413 | int QTimeLine::startFrame() const |
414 | { |
415 | Q_D(const QTimeLine); |
416 | return d->startFrame; |
417 | } |
418 | |
419 | /*! |
420 | Sets the start frame, which is the frame corresponding to the start of the |
421 | timeline (i.e., the frame for which the current value is 0), to \a frame. |
422 | |
423 | \sa startFrame(), endFrame(), setFrameRange() |
424 | */ |
425 | void QTimeLine::setStartFrame(int frame) |
426 | { |
427 | Q_D(QTimeLine); |
428 | d->startFrame = frame; |
429 | } |
430 | |
431 | /*! |
432 | Returns the end frame, which is the frame corresponding to the end of the |
433 | timeline (i.e., the frame for which the current value is 1). |
434 | |
435 | \sa setEndFrame(), setFrameRange() |
436 | */ |
437 | int QTimeLine::endFrame() const |
438 | { |
439 | Q_D(const QTimeLine); |
440 | return d->endFrame; |
441 | } |
442 | |
443 | /*! |
444 | Sets the end frame, which is the frame corresponding to the end of the |
445 | timeline (i.e., the frame for which the current value is 1), to \a frame. |
446 | |
447 | \sa endFrame(), startFrame(), setFrameRange() |
448 | */ |
449 | void QTimeLine::setEndFrame(int frame) |
450 | { |
451 | Q_D(QTimeLine); |
452 | d->endFrame = frame; |
453 | } |
454 | |
455 | /*! |
456 | Sets the timeline's frame counter to start at \a startFrame, and end and |
457 | \a endFrame. For each time value, QTimeLine will find the corresponding |
458 | frame when you call currentFrame() or frameForTime() by interpolating, |
459 | using the return value of valueForTime(). |
460 | |
461 | When in Running state, QTimeLine also emits the frameChanged() signal when |
462 | the frame changes. |
463 | |
464 | \sa startFrame(), endFrame(), start(), currentFrame() |
465 | */ |
466 | void QTimeLine::setFrameRange(int startFrame, int endFrame) |
467 | { |
468 | Q_D(QTimeLine); |
469 | d->startFrame = startFrame; |
470 | d->endFrame = endFrame; |
471 | } |
472 | |
473 | /*! |
474 | \property QTimeLine::updateInterval |
475 | \brief the time in milliseconds between each time QTimeLine updates its |
476 | current time. |
477 | |
478 | When updating the current time, QTimeLine will emit valueChanged() if the |
479 | current value changed, and frameChanged() if the frame changed. |
480 | |
481 | By default, the interval is 40 ms, which corresponds to a rate of 25 |
482 | updates per second. |
483 | */ |
484 | int QTimeLine::updateInterval() const |
485 | { |
486 | Q_D(const QTimeLine); |
487 | return d->updateInterval; |
488 | } |
489 | void QTimeLine::setUpdateInterval(int interval) |
490 | { |
491 | Q_D(QTimeLine); |
492 | d->updateInterval = interval; |
493 | } |
494 | |
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 | If you have reimplemented valueForTime(), this value is ignored. |
503 | |
504 | By default, this property is set to \l EaseInOutCurve. |
505 | |
506 | \sa valueForTime() |
507 | */ |
508 | QTimeLine::CurveShape QTimeLine::curveShape() const |
509 | { |
510 | Q_D(const QTimeLine); |
511 | switch (d->easingCurve.type()) { |
512 | default: |
513 | case QEasingCurve::InOutSine: |
514 | return EaseInOutCurve; |
515 | case QEasingCurve::InCurve: |
516 | return EaseInCurve; |
517 | case QEasingCurve::OutCurve: |
518 | return EaseOutCurve; |
519 | case QEasingCurve::Linear: |
520 | return LinearCurve; |
521 | case QEasingCurve::SineCurve: |
522 | return SineCurve; |
523 | case QEasingCurve::CosineCurve: |
524 | return CosineCurve; |
525 | } |
526 | return EaseInOutCurve; |
527 | } |
528 | |
529 | static QEasingCurve::Type convert(QTimeLine::CurveShape shape) |
530 | { |
531 | switch (shape) { |
532 | #define CASE(x, y) case QTimeLine::x: return QEasingCurve::y |
533 | CASE(EaseInOutCurve, InOutSine); |
534 | CASE(EaseInCurve, InCurve); |
535 | CASE(EaseOutCurve, OutCurve); |
536 | CASE(LinearCurve, Linear); |
537 | CASE(SineCurve, SineCurve); |
538 | CASE(CosineCurve, CosineCurve); |
539 | #undef CASE |
540 | } |
541 | Q_UNREACHABLE(); |
542 | } |
543 | |
544 | void QTimeLine::setCurveShape(CurveShape shape) |
545 | { |
546 | setEasingCurve(convert(shape)); |
547 | } |
548 | |
549 | /*! |
550 | \property QTimeLine::easingCurve |
551 | |
552 | \since 4.6 |
553 | |
554 | Specifies the easing curve that the timeline will use. |
555 | If both easing curve and curveShape are set, the last set property will |
556 | override the previous one. (If valueForTime() is reimplemented it will |
557 | override both) |
558 | */ |
559 | |
560 | QEasingCurve QTimeLine::easingCurve() const |
561 | { |
562 | Q_D(const QTimeLine); |
563 | return d->easingCurve; |
564 | } |
565 | |
566 | void QTimeLine::setEasingCurve(const QEasingCurve& curve) |
567 | { |
568 | Q_D(QTimeLine); |
569 | d->easingCurve = curve; |
570 | } |
571 | |
572 | /*! |
573 | \property QTimeLine::currentTime |
574 | \brief the current time of the time line. |
575 | |
576 | When QTimeLine is in Running state, this value is updated continuously as |
577 | a function of the duration and direction of the timeline. Otherwise, it is |
578 | value that was current when stop() was called last, or the value set by |
579 | setCurrentTime(). |
580 | |
581 | By default, this property contains a value of 0. |
582 | */ |
583 | int QTimeLine::currentTime() const |
584 | { |
585 | Q_D(const QTimeLine); |
586 | return d->currentTime; |
587 | } |
588 | void QTimeLine::setCurrentTime(int msec) |
589 | { |
590 | Q_D(QTimeLine); |
591 | d->startTime = 0; |
592 | d->currentLoopCount = 0; |
593 | d->timer.restart(); |
594 | d->setCurrentTime(msec); |
595 | } |
596 | |
597 | /*! |
598 | Returns the frame corresponding to the current time. |
599 | |
600 | \sa currentTime(), frameForTime(), setFrameRange() |
601 | */ |
602 | int QTimeLine::currentFrame() const |
603 | { |
604 | Q_D(const QTimeLine); |
605 | return frameForTime(d->currentTime); |
606 | } |
607 | |
608 | /*! |
609 | Returns the value corresponding to the current time. |
610 | |
611 | \sa valueForTime(), currentFrame() |
612 | */ |
613 | qreal QTimeLine::currentValue() const |
614 | { |
615 | Q_D(const QTimeLine); |
616 | return valueForTime(d->currentTime); |
617 | } |
618 | |
619 | /*! |
620 | Returns the frame corresponding to the time \a msec. This value is |
621 | calculated using a linear interpolation of the start and end frame, based |
622 | on the value returned by valueForTime(). |
623 | |
624 | \sa valueForTime(), setFrameRange() |
625 | */ |
626 | int QTimeLine::frameForTime(int msec) const |
627 | { |
628 | Q_D(const QTimeLine); |
629 | if (d->direction == Forward) |
630 | return d->startFrame + int((d->endFrame - d->startFrame) * valueForTime(msec)); |
631 | return d->startFrame + qCeil((d->endFrame - d->startFrame) * valueForTime(msec)); |
632 | } |
633 | |
634 | /*! |
635 | Returns the timeline value for the time \a msec. The returned value, which |
636 | varies depending on the curve shape, is always between 0 and 1. If \a msec |
637 | is 0, the default implementation always returns 0. |
638 | |
639 | Reimplement this function to provide a custom curve shape for your |
640 | timeline. |
641 | |
642 | \sa CurveShape, frameForTime() |
643 | */ |
644 | qreal QTimeLine::valueForTime(int msec) const |
645 | { |
646 | Q_D(const QTimeLine); |
647 | msec = qMin(qMax(msec, 0), d->duration); |
648 | |
649 | qreal value = msec / qreal(d->duration); |
650 | return d->easingCurve.valueForProgress(value); |
651 | } |
652 | |
653 | /*! |
654 | Starts the timeline. QTimeLine will enter Running state, and once it |
655 | enters the event loop, it will update its current time, frame and value at |
656 | regular intervals. The default interval is 40 ms (i.e., 25 times per |
657 | second). You can change the update interval by calling |
658 | setUpdateInterval(). |
659 | |
660 | The timeline will start from position 0, or the end if going backward. |
661 | If you want to resume a stopped timeline without restarting, you can call |
662 | resume() instead. |
663 | |
664 | \sa resume(), updateInterval(), frameChanged(), valueChanged() |
665 | */ |
666 | void QTimeLine::start() |
667 | { |
668 | Q_D(QTimeLine); |
669 | if (d->timerId) { |
670 | qWarning("QTimeLine::start: already running" ); |
671 | return; |
672 | } |
673 | int curTime = 0; |
674 | if (d->direction == Backward) |
675 | curTime = d->duration; |
676 | d->timerId = startTimer(d->updateInterval); |
677 | d->startTime = curTime; |
678 | d->currentLoopCount = 0; |
679 | d->timer.start(); |
680 | d->setState(Running); |
681 | d->setCurrentTime(curTime); |
682 | } |
683 | |
684 | /*! |
685 | Resumes the timeline from the current time. QTimeLine will reenter Running |
686 | state, and once it enters the event loop, it will update its current time, |
687 | frame and value at regular intervals. |
688 | |
689 | In contrast to start(), this function does not restart the timeline before |
690 | it resumes. |
691 | |
692 | \sa start(), updateInterval(), frameChanged(), valueChanged() |
693 | */ |
694 | void QTimeLine::resume() |
695 | { |
696 | Q_D(QTimeLine); |
697 | if (d->timerId) { |
698 | qWarning("QTimeLine::resume: already running" ); |
699 | return; |
700 | } |
701 | d->timerId = startTimer(d->updateInterval); |
702 | d->startTime = d->currentTime; |
703 | d->timer.start(); |
704 | d->setState(Running); |
705 | } |
706 | |
707 | /*! |
708 | Stops the timeline, causing QTimeLine to enter NotRunning state. |
709 | |
710 | \sa start() |
711 | */ |
712 | void QTimeLine::stop() |
713 | { |
714 | Q_D(QTimeLine); |
715 | if (d->timerId) |
716 | killTimer(d->timerId); |
717 | d->setState(NotRunning); |
718 | d->timerId = 0; |
719 | } |
720 | |
721 | /*! |
722 | If \a paused is true, the timeline is paused, causing QTimeLine to enter |
723 | Paused state. No updates will be signaled until either start() or |
724 | setPaused(false) is called. If \a paused is false, the timeline is resumed |
725 | and continues where it left. |
726 | |
727 | \sa state(), start() |
728 | */ |
729 | void QTimeLine::setPaused(bool paused) |
730 | { |
731 | Q_D(QTimeLine); |
732 | if (d->state == NotRunning) { |
733 | qWarning("QTimeLine::setPaused: Not running" ); |
734 | return; |
735 | } |
736 | if (paused && d->state != Paused) { |
737 | d->startTime = d->currentTime; |
738 | killTimer(d->timerId); |
739 | d->timerId = 0; |
740 | d->setState(Paused); |
741 | } else if (!paused && d->state == Paused) { |
742 | // Same as resume() |
743 | d->timerId = startTimer(d->updateInterval); |
744 | d->startTime = d->currentTime; |
745 | d->timer.start(); |
746 | d->setState(Running); |
747 | } |
748 | } |
749 | |
750 | /*! |
751 | Toggles the direction of the timeline. If the direction was Forward, it |
752 | becomes Backward, and vice verca. |
753 | |
754 | \sa setDirection() |
755 | */ |
756 | void QTimeLine::toggleDirection() |
757 | { |
758 | Q_D(QTimeLine); |
759 | setDirection(d->direction == Forward ? Backward : Forward); |
760 | } |
761 | |
762 | /*! |
763 | \reimp |
764 | */ |
765 | void QTimeLine::timerEvent(QTimerEvent *event) |
766 | { |
767 | Q_D(QTimeLine); |
768 | if (event->timerId() != d->timerId) { |
769 | event->ignore(); |
770 | return; |
771 | } |
772 | event->accept(); |
773 | |
774 | if (d->direction == Forward) { |
775 | d->setCurrentTime(d->startTime + d->timer.elapsed()); |
776 | } else { |
777 | d->setCurrentTime(d->startTime - d->timer.elapsed()); |
778 | } |
779 | } |
780 | |
781 | QT_END_NAMESPACE |
782 | |
783 | #include "moc_qtimeline.cpp" |
784 | |