Fix undo/redo of keyframes and presets

parent bfcf4bfa
......@@ -304,7 +304,7 @@ bool KeyframeModel::directUpdateKeyframe(GenTime pos, QVariant value)
return operation();
}
bool KeyframeModel::updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &redo)
bool KeyframeModel::updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &redo, bool update)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(m_keyframeList.count(pos) > 0);
......@@ -314,8 +314,8 @@ bool KeyframeModel::updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &
if (m_paramType == ParamType::KeyframeParam) {
if (qFuzzyCompare(oldValue.toDouble(), value.toDouble())) return true;
}
auto operation = updateKeyframe_lambda(pos, type, value, true);
auto reverse = updateKeyframe_lambda(pos, type, oldValue, true);
auto operation = updateKeyframe_lambda(pos, type, value, update);
auto reverse = updateKeyframe_lambda(pos, type, oldValue, update);
bool res = operation();
if (res) {
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
......@@ -731,12 +731,17 @@ void KeyframeModel::parseAnimProperty(const QString &prop)
Fun redo = []() { return true; };
Mlt::Properties mlt_prop;
QLocale locale;
disconnect(this, &KeyframeModel::modelChanged, this, &KeyframeModel::sendModification);
removeAllKeyframes(undo, redo);
mlt_prop.set("key", prop.toUtf8().constData());
// This is a fake query to force the animation to be parsed
(void)mlt_prop.anim_get_int("key", 0, 0);
Mlt::Animation *anim = mlt_prop.get_anim("key");
int in = 0;
if (auto ptr = m_model.lock()) {
in = ptr->data(m_index, AssetParameterModel::ParentInRole).toInt();
}
qDebug() << "Found" << anim->key_count() << "animation properties";
for (int i = 0; i < anim->key_count(); ++i) {
int frame;
......@@ -757,9 +762,18 @@ void KeyframeModel::parseAnimProperty(const QString &prop)
value = QVariant(mlt_prop.anim_get_double("key", frame));
break;
}
addKeyframe(GenTime(frame, pCore->getCurrentFps()), convertFromMltType(type), value, false, undo, redo);
if (i == 0 && frame > in) {
// Always add a keyframe at start pos
addKeyframe(GenTime(in, pCore->getCurrentFps()), convertFromMltType(type), value, true, undo, redo);
} else if (frame == in && hasKeyframe(GenTime(in))) {
// First keyframe already exists, adjust its value
updateKeyframe(GenTime(frame, pCore->getCurrentFps()), value, undo, redo, true);
continue;
}
addKeyframe(GenTime(frame, pCore->getCurrentFps()), convertFromMltType(type), value, true, undo, redo);
}
delete anim;
connect(this, &KeyframeModel::modelChanged, this, &KeyframeModel::sendModification);
}
......@@ -774,6 +788,10 @@ void KeyframeModel::resetAnimProperty(const QString &prop)
Mlt::Properties mlt_prop;
QLocale locale;
int in = 0;
if (auto ptr = m_model.lock()) {
in = ptr->data(m_index, AssetParameterModel::ParentInRole).toInt();
}
mlt_prop.set("key", prop.toUtf8().constData());
// This is a fake query to force the animation to be parsed
(void)mlt_prop.anim_get_int("key", 0, 0);
......@@ -800,6 +818,14 @@ void KeyframeModel::resetAnimProperty(const QString &prop)
value = QVariant(mlt_prop.anim_get_double("key", frame));
break;
}
if (i == 0 && frame > in) {
// Always add a keyframe at start pos
addKeyframe(GenTime(in, pCore->getCurrentFps()), convertFromMltType(type), value, false, undo, redo);
} else if (frame == in && hasKeyframe(GenTime(in))) {
// First keyframe already exists, adjust its value
updateKeyframe(GenTime(frame, pCore->getCurrentFps()), value, undo, redo, false);
continue;
}
addKeyframe(GenTime(frame, pCore->getCurrentFps()), convertFromMltType(type), value, false, undo, redo);
}
delete anim;
......@@ -809,8 +835,14 @@ void KeyframeModel::resetAnimProperty(const QString &prop)
} else {
effectName = i18n("effect");
}
Fun update_local = [this]() {
emit dataChanged(index(0), index(m_keyframeList.size()), {});
return true;
};
update_local();
PUSH_LAMBDA(update_local, undo);
PUSH_LAMBDA(update_local, redo);
PUSH_UNDO(undo, redo, i18n("Reset %1", effectName));
emit dataChanged(index(0), index(0), {ValueRole, NormalizedValueRole, TypeRole});
connect(this, &KeyframeModel::modelChanged, this, &KeyframeModel::sendModification);
}
......@@ -963,8 +995,6 @@ void KeyframeModel::sendModification()
} else {
Q_ASSERT(false); // Not implemented, TODO
}
m_lastData = data;
ptr->dataChanged(m_index, m_index);
}
}
......@@ -980,7 +1010,7 @@ void KeyframeModel::refresh()
}
if (animData == m_lastData) {
// nothing to do
qDebug()<<"// DATA WAS ALREADY PARSED, ABORTING\n_________________";
qDebug()<<"// DATA WAS ALREADY PARSED, ABORTING REFRESH\n_________________";
return;
}
if (m_paramType == ParamType::KeyframeParam || m_paramType == ParamType::AnimatedRect) {
......@@ -999,6 +1029,7 @@ void KeyframeModel::refresh()
Q_ASSERT(false); // Not implemented, TODO
}
}
m_lastData = animData;
}
void KeyframeModel::reset()
......@@ -1011,7 +1042,6 @@ void KeyframeModel::reset()
qDebug() << "WARNING : unable to access keyframe's model";
return;
}
qDebug()<<" + + + RFRSH PARAM: "<<animData;
if (animData == m_lastData) {
// nothing to do
qDebug()<<"// DATA WAS ALREADY PARSED, ABORTING\n_________________";
......@@ -1036,6 +1066,7 @@ void KeyframeModel::reset()
Q_ASSERT(false); // Not implemented, TODO
}
}
m_lastData = animData;
}
QList<QPoint> KeyframeModel::getRanges(const QString &animData)
......
......@@ -108,7 +108,7 @@ public:
Q_INVOKABLE bool updateKeyframe(int pos, double newVal);
bool updateKeyframe(GenTime pos, QVariant value);
bool updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo);
bool updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &redo);
bool updateKeyframe(GenTime pos, QVariant value, Fun &undo, Fun &redo, bool update = true);
/* @brief updates the value of a keyframe, without any management of undo/redo
@param pos is the position of the keyframe
@param value is the new value of the param
......
......@@ -169,7 +169,7 @@ void KeyframeView::mousePressEvent(QMouseEvent *event)
bool ok;
GenTime position(pos + offset, pCore->getCurrentFps());
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) * m_scale < ceil(m_lineHeight / 1.5)) {
m_currentKeyframeOriginal = keyframe.first.frames(pCore->getCurrentFps()) - offset;
// Select and seek to keyframe
m_currentKeyframe = m_currentKeyframeOriginal;
......@@ -207,7 +207,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent *event)
if (event->y() < m_lineHeight) {
bool ok;
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) * m_scale < ceil(m_lineHeight / 1.5)) {
m_hoverKeyframe = keyframe.first.frames(pCore->getCurrentFps()) - offset;
setCursor(Qt::PointingHandCursor);
update();
......@@ -243,7 +243,7 @@ void KeyframeView::mouseDoubleClickEvent(QMouseEvent *event)
GenTime position(pos + offset, pCore->getCurrentFps());
bool ok;
auto keyframe = m_model->getClosestKeyframe(position, &ok);
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) < ceil(m_lineHeight / 1.5)) {
if (ok && qAbs(keyframe.first.frames(pCore->getCurrentFps()) - pos - offset) * m_scale < ceil(m_lineHeight / 1.5)) {
m_model->removeKeyframe(keyframe.first);
if (keyframe.first.frames(pCore->getCurrentFps()) == m_currentKeyframe + offset) {
m_currentKeyframe = m_currentKeyframeOriginal = -1;
......
......@@ -123,7 +123,7 @@ bool AssetKeyframeCommand::mergeWith(const QUndoCommand *other)
return true;
}
AssetUpdateCommand::AssetUpdateCommand(std::shared_ptr<AssetParameterModel> model, QVector<QPair<QString, QVariant> > parameters, QUndoCommand *parent)
AssetUpdateCommand::AssetUpdateCommand(std::shared_ptr<AssetParameterModel> model, const QVector<QPair<QString, QVariant> > parameters, QUndoCommand *parent)
: QUndoCommand(parent)
, m_model(model)
, m_value(parameters)
......@@ -146,3 +146,9 @@ void AssetUpdateCommand::redo()
{
m_model->setParameters(m_value);
}
// virtual
int AssetUpdateCommand::id() const
{
return 3;
}
......@@ -71,6 +71,7 @@ public:
AssetUpdateCommand(std::shared_ptr<AssetParameterModel> model, QVector<QPair<QString, QVariant> > parameters, QUndoCommand *parent = nullptr);
void undo() override;
void redo() override;
int id() const override;
private:
std::shared_ptr<AssetParameterModel> m_model;
......
......@@ -166,9 +166,11 @@ void AssetParameterModel::setParameter(const QString &name, const int value, boo
emit modelChanged();
emit dataChanged(index(0, 0), index(m_rows.count() - 1, 0), {});
}
// Update timeline view if necessary
// Update fades in timeline
pCore->updateItemModel(m_ownerId, m_assetId);
// Trigger monitor refresh
pCore->refreshProjectItem(m_ownerId);
// Invalidate timeline preview
pCore->invalidateItem(m_ownerId);
}
}
......@@ -190,6 +192,7 @@ void AssetParameterModel::setParameter(const QString &name, const QString &value
}
} else {
m_asset->set(name.toLatin1().constData(), value.toUtf8().constData());
qDebug()<<" = = SET EFFECT PARAM: "<<name<<" = "<<value;
if (m_fixedParams.count(name) == 0) {
m_params[name].value = value;
} else {
......@@ -227,8 +230,11 @@ void AssetParameterModel::setParameter(const QString &name, const QString &value
if (!update)
emit modelChanged();
} else {
// Update fades in timeline
pCore->updateItemModel(m_ownerId, m_assetId);
// Trigger monitor refresh
pCore->refreshProjectItem(m_ownerId);
// Invalidate timeline preview
pCore->invalidateItem(m_ownerId);
}
}
......@@ -719,8 +725,11 @@ void AssetParameterModel::setParameters(const QVector<QPair<QString, QVariant>>
setParameter(param.first, param.second.toString(), false);
}
}
emit modelChanged();
emit dataChanged(index(0, 0), index(m_rows.count() - 1, 0), {});
if (m_keyframes) {
m_keyframes->refresh();
}
//emit modelChanged();
emit dataChanged(index(0), index(m_rows.count()), {});
}
ObjectId AssetParameterModel::getOwnerId() const
......
......@@ -116,7 +116,7 @@ void AssetParameterView::setModel(const std::shared_ptr<AssetParameterModel> &mo
}
}
void AssetParameterView::resetValues()
QVector<QPair<QString, QVariant> > AssetParameterView::getDefaultValues() const
{
QVector<QPair<QString, QVariant> > values;
for (int i = 0; i < m_model->rowCount(); ++i) {
......@@ -132,24 +132,18 @@ void AssetParameterView::resetValues()
}
}
values.append({name, defaultValue});
/*m_model->setParameter(name, defaultValue);
if (m_mainKeyframeWidget) {
// Handles additional params like rotation so only refresh initial param at the end
} else if (type == ParamType::ColorWheel) {
if (i == m_model->rowCount() - 1) {
// Special case, the ColorWheel widget handles several params, so only refresh once when all parameters were set.
QModelIndex firstIndex = m_model->index(0, 0);
refresh(firstIndex, firstIndex, QVector<int>());
}
} else {
refresh(index, index, QVector<int>());
}*/
}
return values;
}
void AssetParameterView::resetValues()
{
const QVector<QPair<QString, QVariant> > values = getDefaultValues();
AssetUpdateCommand *command = new AssetUpdateCommand(m_model, values);
pCore->pushUndo(command);
if (m_mainKeyframeWidget) {
/*if (m_mainKeyframeWidget) {
m_mainKeyframeWidget->resetKeyframes();
}
}*/
}
void AssetParameterView::commitChanges(const QModelIndex &index, const QString &value, bool storeUndo)
......
......@@ -100,6 +100,7 @@ private slots:
@param storeUndo: if true, an undo object is created
*/
void commitChanges(const QModelIndex &index, const QString &value, bool storeUndo);
QVector<QPair<QString, QVariant> > getDefaultValues() const;
signals:
void seekToPos(int);
......
......@@ -316,7 +316,7 @@ void KeyframeWidget::resetKeyframes()
int duration = m_model->data(m_index, AssetParameterModel::ParentDurationRole).toInt(&ok);
Q_ASSERT(ok);
// reset keyframes
m_keyframes->reset();
m_keyframes->refresh();
//m_model->dataChanged(QModelIndex(), QModelIndex());
m_keyframeview->setDuration(duration);
m_time->setRange(0, duration - 1);
......
......@@ -392,6 +392,7 @@ Rectangle {
inPoint: clipRoot.inPoint
outPoint: clipRoot.outPoint
masterObject: clipRoot
kfrModel: clipRoot.keyframeModel
}
}
......
......@@ -227,6 +227,7 @@ Item {
inPoint: 0
outPoint: compositionRoot.clipDuration
masterObject: compositionRoot
kfrModel: compositionRoot.keyframeModel
}
}
/*Drag.active: mouseArea.drag.active
......
......@@ -35,6 +35,7 @@ Rectangle
property int outPoint
property bool selected
property var masterObject
property var kfrModel
onKfrCountChanged: {
keyframecanvas.requestPaint()
......@@ -49,7 +50,7 @@ Rectangle
if (activeFrame < 0) {
activeFrame = 0
} else {
keyframeModel.moveKeyframe(oldFrame, activeFrame, true)
kfrModel.moveKeyframe(oldFrame, activeFrame, true)
}
}
event.accepted = true
......@@ -60,7 +61,7 @@ Rectangle
} else {
var oldFrame = activeFrame
activeFrame += 1
keyframeModel.moveKeyframe(oldFrame, activeFrame, true)
kfrModel.moveKeyframe(oldFrame, activeFrame, true)
}
event.accepted = true
}
......@@ -70,19 +71,19 @@ Rectangle
}
if ((event.key == Qt.Key_Plus) && !(event.modifiers & Qt.ControlModifier)) {
var newVal = Math.min(keyframes.itemAt(activeIndex).value / parent.height + .05, 1)
keyframeModel.updateKeyframe(activeFrame, newVal)
kfrModel.updateKeyframe(activeFrame, newVal)
event.accepted = true
}
else if ((event.key == Qt.Key_Minus) && !(event.modifiers & Qt.ControlModifier)) {
var newVal = Math.max(keyframes.itemAt(activeIndex).value / parent.height - .05, 0)
keyframeModel.updateKeyframe(activeFrame, newVal)
kfrModel.updateKeyframe(activeFrame, newVal)
event.accepted = true
}
event.accepted = false
}
Repeater {
id: keyframes
model: keyframeModel
model: kfrModel
Rectangle {
id: keyframe
property int frame : model.frame
......@@ -118,9 +119,9 @@ Rectangle
if (frame != inPoint && newPos != frame) {
if (mouse.modifiers & Qt.ShiftModifier) {
// offset all subsequent keyframes
keyframeModel.offsetKeyframes(frame, newPos, true)
kfrModel.offsetKeyframes(frame, newPos, true)
} else {
keyframeModel.moveKeyframe(frame, newPos, true)
kfrModel.moveKeyframe(frame, newPos, true)
}
}
}
......
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