diff --git a/src/core/Animators/graphanimator.cpp b/src/core/Animators/graphanimator.cpp index c54dc0449..bc81d2e06 100644 --- a/src/core/Animators/graphanimator.cpp +++ b/src/core/Animators/graphanimator.cpp @@ -528,7 +528,10 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, const QString& attrName, const ValueGetter& valueGetter, const bool transform, - const QString& type) const { + const QString& type, + const QString &beginEvent, + const QString &endEvent) const +{ Q_ASSERT(!transform || attrName == "transform"); const auto relRange = prp_absRangeToRelRange(exp.fAbsRange); const auto idRange = prp_getIdenticalRelRange(visRange.fMin); @@ -543,6 +546,10 @@ void GraphAnimator::graph_saveSVG(SvgExporter& exp, } else { const auto tagName = transform ? "animateTransform" : "animate"; auto anim = exp.createElement(tagName); + if (transform) { + 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); const qreal div = span - 1; diff --git a/src/core/Animators/graphanimator.h b/src/core/Animators/graphanimator.h index 0c1c3c9d7..5fe41d268 100644 --- a/src/core/Animators/graphanimator.h +++ b/src/core/Animators/graphanimator.h @@ -92,7 +92,9 @@ class CORE_EXPORT GraphAnimator : public Animator { const QString& attrName, const ValueGetter& valueGetter, const bool transform = false, - const QString& type = "") const; + const QString& type = "", + const QString& beginEvent = "", + const QString& endEvent = "") 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 222b7858d..ce3d1614c 100644 --- a/src/core/Animators/qpointfanimator.cpp +++ b/src/core/Animators/qpointfanimator.cpp @@ -258,10 +258,13 @@ void QPointFAnimator::saveQPointFSVGX(SvgExporter& exp, const qreal y, const qreal multiplier, const bool transform, - const QString& type) const { + const QString& type, + const QString &beginEvent, + const QString &endEvent) const +{ const QString templ = "%1 " + QString::number(y); mXAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier, - transform, type, templ); + transform, type, templ, beginEvent, endEvent); } void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp, @@ -271,10 +274,14 @@ void QPointFAnimator::saveQPointFSVGY(SvgExporter& exp, const qreal x, const qreal multiplier, const bool transform, - const QString& type) const { + const QString& type, + const QString &beginEvent, + const QString &endEvent) const +{ const QString templ = QString::number(x) + " %1"; mYAnimator->saveQrealSVG(exp, parent, visRange, name, multiplier, - transform, type, templ); + transform, type, templ, + beginEvent, endEvent); } QDomElement QPointFAnimator::prp_writePropertyXEV_impl(const XevExporter& exp) const { diff --git a/src/core/Animators/qpointfanimator.h b/src/core/Animators/qpointfanimator.h index 5da5ff06b..902e20444 100644 --- a/src/core/Animators/qpointfanimator.h +++ b/src/core/Animators/qpointfanimator.h @@ -109,7 +109,9 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator { const qreal y, const qreal multiplier, const bool transform = false, - const QString& type = "") const; + const QString& type = "", + const QString& beginEvent = "", + const QString& endEvent = "") const; void saveQPointFSVGY(SvgExporter& exp, QDomElement& parent, const FrameRange& visRange, @@ -117,7 +119,9 @@ class CORE_EXPORT QPointFAnimator : public StaticComplexAnimator { const qreal x, const qreal multiplier, const bool transform = false, - const QString& type = "") const; + const QString& type = "", + const QString& beginEvent = "", + const QString& endEvent = "") 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 b0943ad30..8d1eadf97 100644 --- a/src/core/Animators/qrealanimator.cpp +++ b/src/core/Animators/qrealanimator.cpp @@ -778,18 +778,23 @@ void QrealAnimator::saveQrealSVG(SvgExporter& exp, const qreal multiplier, const bool transform, const QString& type, - const QString& templ) { + const QString& templ, + const QString &beginEvent, + const QString &endEvent) +{ const auto mangler = [multiplier](const qreal value) { return value*multiplier; }; saveQrealSVG(exp, parent, visRange, attrName, - mangler, transform, type, templ); + mangler, transform, type, templ, beginEvent, 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& type, const QString& templ, + const QString &beginEvent, const QString &endEvent) +{ if(hasValidExpression()) { const auto copy = enve::make_shared(""); const auto relRange = prp_absRangeToRelRange(exp.fAbsRange); @@ -797,14 +802,15 @@ void QrealAnimator::saveQrealSVG(SvgExporter& exp, QDomElement& parent, copy->setExpression(mExpression.sptr()); copy->applyExpression(relRange, 10, false); copy->saveQrealSVG(exp, parent, visRange, attrName, - mangler, transform, type, templ); + mangler, transform, type, templ, + beginEvent, endEvent); 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); + }, transform, type, beginEvent, endEvent); } } diff --git a/src/core/Animators/qrealanimator.h b/src/core/Animators/qrealanimator.h index af0157328..7d7e74835 100644 --- a/src/core/Animators/qrealanimator.h +++ b/src/core/Animators/qrealanimator.h @@ -179,7 +179,9 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator { const qreal multiplier = 1., const bool transform = false, const QString& type = "", - const QString& templ = "%1"); + const QString& templ = "%1", + const QString& beginEvent = "", + const QString& endEvent = ""); using Mangler = std::function; void saveQrealSVG(SvgExporter& exp, QDomElement& parent, @@ -188,7 +190,9 @@ class CORE_EXPORT QrealAnimator : public GraphAnimator { const Mangler& mangler, const bool transform = false, const QString& type = "", - const QString& templ = "%1"); + const QString& templ = "%1", + const QString& beginEvent = "", + const QString& endEvent = ""); private: qreal calculateBaseValueAtRelFrame(const qreal frame) const; void startBaseValueTransform(); diff --git a/src/core/Animators/staticcomplexanimator.cpp b/src/core/Animators/staticcomplexanimator.cpp index a1373be2e..92a942f9a 100644 --- a/src/core/Animators/staticcomplexanimator.cpp +++ b/src/core/Animators/staticcomplexanimator.cpp @@ -24,6 +24,7 @@ // Fork of enve - Copyright (C) 2016-2020 Maurycy Liebner #include "staticcomplexanimator.h" +#include "ReadWrite/evformat.h" StaticComplexAnimator::StaticComplexAnimator(const QString &name) : ComplexAnimator(name) {} @@ -34,10 +35,15 @@ void StaticComplexAnimator::prp_writeProperty_impl(eWriteStream &dst) const { prop->prp_writeProperty(dst); } -void StaticComplexAnimator::prp_readProperty_impl(eReadStream &src) { +void StaticComplexAnimator::prp_readProperty_impl(eReadStream &src) +{ const auto& children = ca_getChildren(); - for(const auto& prop : children) + const auto SVGProperties = QStringList() << "begin event" << "end event"; + for (const auto& prop : children) { + if (src.evFileVersion() < EvFormat::svgBeginEnd && + SVGProperties.contains(prop->prp_getName())) { continue; } prop->prp_readProperty(src); + } } void StaticComplexAnimator::prp_readPropertyXEV_impl( diff --git a/src/core/Animators/transformanimator.cpp b/src/core/Animators/transformanimator.cpp index bb7a71d5b..df28016bf 100644 --- a/src/core/Animators/transformanimator.cpp +++ b/src/core/Animators/transformanimator.cpp @@ -45,6 +45,16 @@ BasicTransformAnimator::BasicTransformAnimator() : mRotAnimator = enve::make_shared("rotation"); mRotAnimator->setCurrentBaseValue(0); + const auto events = QStringList() << "none" << "click" << "dblclick" + << "mousedown" << "mouseenter" << "mouseleave" + << "mousemove" << "mouseout" << "mouseover" + << "mouseup"; + + mSVGBeginProperty = enve::make_shared("begin event", events); + mSVGEndProperty = enve::make_shared("end event", events); + + ca_addChild(mSVGBeginProperty); + ca_addChild(mSVGEndProperty); ca_addChild(mPosAnimator); ca_addChild(mRotAnimator); ca_addChild(mScaleAnimator); @@ -588,13 +598,33 @@ BoxTransformAnimator::BoxTransformAnimator() { getPointsHandler()->appendPt(pivotPt); } +const QString BoxTransformAnimator::getSVGPropertyAction(const int value) +{ + switch(value) { + case 1: return "click"; + case 2: return "dblclick"; + case 3: return "mousedown"; + case 4: return "mouseenter"; + case 5: return "mouseleave"; + case 6: return "mousemove"; + case 7: return "mouseout"; + case 8: return "mouseover"; + case 9: return "mouseup"; + default:; + } + return QString(); +} + QDomElement saveSVG_Split(QPointFAnimator* const anim, const FrameRange& visRange, const qreal multiplier, const qreal def, const QString& type, SvgExporter& exp, - const QDomElement& child) { + const QDomElement& child, + const QString& beginEvent, + const QString& endEvent) +{ const auto animX = anim->getXAnimator(); const auto animY = anim->getYAnimator(); @@ -608,21 +638,25 @@ QDomElement saveSVG_Split(QPointFAnimator* const anim, if(yStatic) { const qreal y = multiplier*animY->getEffectiveValue(); anim->saveQPointFSVGX(exp, unpivot, visRange, "transform", y, - multiplier, true, type); + multiplier, true, type, + beginEvent, endEvent); } else { const qreal x = multiplier*animX->getEffectiveValue(); anim->saveQPointFSVGY(exp, unpivot, visRange, "transform", x, - multiplier, true, type); + multiplier, true, type, + beginEvent, endEvent); } unpivot.appendChild(child); return unpivot; } else { auto xEle = exp.createElement("g"); anim->saveQPointFSVGX(exp, xEle, visRange, "transform", def, - multiplier, true, type); + multiplier, true, type, + beginEvent, endEvent); auto yEle = exp.createElement("g"); anim->saveQPointFSVGY(exp, yEle, visRange, "transform", def, - multiplier, true, type); + multiplier, true, type, + beginEvent, endEvent); yEle.appendChild(child); xEle.appendChild(yEle); @@ -630,11 +664,17 @@ QDomElement saveSVG_Split(QPointFAnimator* const anim, } } -QDomElement BoxTransformAnimator::saveSVG( - SvgExporter& exp, const FrameRange& visRange, - const QDomElement& child) const { +QDomElement BoxTransformAnimator::saveSVG(SvgExporter& exp, + const FrameRange& visRange, + const QDomElement& child) const +{ + + const auto beginEvent = getSVGPropertyAction(mSVGBeginProperty->getCurrentValue()); + const auto endEvent = getSVGPropertyAction(mSVGEndProperty->getCurrentValue()); + auto unpivot = saveSVG_Split(getPivotAnimator(), visRange, -1, 0, - "translate", exp, child); + "translate", exp, child, + beginEvent, endEvent); { const auto opaAnim = getOpacityAnimator(); opaAnim->saveQrealSVG(exp, unpivot, visRange, "opacity", 0.01); @@ -646,24 +686,30 @@ QDomElement BoxTransformAnimator::saveSVG( const auto shearXAnim = shearAnim->getXAnimator(); const auto shearYAnim = shearAnim->getYAnimator(); shearXAnim->saveQrealSVG(exp, shear, visRange, - "transform", 45, true, "skewX"); + "transform", 45, true, "skewX", "%1", + beginEvent, endEvent); shearYAnim->saveQrealSVG(exp, shear, visRange, - "transform", 45, true, "skewY"); + "transform", 45, true, "skewY", "%1", + beginEvent, endEvent); shear.appendChild(unpivot); } const auto scale = saveSVG_Split(getScaleAnimator(), visRange, 1, 1, - "scale", exp, shear); + "scale", exp, shear, + beginEvent, endEvent); auto rotate = exp.createElement("g"); { getRotAnimator()->saveQrealSVG(exp, rotate, visRange, - "transform", 1, true, "rotate"); + "transform", 1, true, "rotate", + "%1", beginEvent, endEvent); rotate.appendChild(scale); } const auto translate = saveSVG_Split(getPosAnimator(), visRange, 1, 0, - "translate", exp, rotate); + "translate", exp, rotate, + beginEvent, endEvent); auto pivot = saveSVG_Split(getPivotAnimator(), visRange, 1, 0, - "translate", exp, translate); + "translate", exp, translate, + beginEvent, endEvent); return pivot; } diff --git a/src/core/Animators/transformanimator.h b/src/core/Animators/transformanimator.h index 9d02a6e46..66a90938a 100644 --- a/src/core/Animators/transformanimator.h +++ b/src/core/Animators/transformanimator.h @@ -25,6 +25,7 @@ #ifndef TRANSFORMANIMATOR_H #define TRANSFORMANIMATOR_H +#include "Properties/comboboxproperty.h" #include "staticcomplexanimator.h" #include "../skia/skiaincludes.h" #include "transformvalues.h" @@ -119,6 +120,9 @@ class CORE_EXPORT BasicTransformAnimator : public StaticComplexAnimator { qsptr mPosAnimator; qsptr mScaleAnimator; qsptr mRotAnimator; + qsptr mSVGBeginProperty; + qsptr mSVGEndProperty; + private: bool rotationFlipped() const; signals: @@ -201,6 +205,7 @@ class CORE_EXPORT BoxTransformAnimator : public AdvancedTransformAnimator { protected: BoxTransformAnimator(); public: + static const QString getSVGPropertyAction(const int value); QDomElement saveSVG(SvgExporter& exp, const FrameRange& visRange, const QDomElement& child) const; }; diff --git a/src/core/Boxes/boundingbox.cpp b/src/core/Boxes/boundingbox.cpp index d3e7f2e7a..0e21a5252 100644 --- a/src/core/Boxes/boundingbox.cpp +++ b/src/core/Boxes/boundingbox.cpp @@ -74,6 +74,7 @@ BoundingBox::BoundingBox(const QString& name, const eBoxType type) : mCustomProperties->SWT_setVisible(false); mTransformAnimator->ca_addChild(mTransformEffectCollection); + setSVGPropertiesVisible(false); ca_addChild(mBlendEffectCollection); mBlendEffectCollection->SWT_hide(); @@ -1085,6 +1086,31 @@ void BoundingBox::setBlendEffectsVisible(const bool visible) { prp_afterWholeInfluenceRangeChanged(); } +void BoundingBox::setSVGPropertiesVisible(const bool visible) +{ + const auto& children = mTransformAnimator->ca_getNumberOfChildren(); + const auto properties = QStringList() << "begin event" << "end event"; + for (int i = 0; i < children; i++) { + const auto child = mTransformAnimator->ca_getChildAt(i); + if (!child) { continue; } + if (!properties.contains(child->prp_getName())) { continue; } + child->SWT_setVisible(visible); + } +} + +bool BoundingBox::getSVGPropertiesVisible() +{ + const auto& children = mTransformAnimator->ca_getNumberOfChildren(); + const auto properties = QStringList() << "begin event" << "end event"; + for (int i = 0; i < children; i++) { + const auto child = mTransformAnimator->ca_getChildAt(i); + if (!child) { continue; } + if (!properties.contains(child->prp_getName())) { continue; } + return child->SWT_isVisible(); + } + return false; +} + #include void BoundingBox::prp_setupTreeViewMenu(PropertyMenu * const menu) { if(menu->hasActionsForType()) return; @@ -1094,6 +1120,15 @@ void BoundingBox::prp_setupTreeViewMenu(PropertyMenu * const menu) { PropertyNameDialog::sRenameBox(this, parentWidget); }); menu->addSeparator(); + { + const PropertyMenu::CheckSelectedOp visRangeOp = + [](BoundingBox* const box, const bool checked) { + box->setSVGPropertiesVisible(checked); + }; + menu->addCheckableAction(tr("SVG Properties"), + getSVGPropertiesVisible(), + visRangeOp); + } { const PropertyMenu::CheckSelectedOp visRangeOp = [](BoundingBox* const box, const bool checked) { diff --git a/src/core/Boxes/boundingbox.h b/src/core/Boxes/boundingbox.h index 52ccd75d2..7dbae7a7d 100644 --- a/src/core/Boxes/boundingbox.h +++ b/src/core/Boxes/boundingbox.h @@ -473,6 +473,8 @@ class CORE_EXPORT BoundingBox : public eBoxOrSound { void setCustomPropertiesVisible(const bool visible); void setBlendEffectsVisible(const bool visible); void setTransformEffectsVisible(const bool visible); + void setSVGPropertiesVisible(const bool visible); + bool getSVGPropertiesVisible(); SkBlendMode mBlendMode = SkBlendMode::kSrcOver; diff --git a/src/core/ReadWrite/evformat.h b/src/core/ReadWrite/evformat.h index 27281e051..f816fec2d 100644 --- a/src/core/ReadWrite/evformat.h +++ b/src/core/ReadWrite/evformat.h @@ -41,6 +41,7 @@ namespace EvFormat { codecProfile = 26, effectCustomName = 27, markers = 28, + svgBeginEnd = 29, nextVersion };