QtBase  v6.3.1
qtimeline.cpp
Go to the documentation of this file.
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/qproperty_p.h>
43 #include <private/qobject_p.h>
44 #include <QtCore/qcoreevent.h>
45 #include <QtCore/qmath.h>
46 #include <QtCore/qelapsedtimer.h>
47 
49 
51 {
52  Q_DECLARE_PUBLIC(QTimeLine)
53 public:
57 
58  int startTime = 0;
59  void setDuration(int duration) { q_func()->setDuration(duration); }
62  int startFrame = 0;
63  int endFrame = 0;
64  Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, updateInterval, 1000 / 25)
67 
68  void setCurrentTimeForwardToQ(int time) { q_func()->setCurrentTime(time); }
71  int timerId = 0;
72 
73  void setDirection(QTimeLine::Direction direction) { q_func()->setDirection(direction); }
78  {
79  Q_Q(QTimeLine);
80  if (newState != state)
81  emit q->stateChanged(state = newState, QTimeLine::QPrivateSignal());
82  }
83 
84  void setCurrentTime(int msecs);
85 };
86 
91 {
92  Q_Q(QTimeLine);
93  currentTime.removeBindingUnlessInWrapper();
94  auto previousCurrentTime = currentTime.value();
95 
96  qreal lastValue = q->currentValue();
97  int lastFrame = q->currentFrame();
98 
99  // Determine if we are looping.
100  int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
101  int loopCountNow = elapsed / duration;
102 
103  bool looping = (loopCountNow != currentLoopCount);
104 #ifdef QTIMELINE_DEBUG
105  qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
106  << loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
107 #endif
108  if (looping)
109  currentLoopCount = loopCountNow;
110 
111  // Normalize msecs to be between 0 and duration, inclusive.
112  currentTime.setValueBypassingBindings(elapsed % duration);
113  if (direction.value() == QTimeLine::Backward)
114  currentTime.setValueBypassingBindings(duration - currentTime);
115 
116  // Check if we have reached the end of loopcount.
117  bool finished = false;
118  if (loopCount && currentLoopCount >= loopCount) {
119  finished = true;
120  currentTime.setValueBypassingBindings((direction == QTimeLine::Backward) ? 0 : duration);
121  currentLoopCount = loopCount - 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  if (currentTime.value() != previousCurrentTime)
163  currentTime.notify();
164 }
166 {
167  Q_D(QTimeLine);
168  return &d->currentTime;
169 }
170 
299 {
301 }
302 
307 {
308  Q_D(QTimeLine);
309 
310  if (d->state == Running)
311  stop();
312 }
313 
320 {
321  Q_D(const QTimeLine);
322  return d->state;
323 }
324 
334 {
335  Q_D(const QTimeLine);
336  return d->loopCount;
337 }
338 
340 {
341  Q_D(QTimeLine);
342  d->loopCount = count;
343 }
344 
346 {
347  Q_D(QTimeLine);
348  return &d->loopCount;
349 }
350 
366 {
367  Q_D(const QTimeLine);
368  return d->direction;
369 }
371 {
372  Q_D(QTimeLine);
373  auto previousDirection = d->direction.value();
374  d->direction.setValue(direction);
375  d->startTime = d->currentTime;
376  d->timer.start();
377  if (previousDirection != d->direction.value())
378  d->direction.notify();
379 }
380 
382 {
383  Q_D(QTimeLine);
384  return &d->direction;
385 }
386 
400 {
401  Q_D(const QTimeLine);
402  return d->duration;
403 }
404 void QTimeLine::setDuration(int duration)
405 {
406  Q_D(QTimeLine);
407  if (duration <= 0) {
408  qWarning("QTimeLine::setDuration: cannot set duration <= 0");
409  return;
410  }
411  if (duration == d->duration) {
412  d->duration.removeBindingUnlessInWrapper();
413  return;
414  }
415  d->duration.setValue(duration);
416  d->duration.notify();
417 }
418 
420 {
421  Q_D(QTimeLine);
422  return &d->duration;
423 }
424 
432 {
433  Q_D(const QTimeLine);
434  return d->startFrame;
435 }
436 
444 {
445  Q_D(QTimeLine);
446  d->startFrame = frame;
447 }
448 
456 {
457  Q_D(const QTimeLine);
458  return d->endFrame;
459 }
460 
468 {
469  Q_D(QTimeLine);
470  d->endFrame = frame;
471 }
472 
484 void QTimeLine::setFrameRange(int startFrame, int endFrame)
485 {
486  Q_D(QTimeLine);
487  d->startFrame = startFrame;
488  d->endFrame = endFrame;
489 }
490 
503 {
504  Q_D(const QTimeLine);
505  return d->updateInterval;
506 }
508 {
509  Q_D(QTimeLine);
510  d->updateInterval = interval;
511 }
513 {
514  Q_D(QTimeLine);
515  return &d->updateInterval;
516 }
517 
530 {
531  Q_D(const QTimeLine);
532  return d->easingCurve;
533 }
534 
536 {
537  Q_D(QTimeLine);
538  d->easingCurve = curve;
539 }
540 
542 {
543  Q_D(QTimeLine);
544  return &d->easingCurve;
545 }
546 
563 {
564  Q_D(const QTimeLine);
565  return d->currentTime;
566 }
568 {
569  Q_D(QTimeLine);
570  d->startTime = 0;
571  d->currentLoopCount = 0;
572  d->timer.restart();
573  d->setCurrentTime(msec);
574 }
575 
582 {
583  Q_D(const QTimeLine);
584  return frameForTime(d->currentTime);
585 }
586 
593 {
594  Q_D(const QTimeLine);
595  return valueForTime(d->currentTime);
596 }
597 
605 int QTimeLine::frameForTime(int msec) const
606 {
607  Q_D(const QTimeLine);
608  if (d->direction == Forward)
609  return d->startFrame + int((d->endFrame - d->startFrame) * valueForTime(msec));
610  return d->startFrame + qCeil((d->endFrame - d->startFrame) * valueForTime(msec));
611 }
612 
624 {
625  Q_D(const QTimeLine);
626  msec = qBound(0, msec, d->duration.value());
627 
628  qreal value = msec / qreal(d->duration.value());
629  return d->easingCurve.value().valueForProgress(value);
630 }
631 
646 {
647  Q_D(QTimeLine);
648  if (d->timerId) {
649  qWarning("QTimeLine::start: already running");
650  return;
651  }
652  int curTime = 0;
653  if (d->direction == Backward)
654  curTime = d->duration;
655  d->timerId = startTimer(d->updateInterval);
656  d->startTime = curTime;
657  d->currentLoopCount = 0;
658  d->timer.start();
659  d->setState(Running);
660  d->setCurrentTime(curTime);
661 }
662 
674 {
675  Q_D(QTimeLine);
676  if (d->timerId) {
677  qWarning("QTimeLine::resume: already running");
678  return;
679  }
680  d->timerId = startTimer(d->updateInterval);
681  d->startTime = d->currentTime;
682  d->timer.start();
683  d->setState(Running);
684 }
685 
692 {
693  Q_D(QTimeLine);
694  if (d->timerId)
695  killTimer(d->timerId);
696  d->setState(NotRunning);
697  d->timerId = 0;
698 }
699 
708 void QTimeLine::setPaused(bool paused)
709 {
710  Q_D(QTimeLine);
711  if (d->state == NotRunning) {
712  qWarning("QTimeLine::setPaused: Not running");
713  return;
714  }
715  if (paused && d->state != Paused) {
716  d->startTime = d->currentTime;
717  killTimer(d->timerId);
718  d->timerId = 0;
719  d->setState(Paused);
720  } else if (!paused && d->state == Paused) {
721  // Same as resume()
722  d->timerId = startTimer(d->updateInterval);
723  d->startTime = d->currentTime;
724  d->timer.start();
725  d->setState(Running);
726  }
727 }
728 
738 {
739  Q_D(QTimeLine);
740  setDirection(d->direction == Forward ? Backward : Forward);
741 }
742 
747 {
748  Q_D(QTimeLine);
749  if (event->timerId() != d->timerId) {
750  event->ignore();
751  return;
752  }
753  event->accept();
754 
755  if (d->direction == Forward) {
756  d->setCurrentTime(d->startTime + d->timer.elapsed());
757  } else {
758  d->setCurrentTime(d->startTime - d->timer.elapsed());
759  }
760 }
761 
763 
764 #include "moc_qtimeline.cpp"
QBindable is a wrapper class around binding-enabled properties. It allows type-safe operations while ...
Definition: qproperty.h:753
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
const char * constData() const noexcept
Definition: qbytearray.h:144
bool isEmpty() const noexcept
Definition: qbytearray.h:129
static QByteArray number(int, int base=10)
The QEasingCurve class provides easing curves for controlling animation.
Definition: qeasingcurve.h:55
The QElapsedTimer class provides a fast way to calculate elapsed times.
Definition: qelapsedtimer.h:49
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
Definition: qobject.cpp:1765
void killTimer(int id)
Definition: qobject.cpp:1838
The QTimeLine class provides a timeline for controlling animations.
Definition: qtimeline.h:55
int currentTime
the current time of the time line.
Definition: qtimeline.h:60
int loopCount
the number of times the timeline should loop before it's finished.
Definition: qtimeline.h:62
void timerEvent(QTimerEvent *event) override
Definition: qtimeline.cpp:746
int currentFrame() const
Definition: qtimeline.cpp:581
QTimeLine(int duration=1000, QObject *parent=nullptr)
Definition: qtimeline.cpp:297
int startFrame() const
Definition: qtimeline.cpp:431
qreal currentValue() const
Definition: qtimeline.cpp:592
State state() const
Definition: qtimeline.cpp:319
void setPaused(bool paused)
Definition: qtimeline.cpp:708
int duration
the total duration of the timeline in milliseconds.
Definition: qtimeline.h:57
QBindable< int > bindableCurrentTime()
Definition: qtimeline.cpp:165
int frameForTime(int msec) const
Definition: qtimeline.cpp:605
void setEasingCurve(const QEasingCurve &curve)
Definition: qtimeline.cpp:535
int endFrame() const
Definition: qtimeline.cpp:455
void setUpdateInterval(int interval)
Definition: qtimeline.cpp:507
QBindable< QEasingCurve > bindableEasingCurve()
Definition: qtimeline.cpp:541
int updateInterval
the time in milliseconds between each time QTimeLine updates its current time.
Definition: qtimeline.h:59
QBindable< int > bindableLoopCount()
Definition: qtimeline.cpp:345
virtual qreal valueForTime(int msec) const
Definition: qtimeline.cpp:623
QBindable< int > bindableDuration()
Definition: qtimeline.cpp:419
void start()
Definition: qtimeline.cpp:645
void setLoopCount(int count)
Definition: qtimeline.cpp:339
void setDirection(Direction direction)
Definition: qtimeline.cpp:370
void setStartFrame(int frame)
Definition: qtimeline.cpp:443
Direction direction
the direction of the timeline when QTimeLine is in \l Running state.
Definition: qtimeline.h:61
QBindable< int > bindableUpdateInterval()
Definition: qtimeline.cpp:512
@ NotRunning
Definition: qtimeline.h:67
void setFrameRange(int startFrame, int endFrame)
Definition: qtimeline.cpp:484
void setCurrentTime(int msec)
Definition: qtimeline.cpp:567
QBindable< Direction > bindableDirection()
Definition: qtimeline.cpp:381
QEasingCurve easingCurve
Definition: qtimeline.h:64
void setDuration(int duration)
Definition: qtimeline.cpp:404
void stop()
Definition: qtimeline.cpp:691
void toggleDirection()
Definition: qtimeline.cpp:737
@ Backward
Definition: qtimeline.h:73
void setEndFrame(int frame)
Definition: qtimeline.cpp:467
virtual ~QTimeLine()
Definition: qtimeline.cpp:306
void resume()
Definition: qtimeline.cpp:673
void setCurrentTimeForwardToQ(int time)
Definition: qtimeline.cpp:68
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, duration, &QTimeLinePrivate::setDuration, 1000) int startFrame=0
void setDirection(QTimeLine::Direction direction)
Definition: qtimeline.cpp:73
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, QEasingCurve, easingCurve, QEasingCurve::InOutSine) int startTime=0
void setCurrentTime(int msecs)
Definition: qtimeline.cpp:90
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, currentTime, &QTimeLinePrivate::setCurrentTimeForwardToQ, 0) int timerId=0
void setDuration(int duration)
Definition: qtimeline.cpp:59
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, QTimeLine::Direction, direction, &QTimeLinePrivate::setDirection, QTimeLine::Forward) QTimeLine void setState(QTimeLine::State newState)
Definition: qtimeline.cpp:77
QElapsedTimer timer
Definition: qtimeline.cpp:54
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:367
direction
else opt state
[0]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
EGLOutputLayerEXT EGLint EGLAttrib value
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition: qfloat16.h:233
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
int qCeil(T v)
Definition: qmath.h:72
GLenum GLenum GLsizei count
struct _cl_event * event
Definition: qopenglext.h:2998
GLdouble GLdouble GLdouble GLdouble q
Definition: qopenglext.h:259
#define emit
Definition: qtmetamacros.h:85
QTime time
[5]
QFrame frame
[0]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
Direction
Definition: main.cpp:217