File indexing completed on 2024-05-05 04:52:43
0001 /* 0002 SPDX-FileCopyrightText: 2017 Nicolas Carion 0003 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #pragma once 0007 0008 #include "assets/model/assetparametermodel.hpp" 0009 #include "definitions.h" 0010 #include "undohelper.hpp" 0011 #include "utils/gentime.h" 0012 0013 #include <QAbstractListModel> 0014 #include <QReadWriteLock> 0015 #include <QtGlobal> 0016 0017 #include <framework/mlt_version.h> 0018 0019 #include <map> 0020 #include <memory> 0021 0022 class AssetParameterModel; 0023 class DocUndoStack; 0024 class EffectItemModel; 0025 0026 #define mltMinVersion QT_VERSION_CHECK(7, 20, 0) 0027 #define currentVersion QT_VERSION_CHECK(LIBMLT_VERSION_MAJOR, LIBMLT_VERSION_MINOR, 0) 0028 0029 #if currentVersion > mltMinVersion 0030 #define USE_MLT_NEW_KEYFRAMES 0031 enum class KeyframeType { 0032 Linear = mlt_keyframe_linear, 0033 Discrete = mlt_keyframe_discrete, 0034 Curve = mlt_keyframe_smooth, 0035 CurveSmooth = mlt_keyframe_smooth_natural, 0036 BounceIn = mlt_keyframe_bounce_in, 0037 BounceOut = mlt_keyframe_bounce_out, 0038 CubicIn = mlt_keyframe_cubic_in, 0039 CubicOut = mlt_keyframe_cubic_out, 0040 ExponentialIn = mlt_keyframe_exponential_in, 0041 ExponentialOut = mlt_keyframe_exponential_out, 0042 CircularIn = mlt_keyframe_circular_in, 0043 CircularOut = mlt_keyframe_circular_out, 0044 ElasticIn = mlt_keyframe_elastic_in, 0045 ElasticOut = mlt_keyframe_elastic_out 0046 }; 0047 #else 0048 enum class KeyframeType { Linear = mlt_keyframe_linear, Discrete = mlt_keyframe_discrete, Curve = mlt_keyframe_smooth }; 0049 #endif 0050 extern const QMap<KeyframeType, QString> KeyframeTypeName; 0051 Q_DECLARE_METATYPE(KeyframeType) 0052 using Keyframe = std::pair<GenTime, KeyframeType>; 0053 0054 /** @class KeyframeModel 0055 @brief This class is the model for a list of keyframes. 0056 A keyframe is defined by a time, a type and a value 0057 We store them in a sorted fashion using a std::map 0058 */ 0059 class KeyframeModel : public QAbstractListModel 0060 { 0061 Q_OBJECT 0062 0063 public: 0064 /** @brief Construct a keyframe list bound to the given effect 0065 @param init_value is the value taken by the param at time 0. 0066 @param model is the asset this parameter belong to 0067 @param index is the index of this parameter in its model 0068 */ 0069 explicit KeyframeModel(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, int in = -1, 0070 int out = -1, QObject *parent = nullptr); 0071 0072 enum { TypeRole = Qt::UserRole + 1, PosRole, FrameRole, ValueRole, NormalizedValueRole, SelectedRole, ActiveRole, MoveOnlyRole }; 0073 friend class KeyframeModelList; 0074 friend class KeyframeWidget; 0075 friend class KeyframeImport; 0076 friend class AssetMultiKeyframeCommand; 0077 0078 protected: 0079 /** @brief These methods should ONLY be called by keyframemodellist to ensure synchronisation 0080 * with keyframes from other parameters */ 0081 /** @brief Adds a keyframe at the given position. If there is already one then we update it. 0082 @param pos defines the position of the keyframe, relative to the clip 0083 @param type is the type of the keyframe. 0084 */ 0085 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value); 0086 bool addKeyframe(int frame, double normalizedValue); 0087 /** @brief Same function but accumulates undo/redo 0088 @param notify: if true, send a signal to model 0089 */ 0090 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value, bool notify, Fun &undo, Fun &redo); 0091 0092 /** @brief Removes the keyframe at the given position. */ 0093 bool removeKeyframe(int frame); 0094 bool moveKeyframe(int oldPos, int pos, QVariant newVal); 0095 /** @brief Duplicate a keyframe at the given position. */ 0096 bool duplicateKeyframe(GenTime srcPos, GenTime dstPos, Fun &undo, Fun &redo); 0097 bool removeKeyframe(GenTime pos); 0098 /** @brief Delete all the keyframes of the model */ 0099 bool removeAllKeyframes(); 0100 bool removeAllKeyframes(Fun &undo, Fun &redo); 0101 bool removeNextKeyframes(GenTime pos, Fun &undo, Fun &redo); 0102 QList<GenTime> getKeyframePos() const; 0103 0104 protected: 0105 /** @brief Same function but accumulates undo/redo */ 0106 bool removeKeyframe(GenTime pos, Fun &undo, Fun &redo, bool notify = true, bool updateSelection = true); 0107 0108 public: 0109 /** @brief moves a keyframe 0110 @param oldPos is the old position of the keyframe 0111 @param pos defines the new position of the keyframe, relative to the clip 0112 @param logUndo if true, then an undo object is created 0113 */ 0114 bool moveKeyframe(int oldPos, int pos, bool logUndo); 0115 bool offsetKeyframes(int oldPos, int pos, bool logUndo); 0116 bool moveKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, bool logUndo); 0117 bool moveKeyframe(GenTime oldPos, GenTime pos, const QVariant &newVal, Fun &undo, Fun &redo, bool updateView = true); 0118 0119 /** @brief updates the value of a keyframe 0120 @param old is the position of the keyframe 0121 @param value is the new value of the param 0122 */ 0123 Q_INVOKABLE bool updateKeyframe(int pos, double newVal); 0124 bool updateKeyframe(GenTime pos, QVariant value); 0125 bool updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo); 0126 bool updateKeyframe(GenTime pos, const QVariant &value, Fun &undo, Fun &redo, bool update = true); 0127 /** @brief updates the value of a keyframe, without any management of undo/redo 0128 @param pos is the position of the keyframe 0129 @param value is the new value of the param 0130 */ 0131 bool directUpdateKeyframe(GenTime pos, QVariant value, bool notify = true); 0132 0133 /** @brief Returns a keyframe data at given pos 0134 ok is a return parameter, set to true if everything went good 0135 */ 0136 Keyframe getKeyframe(const GenTime &pos, bool *ok) const; 0137 0138 /** @brief Returns true if we only have 1 keyframe 0139 */ 0140 bool singleKeyframe() const; 0141 /** @brief Returns the keyframe located after given position. 0142 If there is a keyframe at given position it is ignored. 0143 @param ok is a return parameter to tell if a keyframe was found. 0144 */ 0145 Keyframe getNextKeyframe(const GenTime &pos, bool *ok) const; 0146 0147 /** @brief Returns the keyframe located before given position. 0148 If there is a keyframe at given position it is ignored. 0149 @param ok is a return parameter to tell if a keyframe was found. 0150 */ 0151 Keyframe getPrevKeyframe(const GenTime &pos, bool *ok) const; 0152 0153 /** @brief Returns the closest keyframe from given position. 0154 @param ok is a return parameter to tell if a keyframe was found. 0155 */ 0156 Keyframe getClosestKeyframe(const GenTime &pos, bool *ok) const; 0157 0158 /** @brief Returns true if a keyframe exists at given pos 0159 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 0160 */ 0161 Q_INVOKABLE bool hasKeyframe(int frame) const; 0162 Q_INVOKABLE bool hasKeyframe(const GenTime &pos) const; 0163 Q_INVOKABLE QString realValue(double normalizedValue) const; 0164 0165 /** @brief Read the value from the model and update itself accordingly */ 0166 void refresh(int in = -1, int out = -1); 0167 /** @brief Reset all values to their default */ 0168 void reset(); 0169 0170 /** @brief Return the interpolated value at given pos */ 0171 QVariant getInterpolatedValue(int pos) const; 0172 QVariant getInterpolatedValue(const GenTime &pos) const; 0173 QVariant updateInterpolated(const QVariant &interpValue, double val); 0174 /** @brief Return the real value from a normalized one */ 0175 QVariant getNormalizedValue(double newVal) const; 0176 /** @brief Set or add a keyframe to selection */ 0177 Q_INVOKABLE void setSelectedKeyframe(int ix, bool add); 0178 void setSelectedKeyframes(QVector<int> selection); 0179 0180 Q_INVOKABLE int activeKeyframe() const; 0181 Q_INVOKABLE void setActiveKeyframe(int ix); 0182 int getIndexForPos(const GenTime pos) const; 0183 GenTime getPosAtIndex(int ix) const; 0184 0185 // Mandatory overloads 0186 Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override; 0187 QHash<int, QByteArray> roleNames() const override; 0188 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0189 static QList<QPoint> getRanges(const QString &animData, const std::shared_ptr<AssetParameterModel> &model); 0190 static std::shared_ptr<Mlt::Properties> getAnimation(std::shared_ptr<AssetParameterModel> model, const QString &animData, int duration = 0); 0191 static const QString getAnimationStringWithOffset(std::shared_ptr<AssetParameterModel> model, const QString &animData, int offset, int duration, 0192 ParamType paramType, bool useOpacity = true); 0193 static const QString getIconByKeyframeType(KeyframeType type); 0194 0195 0196 protected: 0197 /** @brief Helper function that generate a lambda to change type / value of given keyframe */ 0198 Fun updateKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 0199 0200 /** @brief Helper function that generate a lambda to add given keyframe */ 0201 Fun addKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 0202 0203 /** @brief Helper function that generate a lambda to remove given keyframe */ 0204 Fun deleteKeyframe_lambda(GenTime pos, bool notify); 0205 0206 /** @brief Connects the signals of this object */ 0207 void setup(); 0208 0209 /** @brief Commit the modification to the model */ 0210 void sendModification(); 0211 0212 /** @brief returns the keyframes as a Mlt Anim Property string. 0213 It is defined as pairs of frame and value, separated by ; 0214 Example : "0|=50; 50|=100; 100=200; 200~=60;" 0215 Spaces are ignored by Mlt. 0216 |= represents a discrete keyframe, = a linear one and ~= a Catmull-Rom spline 0217 */ 0218 QString getAnimProperty() const; 0219 QString getRotoProperty() const; 0220 0221 /** @brief this function clears all existing keyframes, and reloads its data from the string passed */ 0222 void resetAnimProperty(const QString &prop); 0223 /** @brief this function does the opposite of getAnimProperty: given a MLT representation of an animation, build the corresponding model */ 0224 void parseAnimProperty(const QString &prop, int in = -1, int out = -1); 0225 void parseRotoProperty(const QString &prop); 0226 0227 private: 0228 std::weak_ptr<AssetParameterModel> m_model; 0229 std::weak_ptr<DocUndoStack> m_undoStack; 0230 QPersistentModelIndex m_index; 0231 QString m_lastData; 0232 ParamType m_paramType; 0233 /** @brief This is a lock that ensures safety in case of concurrent access */ 0234 mutable QReadWriteLock m_lock; 0235 0236 std::map<GenTime, std::pair<KeyframeType, QVariant>> m_keyframeList; 0237 bool moveOneKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, Fun &undo, Fun &redo, bool updateView = true); 0238 0239 Q_SIGNALS: 0240 void modelChanged(); 0241 void requestModelUpdate(const QModelIndex &, const QModelIndex &, const QVector<int> &); 0242 0243 public: 0244 // this is to enable for range loops 0245 auto begin() -> decltype(m_keyframeList.begin()) { return m_keyframeList.begin(); } 0246 auto end() -> decltype(m_keyframeList.end()) { return m_keyframeList.end(); } 0247 }; 0248 // Q_DECLARE_METATYPE(KeyframeModel *)