summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qtimeline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qtimeline.cpp')
-rw-r--r--src/corelib/tools/qtimeline.cpp293
1 files changed, 120 insertions, 173 deletions
diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp
index 0b11e7c77b..5512da867f 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -1,44 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtimeline.h"
+#include <private/qproperty_p.h>
#include <private/qobject_p.h>
#include <QtCore/qcoreevent.h>
#include <QtCore/qmath.h>
@@ -50,31 +15,29 @@ class QTimeLinePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QTimeLine)
public:
- inline QTimeLinePrivate()
- : easingCurve(QEasingCurve::InOutSine),
- startTime(0), duration(1000), startFrame(0), endFrame(0),
- updateInterval(1000 / 25),
- totalLoopCount(1), currentLoopCount(0), currentTime(0), timerId(0),
- direction(QTimeLine::Forward),
- state(QTimeLine::NotRunning)
- { }
-
QElapsedTimer timer;
- QEasingCurve easingCurve;
-
- int startTime;
- int duration;
- int startFrame;
- int endFrame;
- int updateInterval;
- int totalLoopCount;
- int currentLoopCount;
-
- int currentTime;
- int timerId;
-
- QTimeLine::Direction direction;
- QTimeLine::State state;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, QEasingCurve, easingCurve,
+ QEasingCurve::InOutSine)
+
+ int startTime = 0;
+ void setDuration(int duration) { q_func()->setDuration(duration); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, duration,
+ &QTimeLinePrivate::setDuration, 1000)
+ int startFrame = 0;
+ int endFrame = 0;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, updateInterval, 1000 / 25)
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, loopCount, 1)
+ int currentLoopCount = 0;
+
+ void setCurrentTimeForwardToQ(int time) { q_func()->setCurrentTime(time); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, int, currentTime,
+ &QTimeLinePrivate::setCurrentTimeForwardToQ, 0)
+ int timerId = 0;
+
+ void setDirection(QTimeLine::Direction direction) { q_func()->setDirection(direction); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimeLinePrivate, QTimeLine::Direction, direction,
+ &QTimeLinePrivate::setDirection, QTimeLine::Forward)
+ QTimeLine::State state = QTimeLine::NotRunning;
inline void setState(QTimeLine::State newState)
{
Q_Q(QTimeLine);
@@ -91,42 +54,45 @@ public:
void QTimeLinePrivate::setCurrentTime(int msecs)
{
Q_Q(QTimeLine);
+ currentTime.removeBindingUnlessInWrapper();
+ const auto previousCurrentTime = currentTime.valueBypassingBindings();
- qreal lastValue = q->currentValue();
- int lastFrame = q->currentFrame();
+ const qreal lastValue = q->valueForTime(previousCurrentTime);
+ const int lastFrame = q->frameForTime(previousCurrentTime);
// Determine if we are looping.
- int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
- int loopCount = elapsed / duration;
+ const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
+ const int loopCountNow = elapsed / duration;
- bool looping = (loopCount != currentLoopCount);
+ const bool looping = (loopCountNow != currentLoopCount);
#ifdef QTIMELINE_DEBUG
- qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCount" << loopCount
- << "currentLoopCount" << currentLoopCount
- << "looping" << looping;
+ qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
+ << loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
#endif
if (looping)
- currentLoopCount = loopCount;
+ currentLoopCount = loopCountNow;
// Normalize msecs to be between 0 and duration, inclusive.
- currentTime = elapsed % duration;
- if (direction == QTimeLine::Backward)
- currentTime = duration - currentTime;
+ currentTime.setValueBypassingBindings(elapsed % duration);
+ if (direction.value() == QTimeLine::Backward)
+ currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
// Check if we have reached the end of loopcount.
bool finished = false;
- if (totalLoopCount && currentLoopCount >= totalLoopCount) {
+ if (loopCount && currentLoopCount >= loopCount) {
finished = true;
- currentTime = (direction == QTimeLine::Backward) ? 0 : duration;
- currentLoopCount = totalLoopCount - 1;
+ currentTime.setValueBypassingBindings((direction == QTimeLine::Backward) ? 0 : duration);
+ currentLoopCount = loopCount - 1;
}
- int currentFrame = q->frameForTime(currentTime);
+ const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
#ifdef QTIMELINE_DEBUG
- qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime" << currentTime << currentFrame;
+ qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime"
+ << currentTime.valueBypassingBindings() << currentFrame;
#endif
- if (!qFuzzyCompare(lastValue, q->currentValue()))
- emit q->valueChanged(q->currentValue(), QTimeLine::QPrivateSignal());
+ const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
+ if (!qFuzzyCompare(lastValue, currentValue))
+ emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
if (lastFrame != currentFrame) {
const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
if (looping && !finished && transitionframe != currentFrame) {
@@ -159,6 +125,13 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
q->stop();
emit q->finished(QTimeLine::QPrivateSignal());
}
+ if (currentTime.valueBypassingBindings() != previousCurrentTime)
+ currentTime.notify();
+}
+QBindable<int> QTimeLine::bindableCurrentTime()
+{
+ Q_D(QTimeLine);
+ return &d->currentTime;
}
/*!
@@ -185,7 +158,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
\snippet code/src_corelib_tools_qtimeline.cpp 0
- By default the timeline runs once, from the beginning and towards the end,
+ By default the timeline runs once, from its beginning to its end,
upon which you must call start() again to restart from the beginning. To
make the timeline loop, you can call setLoopCount(), passing the number of
times the timeline should run before finishing. The direction can also be
@@ -193,8 +166,8 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
setDirection(). You can also pause and unpause the timeline while it's
running by calling setPaused(). For interactive control, the
setCurrentTime() function is provided, which sets the time position of the
- time line directly. Although most useful in NotRunning state, (e.g.,
- connected to a valueChanged() signal in a QSlider,) this function can be
+ time line directly. Although most useful in NotRunning state (e.g.,
+ connected to a valueChanged() signal in a QSlider), this function can be
called at any time.
The frame interface is useful for standard widgets, but QTimeLine can be
@@ -205,13 +178,12 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
step. When running, QTimeLine generates values between 0 and 1 by calling
valueForTime() and emitting valueChanged(). By default, valueForTime()
applies an interpolation algorithm to generate these value. You can choose
- from a set of predefined timeline algorithms by calling
- setCurveShape().
+ from a set of predefined timeline algorithms by calling setEasingCurve().
- Note that by default, QTimeLine uses the EaseInOut curve shape,
- which provides a value that grows slowly, then grows steadily, and
- finally grows slowly. For a custom timeline, you can reimplement
- valueForTime(), in which case QTimeLine's curveShape property is ignored.
+ Note that, by default, QTimeLine uses QEasingCurve::InOutSine, which
+ provides a value that grows slowly, then grows steadily, and finally grows
+ slowly. For a custom timeline, you can reimplement valueForTime(), in which
+ case QTimeLine's easingCurve property is ignored.
\sa QProgressBar, QProgressDialog
*/
@@ -251,24 +223,6 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
*/
/*!
- \enum QTimeLine::CurveShape
-
- This enum describes the default shape of QTimeLine's value curve. The
- default, shape is EaseInOutCurve. The curve defines the relation
- between the value and the timeline.
-
- \value EaseInCurve The value starts growing slowly, then increases in speed.
- \value EaseOutCurve The value starts growing steadily, then ends slowly.
- \value EaseInOutCurve The value starts growing slowly, then runs steadily, then grows slowly again.
- \value LinearCurve The value grows linearly (e.g., if the duration is 1000 ms,
- the value at time 500 ms is 0.5).
- \value SineCurve The value grows sinusoidally.
- \value CosineCurve The value grows cosinusoidally.
-
- \sa setCurveShape()
-*/
-
-/*!
\fn void QTimeLine::valueChanged(qreal value)
QTimeLine emits this signal at regular intervals when in \l Running state,
@@ -338,19 +292,26 @@ QTimeLine::State QTimeLine::state() const
\property QTimeLine::loopCount
\brief the number of times the timeline should loop before it's finished.
- A loop count of of 0 means that the timeline will loop forever.
+ A loop count of 0 means that the timeline will loop forever.
By default, this property contains a value of 1.
*/
int QTimeLine::loopCount() const
{
Q_D(const QTimeLine);
- return d->totalLoopCount;
+ return d->loopCount;
}
+
void QTimeLine::setLoopCount(int count)
{
Q_D(QTimeLine);
- d->totalLoopCount = count;
+ d->loopCount = count;
+}
+
+QBindable<int> QTimeLine::bindableLoopCount()
+{
+ Q_D(QTimeLine);
+ return &d->loopCount;
}
/*!
@@ -362,6 +323,9 @@ void QTimeLine::setLoopCount(int count)
timeline duration, or from the value of the duration and towards 0 after
start() has been called.
+ Any binding of direction will be removed not only by setDirection(),
+ but also by toggleDirection().
+
By default, this property is set to \l Forward.
*/
QTimeLine::Direction QTimeLine::direction() const
@@ -372,9 +336,19 @@ QTimeLine::Direction QTimeLine::direction() const
void QTimeLine::setDirection(Direction direction)
{
Q_D(QTimeLine);
- d->direction = direction;
+ d->direction.removeBindingUnlessInWrapper();
+ const auto previousDirection = d->direction.valueBypassingBindings();
+ d->direction.setValueBypassingBindings(direction);
d->startTime = d->currentTime;
d->timer.start();
+ if (previousDirection != d->direction.valueBypassingBindings())
+ d->direction.notify();
+}
+
+QBindable<QTimeLine::Direction> QTimeLine::bindableDirection()
+{
+ Q_D(QTimeLine);
+ return &d->direction;
}
/*!
@@ -401,7 +375,17 @@ void QTimeLine::setDuration(int duration)
qWarning("QTimeLine::setDuration: cannot set duration <= 0");
return;
}
- d->duration = duration;
+ d->duration.removeBindingUnlessInWrapper();
+ if (duration != d->duration.valueBypassingBindings()) {
+ d->duration.setValueBypassingBindings(duration);
+ d->duration.notify();
+ }
+}
+
+QBindable<int> QTimeLine::bindableDuration()
+{
+ Q_D(QTimeLine);
+ return &d->duration;
}
/*!
@@ -491,59 +475,10 @@ void QTimeLine::setUpdateInterval(int interval)
Q_D(QTimeLine);
d->updateInterval = interval;
}
-
-/*!
- \property QTimeLine::curveShape
- \brief the shape of the timeline curve.
-
- The curve shape describes the relation between the time and value for the
- base implementation of valueForTime().
-
- If you have reimplemented valueForTime(), this value is ignored.
-
- By default, this property is set to \l EaseInOutCurve.
-
- \sa valueForTime()
-*/
-QTimeLine::CurveShape QTimeLine::curveShape() const
-{
- Q_D(const QTimeLine);
- switch (d->easingCurve.type()) {
- default:
- case QEasingCurve::InOutSine:
- return EaseInOutCurve;
- case QEasingCurve::InCurve:
- return EaseInCurve;
- case QEasingCurve::OutCurve:
- return EaseOutCurve;
- case QEasingCurve::Linear:
- return LinearCurve;
- case QEasingCurve::SineCurve:
- return SineCurve;
- case QEasingCurve::CosineCurve:
- return CosineCurve;
- }
- return EaseInOutCurve;
-}
-
-static QEasingCurve::Type convert(QTimeLine::CurveShape shape)
+QBindable<int> QTimeLine::bindableUpdateInterval()
{
- switch (shape) {
-#define CASE(x, y) case QTimeLine::x: return QEasingCurve::y
- CASE(EaseInOutCurve, InOutSine);
- CASE(EaseInCurve, InCurve);
- CASE(EaseOutCurve, OutCurve);
- CASE(LinearCurve, Linear);
- CASE(SineCurve, SineCurve);
- CASE(CosineCurve, CosineCurve);
-#undef CASE
- }
- Q_UNREACHABLE();
-}
-
-void QTimeLine::setCurveShape(CurveShape shape)
-{
- setEasingCurve(convert(shape));
+ Q_D(QTimeLine);
+ return &d->updateInterval;
}
/*!
@@ -552,9 +487,9 @@ void QTimeLine::setCurveShape(CurveShape shape)
\since 4.6
Specifies the easing curve that the timeline will use.
- If both easing curve and curveShape are set, the last set property will
- override the previous one. (If valueForTime() is reimplemented it will
- override both)
+ If valueForTime() is reimplemented, this value is ignored.
+
+ \sa valueForTime()
*/
QEasingCurve QTimeLine::easingCurve() const
@@ -563,12 +498,18 @@ QEasingCurve QTimeLine::easingCurve() const
return d->easingCurve;
}
-void QTimeLine::setEasingCurve(const QEasingCurve& curve)
+void QTimeLine::setEasingCurve(const QEasingCurve &curve)
{
Q_D(QTimeLine);
d->easingCurve = curve;
}
+QBindable<QEasingCurve> QTimeLine::bindableEasingCurve()
+{
+ Q_D(QTimeLine);
+ return &d->easingCurve;
+}
+
/*!
\property QTimeLine::currentTime
\brief the current time of the time line.
@@ -578,6 +519,10 @@ void QTimeLine::setEasingCurve(const QEasingCurve& curve)
value that was current when stop() was called last, or the value set by
setCurrentTime().
+ \note You can bind other properties to currentTime, but it is not
+ recommended setting bindings to it. As animation progresses, the currentTime
+ is updated automatically, which cancels its bindings.
+
By default, this property contains a value of 0.
*/
int QTimeLine::currentTime() const
@@ -639,15 +584,15 @@ int QTimeLine::frameForTime(int msec) const
Reimplement this function to provide a custom curve shape for your
timeline.
- \sa CurveShape, frameForTime()
+ \sa easingCurve, frameForTime()
*/
qreal QTimeLine::valueForTime(int msec) const
{
Q_D(const QTimeLine);
- msec = qMin(qMax(msec, 0), d->duration);
+ msec = qBound(0, msec, d->duration.value());
- qreal value = msec / qreal(d->duration);
- return d->easingCurve.valueForProgress(value);
+ qreal value = msec / qreal(d->duration.value());
+ return d->easingCurve.value().valueForProgress(value);
}
/*!
@@ -751,6 +696,8 @@ void QTimeLine::setPaused(bool paused)
Toggles the direction of the timeline. If the direction was Forward, it
becomes Backward, and vice verca.
+ Existing bindings of \l direction are removed.
+
\sa setDirection()
*/
void QTimeLine::toggleDirection()