aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hartmann <thomas.hartmann@qt.io>2018-04-23 18:02:15 +0200
committerTim Jenssen <tim.jenssen@qt.io>2018-04-27 14:07:23 +0000
commitb2cd5db1e5bfcd168bce025b126d4c5a2fc9e0ae (patch)
tree5c7c4af9e7c536d1172271b6b2f7849668778c27
parente60155d6af1a9e1c86bfb7679dbd92ce616ad8fd (diff)
Add TimelineAnimation
* New api to define animation clips * Special animation type for timeline * Adding ping pong for TimelineAnimation * Adjusting manual tests * Adding new manual tests Change-Id: Ic670b389062ef4ac92e000bc99574e5fa04a7006 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r--src/imports/timeline/plugins.qmltypes101
-rw-r--r--src/imports/timeline/qquicktimeline.cpp58
-rw-r--r--src/imports/timeline/qquicktimeline_p.h5
-rw-r--r--src/imports/timeline/qquicktimelineanimation.cpp112
-rw-r--r--src/imports/timeline/qquicktimelineanimation_p.h55
-rw-r--r--src/imports/timeline/qtquicktimelineplugin.cpp4
-rw-r--r--src/imports/timeline/timeline.pri6
-rw-r--r--tests/manual/timelineTestApp/main.qml18
-rw-r--r--tests/manual/timelineTestApp/qml.qrc2
-rw-r--r--tests/manual/timelineTestApp/test01.qml24
-rw-r--r--tests/manual/timelineTestApp/test02.qml18
-rw-r--r--tests/manual/timelineTestApp/test04.qml222
-rw-r--r--tests/manual/timelineTestApp/test05.qml266
13 files changed, 858 insertions, 33 deletions
diff --git a/src/imports/timeline/plugins.qmltypes b/src/imports/timeline/plugins.qmltypes
index a795dd0..b77b587 100644
--- a/src/imports/timeline/plugins.qmltypes
+++ b/src/imports/timeline/plugins.qmltypes
@@ -9,6 +9,44 @@ import QtQuick.tooling 1.2
Module {
dependencies: []
Component {
+ name: "QQuickAbstractAnimation"
+ prototype: "QObject"
+ Enum {
+ name: "Loops"
+ values: {
+ "Infinite": -2
+ }
+ }
+ Property { name: "running"; type: "bool" }
+ Property { name: "paused"; type: "bool" }
+ Property { name: "alwaysRunToEnd"; type: "bool" }
+ Property { name: "loops"; type: "int" }
+ Signal { name: "started" }
+ Signal { name: "stopped" }
+ Signal {
+ name: "runningChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "pausedChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "alwaysRunToEndChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "loopCountChanged"
+ Parameter { type: "int" }
+ }
+ Method { name: "restart" }
+ Method { name: "start" }
+ Method { name: "pause" }
+ Method { name: "resume" }
+ Method { name: "stop" }
+ Method { name: "complete" }
+ }
+ Component {
name: "QQuickKeyframe"
prototype: "QObject"
exports: ["QtQuick.Timeline/Keyframe 1.0"]
@@ -19,6 +57,55 @@ Module {
Signal { name: "easingCurveChanged" }
}
Component {
+ name: "QQuickKeyframeGroup"
+ defaultProperty: "keyframes"
+ prototype: "QObject"
+ exports: ["QtQuick.Timeline/KeyframeGroup 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "target"; type: "QObject"; isPointer: true }
+ Property { name: "property"; type: "string" }
+ Property { name: "keyframes"; type: "QQuickKeyframe"; isList: true; isReadonly: true }
+ }
+ Component {
+ name: "QQuickNumberAnimation"
+ prototype: "QQuickPropertyAnimation"
+ Property { name: "from"; type: "double" }
+ Property { name: "to"; type: "double" }
+ }
+ Component {
+ name: "QQuickPropertyAnimation"
+ prototype: "QQuickAbstractAnimation"
+ Property { name: "duration"; type: "int" }
+ Property { name: "from"; type: "QVariant" }
+ Property { name: "to"; type: "QVariant" }
+ Property { name: "easing"; type: "QEasingCurve" }
+ Property { name: "target"; type: "QObject"; isPointer: true }
+ Property { name: "property"; type: "string" }
+ Property { name: "properties"; type: "string" }
+ Property { name: "targets"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "exclude"; type: "QObject"; isList: true; isReadonly: true }
+ Signal {
+ name: "durationChanged"
+ Parameter { type: "int" }
+ }
+ Signal {
+ name: "fromChanged"
+ Parameter { type: "QVariant" }
+ }
+ Signal {
+ name: "toChanged"
+ Parameter { type: "QVariant" }
+ }
+ Signal {
+ name: "easingChanged"
+ Parameter { type: "QEasingCurve" }
+ }
+ Signal {
+ name: "propertiesChanged"
+ Parameter { type: "string" }
+ }
+ }
+ Component {
name: "QQuickTimeline"
defaultProperty: "keyframes"
prototype: "QObject"
@@ -28,16 +115,16 @@ Module {
Property { name: "endFrame"; type: "double" }
Property { name: "currentFrame"; type: "double" }
Property { name: "keyframes"; type: "QQuickKeyframeGroup"; isList: true; isReadonly: true }
+ Property { name: "animations"; type: "QQuickTimelineAnimation"; isList: true; isReadonly: true }
Property { name: "enabled"; type: "bool" }
}
Component {
- name: "QQuickKeyframeGroup"
- defaultProperty: "keyframes"
- prototype: "QObject"
- exports: ["QtQuick.Timeline/KeyframeGroup 1.0"]
+ name: "QQuickTimelineAnimation"
+ prototype: "QQuickNumberAnimation"
+ exports: ["QtQuick.Timeline/TimelineAnimation 1.0"]
exportMetaObjectRevisions: [0]
- Property { name: "target"; type: "QObject"; isPointer: true }
- Property { name: "property"; type: "string" }
- Property { name: "keyframes"; type: "QQuickKeyframe"; isList: true; isReadonly: true }
+ Property { name: "pingPong"; type: "bool" }
+ Signal { name: "finished" }
+ Signal { name: "pingPongChanged" }
}
}
diff --git a/src/imports/timeline/qquicktimeline.cpp b/src/imports/timeline/qquicktimeline.cpp
index 52f9a32..d5e5b26 100644
--- a/src/imports/timeline/qquicktimeline.cpp
+++ b/src/imports/timeline/qquicktimeline.cpp
@@ -53,7 +53,14 @@ protected:
static QQuickKeyframeGroup* keyframe_at(QQmlListProperty<QQuickKeyframeGroup> *list, int pos);
static void clear_keyframes(QQmlListProperty<QQuickKeyframeGroup> *list);
+ static void append_animation(QQmlListProperty<QQuickTimelineAnimation> *list, QQuickTimelineAnimation *a);
+ static int animation_count(QQmlListProperty<QQuickTimelineAnimation> *list);
+ static QQuickTimelineAnimation* animation_at(QQmlListProperty<QQuickTimelineAnimation> *list, int pos);
+ static void clear_animations(QQmlListProperty<QQuickTimelineAnimation> *list);
+
+
QList<QQuickKeyframeGroup *> keyframes;
+ QList<QQuickTimelineAnimation *> animations;
};
void QQuickTimelinePrivate::init()
@@ -97,6 +104,34 @@ void QQuickTimelinePrivate::clear_keyframes(QQmlListProperty<QQuickKeyframeGroup
}
}
+void QQuickTimelinePrivate::append_animation(QQmlListProperty<QQuickTimelineAnimation> *list, QQuickTimelineAnimation *a)
+{
+ QQuickTimeline *q = static_cast<QQuickTimeline *>(list->object);
+ a->setTargetObject(q);
+ q->d_func()->animations.append(a);
+}
+
+int QQuickTimelinePrivate::animation_count(QQmlListProperty<QQuickTimelineAnimation> *list)
+{
+ QQuickTimeline *q = static_cast<QQuickTimeline *>(list->object);
+ return q->d_func()->animations.count();
+}
+
+QQuickTimelineAnimation* QQuickTimelinePrivate::animation_at(QQmlListProperty<QQuickTimelineAnimation> *list, int pos)
+{
+ QQuickTimeline *q = static_cast<QQuickTimeline *>(list->object);
+ return q->d_func()->animations.at(pos);
+}
+
+void QQuickTimelinePrivate::clear_animations(QQmlListProperty<QQuickTimelineAnimation> *list)
+{
+ QQuickTimeline *q = static_cast<QQuickTimeline *>(list->object);
+ while (q->d_func()->animations.count()) {
+ QQuickTimelineAnimation *firstAnimation = q->d_func()->animations.at(0);
+ q->d_func()->animations.removeAll(firstAnimation);
+ }
+}
+
QQuickTimeline::QQuickTimeline(QObject *parent) : QObject(*(new QQuickTimelinePrivate), parent)
{
@@ -107,9 +142,19 @@ QQmlListProperty<QQuickKeyframeGroup> QQuickTimeline::keyframes()
Q_D(QQuickTimeline);
return QQmlListProperty<QQuickKeyframeGroup>(this, &d->keyframes, QQuickTimelinePrivate::append_keyframe,
- QQuickTimelinePrivate::keyframe_count,
- QQuickTimelinePrivate::keyframe_at,
- QQuickTimelinePrivate::clear_keyframes);
+ QQuickTimelinePrivate::keyframe_count,
+ QQuickTimelinePrivate::keyframe_at,
+ QQuickTimelinePrivate::clear_keyframes);
+}
+
+QQmlListProperty<QQuickTimelineAnimation> QQuickTimeline::animations()
+{
+ Q_D(QQuickTimeline);
+
+ return QQmlListProperty<QQuickTimelineAnimation>(this, &d->animations, QQuickTimelinePrivate::append_animation,
+ QQuickTimelinePrivate::animation_count,
+ QQuickTimelinePrivate::animation_at,
+ QQuickTimelinePrivate::clear_animations);
}
bool QQuickTimeline::enabled() const
@@ -201,6 +246,13 @@ void QQuickTimeline::reset()
d->disable();
}
+QList<QQuickTimelineAnimation *> QQuickTimeline::getAnimations() const
+{
+ Q_D(const QQuickTimeline);
+
+ return d->animations;
+}
+
void QQuickTimeline::classBegin()
{
Q_D(QQuickTimeline);
diff --git a/src/imports/timeline/qquicktimeline_p.h b/src/imports/timeline/qquicktimeline_p.h
index b4c2567..e09daff 100644
--- a/src/imports/timeline/qquicktimeline_p.h
+++ b/src/imports/timeline/qquicktimeline_p.h
@@ -31,6 +31,7 @@
//
#include "qquickkeyframe_p.h"
+#include "qquicktimelineanimation_p.h"
#include <QtQml/qqml.h>
@@ -49,6 +50,7 @@ class QQuickTimeline : public QObject, public QQmlParserStatus
Q_PROPERTY(qreal endFrame READ endFrame WRITE setEndFrame NOTIFY endFrameChanged)
Q_PROPERTY(qreal currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged)
Q_PROPERTY(QQmlListProperty<QQuickKeyframeGroup> keyframes READ keyframes)
+ Q_PROPERTY(QQmlListProperty<QQuickTimelineAnimation> animations READ animations)
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
Q_CLASSINFO("DefaultProperty", "keyframes")
@@ -57,6 +59,7 @@ public:
explicit QQuickTimeline(QObject *parent = nullptr);
QQmlListProperty<QQuickKeyframeGroup> keyframes();
+ QQmlListProperty<QQuickTimelineAnimation> animations();
bool enabled() const;
void setEnabled(bool enabled);
@@ -73,6 +76,8 @@ public:
void init();
void reset();
+ QList<QQuickTimelineAnimation*> getAnimations() const;
+
protected:
void classBegin() override;
void componentComplete() override;
diff --git a/src/imports/timeline/qquicktimelineanimation.cpp b/src/imports/timeline/qquicktimelineanimation.cpp
new file mode 100644
index 0000000..e3a816e
--- /dev/null
+++ b/src/imports/timeline/qquicktimelineanimation.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of the Qt Enterprise Qt Quick Timeline Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#include "qquicktimelineanimation_p.h"
+
+#include "qquicktimeline_p.h"
+
+#include <private/qobject_p.h>
+#include <private/qquickanimation_p_p.h>
+
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+
+QQuickTimelineAnimation::QQuickTimelineAnimation(QObject *parent) : QQuickNumberAnimation(parent)
+{
+ setProperty(QLatin1String("currentFrame"));
+ connect(this, &QQuickAbstractAnimation::started, this, &QQuickTimelineAnimation::handleStarted);
+ connect(this, &QQuickAbstractAnimation::stopped, this, &QQuickTimelineAnimation::handleStopped);
+}
+
+void QQuickTimelineAnimation::setPingPong(bool b)
+{
+ if (b == m_pinpong)
+ return;
+
+ m_pinpong = b;
+ emit pingPongChanged();
+}
+
+bool QQuickTimelineAnimation::pingPong() const
+{
+ return m_pinpong;
+}
+
+void QQuickTimelineAnimation::handleStarted()
+{
+ QQuickTimeline* timeline = qobject_cast<QQuickTimeline*>(parent());
+
+ if (!timeline)
+ return;
+
+ for (QQuickTimelineAnimation *other : timeline->getAnimations()) {
+ if (other != this)
+ other->stop();
+ }
+
+ auto *privateObject = static_cast<QQuickPropertyAnimationPrivate*>(QObjectPrivate::get(this));
+
+ if (m_pinpong && m_originalStart) {
+ m_originalLoop = privateObject->loopCount;
+ m_currentLoop = 0;
+ privateObject->loopCount = 1;
+ privateObject->animationInstance->setLoopCount(1);
+ m_originalStart = false;
+ m_reversed = false;
+ }
+}
+
+static void swapStartEnd(QQuickPropertyAnimationPrivate *privateObject)
+{
+ std::swap(privateObject->to, privateObject->from);
+}
+
+void QQuickTimelineAnimation::handleStopped()
+{
+ if (!m_pinpong) {
+ emit finished();
+ return;
+ }
+
+ auto *privateObject = static_cast<QQuickPropertyAnimationPrivate*>(QObjectPrivate::get(this));
+
+ if (m_reversed) {
+ m_currentLoop++;
+ }
+
+ if (!(privateObject->animationInstance->currentTime() < privateObject->duration)
+ && (m_currentLoop < m_originalLoop
+ || m_originalLoop == -1)) {
+ swapStartEnd(privateObject);
+
+ m_reversed = !m_reversed;
+ QQuickTimelineAnimation::start();
+
+ } else {
+ if (m_reversed) {
+ swapStartEnd(privateObject);
+ }
+ m_originalStart = true;
+ m_reversed = false;
+ privateObject->loopCount = m_originalLoop;
+ emit finished();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/timeline/qquicktimelineanimation_p.h b/src/imports/timeline/qquicktimelineanimation_p.h
new file mode 100644
index 0000000..ee85b65
--- /dev/null
+++ b/src/imports/timeline/qquicktimelineanimation_p.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of the Qt Enterprise Qt Quick Timeline Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+#ifndef QQUICKTIMELINEANIMATION_H
+#define QQUICKTIMELINEANIMATION_H
+
+#include <QtQuick/private/qquickanimation_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTimelineAnimation : public QQuickNumberAnimation
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool pingPong READ pingPong WRITE setPingPong NOTIFY pingPongChanged)
+
+public:
+ QQuickTimelineAnimation(QObject *parent = nullptr);
+
+ void setPingPong(bool b);
+ bool pingPong() const;
+
+Q_SIGNALS:
+ void pingPongChanged();
+ void finished();
+
+private:
+ void handleStarted();
+ void handleStopped();
+
+ bool m_pinpong = false;
+ bool m_reversed = false;
+ bool m_originalStart = true;
+ int m_currentLoop = 0;
+ int m_originalLoop = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTIMELINEANIMATION_H
diff --git a/src/imports/timeline/qtquicktimelineplugin.cpp b/src/imports/timeline/qtquicktimelineplugin.cpp
index b1cb0dc..35f47bd 100644
--- a/src/imports/timeline/qtquicktimelineplugin.cpp
+++ b/src/imports/timeline/qtquicktimelineplugin.cpp
@@ -18,8 +18,9 @@
#include <QtQml/qqmlextensionplugin.h>
-#include "qquicktimeline_p.h"
#include "qquickkeyframe_p.h"
+#include "qquicktimeline_p.h"
+#include "qquicktimelineanimation_p.h"
static inline void initResources()
{
@@ -50,6 +51,7 @@ QtQuickTimelinePlugin::QtQuickTimelinePlugin(QObject *parent) : QQmlExtensionPlu
void QtQuickTimelinePlugin::registerTypes(const char *uri)
{
qmlRegisterType<QQuickTimeline>(uri, 1, 0, "Timeline");
+ qmlRegisterType<QQuickTimelineAnimation>(uri, 1, 0, "TimelineAnimation");
qmlRegisterType<QQuickKeyframe>(uri, 1, 0, "Keyframe");
qmlRegisterType<QQuickKeyframeGroup>(uri, 1, 0, "KeyframeGroup");
}
diff --git a/src/imports/timeline/timeline.pri b/src/imports/timeline/timeline.pri
index 5aa0999..2d1d363 100644
--- a/src/imports/timeline/timeline.pri
+++ b/src/imports/timeline/timeline.pri
@@ -1,7 +1,9 @@
HEADERS += \
$$PWD/qquickkeyframe_p.h \
- $$PWD/qquicktimeline_p.h
+ $$PWD/qquicktimeline_p.h \
+ $$PWD/qquicktimelineanimation_p.h
SOURCES += \
$$PWD/qquickkeyframe.cpp \
- $$PWD/qquicktimeline.cpp
+ $$PWD/qquicktimeline.cpp \
+ $$PWD/qquicktimelineanimation.cpp
diff --git a/tests/manual/timelineTestApp/main.qml b/tests/manual/timelineTestApp/main.qml
index 8b43d52..64416dd 100644
--- a/tests/manual/timelineTestApp/main.qml
+++ b/tests/manual/timelineTestApp/main.qml
@@ -61,5 +61,23 @@ Window {
onClicked: loader.source = "test03.qml"
}
}
+
+ Text {
+ text: "Test 04"
+ font.pixelSize: 12
+ MouseArea {
+ anchors.fill: parent
+ onClicked: loader.source = "test04.qml"
+ }
+ }
+
+ Text {
+ text: "Test 05"
+ font.pixelSize: 12
+ MouseArea {
+ anchors.fill: parent
+ onClicked: loader.source = "test05.qml"
+ }
+ }
}
}
diff --git a/tests/manual/timelineTestApp/qml.qrc b/tests/manual/timelineTestApp/qml.qrc
index 4da9ddc..0fffb97 100644
--- a/tests/manual/timelineTestApp/qml.qrc
+++ b/tests/manual/timelineTestApp/qml.qrc
@@ -4,5 +4,7 @@
<file>test01.qml</file>
<file>test02.qml</file>
<file>test03.qml</file>
+ <file>test04.qml</file>
+ <file>test05.qml</file>
</qresource>
</RCC>
diff --git a/tests/manual/timelineTestApp/test01.qml b/tests/manual/timelineTestApp/test01.qml
index d0810aa..d395bbd 100644
--- a/tests/manual/timelineTestApp/test01.qml
+++ b/tests/manual/timelineTestApp/test01.qml
@@ -37,21 +37,10 @@ Item {
color: "blue"
MouseArea {
anchors.fill: parent
- onClicked: animation.start()
+ onClicked: animation.restart()
}
}
- NumberAnimation {
- id: animation
- target: timeline
- property: "currentFrame"
- easing.type: Easing.InOutQuad
- duration: 2000
- from: 0
- to: 100
- running: true
- }
-
Item {
width: 480
height: 480
@@ -65,6 +54,17 @@ Item {
enabled: true
+ animations: [
+ TimelineAnimation {
+ id: animation
+ duration: 2000
+ from: 0
+ to: 100
+ running: false
+ }
+
+ ]
+
KeyframeGroup {
target: rectangle
property: "x"
diff --git a/tests/manual/timelineTestApp/test02.qml b/tests/manual/timelineTestApp/test02.qml
index 861fe45..7d27a21 100644
--- a/tests/manual/timelineTestApp/test02.qml
+++ b/tests/manual/timelineTestApp/test02.qml
@@ -20,14 +20,6 @@ import QtQuick 2.0
import QtQuick.Timeline 1.0
Item {
- PropertyAnimation {
- running: true
- duration: 1000
- target: timeline
- property: "currentFrame"
- from: 0
- to: 1000
- }
Rectangle {
id: leftGauge
@@ -82,6 +74,16 @@ Item {
startFrame: 0
endFrame: 1000
+ animations: [
+
+ TimelineAnimation {
+ running: true
+ duration: 1000
+ from: 0
+ to: 1000
+ }
+ ]
+
KeyframeGroup {
target: leftGauge
property: "x"
diff --git a/tests/manual/timelineTestApp/test04.qml b/tests/manual/timelineTestApp/test04.qml
new file mode 100644
index 0000000..be09f49
--- /dev/null
+++ b/tests/manual/timelineTestApp/test04.qml
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of the Qt Enterprise Qt Quick Timeline Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Timeline 1.0
+
+Item {
+ id: item1
+ state: "pingpong"
+
+ Timeline {
+ id: timeline
+ enabled: true
+ startFrame: 0
+ endFrame: 1000
+ animations: [
+ TimelineAnimation {
+ id: pingPongAnimation
+ to: 200
+ loops: 2
+ from: 0
+ duration: 2000
+ running: false
+ pingPong: true
+ onFinished: item1.state = "firsthalf"
+ },
+
+ TimelineAnimation {
+ id: animation01
+ to: 200
+ loops: 1
+ from: 0
+ duration: 1000
+ running: false
+ onFinished: item1.state = "secondhalf (ping pong)"
+ },
+ TimelineAnimation {
+ id: animation02
+ to: 400
+ loops: 1
+ from: 200
+ duration: 1000
+ running: false
+ pingPong: true
+ onFinished: item1.state = "last"
+ },
+ TimelineAnimation {
+ id: animation03
+ to: 0
+ loops: 1
+ from: 200
+ duration: 500
+ running: false
+ onFinished: item1.state = "pingpong"
+ }
+ ]
+
+ KeyframeGroup {
+ target: rectangle
+ property: "width"
+ Keyframe {
+ frame: 1
+ value: 50
+ }
+ }
+
+ KeyframeGroup {
+ target: rectangle
+ property: "height"
+ Keyframe {
+ frame: 1
+ value: 50
+ }
+ }
+
+ KeyframeGroup {
+ target: rectangle
+ property: "x"
+ Keyframe {
+ frame: 100
+ value: 100
+ }
+
+ Keyframe {
+ frame: 200
+ value: 200
+ }
+
+ Keyframe {
+ frame: 300
+ value: 100
+ }
+
+ Keyframe {
+ frame: 400
+ value: 0
+ }
+ }
+
+ KeyframeGroup {
+ target: rectangle
+ property: "y"
+ Keyframe {
+ frame: 100
+ value: 400
+ }
+
+ Keyframe {
+ frame: 200
+ value: 430
+ }
+
+ Keyframe {
+ frame: 300
+ value: 335
+ }
+
+ Keyframe {
+ frame: 400
+ value: 430
+ }
+ }
+
+ KeyframeGroup {
+ target: rectangle
+ property: "color"
+
+ Keyframe {
+ frame: 400
+ value: "#f61b1b"
+ }
+ }
+ }
+
+ Rectangle {
+ id: rectangle
+ x: 0
+ y: 430
+ width: 50
+ height: 50
+ color: "#f61b1b"
+ MouseArea {
+ anchors.topMargin: 109
+ anchors.fill: parent
+ onClicked: {
+ print("clicked")
+ numberAnimation.start()
+ }
+ }
+ }
+
+ Rectangle {
+ id: rectangle1
+ x: 0
+ y: 0
+ width: 85
+ height: 85
+ color: "#22f4dd"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ print("clicked")
+ numberAnimation.stop()
+ }
+ }
+ }
+
+ Text {
+ id: text1
+ x: 376
+ y: 18
+ text: item1.state
+ font.pixelSize: 12
+ }
+ states: [
+ State {
+ name: "pingpong"
+
+ PropertyChanges {
+ target: pingPongAnimation
+ running: true
+ }
+ },
+ State {
+ name: "firsthalf"
+ PropertyChanges {
+ target: animation01
+ running: true
+ }
+ },
+ State {
+ name: "secondhalf (ping pong)"
+ PropertyChanges {
+ target: animation02
+ running: true
+ }
+ },
+ State {
+ name: "last"
+ PropertyChanges {
+ target: animation03
+ running: true
+ }
+ }
+ ]
+
+}
diff --git a/tests/manual/timelineTestApp/test05.qml b/tests/manual/timelineTestApp/test05.qml
new file mode 100644
index 0000000..5464556
--- /dev/null
+++ b/tests/manual/timelineTestApp/test05.qml
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd
+** All rights reserved.
+** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us
+**
+** This file is part of the Qt Enterprise Qt Quick Timeline Add-on.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://www.qt.io/contact-us
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtQuick.Timeline 1.0
+
+Item {
+ width: 640
+ height: 480
+
+ id: root
+
+ state: "page02"
+
+ Rectangle {
+ id: rectangle
+ x: 0
+ y: 0
+ width: 64
+ height: 64
+ color: "#747474"
+
+ MouseArea {
+ anchors.fill: parent
+ id: leftArea
+ }
+ }
+
+ Rectangle {
+ id: rectangle1
+ x: 576
+ y: 0
+ width: 64
+ height: 64
+ color: "#747474"
+
+ MouseArea {
+ anchors.fill: parent
+ id: rightArea
+ }
+ }
+
+ Item {
+ id: item1
+ x: -640
+ y: 123
+ width: 1920
+ height: 480
+
+ Rectangle {
+ id: screen01
+ x: 0
+ y: 0
+ width: 640
+ height: 359
+ color: "#ffffff"
+
+ Text {
+ x: 0
+ y: 0
+ text: qsTr("Page 01")
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: 38
+ }
+ }
+
+
+ Rectangle {
+ id: screen02
+ x: 640
+ y: 0
+ width: 640
+ height: 359
+ color: "#ffffff"
+
+ Text {
+ x: 0
+ y: 0
+ text: qsTr("Page 02")
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: 38
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+
+
+ Rectangle {
+ id: screen03
+ x: 1280
+ y: 0
+ width: 640
+ height: 359
+ color: "#ffffff"
+
+ Text {
+ x: 0
+ y: 0
+ text: qsTr("Page 03")
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: 38
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ }
+
+ Timeline {
+ id: timeline
+ endFrame: 1000
+ startFrame: 0
+ enabled: true
+
+ animations: [
+ TimelineAnimation {
+ id: animationToPage01
+ from: 500
+ to: 0
+ running: false
+ onFinished: root.state = "page01"
+ },
+ TimelineAnimation {
+ id: animationToPage02Left
+ from: 0
+ to: 500
+ running: false
+ onFinished: root.state = "page02"
+ },
+ TimelineAnimation {
+ id: animationToPage02Right
+ from: 1000
+ to: 500
+ running: false
+ onFinished: root.state = "page02"
+ },
+ TimelineAnimation {
+ id: animationToPage03
+ from: 500
+ to: 1000
+ running: false
+ onFinished: root.state = "page03"
+ }
+
+ ]
+
+ KeyframeGroup {
+ target: item1
+ property: "x"
+
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+
+ Keyframe {
+ frame: 500
+ value: -640
+ }
+
+ Keyframe {
+ frame: 1000
+ value: -1280
+ }
+ }
+ }
+
+ Connections {
+ target: rightArea
+ enabled: root.state == "page01"
+ onClicked: root.state = "toPage02FromLeft"
+ }
+
+ Connections {
+ target: rightArea
+ enabled: root.state == "page02"
+ onClicked: root.state = "toPage03"
+ }
+
+ Connections {
+ target: leftArea
+ enabled: root.state == "page02"
+ onClicked: root.state = "toPage01"
+ }
+
+ Connections {
+ target: leftArea
+ enabled: root.state == "page03"
+ onClicked: root.state = "toPage02FromRight"
+ }
+
+ states: [
+ State {
+ name: "page01"
+
+ PropertyChanges {
+ target: timeline
+ currentFrame: 0
+ }
+ },
+ State {
+ name: "page02"
+
+ PropertyChanges {
+ target: timeline
+ currentFrame: 500
+ }
+ },
+ State {
+ name: "page03"
+
+ PropertyChanges {
+ target: timeline
+ currentFrame: 1000
+ }
+ },
+ State {
+ name: "toPage01"
+ PropertyChanges {
+ target: animationToPage01
+ running: true
+ }
+ },
+ State {
+ name: "toPage02FromLeft"
+ PropertyChanges {
+ target: animationToPage02Left
+ running: true
+ }
+ },
+ State {
+ name: "toPage03"
+ PropertyChanges {
+ target: animationToPage03
+ running: true
+ }
+ },
+ State {
+ name: "toPage02FromRight"
+ PropertyChanges {
+ target: animationToPage02Right
+ running: true
+ }
+ }
+ ]
+
+}
+
+/*##^## Designer {
+ D{i:62;anchors_width:100;anchors_height:100}D{i:47;currentFrame__AT__NodeInstance:1}
+}
+ ##^##*/