From faee2c924451837e45d06f379e11c7080060765d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Tue, 27 Aug 2024 21:25:26 +0200 Subject: [PATCH 01/10] AppSupport: add svg id filter #173 --- src/core/appsupport.cpp | 5 +++++ src/core/appsupport.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/core/appsupport.cpp b/src/core/appsupport.cpp index 67bce6ab7..079511f72 100644 --- a/src/core/appsupport.cpp +++ b/src/core/appsupport.cpp @@ -984,3 +984,8 @@ void AppSupport::handlePortableFirstRun() "

%1").arg(getAppConfigPath())); setSettings("portable", "PortableFirstRun", false); } + +const QString AppSupport::filterId(const QString &input) +{ + return QString(input).simplified().replace(" ", ""); +} diff --git a/src/core/appsupport.h b/src/core/appsupport.h index 38c61a57d..eba475fbb 100644 --- a/src/core/appsupport.h +++ b/src/core/appsupport.h @@ -133,6 +133,7 @@ class CORE_EXPORT AppSupport : public QObject static const ExpressionPreset readEasingPreset(const QString &filename); static const QList> getEasingPresets(); static void handlePortableFirstRun(); + static const QString filterId(const QString &input); }; #endif // APPSUPPORT_H From d5d82b5e6b3de02c4d8b4b7ee7c20cc46ad359f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Tue, 27 Aug 2024 21:29:44 +0200 Subject: [PATCH 02/10] Animators: support SVG animateMotion #173 --- src/core/Animators/graphanimator.cpp | 30 +++++++++---- src/core/Animators/graphanimator.h | 5 ++- src/core/Animators/qpointfanimator.cpp | 41 ++++++++++++++---- src/core/Animators/qpointfanimator.h | 10 ++++- src/core/Animators/qrealanimator.cpp | 58 ++++++++++++++++++++------ src/core/Animators/qrealanimator.h | 10 ++++- 6 files changed, 121 insertions(+), 33 deletions(-) diff --git a/src/core/Animators/graphanimator.cpp b/src/core/Animators/graphanimator.cpp index a9fd87e88..7a70e88e4 100644 --- a/src/core/Animators/graphanimator.cpp +++ b/src/core/Animators/graphanimator.cpp @@ -27,6 +27,7 @@ #include "graphkey.h" #include "qrealpoint.h" #include "svgexporthelpers.h" +#include "appsupport.h" GraphAnimator::GraphAnimator(const QString& name) : Animator(name) { connect(this, &Animator::anim_addedKey, [this](Key * key) { @@ -530,28 +531,41 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, const bool transform, const QString& type, const QString &beginEvent, - const QString &endEvent) const + const QString &endEvent, + const bool motion, + const bool motionRotate, + const QString &motionPath) const { Q_ASSERT(!transform || attrName == "transform"); const auto relRange = prp_absRangeToRelRange(exp.fAbsRange); const auto idRange = prp_getIdenticalRelRange(visRange.fMin); const int span = exp.fAbsRange.span(); - if(idRange.inRange(visRange) || span == 1) { + if (idRange.inRange(visRange) || span == 1) { + if (motion) { return; } auto value = valueGetter(visRange.fMin); - if(transform) { - value = parent.attribute(attrName) + " " + - type + "(" + value + ")"; + if (transform) { + value = parent.attribute(attrName) + " " + type + "(" + value + ")"; } parent.setAttribute(attrName, value.trimmed()); } else { - const auto tagName = transform ? "animateTransform" : "animate"; + const auto tagName = motion ? "animateMotion" : transform ? "animateTransform" : "animate"; auto anim = exp.createElement(tagName); if (!beginEvent.isEmpty()) { anim.setAttribute("begin", beginEvent); } if (!endEvent.isEmpty()) { anim.setAttribute("end", endEvent); } - anim.setAttribute("attributeName", attrName); - if(!type.isEmpty()) anim.setAttribute("type", type); + if (!motion) { + anim.setAttribute("attributeName", attrName); + if (!type.isEmpty()) { anim.setAttribute("type", type); } + } else { + if (motionRotate) { anim.setAttribute("rotate", "auto"); } + if (!motionPath.isEmpty()) { + auto mpath = exp.createElement("mpath"); + mpath.setAttribute("href", QString("#%1").arg(AppSupport::filterId(motionPath))); + anim.appendChild(mpath); + } + } + const qreal div = span - 1; const qreal dur = div/exp.fFps; anim.setAttribute("dur", QString::number(dur) + 's'); diff --git a/src/core/Animators/graphanimator.h b/src/core/Animators/graphanimator.h index 5fe41d268..f3d528bf6 100644 --- a/src/core/Animators/graphanimator.h +++ b/src/core/Animators/graphanimator.h @@ -94,7 +94,10 @@ class CORE_EXPORT GraphAnimator : public Animator { const bool transform = false, const QString& type = "", const QString& beginEvent = "", - const QString& endEvent = "") const; + const QString& endEvent = "", + const bool motion = false, + const bool motionRotate = false, + const QString & motionPath = QString()) const; protected: qreal graph_prevKeyWeight(const GraphKey * const prevKey, const GraphKey * const nextKey, diff --git a/src/core/Animators/qpointfanimator.cpp b/src/core/Animators/qpointfanimator.cpp index ce3d1614c..14f025d60 100644 --- a/src/core/Animators/qpointfanimator.cpp +++ b/src/core/Animators/qpointfanimator.cpp @@ -260,11 +260,25 @@ void QPointFAnimator::saveQPointFSVGX(SvgExporter& exp, const bool transform, const QString& type, const QString &beginEvent, - const QString &endEvent) const + const QString &endEvent, + const bool motion, + const bool motionRotate, + const QString &motionPath) const { const QString templ = "%1 " + QString::number(y); - mXAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier, - transform, type, templ, beginEvent, endEvent); + mXAnimator->saveQrealSVG(exp, + parent, + visRange, + name, + multiplier, + transform, + type, + templ, + beginEvent, + endEvent, + motion, + motionRotate, + motionPath); } void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp, @@ -276,12 +290,25 @@ void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp, const bool transform, const QString& type, const QString &beginEvent, - const QString &endEvent) const + const QString &endEvent, + const bool motion, + const bool motionRotate, + const QString &motionPath) const { const QString templ = QString::number(x) + " %1"; - mYAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier, - transform, type, templ, - beginEvent, endEvent); + mYAnimator->saveQrealSVG(exp, + parent, + visRange, + name, + multiplier, + transform, + type, + templ, + beginEvent, + endEvent, + motion, + motionRotate, + motionPath); } QDomElement QPointFAnimator::prp_writePropertyXEV_impl(const XevExporter& exp) const { diff --git a/src/core/Animators/qpointfanimator.h b/src/core/Animators/qpointfanimator.h index 902e20444..3e56bb9fe 100644 --- a/src/core/Animators/qpointfanimator.h +++ b/src/core/Animators/qpointfanimator.h @@ -111,7 +111,10 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator { const bool transform = false, const QString& type = "", const QString& beginEvent = "", - const QString& endEvent = "") const; + const QString& endEvent = "", + const bool motion = false, + const bool motionRotate = false, + const QString & motionPath = QString()) const; void saveQPointFSVGY(SvgExporter& exp, QDomElement& parent, const FrameRange& visRange, @@ -121,7 +124,10 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator { const bool transform = false, const QString& type = "", const QString& beginEvent = "", - const QString& endEvent = "") const; + const QString& endEvent = "", + const bool motion = false, + const bool motionRotate = false, + const QString & motionPath = QString()) const; QDomElement prp_writePropertyXEV_impl(const XevExporter& exp) const; protected: qsptr mXAnimator; diff --git a/src/core/Animators/qrealanimator.cpp b/src/core/Animators/qrealanimator.cpp index 87321d955..118a5a9b9 100644 --- a/src/core/Animators/qrealanimator.cpp +++ b/src/core/Animators/qrealanimator.cpp @@ -796,37 +796,69 @@ void QrealAnimator::saveQrealSVG(SvgExporter& exp, const QString& type, const QString& templ, const QString &beginEvent, - const QString &endEvent) + const QString &endEvent, + const bool motion, + const bool motionRotate, + const QString &motionPath) { const auto mangler = [multiplier](const qreal value) { return value*multiplier; }; - saveQrealSVG(exp, parent, visRange, attrName, - mangler, transform, type, templ, beginEvent, endEvent); + saveQrealSVG(exp, + parent, + visRange, + attrName, + mangler, + transform, + type, + templ, + beginEvent, + endEvent, + motion, + motionRotate, + motionPath); } -void QrealAnimator::saveQrealSVG(SvgExporter& exp, QDomElement& parent, - const FrameRange& visRange, const QString& attrName, - const Mangler& mangler, const bool transform, - const QString& type, const QString& templ, - const QString &beginEvent, const QString &endEvent) +void QrealAnimator::saveQrealSVG(SvgExporter& exp, + QDomElement& parent, + const FrameRange& visRange, + const QString& attrName, + const Mangler& mangler, + const bool transform, + const QString& type, + const QString& templ, + const QString &beginEvent, + const QString &endEvent, + const bool motion, + const bool motionRotate, + const QString &motionPath) { - if(hasValidExpression()) { + if (hasValidExpression()) { const auto copy = enve::make_shared(""); const auto relRange = prp_absRangeToRelRange(exp.fAbsRange); copy->prp_setInheritedFrameShift(prp_getTotalFrameShift(), nullptr); copy->setExpression(mExpression.sptr()); copy->applyExpression(relRange, 10, false); - copy->saveQrealSVG(exp, parent, visRange, attrName, - mangler, transform, type, templ, - beginEvent, endEvent); + copy->saveQrealSVG(exp, + parent, + visRange, + attrName, + mangler, + transform, + type, + templ, + beginEvent, + endEvent, + motion, + motionRotate, + motionPath); setExpression(mExpression.sptr()); } else { graph_saveSVG(exp, parent, visRange, attrName, [this, mangler, &templ](const int relFrame) { const qreal val = mangler(getEffectiveValue(relFrame)); return templ.arg(val); - }, transform, type, beginEvent, endEvent); + }, transform, type, beginEvent, endEvent, motion, motionRotate, motionPath); } } diff --git a/src/core/Animators/qrealanimator.h b/src/core/Animators/qrealanimator.h index add93d9bf..8d8a39465 100644 --- a/src/core/Animators/qrealanimator.h +++ b/src/core/Animators/qrealanimator.h @@ -183,7 +183,10 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator { const QString& type = "", const QString& templ = "%1", const QString& beginEvent = "", - const QString& endEvent = ""); + const QString& endEvent = "", + const bool motion = false, + const bool motionRotate = false, + const QString & motionPath = QString()); using Mangler = std::function; void saveQrealSVG(SvgExporter& exp, QDomElement& parent, @@ -194,7 +197,10 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator { const QString& type = "", const QString& templ = "%1", const QString& beginEvent = "", - const QString& endEvent = ""); + const QString& endEvent = "", + const bool motion = false, + const bool motionRotate = false, + const QString & motionPath = QString()); private: qreal calculateBaseValueAtRelFrame(const qreal frame) const; void startBaseValueTransform(); From 2f218970ba64424308c12ba0eb8e545f6778fcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Tue, 27 Aug 2024 21:32:25 +0200 Subject: [PATCH 03/10] TransformEffects: support SVG #173 Only 'follow path' is supported. --- .../TransformEffects/followpatheffect.cpp | 28 ++++++++++++++++++ src/core/TransformEffects/followpatheffect.h | 6 ++++ .../transformeffectcollection.cpp | 29 +++++++++++++++++++ .../transformeffectcollection.h | 7 +++++ 4 files changed, 70 insertions(+) diff --git a/src/core/TransformEffects/followpatheffect.cpp b/src/core/TransformEffects/followpatheffect.cpp index 1e577464a..f4e4f8217 100644 --- a/src/core/TransformEffects/followpatheffect.cpp +++ b/src/core/TransformEffects/followpatheffect.cpp @@ -28,6 +28,7 @@ #include "Boxes/pathbox.h" #include "Animators/qrealanimator.h" #include "Animators/transformanimator.h" +#include "svgexporter.h" FollowPathEffect::FollowPathEffect() : TargetTransformEffect("follow path", TransformEffectType::followPath) { @@ -181,3 +182,30 @@ void FollowPathEffect::applyEffect(const qreal relFrame, posX += posXChange; //p1.x()*infl; posY += posYChange; //p1.y()*infl; } + +QDomElement FollowPathEffect::saveFollowPathSVG(SvgExporter &exp, + const FrameRange &visRange, + QDomElement &childElement, + QDomElement &parentElement) const +{ + const auto target = targetProperty()->getTarget(); + if (!target) { return parentElement; } + mComplete->saveQrealSVG(exp, + childElement, + visRange, + "transform", + 1., + false, + "", + "%1", + "", + "", + true, + mRotate->getValue(), + target->prp_getName()); + const auto transform = target->getBoxTransformAnimator(); + const auto transformed = transform->saveSVG(exp, + visRange, + parentElement); + return transformed; +} diff --git a/src/core/TransformEffects/followpatheffect.h b/src/core/TransformEffects/followpatheffect.h index 53a32d82b..9c9f55aca 100644 --- a/src/core/TransformEffects/followpatheffect.h +++ b/src/core/TransformEffects/followpatheffect.h @@ -42,6 +42,12 @@ class FollowPathEffect : public TargetTransformEffect { qreal &shearX, qreal &shearY, QMatrix& postTransform, BoundingBox* const parent) override; + + QDomElement saveFollowPathSVG(SvgExporter& exp, + const FrameRange& visRange, + QDomElement &childElement, + QDomElement &parentElement) const; + private: void setRotScaleAfterTargetChange( BoundingBox* const oldTarget, diff --git a/src/core/TransformEffects/transformeffectcollection.cpp b/src/core/TransformEffects/transformeffectcollection.cpp index 9fd184e16..b9e2c6f51 100644 --- a/src/core/TransformEffects/transformeffectcollection.cpp +++ b/src/core/TransformEffects/transformeffectcollection.cpp @@ -91,6 +91,35 @@ void TransformEffectCollection::prp_readProperty_impl(eReadStream &src) { } } +bool TransformEffectCollection::hasEffectsSVG() +{ + const auto& children = ca_getChildren(); + for (const auto& effect : children) { + if (const auto followPath = enve_cast(effect.get())) { + return true; + } + } + return false; +} + +QDomElement TransformEffectCollection::saveEffectsSVG(SvgExporter &exp, + const FrameRange &visRange, + QDomElement &childElement, + const QDomElement &parentElement) const +{ + QDomElement result = parentElement; + const auto& children = ca_getChildren(); + for (const auto& effect : children) { + if (const auto path = enve_cast(effect.get())) { + result = path->saveFollowPathSVG(exp, + visRange, + childElement, + result); + } + } + return result; +} + void TransformEffectCollection::applyEffects( const qreal relFrame, qreal& pivotX, qreal& pivotY, diff --git a/src/core/TransformEffects/transformeffectcollection.h b/src/core/TransformEffects/transformeffectcollection.h index d6ac7c071..0a27236cf 100644 --- a/src/core/TransformEffects/transformeffectcollection.h +++ b/src/core/TransformEffects/transformeffectcollection.h @@ -59,8 +59,15 @@ class CORE_EXPORT TransformEffectCollection : void prp_readProperty_impl(eReadStream &src); bool hasEffects(); + bool hasEffectsSVG(); + void readTransformEffect(eReadStream &target); + QDomElement saveEffectsSVG(SvgExporter& exp, + const FrameRange& visRange, + QDomElement &childElement, + const QDomElement &parentElement) const; + void applyEffects(const qreal relFrame, qreal& pivotX, qreal& pivotY, qreal& posX, qreal& posY, From 43b2a271dbb73e811b6140a0e085b17919d3344d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Tue, 27 Aug 2024 21:33:39 +0200 Subject: [PATCH 04/10] Box: support SVG transform effects #173 Only 'follow path' is supported. --- src/core/Boxes/boundingbox.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/Boxes/boundingbox.cpp b/src/core/Boxes/boundingbox.cpp index 7bd728f19..033995e62 100644 --- a/src/core/Boxes/boundingbox.cpp +++ b/src/core/Boxes/boundingbox.cpp @@ -1414,15 +1414,29 @@ eTask* BoundingBox::saveSVGWithTransform(SvgExporter& exp, taskPtr->addDependent({[ptr, taskPtr, expPtr, parentPtr, visRange, maskId]() { auto& ele = taskPtr->element(); if (ptr) { + ele.setAttribute("id", AppSupport::filterId(ptr->prp_getName())); SvgExportHelpers::assignVisibility(*expPtr, ele, visRange); + + const auto transformEffects = ptr->mTransformEffectCollection.get(); + const bool hasTransformEffects = transformEffects->hasEffectsSVG(); + const auto transform = ptr->mTransformAnimator.get(); const auto transformed = transform->saveSVG(*expPtr, visRange, ele); const auto effects = ptr->mRasterEffectsAnimators.get(); - const auto withEffects = effects->saveEffectsSVG(*expPtr, visRange, transformed); + const auto withEffects = hasTransformEffects ? + transformEffects->saveEffectsSVG(*expPtr, + visRange, + ele, + effects->saveEffectsSVG(*expPtr, + visRange, + transformed)) : + effects->saveEffectsSVG(*expPtr, + visRange, + transformed); if (maskId == ptr->prp_getName()) { // move mask to defs auto& eleMask = taskPtr->initialize("mask"); - eleMask.setAttribute("id", QString(ptr->prp_getName()).simplified().replace(" ", "")); + eleMask.setAttribute("id", AppSupport::filterId(ptr->prp_getName())); eleMask.appendChild(withEffects); expPtr->addToDefs(eleMask); } else { From 5a9930dd46db38170656e1c3860065221f15d339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Tue, 27 Aug 2024 22:43:33 +0200 Subject: [PATCH 05/10] SVG Mask: add 'Mask' suffix to id's This is needed to avoid same id as child element. --- src/core/Boxes/boundingbox.cpp | 2 +- src/core/Boxes/containerbox.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Boxes/boundingbox.cpp b/src/core/Boxes/boundingbox.cpp index 033995e62..ad7756778 100644 --- a/src/core/Boxes/boundingbox.cpp +++ b/src/core/Boxes/boundingbox.cpp @@ -1436,7 +1436,7 @@ eTask* BoundingBox::saveSVGWithTransform(SvgExporter& exp, if (maskId == ptr->prp_getName()) { // move mask to defs auto& eleMask = taskPtr->initialize("mask"); - eleMask.setAttribute("id", AppSupport::filterId(ptr->prp_getName())); + eleMask.setAttribute("id", QString("%1Mask").arg(AppSupport::filterId(ptr->prp_getName()))); eleMask.appendChild(withEffects); expPtr->addToDefs(eleMask); } else { diff --git a/src/core/Boxes/containerbox.cpp b/src/core/Boxes/containerbox.cpp index 5f1ad891d..3087ae791 100644 --- a/src/core/Boxes/containerbox.cpp +++ b/src/core/Boxes/containerbox.cpp @@ -200,7 +200,7 @@ class GroupSaverSVG : public ComplexTask } } if (!mItemMaskId.isEmpty()) { - mEle.setAttribute("mask", QString("url(#%1)").arg(QString(mItemMaskId).simplified().replace(" ", ""))); + mEle.setAttribute("mask", QString("url(#%1Mask)").arg(AppSupport::filterId(mItemMaskId))); } } } From a8fff9c660dcec99e23c1250842e3221d578b1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Wed, 28 Aug 2024 16:24:02 +0200 Subject: [PATCH 06/10] SVG animateMotion: disable 'rotate' support Yeah... can't used 'rotate' in animateMotion as it forces pivot top-left. Ref: #173 --- src/core/Animators/graphanimator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Animators/graphanimator.cpp b/src/core/Animators/graphanimator.cpp index 7a70e88e4..c735bbc29 100644 --- a/src/core/Animators/graphanimator.cpp +++ b/src/core/Animators/graphanimator.cpp @@ -558,7 +558,7 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, anim.setAttribute("attributeName", attrName); if (!type.isEmpty()) { anim.setAttribute("type", type); } } else { - if (motionRotate) { anim.setAttribute("rotate", "auto"); } + //if (motionRotate) { anim.setAttribute("rotate", "auto"); } if (!motionPath.isEmpty()) { auto mpath = exp.createElement("mpath"); mpath.setAttribute("href", QString("#%1").arg(AppSupport::filterId(motionPath))); From 80b7384c621271a1354a0e4bf086b49df0ab7b1e Mon Sep 17 00:00:00 2001 From: Pablo Gil Date: Mon, 18 Nov 2024 10:53:00 +0100 Subject: [PATCH 07/10] SVG animateMotion: enable 'rotate' support back again as it works if 'translation' and 'pivot' have 0 values --- src/core/Animators/graphanimator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Animators/graphanimator.cpp b/src/core/Animators/graphanimator.cpp index c735bbc29..7a70e88e4 100644 --- a/src/core/Animators/graphanimator.cpp +++ b/src/core/Animators/graphanimator.cpp @@ -558,7 +558,7 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, anim.setAttribute("attributeName", attrName); if (!type.isEmpty()) { anim.setAttribute("type", type); } } else { - //if (motionRotate) { anim.setAttribute("rotate", "auto"); } + if (motionRotate) { anim.setAttribute("rotate", "auto"); } if (!motionPath.isEmpty()) { auto mpath = exp.createElement("mpath"); mpath.setAttribute("href", QString("#%1").arg(AppSupport::filterId(motionPath))); From 12dd0e4f46e514aaa8412990fe80e4f7b9964684 Mon Sep 17 00:00:00 2001 From: Pablo Gil Date: Mon, 18 Nov 2024 10:55:12 +0100 Subject: [PATCH 08/10] SVG animateMotion: added 'keyPoints' atribute to correctly animate keyframes --- src/core/Animators/graphanimator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/Animators/graphanimator.cpp b/src/core/Animators/graphanimator.cpp index 7a70e88e4..6227badca 100644 --- a/src/core/Animators/graphanimator.cpp +++ b/src/core/Animators/graphanimator.cpp @@ -636,6 +636,9 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, anim.setAttribute("calcMode", "spline"); anim.setAttribute("values", values.join(';')); + if (motion) { + anim.setAttribute("keyPoints", values.join(';')); + } anim.setAttribute("keyTimes", keyTimes.join(';')); anim.setAttribute("keySplines", keySplines.join(';')); From ae6b4303d2e925787823f2bd5caa08de992ecc82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Wed, 27 Nov 2024 18:53:44 +0100 Subject: [PATCH 09/10] SVG Export: update warning Don't warn if using follow path. --- src/core/Boxes/boundingbox.cpp | 18 ++++++++++++++++++ src/core/Boxes/boundingbox.h | 1 + src/core/canvasselectedboxesactions.cpp | 11 +++++++---- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/core/Boxes/boundingbox.cpp b/src/core/Boxes/boundingbox.cpp index c2b3ae71e..010c1fed0 100644 --- a/src/core/Boxes/boundingbox.cpp +++ b/src/core/Boxes/boundingbox.cpp @@ -25,6 +25,7 @@ #include "Boxes/boundingbox.h" #include "Boxes/containerbox.h" +#include "TransformEffects/followpatheffect.h" #include "canvas.h" #include "swt_abstraction.h" #include "Timeline/durationrectangle.h" @@ -358,6 +359,23 @@ bool BoundingBox::hasTransformEffects() const { return mTransformEffectCollection->ca_hasChildren(); } +const QStringList BoundingBox::checkTransformEffectsForSVGSupport() +{ + QStringList result; + const int totalEffects = mTransformEffectCollection->ca_getNumberOfChildren(); + for (int i = 0; i < totalEffects; ++i) { + const auto effect = enve_cast(mTransformEffectCollection->getChild(i)); + if (!effect) { continue; } + if (!effect->isVisible()) { continue; } + bool isSafeForSVG = false; + if (const auto followPath = enve_cast(effect)) { + isSafeForSVG = true; + } + if (!isSafeForSVG) { result.append(effect->prp_getName()); } + } + return result; +} + ContainerBox *BoundingBox::getFirstParentLayer() const { const auto parent = getParentGroup(); if(!parent) return nullptr; diff --git a/src/core/Boxes/boundingbox.h b/src/core/Boxes/boundingbox.h index 1a6d3fb3d..ced978d1f 100644 --- a/src/core/Boxes/boundingbox.h +++ b/src/core/Boxes/boundingbox.h @@ -435,6 +435,7 @@ class CORE_EXPORT BoundingBox : public eBoxOrSound { QMatrix& postTransform); bool hasTransformEffects() const; + const QStringList checkTransformEffectsForSVGSupport(); ContainerBox* getFirstParentLayer() const; diff --git a/src/core/canvasselectedboxesactions.cpp b/src/core/canvasselectedboxesactions.cpp index d609fef26..2c8b42028 100644 --- a/src/core/canvasselectedboxesactions.cpp +++ b/src/core/canvasselectedboxesactions.cpp @@ -522,10 +522,13 @@ const QString Canvas::checkForUnsupportedBoxSVG(BoundingBox * const box) QString result; if (!box) { return result; } qDebug() << "check" << box->prp_getName() << "for SVG support"; - if (box->hasTransformEffects()) { - result.append(QString("- %1 => %2 : %3\n").arg(prp_getName(), - box->prp_getName(), - tr("Transform effects are unsupported"))); + + const auto transformEffects = box->checkTransformEffectsForSVGSupport(); + if (transformEffects.size() > 0) { + result.append(QString("- %1 => %2 : %3 %4\n").arg(prp_getName(), + box->prp_getName(), + transformEffects.join(", "), + tr("is unsupported"))); } if (box->hasEnabledBlendEffects()) { result.append(QString("- %1 => %2 : %3\n").arg(prp_getName(), From 619c0b6147ede115b5b9c5588a0299ccf3deab4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole-Andr=C3=A9=20Rodlie?= Date: Thu, 28 Nov 2024 00:36:51 +0100 Subject: [PATCH 10/10] Update followpatheffect.cpp Fix SVG export. Ref: #173 #347 --- src/core/TransformEffects/followpatheffect.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/TransformEffects/followpatheffect.cpp b/src/core/TransformEffects/followpatheffect.cpp index 876756e2c..7b629f396 100644 --- a/src/core/TransformEffects/followpatheffect.cpp +++ b/src/core/TransformEffects/followpatheffect.cpp @@ -188,10 +188,11 @@ QDomElement FollowPathEffect::saveFollowPathSVG(SvgExporter &exp, QDomElement &childElement, QDomElement &parentElement) const { + Q_UNUSED(childElement) const auto target = targetProperty()->getTarget(); if (!target) { return parentElement; } mComplete->saveQrealSVG(exp, - childElement, + parentElement, visRange, "transform", 1.,