1 /* 2 SPDX-FileCopyrightText: 2017 Nicolas Carion 3 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 4 */ 5 6 #ifndef KEYFRAMELISTMODEL_H 7 #define KEYFRAMELISTMODEL_H 8 9 #include "assets/model/assetparametermodel.hpp" 10 #include "definitions.h" 11 #include "gentime.h" 12 #include "undohelper.hpp" 13 14 #include <QAbstractListModel> 15 #include <QReadWriteLock> 16 17 #include <map> 18 #include <memory> 19 20 class AssetParameterModel; 21 class DocUndoStack; 22 class EffectItemModel; 23 24 25 enum class KeyframeType { Linear = mlt_keyframe_linear, Discrete = mlt_keyframe_discrete, Curve = mlt_keyframe_smooth }; 26 Q_DECLARE_METATYPE(KeyframeType) 27 using Keyframe = std::pair<GenTime, KeyframeType>; 28 29 /** @class KeyframeModel 30 @brief This class is the model for a list of keyframes. 31 A keyframe is defined by a time, a type and a value 32 We store them in a sorted fashion using a std::map 33 */ 34 class KeyframeModel : public QAbstractListModel 35 { 36 Q_OBJECT 37 38 public: 39 /** @brief Construct a keyframe list bound to the given effect 40 @param init_value is the value taken by the param at time 0. 41 @param model is the asset this parameter belong to 42 @param index is the index of this parameter in its model 43 */ 44 explicit KeyframeModel(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, 45 QObject *parent = nullptr); 46 47 enum { TypeRole = Qt::UserRole + 1, PosRole, FrameRole, ValueRole, NormalizedValueRole, SelectedRole, ActiveRole }; 48 friend class KeyframeModelList; 49 friend class KeyframeWidget; 50 friend class KeyframeImport; 51 52 protected: 53 /** @brief These methods should ONLY be called by keyframemodellist to ensure synchronisation 54 * with keyframes from other parameters */ 55 /** @brief Adds a keyframe at the given position. If there is already one then we update it. 56 @param pos defines the position of the keyframe, relative to the clip 57 @param type is the type of the keyframe. 58 */ 59 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value); 60 bool addKeyframe(int frame, double normalizedValue); 61 /** @brief Same function but accumulates undo/redo 62 @param notify: if true, send a signal to model 63 */ 64 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value, bool notify, Fun &undo, Fun &redo); 65 66 /** @brief Removes the keyframe at the given position. */ 67 bool removeKeyframe(int frame); 68 bool moveKeyframe(int oldPos, int pos, QVariant newVal); 69 /** @brief Duplicate a keyframe at the given position. */ 70 bool duplicateKeyframe(GenTime srcPos, GenTime dstPos, Fun &undo, Fun &redo); 71 bool removeKeyframe(GenTime pos); 72 /** @brief Delete all the keyframes of the model */ 73 bool removeAllKeyframes(); 74 bool removeAllKeyframes(Fun &undo, Fun &redo); 75 bool removeNextKeyframes(GenTime pos, Fun &undo, Fun &redo); 76 QList<GenTime> getKeyframePos() const; 77 78 protected: 79 /** @brief Same function but accumulates undo/redo */ 80 bool removeKeyframe(GenTime pos, Fun &undo, Fun &redo, bool notify = true, bool updateSelection = true); 81 82 public: 83 /** @brief moves a keyframe 84 @param oldPos is the old position of the keyframe 85 @param pos defines the new position of the keyframe, relative to the clip 86 @param logUndo if true, then an undo object is created 87 */ 88 bool moveKeyframe(int oldPos, int pos, bool logUndo); 89 bool offsetKeyframes(int oldPos, int pos, bool logUndo); 90 bool moveKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, bool logUndo); 91 bool moveKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, Fun &undo, Fun &redo, bool updateView = true); 92 93 /** @brief updates the value of a keyframe 94 @param old is the position of the keyframe 95 @param value is the new value of the param 96 */ 97 Q_INVOKABLE bool updateKeyframe(int pos, double newVal); 98 bool updateKeyframe(GenTime pos, QVariant value); 99 bool updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo); 100 bool updateKeyframe(GenTime pos, const QVariant &value, Fun &undo, Fun &redo, bool update = true); 101 /** @brief updates the value of a keyframe, without any management of undo/redo 102 @param pos is the position of the keyframe 103 @param value is the new value of the param 104 */ 105 bool directUpdateKeyframe(GenTime pos, QVariant value); 106 107 /** @brief Returns a keyframe data at given pos 108 ok is a return parameter, set to true if everything went good 109 */ 110 Keyframe getKeyframe(const GenTime &pos, bool *ok) const; 111 112 /** @brief Returns true if we only have 1 keyframe 113 */ 114 bool singleKeyframe() const; 115 /** @brief Returns the keyframe located after given position. 116 If there is a keyframe at given position it is ignored. 117 @param ok is a return parameter to tell if a keyframe was found. 118 */ 119 Keyframe getNextKeyframe(const GenTime &pos, bool *ok) const; 120 121 /** @brief Returns the keyframe located before given position. 122 If there is a keyframe at given position it is ignored. 123 @param ok is a return parameter to tell if a keyframe was found. 124 */ 125 Keyframe getPrevKeyframe(const GenTime &pos, bool *ok) const; 126 127 /** @brief Returns the closest keyframe from given position. 128 @param ok is a return parameter to tell if a keyframe was found. 129 */ 130 Keyframe getClosestKeyframe(const GenTime &pos, bool *ok) const; 131 132 /** @brief Returns true if a keyframe exists at given pos 133 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 134 */ 135 Q_INVOKABLE bool hasKeyframe(int frame) const; 136 Q_INVOKABLE bool hasKeyframe(const GenTime &pos) const; 137 Q_INVOKABLE QString realValue(double normalizedValue) const; 138 139 /** @brief Read the value from the model and update itself accordingly */ 140 void refresh(); 141 /** @brief Reset all values to their default */ 142 void reset(); 143 144 /** @brief Return the interpolated value at given pos */ 145 QVariant getInterpolatedValue(int pos) const; 146 QVariant getInterpolatedValue(const GenTime &pos) const; 147 QVariant updateInterpolated(const QVariant &interpValue, double val); 148 /** @brief Return the real value from a normalized one */ 149 QVariant getNormalizedValue(double newVal) const; 150 /** @brief Set or add a keyframe to selection */ 151 Q_INVOKABLE void setSelectedKeyframe(int ix, bool add); 152 void setSelectedKeyframes(QVector<int> selection); 153 154 Q_INVOKABLE int activeKeyframe() const; 155 Q_INVOKABLE void setActiveKeyframe(int ix); 156 int getIndexForPos(const GenTime pos) const; 157 GenTime getPosAtIndex(int ix) const; 158 159 // Mandatory overloads 160 Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override; 161 QHash<int, QByteArray> roleNames() const override; 162 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 163 static QList<QPoint> getRanges(const QString &animData, const std::shared_ptr<AssetParameterModel> &model); 164 static std::shared_ptr<Mlt::Properties> getAnimation(std::shared_ptr<AssetParameterModel> model, const QString &animData, int duration = 0); 165 static const QString getAnimationStringWithOffset(std::shared_ptr<AssetParameterModel> model, const QString &animData, int offset); 166 167 protected: 168 /** @brief Helper function that generate a lambda to change type / value of given keyframe */ 169 Fun updateKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 170 171 /** @brief Helper function that generate a lambda to add given keyframe */ 172 Fun addKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 173 174 /** @brief Helper function that generate a lambda to remove given keyframe */ 175 Fun deleteKeyframe_lambda(GenTime pos, bool notify); 176 177 /** @brief Connects the signals of this object */ 178 void setup(); 179 180 /** @brief Commit the modification to the model */ 181 void sendModification(); 182 183 /** @brief returns the keyframes as a Mlt Anim Property string. 184 It is defined as pairs of frame and value, separated by ; 185 Example : "0|=50; 50|=100; 100=200; 200~=60;" 186 Spaces are ignored by Mlt. 187 |= represents a discrete keyframe, = a linear one and ~= a Catmull-Rom spline 188 */ 189 QString getAnimProperty() const; 190 QString getRotoProperty() const; 191 192 /** @brief this function clears all existing keyframes, and reloads its data from the string passed */ 193 void resetAnimProperty(const QString &prop); 194 /** @brief this function does the opposite of getAnimProperty: given a MLT representation of an animation, build the corresponding model */ 195 void parseAnimProperty(const QString &prop); 196 void parseRotoProperty(const QString &prop); 197 198 private: 199 std::weak_ptr<AssetParameterModel> m_model; 200 std::weak_ptr<DocUndoStack> m_undoStack; 201 QPersistentModelIndex m_index; 202 QString m_lastData; 203 ParamType m_paramType; 204 /** @brief This is a lock that ensures safety in case of concurrent access */ 205 mutable QReadWriteLock m_lock; 206 207 std::map<GenTime, std::pair<KeyframeType, QVariant>> m_keyframeList; 208 bool moveOneKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, Fun &undo, Fun &redo, bool updateView = true); 209 210 signals: 211 void modelChanged(); 212 void requestModelUpdate(const QModelIndex &, const QModelIndex &, const QVector<int>&); 213 214 public: 215 // this is to enable for range loops begin()216 auto begin() -> decltype(m_keyframeList.begin()) { return m_keyframeList.begin(); } end()217 auto end() -> decltype(m_keyframeList.end()) { return m_keyframeList.end(); } 218 }; 219 // Q_DECLARE_METATYPE(KeyframeModel *) 220 221 #endif 222