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 *)