File indexing completed on 2025-11-09 08:26:33
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 Q_DECLARE_METATYPE(KeyframeType) 0051 using Keyframe = std::pair<GenTime, KeyframeType>; 0052 0053 /** @class KeyframeModel 0054 @brief This class is the model for a list of keyframes. 0055 A keyframe is defined by a time, a type and a value 0056 We store them in a sorted fashion using a std::map 0057 */ 0058 class KeyframeModel : public QAbstractListModel 0059 { 0060 Q_OBJECT 0061 0062 public: 0063 /** @brief Construct a keyframe list bound to the given effect 0064 @param init_value is the value taken by the param at time 0. 0065 @param model is the asset this parameter belong to 0066 @param index is the index of this parameter in its model 0067 */ 0068 explicit KeyframeModel(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, int in = -1, 0069 int out = -1, QObject *parent = nullptr); 0070 0071 enum { TypeRole = Qt::UserRole + 1, PosRole, FrameRole, ValueRole, NormalizedValueRole, SelectedRole, ActiveRole, MoveOnlyRole }; 0072 friend class KeyframeModelList; 0073 friend class KeyframeWidget; 0074 friend class KeyframeImport; 0075 friend class AssetMultiKeyframeCommand; 0076 0077 protected: 0078 /** @brief These methods should ONLY be called by keyframemodellist to ensure synchronisation 0079 * with keyframes from other parameters */ 0080 /** @brief Adds a keyframe at the given position. If there is already one then we update it. 0081 @param pos defines the position of the keyframe, relative to the clip 0082 @param type is the type of the keyframe. 0083 */ 0084 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value); 0085 bool addKeyframe(int frame, double normalizedValue); 0086 /** @brief Same function but accumulates undo/redo 0087 @param notify: if true, send a signal to model 0088 */ 0089 bool addKeyframe(GenTime pos, KeyframeType type, QVariant value, bool notify, Fun &undo, Fun &redo); 0090 0091 /** @brief Removes the keyframe at the given position. */ 0092 bool removeKeyframe(int frame); 0093 bool moveKeyframe(int oldPos, int pos, QVariant newVal); 0094 /** @brief Duplicate a keyframe at the given position. */ 0095 bool duplicateKeyframe(GenTime srcPos, GenTime dstPos, Fun &undo, Fun &redo); 0096 bool removeKeyframe(GenTime pos); 0097 /** @brief Delete all the keyframes of the model */ 0098 bool removeAllKeyframes(); 0099 bool removeAllKeyframes(Fun &undo, Fun &redo); 0100 bool removeNextKeyframes(GenTime pos, Fun &undo, Fun &redo); 0101 QList<GenTime> getKeyframePos() const; 0102 0103 protected: 0104 /** @brief Same function but accumulates undo/redo */ 0105 bool removeKeyframe(GenTime pos, Fun &undo, Fun &redo, bool notify = true, bool updateSelection = true); 0106 0107 public: 0108 /** @brief moves a keyframe 0109 @param oldPos is the old position of the keyframe 0110 @param pos defines the new position of the keyframe, relative to the clip 0111 @param logUndo if true, then an undo object is created 0112 */ 0113 bool moveKeyframe(int oldPos, int pos, bool logUndo); 0114 bool offsetKeyframes(int oldPos, int pos, bool logUndo); 0115 bool moveKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, bool logUndo); 0116 bool moveKeyframe(GenTime oldPos, GenTime pos, const QVariant &newVal, Fun &undo, Fun &redo, bool updateView = true); 0117 0118 /** @brief updates the value of a keyframe 0119 @param old is the position of the keyframe 0120 @param value is the new value of the param 0121 */ 0122 Q_INVOKABLE bool updateKeyframe(int pos, double newVal); 0123 bool updateKeyframe(GenTime pos, QVariant value); 0124 bool updateKeyframeType(GenTime pos, int type, Fun &undo, Fun &redo); 0125 bool updateKeyframe(GenTime pos, const QVariant &value, Fun &undo, Fun &redo, bool update = true); 0126 /** @brief updates the value of a keyframe, without any management of undo/redo 0127 @param pos is the position of the keyframe 0128 @param value is the new value of the param 0129 */ 0130 bool directUpdateKeyframe(GenTime pos, QVariant value, bool notify = true); 0131 0132 /** @brief Returns a keyframe data at given pos 0133 ok is a return parameter, set to true if everything went good 0134 */ 0135 Keyframe getKeyframe(const GenTime &pos, bool *ok) const; 0136 0137 /** @brief Returns true if we only have 1 keyframe 0138 */ 0139 bool singleKeyframe() const; 0140 /** @brief Returns the keyframe located after given position. 0141 If there is a keyframe at given position it is ignored. 0142 @param ok is a return parameter to tell if a keyframe was found. 0143 */ 0144 Keyframe getNextKeyframe(const GenTime &pos, bool *ok) const; 0145 0146 /** @brief Returns the keyframe located before given position. 0147 If there is a keyframe at given position it is ignored. 0148 @param ok is a return parameter to tell if a keyframe was found. 0149 */ 0150 Keyframe getPrevKeyframe(const GenTime &pos, bool *ok) const; 0151 0152 /** @brief Returns the closest keyframe from given position. 0153 @param ok is a return parameter to tell if a keyframe was found. 0154 */ 0155 Keyframe getClosestKeyframe(const GenTime &pos, bool *ok) const; 0156 0157 /** @brief Returns true if a keyframe exists at given pos 0158 Notice that add/remove queries are done in real time (gentime), but this request is made in frame 0159 */ 0160 Q_INVOKABLE bool hasKeyframe(int frame) const; 0161 Q_INVOKABLE bool hasKeyframe(const GenTime &pos) const; 0162 Q_INVOKABLE QString realValue(double normalizedValue) const; 0163 0164 /** @brief Read the value from the model and update itself accordingly */ 0165 void refresh(int in = -1, int out = -1); 0166 /** @brief Reset all values to their default */ 0167 void reset(); 0168 0169 /** @brief Return the interpolated value at given pos */ 0170 QVariant getInterpolatedValue(int pos) const; 0171 QVariant getInterpolatedValue(const GenTime &pos) const; 0172 QVariant updateInterpolated(const QVariant &interpValue, double val); 0173 /** @brief Return the real value from a normalized one */ 0174 QVariant getNormalizedValue(double newVal) const; 0175 /** @brief Set or add a keyframe to selection */ 0176 Q_INVOKABLE void setSelectedKeyframe(int ix, bool add); 0177 void setSelectedKeyframes(QVector<int> selection); 0178 0179 Q_INVOKABLE int activeKeyframe() const; 0180 Q_INVOKABLE void setActiveKeyframe(int ix); 0181 int getIndexForPos(const GenTime pos) const; 0182 GenTime getPosAtIndex(int ix) const; 0183 0184 // Mandatory overloads 0185 Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override; 0186 QHash<int, QByteArray> roleNames() const override; 0187 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 0188 static QList<QPoint> getRanges(const QString &animData, const std::shared_ptr<AssetParameterModel> &model); 0189 static std::shared_ptr<Mlt::Properties> getAnimation(std::shared_ptr<AssetParameterModel> model, const QString &animData, int duration = 0); 0190 static const QString getAnimationStringWithOffset(std::shared_ptr<AssetParameterModel> model, const QString &animData, int offset, int duration, 0191 ParamType paramType, bool useOpacity = true); 0192 0193 protected: 0194 /** @brief Helper function that generate a lambda to change type / value of given keyframe */ 0195 Fun updateKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 0196 0197 /** @brief Helper function that generate a lambda to add given keyframe */ 0198 Fun addKeyframe_lambda(GenTime pos, KeyframeType type, const QVariant &value, bool notify); 0199 0200 /** @brief Helper function that generate a lambda to remove given keyframe */ 0201 Fun deleteKeyframe_lambda(GenTime pos, bool notify); 0202 0203 /** @brief Connects the signals of this object */ 0204 void setup(); 0205 0206 /** @brief Commit the modification to the model */ 0207 void sendModification(); 0208 0209 /** @brief returns the keyframes as a Mlt Anim Property string. 0210 It is defined as pairs of frame and value, separated by ; 0211 Example : "0|=50; 50|=100; 100=200; 200~=60;" 0212 Spaces are ignored by Mlt. 0213 |= represents a discrete keyframe, = a linear one and ~= a Catmull-Rom spline 0214 */ 0215 QString getAnimProperty() const; 0216 QString getRotoProperty() const; 0217 0218 /** @brief this function clears all existing keyframes, and reloads its data from the string passed */ 0219 void resetAnimProperty(const QString &prop); 0220 /** @brief this function does the opposite of getAnimProperty: given a MLT representation of an animation, build the corresponding model */ 0221 void parseAnimProperty(const QString &prop, int in = -1, int out = -1); 0222 void parseRotoProperty(const QString &prop); 0223 0224 private: 0225 std::weak_ptr<AssetParameterModel> m_model; 0226 std::weak_ptr<DocUndoStack> m_undoStack; 0227 QPersistentModelIndex m_index; 0228 QString m_lastData; 0229 ParamType m_paramType; 0230 /** @brief This is a lock that ensures safety in case of concurrent access */ 0231 mutable QReadWriteLock m_lock; 0232 0233 std::map<GenTime, std::pair<KeyframeType, QVariant>> m_keyframeList; 0234 bool moveOneKeyframe(GenTime oldPos, GenTime pos, QVariant newVal, Fun &undo, Fun &redo, bool updateView = true); 0235 0236 Q_SIGNALS: 0237 void modelChanged(); 0238 void requestModelUpdate(const QModelIndex &, const QModelIndex &, const QVector<int> &); 0239 0240 public: 0241 // this is to enable for range loops 0242 auto begin() -> decltype(m_keyframeList.begin()) { return m_keyframeList.begin(); } 0243 auto end() -> decltype(m_keyframeList.end()) { return m_keyframeList.end(); } 0244 }; 0245 // Q_DECLARE_METATYPE(KeyframeModel *)