Copy / paste effect with keyframes now correctly adjusts the keyframes to offset

parent 821e96eb
......@@ -1158,6 +1158,30 @@ std::shared_ptr<Mlt::Properties> KeyframeModel::getAnimation(std::shared_ptr<Ass
return mlt_prop;
}
const QString KeyframeModel::getAnimationStringWithOffset(std::shared_ptr<AssetParameterModel> model, const QString &animData, int offset)
{
Mlt::Properties mlt_prop;
model->passProperties(mlt_prop);
mlt_prop.set("key", animData.toUtf8().constData());
// This is a fake query to force the animation to be parsed
(void)mlt_prop.anim_get_rect("key", 0);
Mlt::Animation anim = mlt_prop.get_animation("key");
if (offset > 0) {
for (int i = anim.key_count() - 1; i >=0 ; --i) {
int pos = anim.key_get_frame(i) + offset;
anim.key_set_frame(i, pos);
}
} else {
for (int i = 0; i < anim.key_count(); ++i) {
int pos = anim.key_get_frame(i) + offset;
if (pos > 0) {
anim.key_set_frame(i, pos);
}
}
}
return qstrdup(anim.serialize_cut());
}
QList<GenTime> KeyframeModel::getKeyframePos() const
{
QList<GenTime> all_pos;
......
......@@ -166,6 +166,7 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
static QList<QPoint> getRanges(const QString &animData, const std::shared_ptr<AssetParameterModel> &model);
static std::shared_ptr<Mlt::Properties> getAnimation(std::shared_ptr<AssetParameterModel> model, const QString &animData, int duration = 0);
static const QString getAnimationStringWithOffset(std::shared_ptr<AssetParameterModel> model, const QString &animData, int offset);
protected:
/** @brief Helper function that generate a lambda to change type / value of given keyframe */
......
......@@ -134,8 +134,8 @@ void AssetParameterModel::prepareKeyframes()
if (m_keyframes) return;
int ix = 0;
for (const auto &name : m_rows) {
if (m_params[name].type == ParamType::KeyframeParam || m_params[name].type == ParamType::AnimatedRect ||
m_params[name].type == ParamType::Roto_spline) {
if (m_params.at(name).type == ParamType::KeyframeParam || m_params.at(name).type == ParamType::AnimatedRect ||
m_params.at(name).type == ParamType::Roto_spline) {
addKeyframeParam(index(ix, 0));
}
ix++;
......@@ -146,6 +146,20 @@ void AssetParameterModel::prepareKeyframes()
}
}
QStringList AssetParameterModel::getKeyframableParameters() const
{
QStringList paramNames;
int ix = 0;
for (const auto &name : m_rows) {
if (m_params.at(name).type == ParamType::KeyframeParam || m_params.at(name).type == ParamType::AnimatedRect) {
//addKeyframeParam(index(ix, 0));
paramNames << name;
}
ix++;
}
return paramNames;
}
void AssetParameterModel::setParameter(const QString &name, int value, bool update)
{
Q_ASSERT(m_asset->is_valid());
......
......@@ -168,6 +168,8 @@ public:
bool hasMoreThanOneKeyframe() const;
int time_to_frames(const QString &time);
void passProperties(Mlt::Properties &target);
/* @brief Returns a list of the parameter names that are keyframable */
QStringList getKeyframableParameters() const;
protected:
/* @brief Helper function to retrieve the type of a parameter given the string corresponding to it*/
......
......@@ -210,8 +210,12 @@ QDomElement EffectStackModel::toXml(QDomDocument &document)
std::shared_ptr<EffectItemModel> sourceEffect = std::static_pointer_cast<EffectItemModel>(rootItem->child(i));
QDomElement sub = document.createElement(QStringLiteral("effect"));
sub.setAttribute(QStringLiteral("id"), sourceEffect->getAssetId());
sub.setAttribute(QStringLiteral("in"), sourceEffect->filter().get_int("in"));
sub.setAttribute(QStringLiteral("out"), sourceEffect->filter().get_int("out"));
int filterIn = sourceEffect->filter().get_int("in");
int filterOut = sourceEffect->filter().get_int("out");
if (filterOut > filterIn) {
sub.setAttribute(QStringLiteral("in"), filterIn);
sub.setAttribute(QStringLiteral("out"), filterOut);
}
QVector<QPair<QString, QVariant>> params = sourceEffect->getAllParameters();
QLocale locale;
for (const auto &param : params) {
......@@ -229,6 +233,8 @@ QDomElement EffectStackModel::toXml(QDomDocument &document)
bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo)
{
QDomNodeList nodeList = effectsXml.elementsByTagName(QStringLiteral("effect"));
int parentIn = effectsXml.attribute(QStringLiteral("parentIn")).toInt();
int currentIn = pCore->getItemIn(m_ownerId);
PlaylistState::ClipState state = pCore->getItemState(m_ownerId);
for (int i = 0; i < nodeList.count(); ++i) {
QDomElement node = nodeList.item(i).toElement();
......@@ -248,11 +254,19 @@ bool EffectStackModel::fromXml(const QDomElement &effectsXml, Fun &undo, Fun &re
effect->filter().set("in", in);
effect->filter().set("out", out);
}
QStringList keyframeParams = effect->getKeyframableParameters();
QVector<QPair<QString, QVariant>> parameters;
QDomNodeList params = node.elementsByTagName(QStringLiteral("property"));
for (int j = 0; j < params.count(); j++) {
QDomElement pnode = params.item(j).toElement();
parameters.append(QPair<QString, QVariant>(pnode.attribute(QStringLiteral("name")), QVariant(pnode.text())));
const QString pName = pnode.attribute(QStringLiteral("name"));
if (keyframeParams.contains(pName)) {
// This is a keyframable parameter, fix offest
QString pValue = KeyframeModel::getAnimationStringWithOffset(effect, pnode.text(), currentIn - parentIn);
parameters.append(QPair<QString, QVariant>(pName, QVariant(pValue)));
} else {
parameters.append(QPair<QString, QVariant>(pName, QVariant(pnode.text())));
}
}
effect->setParameters(parameters);
Fun local_undo = removeItem_lambda(effect->getId());
......
......@@ -1834,9 +1834,12 @@ void TimelineController::pasteEffects(int targetId)
std::function<bool(void)> undo = []() { return true; };
std::function<bool(void)> redo = []() { return true; };
QDomElement effects = clips.at(0).firstChildElement(QStringLiteral("effects"));
effects.setAttribute(QStringLiteral("parentIn"), clips.at(0).toElement().attribute(QStringLiteral("in")));
for (int i = 1; i < clips.size(); i++) {
QDomNodeList subs = clips.at(i).childNodes();
QDomElement subeffects = clips.at(i).firstChildElement(QStringLiteral("effects"));
QDomNodeList subs = subeffects.childNodes();
for (int j = 0; j < subs.size(); j++) {
subs.at(j).toElement().setAttribute(QStringLiteral("parentIn"), clips.at(i).toElement().attribute(QStringLiteral("in")));
effects.appendChild(subs.at(j));
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment