File indexing completed on 2024-05-12 04:52:47
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "keyframemodellist.hpp" 0007 #include "assets/model/assetcommand.hpp" 0008 #include "assets/model/assetparametermodel.hpp" 0009 #include "core.h" 0010 #include "doc/docundostack.hpp" 0011 #include "keyframemodel.hpp" 0012 #include "klocalizedstring.h" 0013 #include "macros.hpp" 0014 #include <kdenlivesettings.h> 0015 0016 #include <QDebug> 0017 #include <utility> 0018 KeyframeModelList::KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, int in, 0019 int out) 0020 : m_model(std::move(model)) 0021 , m_undoStack(std::move(undo_stack)) 0022 , m_lock(QReadWriteLock::Recursive) 0023 { 0024 qDebug() << "Construct keyframemodellist. Checking model:" << m_model.expired(); 0025 addParameter(index, in, out); 0026 } 0027 0028 ObjectId KeyframeModelList::getOwnerId() const 0029 { 0030 if (auto ptr = m_model.lock()) { 0031 return ptr->getOwnerId(); 0032 } 0033 return ObjectId(); 0034 } 0035 0036 const QString KeyframeModelList::getAssetId() 0037 { 0038 if (auto ptr = m_model.lock()) { 0039 return ptr->getAssetId(); 0040 } 0041 return {}; 0042 } 0043 0044 QVector<int> KeyframeModelList::selectedKeyframes() const 0045 { 0046 if (auto ptr = m_model.lock()) { 0047 return ptr->m_selectedKeyframes; 0048 } 0049 return {}; 0050 } 0051 0052 int KeyframeModelList::activeKeyframe() const 0053 { 0054 if (auto ptr = m_model.lock()) { 0055 return ptr->m_activeKeyframe; 0056 } 0057 return -1; 0058 } 0059 0060 void KeyframeModelList::setActiveKeyframe(int ix) 0061 { 0062 m_parameters.begin()->second->setActiveKeyframe(ix); 0063 } 0064 0065 void KeyframeModelList::removeFromSelected(int ix) 0066 { 0067 m_parameters.begin()->second->setSelectedKeyframe(ix, true); 0068 } 0069 0070 void KeyframeModelList::setSelectedKeyframes(const QVector<int> &list) 0071 { 0072 m_parameters.begin()->second->setSelectedKeyframes(list); 0073 } 0074 0075 void KeyframeModelList::appendSelectedKeyframe(int ix) 0076 { 0077 m_parameters.begin()->second->setSelectedKeyframe(ix, true); 0078 } 0079 0080 const QString KeyframeModelList::getAssetRow() 0081 { 0082 if (auto ptr = m_model.lock()) { 0083 return ptr->getAssetMltId(); 0084 } 0085 return QString(); 0086 } 0087 0088 void KeyframeModelList::addParameter(const QModelIndex &index, int in, int out) 0089 { 0090 std::shared_ptr<KeyframeModel> parameter(new KeyframeModel(m_model, index, m_undoStack, in, out)); 0091 connect(parameter.get(), &KeyframeModel::modelChanged, this, &KeyframeModelList::modelChanged); 0092 connect(parameter.get(), &KeyframeModel::requestModelUpdate, this, &KeyframeModelList::slotUpdateModels); 0093 m_parameters.insert({index, std::move(parameter)}); 0094 } 0095 0096 void KeyframeModelList::slotUpdateModels(const QModelIndex &ix1, const QModelIndex &ix2, const QVector<int> &roles) 0097 { 0098 // Propagate change to all keyframe models 0099 for (const auto ¶m : m_parameters) { 0100 Q_EMIT param.second->dataChanged(ix1, ix2, roles); 0101 } 0102 Q_EMIT modelDisplayChanged(); 0103 } 0104 0105 bool KeyframeModelList::applyOperation(const std::function<bool(std::shared_ptr<KeyframeModel>, Fun &, Fun &)> &op, const QString &undoString) 0106 { 0107 QWriteLocker locker(&m_lock); 0108 Q_ASSERT(m_parameters.size() > 0); 0109 Fun undo = []() { return true; }; 0110 Fun redo = []() { return true; }; 0111 0112 bool res = true; 0113 for (const auto ¶m : m_parameters) { 0114 res = op(param.second, undo, redo); 0115 if (!res) { 0116 bool undone = undo(); 0117 Q_ASSERT(undone); 0118 return res; 0119 } 0120 } 0121 if (res && !undoString.isEmpty()) { 0122 PUSH_UNDO(undo, redo, undoString); 0123 } 0124 return res; 0125 } 0126 0127 bool KeyframeModelList::addKeyframe(GenTime pos, KeyframeType type) 0128 { 0129 QWriteLocker locker(&m_lock); 0130 Q_ASSERT(m_parameters.size() > 0); 0131 bool update = (m_parameters.begin()->second->hasKeyframe(pos) > 0); 0132 auto op = [pos, type](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { 0133 QVariant value = param->getInterpolatedValue(pos); 0134 return param->addKeyframe(pos, type, value, true, undo, redo); 0135 }; 0136 return applyOperation(op, update ? i18n("Change keyframe type") : i18n("Add keyframe")); 0137 } 0138 0139 bool KeyframeModelList::addKeyframe(int frame, double val) 0140 { 0141 QWriteLocker locker(&m_lock); 0142 GenTime pos(frame, pCore->getCurrentFps()); 0143 Q_ASSERT(m_parameters.size() > 0); 0144 bool update = (m_parameters.begin()->second->hasKeyframe(pos) > 0); 0145 bool isRectParam = false; 0146 if (m_inTimelineIndex.isValid()) { 0147 if (auto ptr = m_model.lock()) { 0148 auto tp = ptr->data(m_inTimelineIndex, AssetParameterModel::TypeRole).value<ParamType>(); 0149 if (tp == ParamType::AnimatedRect) { 0150 isRectParam = true; 0151 } 0152 } 0153 } 0154 auto op = [this, pos, val, isRectParam](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { 0155 QVariant value; 0156 if (m_inTimelineIndex.isValid()) { 0157 if (m_parameters.at(m_inTimelineIndex) == param) { 0158 if (isRectParam) { 0159 value = param->getInterpolatedValue(pos); 0160 value = param->updateInterpolated(value, val); 0161 } else { 0162 value = param->getNormalizedValue(val); 0163 } 0164 } else { 0165 value = param->getInterpolatedValue(pos); 0166 } 0167 } else if (m_parameters.begin()->second == param) { 0168 value = param->getNormalizedValue(val); 0169 } else { 0170 value = param->getInterpolatedValue(pos); 0171 } 0172 return param->addKeyframe(pos, KeyframeType(KdenliveSettings::defaultkeyframeinterp()), value, true, undo, redo); 0173 }; 0174 return applyOperation(op, update ? i18n("Change keyframe type") : i18n("Add keyframe")); 0175 } 0176 0177 bool KeyframeModelList::removeKeyframe(GenTime pos) 0178 { 0179 QWriteLocker locker(&m_lock); 0180 Q_ASSERT(m_parameters.size() > 0); 0181 auto op = [pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeKeyframe(pos, undo, redo); }; 0182 return applyOperation(op, i18n("Delete keyframe")); 0183 } 0184 0185 bool KeyframeModelList::removeKeyframeWithUndo(GenTime pos, Fun &undo, Fun &redo) 0186 { 0187 bool result = true; 0188 for (const auto ¶m : m_parameters) { 0189 result = result && param.second->removeKeyframe(pos, undo, redo); 0190 } 0191 return result; 0192 } 0193 0194 bool KeyframeModelList::duplicateKeyframeWithUndo(GenTime srcPos, GenTime destPos, Fun &undo, Fun &redo) 0195 { 0196 bool result = true; 0197 for (const auto ¶m : m_parameters) { 0198 result = result && param.second->duplicateKeyframe(srcPos, destPos, undo, redo); 0199 } 0200 return result; 0201 } 0202 0203 bool KeyframeModelList::removeAllKeyframes() 0204 { 0205 QWriteLocker locker(&m_lock); 0206 Q_ASSERT(m_parameters.size() > 0); 0207 auto op = [](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeAllKeyframes(undo, redo); }; 0208 return applyOperation(op, i18n("Delete all keyframes")); 0209 } 0210 0211 bool KeyframeModelList::removeNextKeyframes(GenTime pos) 0212 { 0213 QWriteLocker locker(&m_lock); 0214 Q_ASSERT(m_parameters.size() > 0); 0215 auto op = [pos](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { return param->removeNextKeyframes(pos, undo, redo); }; 0216 return applyOperation(op, i18n("Delete keyframes")); 0217 } 0218 0219 bool KeyframeModelList::moveKeyframe(GenTime oldPos, GenTime pos, bool logUndo, bool updateView) 0220 { 0221 QWriteLocker locker(&m_lock); 0222 Q_ASSERT(m_parameters.size() > 0); 0223 auto op = [oldPos, pos, updateView](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { 0224 return param->moveKeyframe(oldPos, pos, QVariant(), undo, redo, updateView); 0225 }; 0226 return applyOperation(op, logUndo ? i18nc("@action", "Move keyframe") : QString()); 0227 } 0228 0229 bool KeyframeModelList::moveKeyframeWithUndo(GenTime oldPos, GenTime pos, Fun &undo, Fun &redo) 0230 { 0231 bool result = true; 0232 for (const auto ¶m : m_parameters) { 0233 result = result && param.second->moveKeyframe(oldPos, pos, QVariant(), undo, redo); 0234 } 0235 return result; 0236 } 0237 0238 bool KeyframeModelList::updateKeyframe(GenTime oldPos, GenTime pos, const QVariant &normalizedVal, bool logUndo) 0239 { 0240 QWriteLocker locker(&m_lock); 0241 Q_ASSERT(m_parameters.size() > 0); 0242 bool isRectParam = false; 0243 if (m_inTimelineIndex.isValid()) { 0244 if (auto ptr = m_model.lock()) { 0245 auto tp = ptr->data(m_inTimelineIndex, AssetParameterModel::TypeRole).value<ParamType>(); 0246 if (tp == ParamType::AnimatedRect) { 0247 isRectParam = true; 0248 } 0249 } 0250 } 0251 auto op = [this, oldPos, pos, normalizedVal, isRectParam](std::shared_ptr<KeyframeModel> param, Fun &undo, Fun &redo) { 0252 QVariant value; 0253 if (m_inTimelineIndex.isValid()) { 0254 if (m_parameters.at(m_inTimelineIndex) == param) { 0255 if (isRectParam) { 0256 if (normalizedVal.isValid()) { 0257 double newValue = normalizedVal.toDouble(); 0258 value = param->getInterpolatedValue(oldPos); 0259 value = param->updateInterpolated(value, newValue); 0260 } 0261 } else { 0262 value = normalizedVal; 0263 } 0264 } 0265 } else if (m_parameters.begin()->second == param) { 0266 value = normalizedVal; 0267 } 0268 return param->moveKeyframe(oldPos, pos, value, undo, redo); 0269 }; 0270 return applyOperation(op, logUndo ? i18nc("@action", "Move keyframe") : QString()); 0271 } 0272 0273 bool KeyframeModelList::updateKeyframe(GenTime pos, const QVariant &value, const QPersistentModelIndex &index, QUndoCommand *parentCommand) 0274 { 0275 if (singleKeyframe()) { 0276 bool ok = false; 0277 Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok); 0278 pos = kf.first; 0279 } 0280 if (auto ptr = m_model.lock()) { 0281 auto *command = new AssetKeyframeCommand(ptr, index, value, pos, parentCommand); 0282 if (parentCommand == nullptr) { 0283 pCore->pushUndo(command); 0284 } // clang-tidy: else "command" is leaked? no because is was pushed to parentCommand 0285 } 0286 return true; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) 0287 } 0288 0289 bool KeyframeModelList::updateMultiKeyframe(GenTime pos, const QStringList &sourceValues, const QStringList &values, const QList<QModelIndex> &indexes, 0290 QUndoCommand *parentCommand) 0291 { 0292 if (singleKeyframe()) { 0293 bool ok = false; 0294 Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok); 0295 pos = kf.first; 0296 } 0297 if (auto ptr = m_model.lock()) { 0298 auto *command = new AssetMultiKeyframeCommand(ptr, indexes, sourceValues, values, pos, parentCommand); 0299 if (parentCommand == nullptr) { 0300 pCore->pushUndo(command); 0301 } // clang-tidy: else "command" is leaked? no because is was pushed to parentCommand 0302 } 0303 return true; // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) 0304 } 0305 0306 bool KeyframeModelList::updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index) 0307 { 0308 QWriteLocker locker(&m_lock); 0309 Q_ASSERT(m_parameters.count(index) > 0); 0310 Fun undo = []() { return true; }; 0311 Fun redo = []() { return true; }; 0312 if (singleKeyframe()) { 0313 bool ok = false; 0314 Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok); 0315 pos = kf.first; 0316 } 0317 // Update kf type in all parameters 0318 bool res = true; 0319 for (const auto ¶m : m_parameters) { 0320 res = res && param.second->updateKeyframeType(pos, type, undo, redo); 0321 } 0322 if (res) { 0323 PUSH_UNDO(undo, redo, i18n("Update keyframe")); 0324 } 0325 return res; 0326 } 0327 0328 KeyframeType KeyframeModelList::keyframeType(GenTime pos) const 0329 { 0330 QWriteLocker locker(&m_lock); 0331 if (singleKeyframe()) { 0332 bool ok = false; 0333 Keyframe kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &ok); 0334 return kf.second; 0335 } 0336 bool ok = false; 0337 Keyframe kf = m_parameters.begin()->second->getKeyframe(pos, &ok); 0338 return kf.second; 0339 } 0340 0341 Keyframe KeyframeModelList::getKeyframe(const GenTime &pos, bool *ok) const 0342 { 0343 READ_LOCK(); 0344 Q_ASSERT(m_parameters.size() > 0); 0345 return m_parameters.begin()->second->getKeyframe(pos, ok); 0346 } 0347 0348 bool KeyframeModelList::singleKeyframe() const 0349 { 0350 READ_LOCK(); 0351 Q_ASSERT(m_parameters.size() > 0); 0352 return m_parameters.begin()->second->singleKeyframe(); 0353 } 0354 0355 bool KeyframeModelList::isEmpty() const 0356 { 0357 READ_LOCK(); 0358 return (m_parameters.size() == 0 || m_parameters.begin()->second->rowCount() == 0); 0359 } 0360 0361 int KeyframeModelList::count() const 0362 { 0363 READ_LOCK(); 0364 if (m_parameters.size() > 0) return m_parameters.begin()->second->rowCount(); 0365 return 0; 0366 } 0367 0368 Keyframe KeyframeModelList::getNextKeyframe(const GenTime &pos, bool *ok) const 0369 { 0370 READ_LOCK(); 0371 Q_ASSERT(m_parameters.size() > 0); 0372 return m_parameters.begin()->second->getNextKeyframe(pos, ok); 0373 } 0374 0375 Keyframe KeyframeModelList::getPrevKeyframe(const GenTime &pos, bool *ok) const 0376 { 0377 READ_LOCK(); 0378 Q_ASSERT(m_parameters.size() > 0); 0379 return m_parameters.begin()->second->getPrevKeyframe(pos, ok); 0380 } 0381 0382 Keyframe KeyframeModelList::getClosestKeyframe(const GenTime &pos, bool *ok) const 0383 { 0384 READ_LOCK(); 0385 Q_ASSERT(m_parameters.size() > 0); 0386 return m_parameters.begin()->second->getClosestKeyframe(pos, ok); 0387 } 0388 0389 bool KeyframeModelList::hasKeyframe(int frame) const 0390 { 0391 READ_LOCK(); 0392 Q_ASSERT(m_parameters.size() > 0); 0393 return m_parameters.begin()->second->hasKeyframe(frame); 0394 } 0395 0396 void KeyframeModelList::refresh() 0397 { 0398 QWriteLocker locker(&m_lock); 0399 for (const auto ¶m : m_parameters) { 0400 param.second->refresh(); 0401 } 0402 } 0403 0404 void KeyframeModelList::setParametersFromTask(const paramVector ¶ms) 0405 { 0406 Fun redo = []() { return true; }; 0407 Fun undo = []() { return true; }; 0408 paramVector previousParams; 0409 // Collect all parameters previous values for undo 0410 if (auto ptr = m_model.lock()) { 0411 READ_LOCK(); 0412 for (const auto ¶m : m_parameters) { 0413 const QString paramName = ptr->data(param.first, AssetParameterModel::NameRole).toString(); 0414 QPair<QString, QVariant> val(paramName, ptr->getParamFromName(paramName)); 0415 previousParams.append(val); 0416 } 0417 } 0418 QStringList updatedNames; 0419 paramVector currentValues; 0420 if (auto ptr = m_model.lock()) { 0421 for (auto &p : params) { 0422 currentValues.append({p.first, ptr->getParamFromName(p.first)}); 0423 updatedNames << p.first; 0424 } 0425 } 0426 Fun local_redo = [this, params]() { 0427 if (auto ptr = m_model.lock()) { 0428 ptr->setParameters(params); 0429 } 0430 return true; 0431 }; 0432 Fun local_undo = [this, currentValues]() { 0433 if (auto ptr = m_model.lock()) { 0434 ptr->setParameters(currentValues); 0435 } 0436 return true; 0437 }; 0438 local_redo(); 0439 if (auto ptr = m_model.lock()) { 0440 const QModelIndex ix = ptr->getParamIndexFromName(params.first().first); 0441 if (ix.isValid()) { 0442 QList<GenTime> kfrs = m_parameters.at(ix)->getKeyframePos(); 0443 auto type = KeyframeType(KdenliveSettings::defaultkeyframeinterp()); 0444 for (const auto &p : m_parameters) { 0445 const QString paramName = ptr->data(p.first, AssetParameterModel::NameRole).toString(); 0446 if (!updatedNames.contains(paramName)) { 0447 // We need to sync this parameter keyframes. 0448 // Remove all kfrs first 0449 p.second->removeAllKeyframes(undo, redo); 0450 // Now, sync 0451 for (auto &k : kfrs) { 0452 if (!p.second->hasKeyframe(k)) { 0453 QVariant value = p.second->getInterpolatedValue(k); 0454 p.second->addKeyframe(k, type, value, false, undo, redo); 0455 } 0456 } 0457 } 0458 } 0459 } 0460 refresh(); 0461 UPDATE_UNDO_REDO_NOLOCK(local_redo, local_undo, undo, redo); 0462 } 0463 pCore->pushUndo(undo, redo, i18n("Update effect")); 0464 } 0465 0466 void KeyframeModelList::reset() 0467 { 0468 QWriteLocker locker(&m_lock); 0469 for (const auto ¶m : m_parameters) { 0470 param.second->reset(); 0471 } 0472 } 0473 0474 QVariant KeyframeModelList::getInterpolatedValue(int pos, const QPersistentModelIndex &index) const 0475 { 0476 READ_LOCK(); 0477 Q_ASSERT(m_parameters.count(index) > 0); 0478 return m_parameters.at(index)->getInterpolatedValue(pos); 0479 } 0480 0481 QVariant KeyframeModelList::getInterpolatedValue(const GenTime &pos, const QPersistentModelIndex &index) const 0482 { 0483 READ_LOCK(); 0484 Q_ASSERT(m_parameters.count(index) > 0); 0485 return m_parameters.at(index)->getInterpolatedValue(pos); 0486 } 0487 0488 KeyframeModel *KeyframeModelList::getKeyModel() 0489 { 0490 if (m_inTimelineIndex.isValid()) { 0491 return m_parameters.at(m_inTimelineIndex).get(); 0492 } 0493 if (auto ptr = m_model.lock()) { 0494 for (const auto ¶m : m_parameters) { 0495 auto tp = ptr->data(param.first, AssetParameterModel::TypeRole).value<ParamType>(); 0496 if (tp == ParamType::AnimatedRect) { 0497 // Check if we have an opacity 0498 if (ptr->data(param.first, AssetParameterModel::OpacityRole).toBool() == false) { 0499 // Rect with no opacity, don't show timeline keyframes 0500 continue; 0501 } 0502 } 0503 if (ptr->data(param.first, AssetParameterModel::ShowInTimelineRole) == true) { 0504 m_inTimelineIndex = param.first; 0505 return param.second.get(); 0506 } 0507 } 0508 } 0509 return nullptr; 0510 } 0511 0512 KeyframeModel *KeyframeModelList::getKeyModel(const QPersistentModelIndex &index) 0513 { 0514 if (m_parameters.size() > 0 && m_parameters.find(index) != m_parameters.end()) { 0515 return m_parameters.at(index).get(); 0516 } 0517 return nullptr; 0518 } 0519 0520 void KeyframeModelList::moveKeyframes(int oldIn, int in, Fun &undo, Fun &redo) 0521 { 0522 // Get list of keyframes positions 0523 QList<GenTime> positions = m_parameters.begin()->second->getKeyframePos(); 0524 GenTime offset(in - oldIn, pCore->getCurrentFps()); 0525 if (in > oldIn) { 0526 // Moving to the right, process in reverse order to prevent collisions 0527 std::sort(positions.begin(), positions.end(), std::greater<>()); 0528 } else { 0529 std::sort(positions.begin(), positions.end()); 0530 } 0531 for (const auto ¶m : m_parameters) { 0532 for (auto frame : qAsConst(positions)) { 0533 param.second->moveKeyframe(frame, frame + offset, QVariant(), undo, redo); 0534 } 0535 } 0536 } 0537 0538 void KeyframeModelList::resizeKeyframes(int oldIn, int oldOut, int in, int out, int offset, bool adjustFromEnd, Fun &undo, Fun &redo) 0539 { 0540 bool ok = false, ok2 = false; 0541 QList<GenTime> positions; 0542 if (!adjustFromEnd) { 0543 if (offset != 0) { 0544 // this is an endless resize clip 0545 GenTime old_in(oldIn, pCore->getCurrentFps()); 0546 GenTime new_in(in + offset, pCore->getCurrentFps()); 0547 getKeyframe(new_in, &ok2); 0548 positions = m_parameters.begin()->second->getKeyframePos(); 0549 std::sort(positions.begin(), positions.end()); 0550 for (const auto ¶m : m_parameters) { 0551 if (offset > 0) { 0552 QVariant value = param.second->getInterpolatedValue(new_in); 0553 param.second->updateKeyframe(old_in, value, undo, redo); 0554 } 0555 for (auto frame : qAsConst(positions)) { 0556 if (new_in > GenTime()) { 0557 if (frame > new_in) { 0558 param.second->moveKeyframe(frame, frame - new_in, QVariant(), undo, redo); 0559 continue; 0560 } 0561 } else if (frame > GenTime()) { 0562 param.second->moveKeyframe(frame, frame - new_in, QVariant(), undo, redo); 0563 continue; 0564 } 0565 if (frame != GenTime()) { 0566 param.second->removeKeyframe(frame, undo, redo); 0567 } 0568 } 0569 } 0570 } else if (oldIn != in) { 0571 GenTime old_in(oldIn, pCore->getCurrentFps()); 0572 GenTime new_in(in, pCore->getCurrentFps()); 0573 Keyframe kf = getKeyframe(old_in, &ok); 0574 KeyframeType type = kf.second; 0575 getKeyframe(new_in, &ok2); 0576 if (!ok2) { 0577 // Add new in point 0578 for (const auto ¶m : m_parameters) { 0579 QVariant value = param.second->getInterpolatedValue(new_in); 0580 param.second->addKeyframe(new_in, type, value, true, undo, redo); 0581 } 0582 } 0583 if (ok) { 0584 // Remove previous in point 0585 for (const auto ¶m : m_parameters) { 0586 param.second->removeKeyframe(old_in, undo, redo); 0587 } 0588 } 0589 // Remove all keyframes before in 0590 bool nextOk = false; 0591 kf = m_parameters.begin()->second->getNextKeyframe(GenTime(-1), &nextOk); 0592 GenTime pos; 0593 while (nextOk) { 0594 pos = kf.first; 0595 if (pos < new_in) { 0596 for (const auto ¶m : m_parameters) { 0597 param.second->removeKeyframe(pos, undo, redo); 0598 } 0599 kf = m_parameters.begin()->second->getNextKeyframe(pos, &nextOk); 0600 } else { 0601 break; 0602 } 0603 } 0604 // qDebug()<<"/// \n\nKEYS TO DELETE: "<<positions<<"\n------------------------"; 0605 } 0606 } else { 0607 // Adjusting clip end 0608 GenTime old_out(oldOut, pCore->getCurrentFps()); 0609 GenTime new_out(out, pCore->getCurrentFps()); 0610 Keyframe kf = getKeyframe(old_out, &ok); 0611 KeyframeType type = kf.second; 0612 getKeyframe(new_out, &ok2); 0613 // Check keyframes after last position 0614 bool ok3; 0615 Keyframe toDel = getNextKeyframe(new_out, &ok3); 0616 if (ok && !ok2) { 0617 // Check if we have only 2 keyframes (in/out), in which case we move the out keyframe to new position 0618 bool ok4; 0619 kf = getPrevKeyframe(old_out, &ok4); 0620 if (ok4) { 0621 GenTime current_in(oldIn, pCore->getCurrentFps()); 0622 qDebug() << " = = = = = = = \n\nGOT 2 KF SITUATION: " << current_in.frames(25) << " = " << kf.first.frames(25); 0623 if (kf.first == current_in) { 0624 // We have a 2 keyframes situation, move last one to new out 0625 for (const auto ¶m : m_parameters) { 0626 param.second->moveKeyframe(old_out, new_out, QVariant(), undo, redo); 0627 } 0628 return; 0629 } 0630 } 0631 positions << old_out; 0632 } 0633 if (toDel.first == GenTime()) { 0634 // No keyframes 0635 return; 0636 } 0637 while (ok3) { 0638 if (!positions.contains(toDel.first)) { 0639 positions << toDel.first; 0640 } 0641 toDel = getNextKeyframe(toDel.first, &ok3); 0642 } 0643 if ((ok || positions.size() > 0) && !ok2 && !singleKeyframe()) { 0644 for (const auto ¶m : m_parameters) { 0645 QVariant value = param.second->getInterpolatedValue(new_out); 0646 param.second->addKeyframe(new_out, type, value, true, undo, redo); 0647 for (auto frame : qAsConst(positions)) { 0648 param.second->removeKeyframe(frame, undo, redo); 0649 } 0650 } 0651 } 0652 } 0653 } 0654 0655 void KeyframeModelList::checkConsistency() 0656 { 0657 if (m_parameters.size() < 2) { 0658 return; 0659 } 0660 // Check keyframes in all parameters 0661 QList<GenTime> fullList; 0662 for (const auto ¶m : m_parameters) { 0663 QList<GenTime> list = param.second->getKeyframePos(); 0664 for (auto &time : list) { 0665 if (!fullList.contains(time)) { 0666 fullList << time; 0667 } 0668 } 0669 } 0670 Fun local_update = []() { return true; }; 0671 auto type = KeyframeType(KdenliveSettings::defaultkeyframeinterp()); 0672 for (const auto ¶m : m_parameters) { 0673 QList<GenTime> list = param.second->getKeyframePos(); 0674 for (auto &time : fullList) { 0675 if (!list.contains(time)) { 0676 qDebug() << " = = = \n\n = = = = \n\nWARNING; MISSING KF DETECTED AT: " << time.seconds() << "\n\n= = = \n\n= = ="; 0677 pCore->displayMessage(i18n("Missing keyframe detected at %1, automatically re-added", time.seconds()), ErrorMessage); 0678 QVariant missingVal = param.second->getInterpolatedValue(time); 0679 local_update = param.second->addKeyframe_lambda(time, type, missingVal, false); 0680 local_update(); 0681 } 0682 } 0683 } 0684 } 0685 0686 GenTime KeyframeModelList::getPosAtIndex(int ix) 0687 { 0688 return m_parameters.begin()->second->getPosAtIndex(ix); 0689 } 0690 0691 int KeyframeModelList::getIndexForPos(GenTime pos) 0692 { 0693 return m_parameters.begin()->second->getIndexForPos(pos); 0694 } 0695 0696 QModelIndex KeyframeModelList::getIndexAtRow(int row) 0697 { 0698 for (auto &w : m_parameters) { 0699 if (w.first.row() == row) { 0700 return w.first; 0701 } 0702 } 0703 return QModelIndex(); 0704 } 0705 0706 std::vector<QPersistentModelIndex> KeyframeModelList::getIndexes() 0707 { 0708 std::vector<QPersistentModelIndex> keys; 0709 keys.reserve(m_parameters.size()); 0710 0711 for (auto kv : m_parameters) { 0712 keys.push_back(kv.first); 0713 } 0714 return keys; 0715 }