1 /* 2 SPDX-FileCopyrightText: 2017 Nicolas Carion 3 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 4 */ 5 6 #ifndef KEYFRAMELISTMODELLIST_H 7 #define KEYFRAMELISTMODELLIST_H 8 9 #include "definitions.h" 10 #include "gentime.h" 11 #include "keyframemodel.hpp" 12 #include "undohelper.hpp" 13 14 #include <QReadWriteLock> 15 16 #include <QObject> 17 #include <map> 18 #include <memory> 19 #include <unordered_map> 20 21 class AssetParameterModel; 22 class DocUndoStack; 23 24 /** @class KeyframeModelList 25 @brief This class is a container for the keyframe models. 26 If an asset has several keyframable parameters, each one has its own keyframeModel, 27 but we regroup all of these in a common class to provide unified access. 28 */ 29 class KeyframeModelList : public QObject 30 { 31 Q_OBJECT 32 33 public: 34 /** @brief Construct a keyframe list bound to the given asset 35 @param init_value and index correspond to the first parameter 36 */ 37 explicit KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack); 38 39 /** @brief Add a keyframable parameter to be managed by this model */ 40 void addParameter(const QModelIndex &index); 41 42 /** @brief Adds a keyframe at the given position. If there is already one then we update it. 43 @param pos defines the position of the keyframe, relative to the clip 44 @param type is the type of the keyframe. 45 */ 46 bool addKeyframe(GenTime pos, KeyframeType type); 47 bool addKeyframe(int frame, double val); 48 49 /** @brief Removes the keyframe at the given position. */ 50 bool removeKeyframe(GenTime pos); 51 bool removeKeyframeWithUndo(GenTime pos, Fun &undo, Fun &redo); 52 53 /** @brief Duplicate a keyframe at the given position. */ 54 bool duplicateKeyframeWithUndo(GenTime srcPos, GenTime destPos, Fun &undo, Fun &redo); 55 /** @brief Delete all the keyframes of the model (except first) */ 56 bool removeAllKeyframes(); 57 /** @brief Delete all the keyframes after a certain position (except first) */ 58 bool removeNextKeyframes(GenTime pos); 59 60 /** @brief moves a keyframe 61 @param oldPos is the old position of the keyframe 62 @param pos defines the new position of the keyframe, relative to the clip 63 @param logUndo if true, then an undo object is created 64 */ 65 bool moveKeyframe(GenTime oldPos, GenTime pos, bool logUndo, bool updateView = true); 66 bool moveKeyframeWithUndo(GenTime oldPos, GenTime pos, Fun &undo, Fun &redo); 67 68 /** @brief updates the value of a keyframe 69 @param old is the position of the keyframe 70 @param value is the new value of the param 71 @param index is the index of the wanted keyframe 72 */ 73 bool updateKeyframe(GenTime pos, const QVariant &value, const QPersistentModelIndex &index, QUndoCommand *parentCommand = nullptr); 74 bool updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index); 75 bool updateKeyframe(GenTime oldPos, GenTime pos, const QVariant &normalizedVal, bool logUndo = true); 76 KeyframeType keyframeType(GenTime pos) const; 77 /** @brief Returns a keyframe data at given pos 78 ok is a return parameter, set to true if everything went good 79 */ 80 Keyframe getKeyframe(const GenTime &pos, bool *ok) const; 81 82 /** @brief Returns true if we only have 1 keyframe 83 */ 84 bool singleKeyframe() const; 85 /** @brief Returns true if we only have no keyframe 86 */ 87 bool isEmpty() const; 88 /** @brief Returns the number of keyframes 89 */ 90 int count() const; 91 92 /** @brief Returns the keyframe located after given position. 93 If there is a keyframe at given position it is ignored. 94 @param ok is a return parameter to tell if a keyframe was found. 95 */ 96 Keyframe getNextKeyframe(const GenTime &pos, bool *ok) const; 97 98 /** @brief Returns the keyframe located before given position. 99 If there is a keyframe at given position it is ignored. 100 @param ok is a return parameter to tell if a keyframe was found. 101 */ 102 Keyframe getPrevKeyframe(const GenTime &pos, bool *ok) const; 103 104 /** @brief Returns the closest keyframe from given position. 105 @param ok is a return parameter to tell if a keyframe was found. 106 */ 107 Keyframe getClosestKeyframe(const GenTime &pos, bool *ok) const; 108 109 /** @brief Returns true if a keyframe exists at given pos 110 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 111 */ 112 Q_INVOKABLE bool hasKeyframe(int frame) const; 113 114 /** @brief Return the interpolated value of a parameter. 115 @param pos is the position where we interpolate 116 @param index is the index of the queried parameter. */ 117 QVariant getInterpolatedValue(int pos, const QPersistentModelIndex &index) const; 118 /** @brief Return the interpolated value of a parameter. 119 @param pos is the position where we interpolate 120 @param index is the index of the queried parameter. */ 121 QVariant getInterpolatedValue(const GenTime &pos, const QPersistentModelIndex &index) const; 122 123 124 /** @brief Load keyframes from the current parameter value. */ 125 void refresh(); 126 /** @brief Reset all keyframes and add a default one */ 127 void reset(); 128 Q_INVOKABLE KeyframeModel *getKeyModel(); 129 KeyframeModel *getKeyModel(const QPersistentModelIndex &index); 130 /** @brief Returns parent asset owner id*/ 131 ObjectId getOwnerId() const; 132 /** @brief Returns parent asset id*/ 133 const QString getAssetId(); 134 const QString getAssetRow(); 135 136 /** @brief Returns the list of selected keyframes */ 137 QVector<int> selectedKeyframes() const; 138 /** @brief Remove a position from selected keyframes */ 139 void removeFromSelected(int pos); 140 /** @brief Replace list of selected keyframes */ 141 void setSelectedKeyframes(QVector<int> list); 142 /** @brief Append a keyframe to selection */ 143 void appendSelectedKeyframe(int frame); 144 145 /** @brief Get the currently active keyframe */ 146 int activeKeyframe() const; 147 /** @brief Set the currently active keyframe */ 148 void setActiveKeyframe(int pos); 149 150 /** @brief Parent item size change, update keyframes*/ 151 void resizeKeyframes(int oldIn, int oldOut, int in, int out, int offset, bool adjustFromEnd, Fun &undo, Fun &redo); 152 153 /** @brief Parent item size change, update keyframes*/ 154 void moveKeyframes(int oldIn, int in, Fun &undo, Fun &redo); 155 156 /** @brief Return position of the nth keyframe (ix = nth)*/ 157 GenTime getPosAtIndex(int ix); 158 int getIndexForPos(GenTime pos); 159 QModelIndex getIndexAtRow(int row); 160 161 /** @brief Check that all keyframable parameters have the same keyframes on loading 162 * (that's how our model works) */ 163 void checkConsistency(); 164 165 protected: 166 /** @brief Helper function to apply a given operation on all parameters */ 167 bool applyOperation(const std::function<bool(std::shared_ptr<KeyframeModel>, Fun &, Fun &)> &op, const QString &undoString); 168 169 signals: 170 void modelChanged(); 171 void modelDisplayChanged(); 172 173 private: 174 std::weak_ptr<AssetParameterModel> m_model; 175 std::weak_ptr<DocUndoStack> m_undoStack; 176 std::unordered_map<QPersistentModelIndex, std::shared_ptr<KeyframeModel>> m_parameters; 177 /** @brief Index of the parameter that is displayed in timeline */ 178 QModelIndex m_inTimelineIndex; 179 mutable QReadWriteLock m_lock; // This is a lock that ensures safety in case of concurrent access 180 181 private slots: 182 void slotUpdateModels(const QModelIndex &ix1, const QModelIndex &ix2, const QVector<int> &roles); 183 184 public: 185 // this is to enable for range loops begin()186 auto begin() -> decltype(m_parameters.begin()->second->begin()) { return m_parameters.begin()->second->begin(); } end()187 auto end() -> decltype(m_parameters.begin()->second->end()) { return m_parameters.begin()->second->end(); } 188 }; 189 190 #endif 191