aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hartmann <thomas.hartmann@qt.io>2017-11-27 10:17:41 +0100
committerThomas Hartmann <thomas.hartmann@qt.io>2017-11-29 13:48:22 +0000
commitfe7e09d8ccf6daaf50a8152329960a6bd0157bc8 (patch)
tree05a6a8671c9d1c97f4c9e81b9405a9d6a58615dc
parent575402ef399d949ce14ae0235ce126edebfbe29f (diff)
Initial commit
This implements the timeline module for keyframe based animations in Qt Quick. Change-Id: Icf4a4191da7580f670a02ef52e4b0bee4befed18 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r--.qmake.conf5
-rw-r--r--src/imports/imports.pro3
-rw-r--r--src/imports/timeline/designer/designer.pri2
-rw-r--r--src/imports/timeline/qmldir4
-rw-r--r--src/imports/timeline/qquickkeyframe.cpp320
-rw-r--r--src/imports/timeline/qquickkeyframe_p.h124
-rw-r--r--src/imports/timeline/qquickkeyframemutator.cpp219
-rw-r--r--src/imports/timeline/qquickkeyframemutator_p.h89
-rw-r--r--src/imports/timeline/qtquicktimelineplugin.cpp64
-rw-r--r--src/imports/timeline/qtquicktimelineplugin.qrc4
-rw-r--r--src/imports/timeline/timeline.pri7
-rw-r--r--src/imports/timeline/timeline.pro25
-rw-r--r--src/src.pro3
-rw-r--r--tests/manual/timelineTestApp/main.cpp32
-rw-r--r--tests/manual/timelineTestApp/main.qml65
-rw-r--r--tests/manual/timelineTestApp/qml.qrc8
-rw-r--r--tests/manual/timelineTestApp/test01.qml137
-rw-r--r--tests/manual/timelineTestApp/test02.qml237
-rw-r--r--tests/manual/timelineTestApp/test03.qml103
-rw-r--r--tests/manual/timelineTestApp/timelineTestApp.pro6
-rw-r--r--timeline.pro2
21 files changed, 1459 insertions, 0 deletions
diff --git a/.qmake.conf b/.qmake.conf
new file mode 100644
index 0000000..168dab9
--- /dev/null
+++ b/.qmake.conf
@@ -0,0 +1,5 @@
+load(qt_build_config)
+CONFIG += warning_clean
+DEFINES += QT_NO_FOREACH
+
+MODULE_VERSION = 5.10.0
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
new file mode 100644
index 0000000..9dca5d7
--- /dev/null
+++ b/src/imports/imports.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += \
+ timeline
diff --git a/src/imports/timeline/designer/designer.pri b/src/imports/timeline/designer/designer.pri
new file mode 100644
index 0000000..0c5d5b6
--- /dev/null
+++ b/src/imports/timeline/designer/designer.pri
@@ -0,0 +1,2 @@
+QML_FILES += \
+ $$PWD/images/*.png
diff --git a/src/imports/timeline/qmldir b/src/imports/timeline/qmldir
new file mode 100644
index 0000000..b7daa69
--- /dev/null
+++ b/src/imports/timeline/qmldir
@@ -0,0 +1,4 @@
+module QtQuick.Timeline
+plugin qtquicktimelineplugin
+classname QtQuickTimelinePlugin
+designersupported
diff --git a/src/imports/timeline/qquickkeyframe.cpp b/src/imports/timeline/qquickkeyframe.cpp
new file mode 100644
index 0000000..3e3dbb3
--- /dev/null
+++ b/src/imports/timeline/qquickkeyframe.cpp
@@ -0,0 +1,320 @@
+/****************************************************************************
+**
+** 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 "qquickkeyframe_p.h"
+
+#include "qquickkeyframemutator_p.h"
+
+#include <QtCore/QVariantAnimation>
+#include <QtCore/qmath.h>
+#include <QtGui/qpainter.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQml/QQmlProperty>
+
+#include <private/qvariantanimation_p.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickKeyframesPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickKeyframes)
+public:
+ QQuickKeyframesPrivate()
+ : target(nullptr),
+ componentComplete(false)
+ {
+ }
+
+ QObject *target;
+ QString propertyName;
+ bool componentComplete;
+
+protected:
+ void setupKeyframes();
+
+ static void append_keyframe(QQmlListProperty<QQuickKeyframe> *list, QQuickKeyframe *a);
+ static int keyframe_count(QQmlListProperty<QQuickKeyframe> *list);
+ static QQuickKeyframe* keyframe_at(QQmlListProperty<QQuickKeyframe> *list, int pos);
+ static void clear_keyframes(QQmlListProperty<QQuickKeyframe> *list);
+
+ QList<QQuickKeyframe *> keyframes;
+ QList<QQuickKeyframe *> sortedKeyframes;
+
+ QVariant originalValue;
+};
+
+void QQuickKeyframesPrivate::setupKeyframes()
+{
+ sortedKeyframes = keyframes;
+ std::sort(sortedKeyframes.begin(), sortedKeyframes.end(), [](const QQuickKeyframe *first, const QQuickKeyframe *second) {
+ return first->frame() < second->frame();
+ });
+}
+
+void QQuickKeyframesPrivate::append_keyframe(QQmlListProperty<QQuickKeyframe> *list, QQuickKeyframe *a)
+{
+ QQuickKeyframes *q = static_cast<QQuickKeyframes *>(list->object);
+ q->d_func()->keyframes.append(a);
+ q->d_func()->setupKeyframes();
+ q->reset();
+}
+
+int QQuickKeyframesPrivate::keyframe_count(QQmlListProperty<QQuickKeyframe> *list)
+{
+ QQuickKeyframes *q = static_cast<QQuickKeyframes *>(list->object);
+ return q->d_func()->keyframes.count();
+}
+
+QQuickKeyframe* QQuickKeyframesPrivate::keyframe_at(QQmlListProperty<QQuickKeyframe> *list, int pos)
+{
+ QQuickKeyframes *q = static_cast<QQuickKeyframes *>(list->object);
+ return q->d_func()->keyframes.at(pos);
+}
+
+void QQuickKeyframesPrivate::clear_keyframes(QQmlListProperty<QQuickKeyframe> *list)
+{
+ QQuickKeyframes *q = static_cast<QQuickKeyframes *>(list->object);
+ while (q->d_func()->keyframes.count()) {
+ QQuickKeyframe *firstKeyframe = q->d_func()->keyframes.at(0);
+ q->d_func()->keyframes.removeAll(firstKeyframe);
+ }
+}
+
+class QQuickKeyframePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickKeyframe)
+public:
+ QQuickKeyframePrivate()
+ : frame(0)
+ {
+ }
+
+ qreal frame;
+ QEasingCurve easingCurve;
+ QVariant value;
+};
+
+QQuickKeyframe::QQuickKeyframe(QObject *parent)
+ : QObject(*(new QQuickKeyframePrivate), parent)
+{
+
+}
+
+qreal QQuickKeyframe::frame() const
+{
+ Q_D(const QQuickKeyframe);
+ return d->frame;
+}
+
+void QQuickKeyframe::setFrame(qreal f)
+{
+ Q_D(QQuickKeyframe);
+ if (d->frame == f)
+ return;
+ d->frame = f;
+ emit frameChanged();
+}
+
+void QQuickKeyframe::reset()
+{
+ QQuickKeyframes *keyframes = qobject_cast<QQuickKeyframes*>(parent());
+ if (keyframes)
+ keyframes->reset();
+}
+
+QQuickKeyframe::QQuickKeyframe(QQuickKeyframePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+
+}
+
+QQuickKeyframes::QQuickKeyframes(QObject *parent)
+ : QObject(*(new QQuickKeyframesPrivate), parent)
+{
+
+}
+
+QQmlListProperty<QQuickKeyframe> QQuickKeyframes::keyframes()
+{
+ Q_D(QQuickKeyframes);
+
+ return QQmlListProperty<QQuickKeyframe>(this, &d->keyframes, QQuickKeyframesPrivate::append_keyframe,
+ QQuickKeyframesPrivate::keyframe_count,
+ QQuickKeyframesPrivate::keyframe_at,
+ QQuickKeyframesPrivate::clear_keyframes);
+}
+
+QObject *QQuickKeyframes::target() const
+{
+ Q_D(const QQuickKeyframes);
+ return d->target;
+}
+
+void QQuickKeyframes::setTargetObject(QObject *o)
+{
+ Q_D(QQuickKeyframes);
+ if (d->target == o)
+ return;
+ d->target = o;
+ emit targetChanged();
+}
+
+QString QQuickKeyframes::property() const
+{
+ Q_D(const QQuickKeyframes);
+ return d->propertyName;
+}
+
+void QQuickKeyframes::setProperty(const QString &n)
+{
+ Q_D(QQuickKeyframes);
+ if (d->propertyName == n)
+ return;
+ d->propertyName = n;
+ emit propertyChanged();
+}
+
+QVariant QQuickKeyframes::evaluate(qreal frame) const
+{
+ Q_D(const QQuickKeyframes);
+
+ if (d->sortedKeyframes.isEmpty())
+ return QVariant();
+
+ QQuickKeyframe *lastFrame = nullptr;
+
+ for (auto keyFrame : qAsConst(d->sortedKeyframes)) {
+ if (frame <= keyFrame->frame())
+ return keyFrame->evaluate(lastFrame, frame, QQmlProperty(target(), property()).property().userType());
+ lastFrame = keyFrame;
+ }
+
+ return QVariant();
+}
+
+void QQuickKeyframes::setProperty(qreal frame)
+{
+ QQmlProperty property(target(), property());
+
+ property.write(evaluate(frame));
+}
+
+void QQuickKeyframes::init()
+{
+ Q_D(QQuickKeyframes);
+ d->originalValue = QQmlProperty::read(target(), property());
+}
+
+void QQuickKeyframes::resetDefaultValue()
+{
+ Q_D(QQuickKeyframes);
+ QQmlProperty::write(target(), property(), d->originalValue);
+}
+
+void QQuickKeyframes::reset()
+{
+ Q_D(QQuickKeyframes);
+ if (!d->componentComplete)
+ return;
+
+ QQuickKeyframeMutator *mutator = qobject_cast<QQuickKeyframeMutator*>(parent());
+ if (mutator)
+ setProperty(mutator->currentFrame());
+}
+
+void QQuickKeyframes::setupKeyframes()
+{
+ Q_D(QQuickKeyframes);
+
+ if (d->componentComplete)
+ d->setupKeyframes();
+}
+
+void QQuickKeyframes::classBegin()
+{
+ Q_D(QQuickKeyframes);
+ d->componentComplete = false;
+}
+
+void QQuickKeyframes::componentComplete()
+{
+ Q_D(QQuickKeyframes);
+ d->componentComplete = true;
+ setupKeyframes();
+}
+
+QEasingCurve QQuickKeyframe::easing() const
+{
+ Q_D(const QQuickKeyframe);
+ return d->easingCurve;
+}
+
+void QQuickKeyframe::setEasing(const QEasingCurve &e)
+{
+ Q_D(QQuickKeyframe);
+ if (d->easingCurve == e)
+ return;
+
+ d->easingCurve = e;
+ emit easingCurveChanged();
+}
+
+QVariant QQuickKeyframe::value() const
+{
+ Q_D(const QQuickKeyframe);
+ return d->value;
+}
+
+void QQuickKeyframe::setValue(QVariant v)
+{
+ Q_D(QQuickKeyframe);
+ if (d->value == v)
+ return;
+ d->value = v;
+
+ reset();
+
+ emit valueChanged();
+}
+
+QVariant QQuickKeyframe::evaluate(QQuickKeyframe *pre, qreal frametime, int userType) const
+{
+ QVariantAnimation::Interpolator interpolator = QVariantAnimationPrivate::getInterpolator(userType);
+ if (!pre)
+ return value();
+
+ QVariant preValue = pre->value();
+ qreal preFrame = pre->frame();
+
+ qreal duration = frame() - preFrame;
+ qreal offset = frametime - preFrame;
+
+ qreal progress = easing().valueForProgress(offset / duration);
+
+ preValue.convert(userType);
+ QVariant convertedValue = value();
+ convertedValue.convert(userType);
+
+ return interpolator(preValue.constData(), convertedValue.constData(), progress);
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/imports/timeline/qquickkeyframe_p.h b/src/imports/timeline/qquickkeyframe_p.h
new file mode 100644
index 0000000..fec1493
--- /dev/null
+++ b/src/imports/timeline/qquickkeyframe_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** 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 QQUICKKEYFRAME_P_H
+#define QQUICKKEYFRAME_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/QObject>
+#include <QtCore/qeasingcurve.h>
+
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickKeyframesPrivate;
+class QQuickKeyframePrivate;
+class QQuickNumberKeyframePrivate;
+
+class QQuickKeyframe : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickKeyframe)
+
+ Q_PROPERTY(qreal frame READ frame WRITE setFrame NOTIFY frameChanged)
+ Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingCurveChanged)
+ Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
+
+public:
+ explicit QQuickKeyframe(QObject *parent = nullptr);
+
+ qreal frame() const;
+ void setFrame(qreal);
+ void reset();
+
+ QEasingCurve easing() const;
+ void setEasing(const QEasingCurve &);
+
+ QVariant value() const;
+ void setValue(QVariant);
+
+ virtual QVariant evaluate(QQuickKeyframe *pre, qreal frame, int userType) const;
+
+protected:
+ QQuickKeyframe(QQuickKeyframePrivate &dd, QObject *parent);
+
+Q_SIGNALS:
+ void frameChanged();
+ void easingCurveChanged();
+ void valueChanged();
+};
+
+class QQuickKeyframes : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickKeyframes)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(QObject *target READ target WRITE setTargetObject NOTIFY targetChanged)
+ Q_PROPERTY(QString property READ property WRITE setProperty NOTIFY propertyChanged)
+ Q_PROPERTY(QQmlListProperty<QQuickKeyframe> keyframes READ keyframes)
+
+ Q_CLASSINFO("DefaultProperty", "keyframes")
+
+public:
+ explicit QQuickKeyframes(QObject *parent = nullptr);
+
+ QQmlListProperty<QQuickKeyframe> keyframes();
+
+ QObject *target() const;
+ void setTargetObject(QObject *);
+
+ QString property() const;
+ void setProperty(const QString &);
+
+ QVariant evaluate(qreal frame) const;
+
+ void setProperty(qreal frame);
+
+ void init();
+
+ void resetDefaultValue();
+
+ void reset();
+
+protected:
+ void setupKeyframes();
+
+ void classBegin() override;
+ void componentComplete() override;
+
+Q_SIGNALS:
+ void targetChanged();
+ void propertyChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKKEYFRAME_P_H
diff --git a/src/imports/timeline/qquickkeyframemutator.cpp b/src/imports/timeline/qquickkeyframemutator.cpp
new file mode 100644
index 0000000..ab4b593
--- /dev/null
+++ b/src/imports/timeline/qquickkeyframemutator.cpp
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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 "qquickkeyframemutator_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtGui/qpainter.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickKeyframeMutatorPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickKeyframeMutator)
+public:
+ QQuickKeyframeMutatorPrivate()
+ : startFrame(0),
+ endFrame(0),
+ currentFrame(0),
+ enabled(false),
+ componentComplete(true)
+ {
+ }
+
+ qreal startFrame;
+ qreal endFrame;
+ qreal currentFrame;
+
+ bool enabled:1;
+ bool componentComplete:1;
+
+protected:
+ void init();
+ void disable();
+
+ static void append_keyframe(QQmlListProperty<QQuickKeyframes> *list, QQuickKeyframes *a);
+ static int keyframe_count(QQmlListProperty<QQuickKeyframes> *list);
+ static QQuickKeyframes* keyframe_at(QQmlListProperty<QQuickKeyframes> *list, int pos);
+ static void clear_keyframes(QQmlListProperty<QQuickKeyframes> *list);
+
+ QList<QQuickKeyframes *> keyframes;
+};
+
+void QQuickKeyframeMutatorPrivate::init()
+{
+ for (auto keyFrames : keyframes) {
+ keyFrames->init();
+ keyFrames->setProperty(currentFrame);
+ }
+}
+
+void QQuickKeyframeMutatorPrivate::disable()
+{
+ for (auto keyFrames : keyframes)
+ keyFrames->resetDefaultValue();
+}
+
+void QQuickKeyframeMutatorPrivate::append_keyframe(QQmlListProperty<QQuickKeyframes> *list, QQuickKeyframes *a)
+{
+ QQuickKeyframeMutator *q = static_cast<QQuickKeyframeMutator *>(list->object);
+ q->d_func()->keyframes.append(a);
+}
+
+int QQuickKeyframeMutatorPrivate::keyframe_count(QQmlListProperty<QQuickKeyframes> *list)
+{
+ QQuickKeyframeMutator *q = static_cast<QQuickKeyframeMutator *>(list->object);
+ return q->d_func()->keyframes.count();
+}
+
+QQuickKeyframes* QQuickKeyframeMutatorPrivate::keyframe_at(QQmlListProperty<QQuickKeyframes> *list, int pos)
+{
+ QQuickKeyframeMutator *q = static_cast<QQuickKeyframeMutator *>(list->object);
+ return q->d_func()->keyframes.at(pos);
+}
+
+void QQuickKeyframeMutatorPrivate::clear_keyframes(QQmlListProperty<QQuickKeyframes> *list)
+{
+ QQuickKeyframeMutator *q = static_cast<QQuickKeyframeMutator *>(list->object);
+ while (q->d_func()->keyframes.count()) {
+ QQuickKeyframes *firstKeyframe = q->d_func()->keyframes.at(0);
+ q->d_func()->keyframes.removeAll(firstKeyframe);
+ }
+}
+
+QQuickKeyframeMutator::QQuickKeyframeMutator(QObject *parent) : QObject(*(new QQuickKeyframeMutatorPrivate), parent)
+{
+
+}
+
+QQmlListProperty<QQuickKeyframes> QQuickKeyframeMutator::keyframes()
+{
+ Q_D(QQuickKeyframeMutator);
+
+ return QQmlListProperty<QQuickKeyframes>(this, &d->keyframes, QQuickKeyframeMutatorPrivate::append_keyframe,
+ QQuickKeyframeMutatorPrivate::keyframe_count,
+ QQuickKeyframeMutatorPrivate::keyframe_at,
+ QQuickKeyframeMutatorPrivate::clear_keyframes);
+}
+
+bool QQuickKeyframeMutator::enabled() const
+{
+ Q_D(const QQuickKeyframeMutator);
+ return d->enabled;
+}
+
+void QQuickKeyframeMutator::setEnabled(bool b)
+{
+ Q_D(QQuickKeyframeMutator);
+ if (d->enabled == b)
+ return;
+ d->enabled = b;
+
+ if (d->componentComplete) {
+ if (b)
+ init();
+ else
+ reset();
+ }
+
+ emit enabledChanged();
+}
+
+qreal QQuickKeyframeMutator::startFrame() const
+{
+ Q_D(const QQuickKeyframeMutator);
+ return d->startFrame;
+}
+
+void QQuickKeyframeMutator::setStartFrame(qreal frame)
+{
+ Q_D(QQuickKeyframeMutator);
+ if (d->startFrame == frame)
+ return;
+ d->startFrame = frame;
+ emit startFrameChanged();
+}
+
+qreal QQuickKeyframeMutator::endFrame() const
+{
+ Q_D(const QQuickKeyframeMutator);
+ return d->endFrame;
+}
+
+void QQuickKeyframeMutator::setEndFrame(qreal frame)
+{
+ Q_D(QQuickKeyframeMutator);
+ if (d->endFrame == frame)
+ return;
+ d->endFrame = frame;
+ emit endFrameChanged();
+}
+
+qreal QQuickKeyframeMutator::currentFrame() const
+{
+ Q_D(const QQuickKeyframeMutator);
+ return d->currentFrame;
+}
+
+void QQuickKeyframeMutator::setCurrentFrame(qreal frame)
+{
+ Q_D(QQuickKeyframeMutator);
+ if (d->currentFrame == frame)
+ return;
+ d->currentFrame = frame;
+
+ if (d->componentComplete && d->enabled)
+ for (auto keyFrames : d->keyframes)
+ keyFrames->setProperty(d->currentFrame);
+
+ emit currentFrameChanged();
+}
+
+void QQuickKeyframeMutator::init()
+{
+ Q_D(QQuickKeyframeMutator);
+
+ if (d->componentComplete)
+ d->init();
+}
+
+void QQuickKeyframeMutator::reset()
+{
+ Q_D(QQuickKeyframeMutator);
+
+ if (d->componentComplete)
+ d->disable();
+}
+
+void QQuickKeyframeMutator::classBegin()
+{
+ Q_D(QQuickKeyframeMutator);
+ d->componentComplete = false;
+}
+
+void QQuickKeyframeMutator::componentComplete()
+{
+ Q_D(QQuickKeyframeMutator);
+ d->componentComplete = true;
+
+ if (d->enabled)
+ init();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/timeline/qquickkeyframemutator_p.h b/src/imports/timeline/qquickkeyframemutator_p.h
new file mode 100644
index 0000000..8cba93a
--- /dev/null
+++ b/src/imports/timeline/qquickkeyframemutator_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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 QQUICKKEYFRAMEMUTATOR_P_H
+#define QQUICKKEYFRAMEMUTATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickkeyframe_p.h"
+
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickKeyframeMutatorPrivate;
+
+class QQuickKeyframeMutator : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickKeyframeMutator)
+
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(qreal startFrame READ startFrame WRITE setStartFrame NOTIFY startFrameChanged)
+ Q_PROPERTY(qreal endFrame READ endFrame WRITE setEndFrame NOTIFY endFrameChanged)
+ Q_PROPERTY(qreal currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged)
+ Q_PROPERTY(QQmlListProperty<QQuickKeyframes> keyframes READ keyframes)
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+
+ Q_CLASSINFO("DefaultProperty", "keyframes")
+
+public:
+ explicit QQuickKeyframeMutator(QObject *parent = nullptr);
+
+ QQmlListProperty<QQuickKeyframes> keyframes();
+
+ bool enabled() const;
+ void setEnabled(bool enabled);
+
+ qreal startFrame() const;
+ void setStartFrame(qreal);
+
+ qreal endFrame() const;
+ void setEndFrame(qreal);
+
+ qreal currentFrame() const;
+ void setCurrentFrame(qreal);
+
+ void init();
+ void reset();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+Q_SIGNALS:
+ void enabledChanged();
+ void startFrameChanged();
+ void endFrameChanged();
+ void currentFrameChanged();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKKEYFRAMEMUTATOR_P_H
diff --git a/src/imports/timeline/qtquicktimelineplugin.cpp b/src/imports/timeline/qtquicktimelineplugin.cpp
new file mode 100644
index 0000000..2a69ddf
--- /dev/null
+++ b/src/imports/timeline/qtquicktimelineplugin.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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 <QtQml/qqmlextensionplugin.h>
+
+#include "qquickkeyframemutator_p.h"
+#include "qquickkeyframe_p.h"
+
+static inline void initResources()
+{
+ Q_INIT_RESOURCE(qtquicktimelineplugin);
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_QtQuick_Controls_2);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickTimelinePlugin: public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickTimelinePlugin(QObject *parent = nullptr);
+ void registerTypes(const char *uri) override;
+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
+};
+
+QtQuickTimelinePlugin::QtQuickTimelinePlugin(QObject *parent) : QQmlExtensionPlugin(parent)
+{
+ initResources();
+}
+
+void QtQuickTimelinePlugin::registerTypes(const char *uri)
+{
+ qmlRegisterType<QQuickKeyframeMutator>(uri, 1, 0, "KeyframeMutator");
+ qmlRegisterType<QQuickKeyframe>(uri, 1, 0, "Keyframe");
+ qmlRegisterType<QQuickKeyframes>(uri, 1, 0, "Keyframes");
+}
+
+void QtQuickTimelinePlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+{
+ QQmlExtensionPlugin::initializeEngine(engine, uri);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquicktimelineplugin.moc"
diff --git a/src/imports/timeline/qtquicktimelineplugin.qrc b/src/imports/timeline/qtquicktimelineplugin.qrc
new file mode 100644
index 0000000..f34aa6c
--- /dev/null
+++ b/src/imports/timeline/qtquicktimelineplugin.qrc
@@ -0,0 +1,4 @@
+<RCC>
+ <qresource prefix="/qt-project.org/imports/QtQuick/Timeline">
+ </qresource>
+</RCC>
diff --git a/src/imports/timeline/timeline.pri b/src/imports/timeline/timeline.pri
new file mode 100644
index 0000000..df73d4e
--- /dev/null
+++ b/src/imports/timeline/timeline.pri
@@ -0,0 +1,7 @@
+HEADERS += \
+ $$PWD/qquickkeyframemutator_p.h \
+ $$PWD/qquickkeyframe_p.h
+
+SOURCES += \
+ $$PWD/qquickkeyframemutator.cpp \
+ $$PWD/qquickkeyframe.cpp
diff --git a/src/imports/timeline/timeline.pro b/src/imports/timeline/timeline.pro
new file mode 100644
index 0000000..26e5e2f
--- /dev/null
+++ b/src/imports/timeline/timeline.pro
@@ -0,0 +1,25 @@
+TARGET = qtquicktimelineplugin
+TARGETPATH = QtQuick/Timeline
+IMPORT_VERSION = 1.0
+
+QT += qml quick core-private
+
+QT_PRIVATE += core-private gui-private qml-private quick-private
+
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
+
+include(timeline.pri)
+
+DISTFILES += \
+ qmldir
+
+SOURCES += \
+ $$PWD/qtquicktimelineplugin.cpp
+
+RESOURCES += \
+ $$PWD/qtquicktimelineplugin.qrc
+
+!static: qtConfig(quick-designer): include(designer/designer.pri)
+
+CONFIG += no_cxx_module
+load(qml_plugin)
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..5377565
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += \
+ imports
diff --git a/tests/manual/timelineTestApp/main.cpp b/tests/manual/timelineTestApp/main.cpp
new file mode 100644
index 0000000..405b8a9
--- /dev/null
+++ b/tests/manual/timelineTestApp/main.cpp
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** 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 <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ if (engine.rootObjects().isEmpty())
+ return -1;
+
+ return app.exec();
+}
diff --git a/tests/manual/timelineTestApp/main.qml b/tests/manual/timelineTestApp/main.qml
new file mode 100644
index 0000000..8b43d52
--- /dev/null
+++ b/tests/manual/timelineTestApp/main.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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.6
+import QtQuick.Window 2.2
+import QtQuick.Timeline 1.0
+
+Window {
+ visible: true
+ width: 640
+ height: 480
+ title: qsTr("Hello World")
+
+ Loader {
+ id: loader
+ anchors.fill: parent
+ }
+
+ Row {
+ x: 8
+ y: 457
+
+ Text {
+ text: "Test 01"
+ font.pixelSize: 12
+ MouseArea {
+ anchors.fill: parent
+ onClicked: loader.source = "test01.qml"
+ }
+ }
+
+ Text {
+ text: "Test 02"
+ font.pixelSize: 12
+ MouseArea {
+ anchors.fill: parent
+ onClicked: loader.source = "test02.qml"
+ }
+ }
+
+ Text {
+ text: "Test 03"
+ font.pixelSize: 12
+ MouseArea {
+ anchors.fill: parent
+ onClicked: loader.source = "test03.qml"
+ }
+ }
+ }
+}
diff --git a/tests/manual/timelineTestApp/qml.qrc b/tests/manual/timelineTestApp/qml.qrc
new file mode 100644
index 0000000..4da9ddc
--- /dev/null
+++ b/tests/manual/timelineTestApp/qml.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>test01.qml</file>
+ <file>test02.qml</file>
+ <file>test03.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/timelineTestApp/test01.qml b/tests/manual/timelineTestApp/test01.qml
new file mode 100644
index 0000000..95af21d
--- /dev/null
+++ b/tests/manual/timelineTestApp/test01.qml
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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 {
+ Rectangle {
+ width: 40
+ height: 40
+ color: "blue"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: mutator.enabled = !mutator.enabled
+ }
+ }
+
+ Rectangle {
+ x: 80
+ width: 40
+ height: 40
+ color: "blue"
+ MouseArea {
+ anchors.fill: parent
+ onClicked: animation.start()
+ }
+ }
+
+ NumberAnimation {
+ id: animation
+ target: mutator
+ property: "currentFrame"
+ easing.type: Easing.InOutQuad
+ duration: 2000
+ from: 0
+ to: 100
+ running: true
+ }
+
+ Item {
+ width: 480
+ height: 480
+
+ KeyframeMutator {
+ id: mutator
+
+ startFrame: 0
+ endFrame: 100
+ currentFrame: 50
+
+ enabled: true
+
+ Keyframes {
+ target: rectangle
+ property: "x"
+
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+
+ Keyframe {
+ frame: 50
+ value: 100
+ }
+
+ Keyframe {
+ frame: 100
+ value: 200
+ }
+ }
+
+ Keyframes {
+ target: rectangle
+ property: "y"
+
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+
+ Keyframe {
+ frame: 50
+ value: 100
+ easing.type: Easing.InBounce
+ }
+
+ Keyframe {
+ frame: 100
+ value: 200
+ }
+ }
+
+ Keyframes {
+ target: rectangle
+ property: "color"
+
+ Keyframe {
+ frame: 0
+ value: "red"
+ }
+
+ Keyframe {
+ frame: 50
+ value: "blue"
+ }
+
+ Keyframe {
+ frame: 100
+ value: "yellow"
+ }
+ }
+ }
+
+ Rectangle {
+ id: rectangle
+ width: 20
+ height: 20
+ color: "red"
+ }
+ }
+}
diff --git a/tests/manual/timelineTestApp/test02.qml b/tests/manual/timelineTestApp/test02.qml
new file mode 100644
index 0000000..449b69e
--- /dev/null
+++ b/tests/manual/timelineTestApp/test02.qml
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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 {
+ PropertyAnimation {
+ running: true
+ duration: 1000
+ target: mutator
+ property: "currentFrame"
+ from: 0
+ to: 1000
+ }
+
+ Rectangle {
+ id: leftGauge
+ x: 20
+ y: 140
+ width: 200
+ height: 200
+ color: "#969696"
+ radius: width / 2
+
+ Rectangle {
+ x: 5
+ y: 5
+ width: 190
+ height: 190
+ color: "#0d0d0d"
+ radius: width /2
+ }
+ }
+
+ Rectangle {
+ id: rightGauge
+ x: 420
+ y: 140
+ width: 200
+ height: 200
+ color: "#969696"
+ radius: width / 2
+ Rectangle {
+ x: 5
+ y: 5
+ width: 190
+ height: 190
+ color: "#0d0d0d"
+ radius: width /2
+ }
+ }
+
+ Rectangle {
+ id: bottomPane
+ x: 81
+ y: 424
+ width: 478
+ height: 48
+ color: "#242424"
+ }
+
+ KeyframeMutator {
+ id: mutator
+ enabled: true
+
+ startFrame: 0
+ endFrame: 1000
+
+ Keyframes {
+ target: leftGauge
+ property: "x"
+ Keyframe {
+ frame: 0
+ value: -200
+ }
+ Keyframe {
+ frame: 500
+ value: 0
+ easing.type: Easing.InQuad
+ }
+
+ Keyframe {
+ frame: 1000
+ value: 20
+ easing.type: Easing.OutQuad
+ }
+ }
+ Keyframes {
+ target: leftGauge
+ property: "y"
+ Keyframe {
+ frame: 0
+ value: 280
+ }
+
+ Keyframe {
+ frame: 500
+ value: 226
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 140
+ easing.type: Easing.OutQuad
+ }
+ }
+ Keyframes {
+ target: leftGauge
+ property: "opacity"
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+ Keyframe {
+ frame: 500
+ value: 0.2
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 1
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ Keyframes {
+ target: rightGauge
+ property: "x"
+ Keyframe {
+ frame: 0
+ value: 639
+ }
+ Keyframe {
+ frame: 500
+ value: 440
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 420
+ easing.type: Easing.OutQuad
+ }
+ }
+ Keyframes {
+ target: rightGauge
+ property: "y"
+ Keyframe {
+ frame: 0
+ value: 280
+ }
+ Keyframe {
+ frame: 500
+ value: 226
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 140
+ easing.type: Easing.OutQuad
+ }
+ }
+ Keyframes {
+ target: rightGauge
+ property: "opacity"
+ Keyframe {
+ frame: 0
+ value: 0.0
+ }
+ Keyframe {
+ frame: 500
+ value: 0.2
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 1.0
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ Keyframes {
+ target: bottomPane
+ property: "y"
+
+ Keyframe {
+ frame: 0
+ value: 502
+ }
+ Keyframe {
+ frame: 500
+ value: 432
+ easing.type: Easing.InQuad
+ }
+
+ Keyframe {
+ frame: 1000
+ value: 424
+ easing.type: Easing.OutQuad
+ }
+ }
+ Keyframes {
+ target: bottomPane
+ property: "opacity"
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+ Keyframe {
+ frame: 500
+ value: 0.7
+ easing.type: Easing.InQuad
+ }
+ Keyframe {
+ frame: 1000
+ value: 1
+ easing.type: Easing.OutQuad
+ }
+ }
+ }
+
+}
diff --git a/tests/manual/timelineTestApp/test03.qml b/tests/manual/timelineTestApp/test03.qml
new file mode 100644
index 0000000..19368f8
--- /dev/null
+++ b/tests/manual/timelineTestApp/test03.qml
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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
+
+ KeyframeMutator {
+ id: mutator
+ enabled: true
+
+ startFrame: 0
+ endFrame: 200
+ currentFrame: input.text
+ Keyframes {
+ target: needle
+ property: "rotation"
+ Keyframe {
+ frame: 0
+ value: 0
+ }
+
+ Keyframe {
+ frame: 100
+ value: 90
+ }
+ Keyframe {
+ frame: 200
+ value: 180
+ }
+ }
+
+ Keyframes {
+ target: needle
+ property: "color"
+ Keyframe {
+ frame: 0
+ value: "blue"
+ }
+
+ Keyframe {
+ frame: 100
+ value: "green"
+ }
+ Keyframe {
+ frame: 200
+ value: "red"
+ }
+ }
+
+ }
+
+ Rectangle {
+ id: rectangle
+ x: 220
+ y: 140
+ width: 300
+ height: 300
+ color: "#000000"
+ radius: 150
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+
+ Rectangle {
+ id: needle
+ x: 0
+ y: 148
+ width: 150
+ height: 4
+ color: "#c41616"
+ transformOrigin: Item.Right
+ }
+ }
+
+ TextInput {
+ id: input
+ x: 207
+ y: 392
+ width: 227
+ height: 65
+ text: "10"
+ anchors.horizontalCenter: parent.horizontalCenter
+ horizontalAlignment: Text.AlignHCenter
+ font.pointSize: 14
+ }
+}
diff --git a/tests/manual/timelineTestApp/timelineTestApp.pro b/tests/manual/timelineTestApp/timelineTestApp.pro
new file mode 100644
index 0000000..25a916c
--- /dev/null
+++ b/tests/manual/timelineTestApp/timelineTestApp.pro
@@ -0,0 +1,6 @@
+QT += quick
+CONFIG += c++11
+
+SOURCES += main.cpp
+
+RESOURCES += qml.qrc
diff --git a/timeline.pro b/timeline.pro
new file mode 100644
index 0000000..ce6617e
--- /dev/null
+++ b/timeline.pro
@@ -0,0 +1,2 @@
+requires(qtHaveModule(quick))
+load(qt_parts)