Port QAbstractAnimation to the new property system
Task-number: QTBUG-85520 Change-Id: I2710c314b8c32b03fccb826fd78482ee7095fdda Reviewed-by: Andreas Buhr <andreas.buhr@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
31f90e99b8
commit
a67002dc5b
@ -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();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -7,4 +7,6 @@
|
||||
qt_internal_add_test(tst_qabstractanimation
|
||||
SOURCES
|
||||
tst_qabstractanimation.cpp
|
||||
LIBRARIES
|
||||
Qt::TestPrivate
|
||||
)
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user