summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/animation/qabstractanimation.cpp66
-rw-r--r--src/corelib/animation/qabstractanimation.h19
-rw-r--r--src/corelib/animation/qabstractanimation_p.h27
-rw-r--r--tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt2
-rw-r--r--tests/auto/corelib/animation/qabstractanimation/tst_qabstractanimation.cpp91
5 files changed, 189 insertions, 16 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index d5d75e8ab3..18dab48e5a 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -930,14 +930,17 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
// check if we should Rewind
if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running)
&& oldState == QAbstractAnimation::Stopped) {
+ const int oldTotalCurrentTime = totalCurrentTime;
//here we reset the time if needed
//we don't call setCurrentTime because this might change the way the animation
//behaves: changing the state or changing the current value
totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ?
0 : (loopCount == -1 ? q->duration() : q->totalDuration());
+ if (totalCurrentTime != oldTotalCurrentTime)
+ totalCurrentTime.notify();
}
- state = newState;
+ state.setValueBypassingBindings(newState);
QPointer<QAbstractAnimation> guard(q);
//(un)registration of the animation must always happen before calls to
@@ -957,6 +960,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
return;
// Notify state change
+ state.notify();
emit q->stateChanged(newState, oldState);
if (!guard || newState != state) //this is to be safe if updateState changes the state
return;
@@ -1028,6 +1032,7 @@ QAbstractAnimation::~QAbstractAnimation()
if (d->state != Stopped) {
QAbstractAnimation::State oldState = d->state;
d->state = Stopped;
+ d->state.notify();
emit stateChanged(d->state, oldState);
if (oldState == QAbstractAnimation::Running)
QAnimationTimer::unregisterAnimation(this);
@@ -1043,6 +1048,11 @@ QAbstractAnimation::~QAbstractAnimation()
This property describes the current state of the animation. When the
animation state changes, QAbstractAnimation emits the stateChanged()
signal.
+
+ \note State updates might cause updates of the currentTime property,
+ which, in turn, can cancel its bindings. So be careful when setting
+ bindings to the currentTime property, when you expect the state of the
+ animation to change.
*/
QAbstractAnimation::State QAbstractAnimation::state() const
{
@@ -1050,6 +1060,12 @@ QAbstractAnimation::State QAbstractAnimation::state() const
return d->state;
}
+QBindable<QAbstractAnimation::State> QAbstractAnimation::bindableState() const
+{
+ Q_D(const QAbstractAnimation);
+ return &d->state;
+}
+
/*!
If this animation is part of a QAnimationGroup, this function returns a
pointer to the group; otherwise, it returns \nullptr.
@@ -1115,9 +1131,13 @@ QAbstractAnimation::Direction QAbstractAnimation::direction() const
void QAbstractAnimation::setDirection(Direction direction)
{
Q_D(QAbstractAnimation);
- if (d->direction == direction)
+ if (d->direction == direction) {
+ d->direction.removeBindingUnlessInWrapper();
return;
+ }
+ Qt::beginPropertyUpdateGroup();
+ const int oldCurrentLoop = d->currentLoop;
if (state() == Stopped) {
if (direction == Backward) {
d->currentTime = duration();
@@ -1140,7 +1160,16 @@ void QAbstractAnimation::setDirection(Direction direction)
// needed to update the timer interval in case of a pause animation
QAnimationTimer::updateAnimationTimer();
- emit directionChanged(direction);
+ if (d->currentLoop != oldCurrentLoop)
+ d->currentLoop.notify();
+ d->direction.notify();
+ Qt::endPropertyUpdateGroup();
+}
+
+QBindable<QAbstractAnimation::Direction> QAbstractAnimation::bindableDirection()
+{
+ Q_D(QAbstractAnimation);
+ return &d->direction;
}
/*!
@@ -1175,6 +1204,12 @@ void QAbstractAnimation::setLoopCount(int loopCount)
d->loopCount = loopCount;
}
+QBindable<int> QAbstractAnimation::bindableLoopCount()
+{
+ Q_D(QAbstractAnimation);
+ return &d->loopCount;
+}
+
/*!
\property QAbstractAnimation::currentLoop
\brief the current loop of the animation
@@ -1194,6 +1229,12 @@ int QAbstractAnimation::currentLoop() const
return d->currentLoop;
}
+QBindable<int> QAbstractAnimation::bindableCurrentLoop() const
+{
+ Q_D(const QAbstractAnimation);
+ return &d->currentLoop;
+}
+
/*!
\fn virtual int QAbstractAnimation::duration() const = 0
@@ -1252,6 +1293,10 @@ int QAbstractAnimation::currentLoopTime() const
The animation's current time starts at 0, and ends at totalDuration().
+ \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.
+
\sa loopCount, currentLoopTime()
*/
int QAbstractAnimation::currentTime() const
@@ -1259,6 +1304,13 @@ int QAbstractAnimation::currentTime() const
Q_D(const QAbstractAnimation);
return d->totalCurrentTime;
}
+
+QBindable<int> QAbstractAnimation::bindableCurrentTime()
+{
+ Q_D(QAbstractAnimation);
+ return &d->totalCurrentTime;
+}
+
void QAbstractAnimation::setCurrentTime(int msecs)
{
Q_D(QAbstractAnimation);
@@ -1269,6 +1321,8 @@ void QAbstractAnimation::setCurrentTime(int msecs)
int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
if (totalDura != -1)
msecs = qMin(totalDura, msecs);
+
+ const int oldCurrentTime = d->totalCurrentTime;
d->totalCurrentTime = msecs;
// Update new values.
@@ -1284,13 +1338,13 @@ void QAbstractAnimation::setCurrentTime(int msecs)
} else {
d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
if (d->currentTime == dura)
- --d->currentLoop;
+ d->currentLoop = d->currentLoop - 1;
}
}
updateCurrentTime(d->currentTime);
if (d->currentLoop != oldLoop)
- emit currentLoopChanged(d->currentLoop);
+ d->currentLoop.notify();
// All animations are responsible for stopping the animation when their
// own end state is reached; in this case the animation is time driven,
@@ -1299,6 +1353,8 @@ void QAbstractAnimation::setCurrentTime(int msecs)
|| (d->direction == Backward && d->totalCurrentTime == 0)) {
stop();
}
+ if (oldCurrentTime != d->totalCurrentTime)
+ d->totalCurrentTime.notify();
}
/*!
diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h
index 2bb1d52582..3165c2b049 100644
--- a/src/corelib/animation/qabstractanimation.h
+++ b/src/corelib/animation/qabstractanimation.h
@@ -55,11 +55,13 @@ class Q_CORE_EXPORT QAbstractAnimation : public QObject
{
Q_OBJECT
- Q_PROPERTY(State state READ state NOTIFY stateChanged)
- Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount)
- Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime)
- Q_PROPERTY(int currentLoop READ currentLoop NOTIFY currentLoopChanged)
- Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged)
+ Q_PROPERTY(State state READ state NOTIFY stateChanged BINDABLE bindableState)
+ Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount BINDABLE bindableLoopCount)
+ Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime BINDABLE bindableCurrentTime)
+ Q_PROPERTY(int currentLoop READ currentLoop NOTIFY currentLoopChanged
+ BINDABLE bindableCurrentLoop)
+ Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged
+ BINDABLE bindableDirection)
Q_PROPERTY(int duration READ duration)
public:
@@ -85,18 +87,25 @@ public:
virtual ~QAbstractAnimation();
State state() const;
+ QBindable<QAbstractAnimation::State> bindableState() const;
QAnimationGroup *group() const;
Direction direction() const;
void setDirection(Direction direction);
+ QBindable<Direction> bindableDirection();
int currentTime() const;
+ QBindable<int> bindableCurrentTime();
+
int currentLoopTime() const;
int loopCount() const;
void setLoopCount(int loopCount);
+ QBindable<int> bindableLoopCount();
+
int currentLoop() const;
+ QBindable<int> bindableCurrentLoop() const;
virtual int duration() const = 0;
int totalDuration() const;
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 9debb64424..6a94d2bb8a 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -56,6 +56,7 @@
#include <QtCore/qtimer.h>
#include <QtCore/qelapsedtimer.h>
#include <private/qobject_p.h>
+#include <private/qproperty_p.h>
#include <qabstractanimation.h>
QT_REQUIRE_CONFIG(animation);
@@ -74,14 +75,30 @@ public:
return q->d_func();
}
- QAbstractAnimation::State state = QAbstractAnimation::Stopped;
- QAbstractAnimation::Direction direction = QAbstractAnimation::Forward;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, QAbstractAnimation::State,
+ state, QAbstractAnimation::Stopped)
void setState(QAbstractAnimation::State state);
- int totalCurrentTime = 0;
+ void setDirection(QAbstractAnimation::Direction direction)
+ {
+ q_func()->setDirection(direction);
+ }
+ void emitDirectionChanged() { emit q_func()->directionChanged(direction); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, QAbstractAnimation::Direction,
+ direction, &QAbstractAnimationPrivate::setDirection,
+ &QAbstractAnimationPrivate::emitDirectionChanged,
+ QAbstractAnimation::Forward)
+
+ void setCurrentTime(int msecs) { q_func()->setCurrentTime(msecs); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, int, totalCurrentTime,
+ &QAbstractAnimationPrivate::setCurrentTime, 0)
int currentTime = 0;
- int loopCount = 1;
- int currentLoop = 0;
+
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, int, loopCount, 1)
+
+ void emitCurrentLoopChanged() { emit q_func()->currentLoopChanged(currentLoop); }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, int, currentLoop, nullptr,
+ &QAbstractAnimationPrivate::emitCurrentLoopChanged, 0)
bool deleteWhenStopped = false;
bool hasRegisteredTimer = false;
diff --git a/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt b/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt
index 7db3ef9462..1ab378546d 100644
--- a/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt
+++ b/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt
@@ -7,4 +7,6 @@
qt_internal_add_test(tst_qabstractanimation
SOURCES
tst_qabstractanimation.cpp
+ LIBRARIES
+ Qt::TestPrivate
)
diff --git a/tests/auto/corelib/animation/qabstractanimation/tst_qabstractanimation.cpp b/tests/auto/corelib/animation/qabstractanimation/tst_qabstractanimation.cpp
index b9cf91444f..65e57e2d84 100644
--- a/tests/auto/corelib/animation/qabstractanimation/tst_qabstractanimation.cpp
+++ b/tests/auto/corelib/animation/qabstractanimation/tst_qabstractanimation.cpp
@@ -30,6 +30,7 @@
#include <QtCore/qabstractanimation.h>
#include <QtCore/qanimationgroup.h>
#include <QTest>
+#include <QtTest/private/qpropertytesthelper_p.h>
class tst_QAbstractAnimation : public QObject
{
@@ -48,6 +49,11 @@ private slots:
void avoidJumpAtStart();
void avoidJumpAtStartWithStop();
void avoidJumpAtStartWithRunning();
+ void stateBinding();
+ void loopCountBinding();
+ void currentTimeBinding();
+ void currentLoopBinding();
+ void directionBinding();
};
class TestableQAbstractAnimation : public QAbstractAnimation
@@ -56,7 +62,7 @@ class TestableQAbstractAnimation : public QAbstractAnimation
public:
TestableQAbstractAnimation() : m_duration(10) {}
- virtual ~TestableQAbstractAnimation() {};
+ virtual ~TestableQAbstractAnimation() override { }
int duration() const override { return m_duration; }
virtual void updateCurrentTime(int) override {}
@@ -228,6 +234,89 @@ void tst_QAbstractAnimation::avoidJumpAtStartWithRunning()
QVERIFY(anim3.currentTime() < 50);
}
+void tst_QAbstractAnimation::stateBinding()
+{
+ TestableQAbstractAnimation animation;
+ QTestPrivate::testReadOnlyPropertyBasics(animation, QAbstractAnimation::Stopped,
+ QAbstractAnimation::Running, "state",
+ [&] { animation.start(); });
+}
+
+void tst_QAbstractAnimation::loopCountBinding()
+{
+ TestableQAbstractAnimation animation;
+ QTestPrivate::testReadWritePropertyBasics(animation, 42, 43, "loopCount");
+}
+
+void tst_QAbstractAnimation::currentTimeBinding()
+{
+ TestableQAbstractAnimation animation;
+
+ QProperty<int> currentTimeProperty;
+ animation.bindableCurrentTime().setBinding(Qt::makePropertyBinding(currentTimeProperty));
+ QCOMPARE(animation.currentTime(), currentTimeProperty);
+
+ // This should cancel the binding
+ animation.start();
+
+ currentTimeProperty = 5;
+ QVERIFY(animation.currentTime() != currentTimeProperty);
+
+ QTestPrivate::testReadWritePropertyBasics(animation, 6, 7, "currentTime");
+}
+
+void tst_QAbstractAnimation::currentLoopBinding()
+{
+ TestableQAbstractAnimation animation;
+
+ QTestPrivate::testReadOnlyPropertyBasics(animation, 0, 3, "currentLoop", [&] {
+ // Trigger an update of currentLoop
+ animation.setLoopCount(4);
+ // This brings us to the end of the animation, so currentLoop should be loopCount - 1
+ animation.setCurrentTime(42);
+ });
+}
+
+void tst_QAbstractAnimation::directionBinding()
+{
+ TestableQAbstractAnimation animation;
+ QTestPrivate::testReadWritePropertyBasics(animation, QAbstractAnimation::Backward,
+ QAbstractAnimation::Forward, "direction");
+
+ // setDirection() may trigger a currentLoop update. Make sure the observers
+ // are notified about direction and currentLoop changes only after a consistent
+ // state is reached.
+ QProperty<int> currLoopObserver;
+ currLoopObserver.setBinding([&] { return animation.currentLoop(); });
+
+ QProperty<QAbstractAnimation::Direction> directionObserver;
+ directionObserver.setBinding([&] { return animation.direction(); });
+
+ animation.setLoopCount(10);
+
+ bool currentLoopChanged = false;
+ auto currentLoopHandler = animation.bindableCurrentLoop().onValueChanged([&] {
+ QVERIFY(!currentLoopChanged);
+ QCOMPARE(currLoopObserver, 9);
+ QCOMPARE(directionObserver, QAbstractAnimation::Backward);
+ currentLoopChanged = true;
+ });
+
+ bool directionChanged = false;
+ auto directionHandler = animation.bindableDirection().onValueChanged([&] {
+ QVERIFY(!directionChanged);
+ QCOMPARE(currLoopObserver, 9);
+ QCOMPARE(directionObserver, QAbstractAnimation::Backward);
+ directionChanged = true;
+ });
+
+ QCOMPARE(animation.direction(), QAbstractAnimation::Forward);
+ // This will set currentLoop to 9
+ animation.setDirection(QAbstractAnimation::Backward);
+
+ QVERIFY(currentLoopChanged);
+ QVERIFY(directionChanged);
+}
QTEST_MAIN(tst_QAbstractAnimation)