Allow AnimatedSprite to finish on the last frame

[ChangeLog][AnimatedSprite] Add finishBehavior to allow a sprite to
finish on the last frame.

Task-number: QTBUG-59090
Change-Id: Id45e879cdc4905f43e2ac3cb2529181390d47aab
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
Michael Brasser 2019-10-29 09:45:54 -05:00
parent c18d261971
commit 2c6966c775
5 changed files with 91 additions and 4 deletions

View File

@ -262,6 +262,19 @@ QT_BEGIN_NAMESPACE
*/
/*!
\qmlproperty enumeration QtQuick::AnimatedSprite::finishBehavior
The behavior when the animation finishes on its own.
\value FinishAtInitialFrame
When the animation finishes it returns to the initial frame.
This is the default behavior.
\value FinishAtFinalFrame
When the animation finishes it stays on the final frame.
*/
/*!
\qmlmethod int QtQuick::AnimatedSprite::restart()
@ -381,6 +394,12 @@ int QQuickAnimatedSprite::currentFrame() const
return d->m_curFrame;
}
QQuickAnimatedSprite::FinishBehavior QQuickAnimatedSprite::finishBehavior() const
{
Q_D(const QQuickAnimatedSprite);
return d->m_finishBehavior;
}
bool QQuickAnimatedSprite::isCurrentFrameChangedConnected()
{
IS_SIGNAL_CONNECTED(this, QQuickAnimatedSprite, currentFrameChanged, (int));
@ -704,6 +723,16 @@ void QQuickAnimatedSprite::setCurrentFrame(int arg) //TODO-C: Probably only work
}
}
void QQuickAnimatedSprite::setFinishBehavior(FinishBehavior arg)
{
Q_D(QQuickAnimatedSprite);
if (d->m_finishBehavior != arg) {
d->m_finishBehavior = arg;
Q_EMIT finishBehaviorChanged(arg);
}
}
void QQuickAnimatedSprite::createEngine()
{
Q_D(QQuickAnimatedSprite);
@ -838,7 +867,11 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
progress = 0;
}
if (d->m_loops > 0 && d->m_curLoop >= d->m_loops) {
frameAt = 0;
if (d->m_finishBehavior == FinishAtInitialFrame)
frameAt = 0;
else
frameAt = frameCount() - 1;
d->m_curFrame = frameAt;
d->m_running = false;
emit runningChanged(false);
emit finished();

View File

@ -92,6 +92,7 @@ class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem
Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged)
Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged)
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged)
Q_PROPERTY(FinishBehavior finishBehavior READ finishBehavior WRITE setFinishBehavior NOTIFY finishBehaviorChanged REVISION 15)
QML_NAMED_ELEMENT(AnimatedSprite)
public:
@ -101,6 +102,12 @@ public:
};
Q_ENUM(LoopParameters)
enum FinishBehavior {
FinishAtInitialFrame,
FinishAtFinalFrame
};
Q_ENUM(FinishBehavior)
bool running() const;
bool interpolate() const;
QUrl source() const;
@ -116,6 +123,7 @@ public:
int loops() const;
bool paused() const;
int currentFrame() const;
FinishBehavior finishBehavior() const;
Q_SIGNALS:
@ -135,6 +143,7 @@ Q_SIGNALS:
void frameDurationChanged(int arg);
void loopsChanged(int arg);
void currentFrameChanged(int arg);
Q_REVISION(15) void finishBehaviorChanged(FinishBehavior arg);
Q_REVISION(12) void finished();
@ -163,7 +172,7 @@ public Q_SLOTS:
void resetFrameDuration();
void setLoops(int arg);
void setCurrentFrame(int arg);
void setFinishBehavior(FinishBehavior arg);
private Q_SLOTS:
void createEngine();

View File

@ -57,11 +57,10 @@ QT_REQUIRE_CONFIG(quick_sprite);
#include "qquickitem_p.h"
#include "qquicksprite_p.h"
#include "qquickanimatedsprite_p.h"
QT_BEGIN_NAMESPACE
class QQuickAnimatedSprite;
class QQuickAnimatedSpritePrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickAnimatedSprite)
@ -78,6 +77,7 @@ public:
, m_loops(-1)
, m_curLoop(0)
, m_pauseOffset(0)
, m_finishBehavior(QQuickAnimatedSprite::FinishAtInitialFrame)
{
}
@ -93,6 +93,7 @@ public:
int m_loops;
int m_curLoop;
int m_pauseOffset;
QQuickAnimatedSprite::FinishBehavior m_finishBehavior;
};
QT_END_NAMESPACE

View File

@ -0,0 +1,18 @@
import QtQuick 2.15
Rectangle {
color: "black"
width: 320
height: 320
AnimatedSprite {
objectName: "sprite"
loops: 1
source: "squarefacesprite.png"
frameCount: 6
frameDuration: 64
width: 160
height: 160
finishBehavior: AnimatedSprite.FinishAtFinalFrame
}
}

View File

@ -57,6 +57,7 @@ private slots:
void test_changeSourceToSmallerImgKeepingBigFrameSize();
void test_infiniteLoops();
void test_implicitSize();
void test_finishBehavior();
};
void tst_qquickanimatedsprite::initTestCase()
@ -428,6 +429,31 @@ void tst_qquickanimatedsprite::test_infiniteLoops()
QCOMPARE(finishedSpy.count(), 0);
}
void tst_qquickanimatedsprite::test_finishBehavior()
{
QQuickView window;
window.setSource(testFileUrl("finishBehavior.qml"));
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QVERIFY(window.rootObject());
QQuickAnimatedSprite* sprite = window.rootObject()->findChild<QQuickAnimatedSprite*>("sprite");
QVERIFY(sprite);
QTRY_VERIFY(sprite->running());
// correctly stops at last frame
QSignalSpy finishedSpy(sprite, SIGNAL(finished()));
QVERIFY(finishedSpy.wait(2000));
QCOMPARE(sprite->running(), false);
QCOMPARE(sprite->currentFrame(), 5);
// correctly starts a second time
sprite->start();
QTRY_VERIFY(sprite->running());
QTRY_COMPARE(sprite->currentFrame(), 5);
}
QTEST_MAIN(tst_qquickanimatedsprite)
#include "tst_qquickanimatedsprite.moc"