diff options
-rw-r--r-- | src/quickvectorimage/generator/qquickgenerator_p.h | 2 | ||||
-rw-r--r-- | src/quickvectorimage/generator/qquickqmlgenerator.cpp | 97 | ||||
-rw-r--r-- | src/quickvectorimage/generator/qquickqmlgenerator_p.h | 4 | ||||
-rw-r--r-- | src/quickvectorimage/qquickvectorimage.cpp | 97 | ||||
-rw-r--r-- | src/quickvectorimage/qquickvectorimage_p.h | 37 | ||||
-rw-r--r-- | src/quickvectorimage/qquickvectorimage_p_p.h | 6 |
6 files changed, 214 insertions, 29 deletions
diff --git a/src/quickvectorimage/generator/qquickgenerator_p.h b/src/quickvectorimage/generator/qquickgenerator_p.h index 4ab7671b69..e287a667ef 100644 --- a/src/quickvectorimage/generator/qquickgenerator_p.h +++ b/src/quickvectorimage/generator/qquickgenerator_p.h @@ -51,7 +51,7 @@ public: bool generate(); - virtual void generateNodeBase(const NodeInfo &info) = 0; + virtual QString generateNodeBase(const NodeInfo &info) = 0; virtual bool generateDefsNode(const NodeInfo &info) = 0; virtual void generateImageNode(const ImageNodeInfo &info) = 0; virtual void generatePath(const PathNodeInfo &info, const QRectF &overrideBoundingRect = QRectF{}) = 0; diff --git a/src/quickvectorimage/generator/qquickqmlgenerator.cpp b/src/quickvectorimage/generator/qquickqmlgenerator.cpp index 2e71b415bd..e7595c315e 100644 --- a/src/quickvectorimage/generator/qquickqmlgenerator.cpp +++ b/src/quickvectorimage/generator/qquickqmlgenerator.cpp @@ -77,7 +77,7 @@ QString QQuickQmlGenerator::commentString() const return m_commentString; } -void QQuickQmlGenerator::generateNodeBase(const NodeInfo &info) +QString QQuickQmlGenerator::generateNodeBase(const NodeInfo &info) { if (!info.nodeId.isEmpty()) stream() << "objectName: \"" << info.nodeId << "\""; @@ -134,6 +134,8 @@ void QQuickQmlGenerator::generateNodeBase(const NodeInfo &info) if (info.opacity.isAnimated()) generatePropertyAnimation(info.opacity, idString, QStringLiteral("opacity")); + + return idString; } bool QQuickQmlGenerator::generateDefsNode(const NodeInfo &info) @@ -258,16 +260,40 @@ void QQuickQmlGenerator::generateGradient(const QGradient *grad) } } +void QQuickQmlGenerator::generateAnimationBindings() +{ + stream() << "loops: " << m_topLevelIdString << ".animations.loops"; + stream() << "paused: " << m_topLevelIdString << ".animations.paused"; + stream() << "running: true"; + + stream() << "property bool wasRunning: false"; + + // We need to reset the animation when the loop count changes + stream() << "onLoopsChanged: { if (running) { restart() } }"; +} + void QQuickQmlGenerator::generatePropertyAnimation(const QQuickAnimatedProperty &property, const QString &targetName, const QString &propertyName, AnimationType animationType) { - if (property.animationCount() > 1) { - stream() << "ParallelAnimation {"; - m_indentLevel++; - stream() << "running: true"; - } + if (!property.isAnimated()) + return; + + QString mainAnimationId = targetName + + QStringLiteral("_") + + propertyName + + QStringLiteral("_animation"); + mainAnimationId.replace(QLatin1Char('.'), QLatin1Char('_')); + + stream() << "Connections { target: " << m_topLevelIdString << ".animations; function onRestart() {" << mainAnimationId << ".restart() } }"; + + stream() << "ParallelAnimation {"; + m_indentLevel++; + + stream() << "id: " << mainAnimationId; + + generateAnimationBindings(); for (int i = 0; i < property.animationCount(); ++i) { const QQuickAnimatedProperty::PropertyAnimation &animation = property.animation(i); @@ -275,9 +301,6 @@ void QQuickQmlGenerator::generatePropertyAnimation(const QQuickAnimatedProperty stream() << "SequentialAnimation {"; m_indentLevel++; - if (property.animationCount() == 1) - stream() << "running: true"; - const int startOffset = animation.startOffset; if (startOffset > 0) stream() << "PauseAnimation { duration: " << startOffset << " }"; @@ -354,10 +377,8 @@ void QQuickQmlGenerator::generatePropertyAnimation(const QQuickAnimatedProperty stream() << "}"; } - if (property.animationCount() > 1) { - m_indentLevel--; - stream() << "}"; - } + m_indentLevel--; + stream() << "}"; } void QQuickQmlGenerator::generateTransform(const QTransform &xf) @@ -649,11 +670,19 @@ void QQuickQmlGenerator::generatePathContainer(const StructureNodeInfo &info) void QQuickQmlGenerator::generateAnimateTransform(const QString &targetName, const NodeInfo &info) { - if (info.transform.animationCount() > 1) { - stream() << "ParallelAnimation {"; - m_indentLevel++; - stream() << "running: true"; - } + if (!info.transform.isAnimated()) + return; + + const QString mainAnimationId = targetName + + QStringLiteral("_transform_animation"); + stream() << "Connections { target: " << m_topLevelIdString << ".animations; function onRestart() {" << mainAnimationId << ".restart() } }"; + + stream() << "ParallelAnimation {"; + m_indentLevel++; + + stream() << "id:" << mainAnimationId; + + generateAnimationBindings(); for (int i = 0; i < info.transform.animationCount(); ++i) { const QQuickAnimatedProperty::PropertyAnimation &animation = info.transform.animation(i); @@ -661,9 +690,6 @@ void QQuickQmlGenerator::generateAnimateTransform(const QString &targetName, con stream() << "SequentialAnimation {"; m_indentLevel++; - if (info.transform.animationCount() == 1) - stream() << "running: true"; - const int startOffset = animation.startOffset; if (startOffset > 0) stream() << "PauseAnimation { duration: " << startOffset << " }"; @@ -838,10 +864,8 @@ void QQuickQmlGenerator::generateAnimateTransform(const QString &targetName, con stream() << "}"; } - if (info.transform.animationCount() > 1) { - m_indentLevel--; - stream() << "}"; - } + m_indentLevel--; + stream() << "}"; } bool QQuickQmlGenerator::generateStructureNode(const StructureNodeInfo &info) @@ -924,6 +948,7 @@ bool QQuickQmlGenerator::generateRootNode(const StructureNodeInfo &info) stream() << "// " << comment; stream() << "import QtQuick"; + stream() << "import QtQuick.VectorImage"; stream() << "import QtQuick.VectorImage.Helpers"; stream() << "import QtQuick.Shapes" << Qt::endl; stream() << "Item {"; @@ -936,6 +961,19 @@ bool QQuickQmlGenerator::generateRootNode(const StructureNodeInfo &info) if (h > 0) stream() << "implicitHeight: " << h; + stream() << "component AnimationsInfo : QtObject"; + stream() << "{"; + m_indentLevel++; + + stream() << "property bool paused: false"; + stream() << "property int loops: 1"; + stream() << "signal restart()"; + + m_indentLevel--; + stream() << "}"; + + stream() << "property AnimationsInfo animations : AnimationsInfo {}"; + if (!info.viewBox.isEmpty()) { stream() << "transform: ["; m_indentLevel++; @@ -948,11 +986,16 @@ bool QQuickQmlGenerator::generateRootNode(const StructureNodeInfo &info) } if (!info.forceSeparatePaths && info.isPathContainer) { + m_topLevelIdString = QStringLiteral("__qt_toplevel"); + stream() << "id: " << m_topLevelIdString; + generatePathContainer(info); m_indentLevel++; - } - generateNodeBase(info); + generateNodeBase(info); + } else { + m_topLevelIdString = generateNodeBase(info); + } } else { if (m_inShapeItemLevel > 0) { m_inShapeItemLevel--; diff --git a/src/quickvectorimage/generator/qquickqmlgenerator_p.h b/src/quickvectorimage/generator/qquickqmlgenerator_p.h index d65bd4ccc5..63590365a7 100644 --- a/src/quickvectorimage/generator/qquickqmlgenerator_p.h +++ b/src/quickvectorimage/generator/qquickqmlgenerator_p.h @@ -80,7 +80,7 @@ public: } protected: - void generateNodeBase(const NodeInfo &info) override; + QString generateNodeBase(const NodeInfo &info) override; bool generateDefsNode(const NodeInfo &info) override; void generateImageNode(const ImageNodeInfo &info) override; void generatePath(const PathNodeInfo &info, const QRectF &overrideBoundingRect) override; @@ -96,6 +96,7 @@ private: void generateTransform(const QTransform &xf); void generatePathContainer(const StructureNodeInfo &info); void generateAnimateTransform(const QString &targetName, const NodeInfo &info); + void generateAnimationBindings(); enum class AnimationType { Auto = 0, @@ -126,6 +127,7 @@ private: QString m_assetFileDirectory; QString m_assetFilePrefix; QString m_urlPrefix; + QString m_topLevelIdString; }; QT_END_NAMESPACE diff --git a/src/quickvectorimage/qquickvectorimage.cpp b/src/quickvectorimage/qquickvectorimage.cpp index 614514c393..f4cde81e21 100644 --- a/src/quickvectorimage/qquickvectorimage.cpp +++ b/src/quickvectorimage/qquickvectorimage.cpp @@ -79,6 +79,7 @@ void QQuickVectorImagePrivate::loadSvg() q->setImplicitWidth(svgItem->width()); q->setImplicitHeight(svgItem->height()); + q->updateAnimationProperties(); q->updateSvgItemScale(); q->update(); } @@ -186,6 +187,35 @@ void QQuickVectorImage::updateSvgItemScale() } } +void QQuickVectorImage::updateAnimationProperties() +{ + Q_D(QQuickVectorImage); + if (Q_UNLIKELY(d->svgItem == nullptr || d->svgItem->childItems().isEmpty())) + return; + + QQuickItem *childItem = d->svgItem->childItems().first(); + if (Q_UNLIKELY(d->animations != nullptr)) { + QObject *animationsInfo = childItem->property("animations").value<QObject*>(); + if (Q_UNLIKELY(animationsInfo != nullptr)) { + animationsInfo->setProperty("loops", d->animations->loops()); + animationsInfo->setProperty("paused", d->animations->paused()); + } + } +} + +QQuickVectorImageAnimations *QQuickVectorImage::animations() +{ + Q_D(QQuickVectorImage); + if (d->animations == nullptr) { + d->animations = new QQuickVectorImageAnimations; + QQml_setParent_noEvent(d->animations, this); + QObject::connect(d->animations, &QQuickVectorImageAnimations::loopsChanged, this, &QQuickVectorImage::updateAnimationProperties); + QObject::connect(d->animations, &QQuickVectorImageAnimations::pausedChanged, this, &QQuickVectorImage::updateAnimationProperties); + } + + return d->animations; +} + /*! \qmlproperty enumeration QtQuick.VectorImage::VectorImage::fillMode @@ -252,6 +282,73 @@ void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRender emit preferredRendererTypeChanged(); } +/*! + \qmlpropertygroup QtQuick.VectorImage::VectorImage::animations + \qmlproperty bool QtQuick.VectorImage::VectorImage::animations.paused + \qmlproperty int QtQuick.VectorImage::VectorImage::animations.loops + \since 6.10 + + These properties can be used to control animations in the image, if it contains any. + + The \c paused property can be set to true to temporarily pause all animations. When the + property is reset to \c false, the animations will resume where they were. By default this + property is \c false. + + The \c loops property defines the number of times the animations in the document will repeat. + By default this property is 1. Any animations that is set to loop indefinitely in the source + image will be unaffected by this property. To make all animations in the document repeat + indefinitely, the \c loops property can be set to \c{Animation.Infinite}. +*/ +int QQuickVectorImageAnimations::loops() const +{ + return m_loops; +} + +void QQuickVectorImageAnimations::setLoops(int loops) +{ + if (m_loops == loops) + return; + m_loops = loops; + emit loopsChanged(); +} + +bool QQuickVectorImageAnimations::paused() const +{ + return m_paused; +} + +void QQuickVectorImageAnimations::setPaused(bool paused) +{ + if (m_paused == paused) + return; + m_paused = paused; + emit pausedChanged(); +} + +void QQuickVectorImageAnimations::restart() +{ + QQuickVectorImage *parentVectorImage = qobject_cast<QQuickVectorImage *>(parent()); + if (Q_UNLIKELY(parentVectorImage == nullptr)) { + qCWarning(lcQuickVectorImage) << Q_FUNC_INFO << "Parent is not a VectorImage"; + return; + } + + QQuickVectorImagePrivate *d = QQuickVectorImagePrivate::get(parentVectorImage); + + if (Q_UNLIKELY(d->svgItem == nullptr || d->svgItem->childItems().isEmpty())) + return; + + QQuickItem *childItem = d->svgItem->childItems().first(); + QObject *animationsInfo = childItem->property("animations").value<QObject*>(); + + if (Q_UNLIKELY(animationsInfo == nullptr)) { + qCWarning(lcQuickVectorImage) << Q_FUNC_INFO << "Item does not have animations property"; + return; + } + + QMetaObject::invokeMethod(animationsInfo, "restart"); +} + QT_END_NAMESPACE #include <moc_qquickvectorimage_p.cpp> diff --git a/src/quickvectorimage/qquickvectorimage_p.h b/src/quickvectorimage/qquickvectorimage_p.h index cce935d3ea..a997f2e8ba 100644 --- a/src/quickvectorimage/qquickvectorimage_p.h +++ b/src/quickvectorimage/qquickvectorimage_p.h @@ -16,11 +16,13 @@ // #include <QQuickItem> +#include <QtQuick/private/qquickanimation_p.h> #include <QtQuickVectorImage/qtquickvectorimageexports.h> QT_BEGIN_NAMESPACE class QQuickVectorImagePrivate; +class QQuickVectorImageAnimations; class Q_QUICKVECTORIMAGE_EXPORT QQuickVectorImage : public QQuickItem { @@ -29,6 +31,7 @@ class Q_QUICKVECTORIMAGE_EXPORT QQuickVectorImage : public QQuickItem Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) Q_PROPERTY(RendererType preferredRendererType READ preferredRendererType WRITE setPreferredRendererType NOTIFY preferredRendererTypeChanged) + Q_PROPERTY(QQuickVectorImageAnimations *animations READ animations CONSTANT REVISION(6, 10) FINAL) QML_NAMED_ELEMENT(VectorImage) public: @@ -57,6 +60,8 @@ public: RendererType preferredRendererType() const; void setPreferredRendererType(RendererType newPreferredRendererType); + QQuickVectorImageAnimations *animations(); + signals: void sourceChanged(); void fillModeChanged(); @@ -65,12 +70,44 @@ signals: private slots: void updateSvgItemScale(); + void updateAnimationProperties(); private: Q_DISABLE_COPY(QQuickVectorImage) Q_DECLARE_PRIVATE(QQuickVectorImage) }; +class Q_QUICKVECTORIMAGE_EXPORT QQuickVectorImageAnimations : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged FINAL) + Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged FINAL) + + QML_ANONYMOUS + QML_ADDED_IN_VERSION(6, 10) +public: + QQuickVectorImageAnimations(QObject *parent = nullptr) : QObject(parent) {} + + int loops() const; + + void setLoops(int loops); + + bool paused() const; + void setPaused(bool paused); + + Q_INVOKABLE void restart(); + +Q_SIGNALS: + void loopsChanged(); + void enabledChanged(); + void pausedChanged(); + +private: + int m_loops = 1; + bool m_paused = false; +}; + QT_END_NAMESPACE #endif // QQUICKVECTORIMAGE_P_H diff --git a/src/quickvectorimage/qquickvectorimage_p_p.h b/src/quickvectorimage/qquickvectorimage_p_p.h index 4ad408b628..0114d611a9 100644 --- a/src/quickvectorimage/qquickvectorimage_p_p.h +++ b/src/quickvectorimage/qquickvectorimage_p_p.h @@ -32,6 +32,11 @@ public: void setSource(const QUrl &source); void loadSvg(); + static QQuickVectorImagePrivate *get(QQuickVectorImage *q) + { + return q->d_func(); + } + enum Format { Unknown, Svg @@ -42,6 +47,7 @@ public: QQuickItem *svgItem = nullptr; QQuickVectorImage::FillMode fillMode = QQuickVectorImage::Stretch; QQuickVectorImage::RendererType preferredRendererType = QQuickVectorImage::GeometryRenderer; + QQuickVectorImageAnimations *animations = nullptr; }; QT_END_NAMESPACE |