File indexing completed on 2024-05-12 04:52:47

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 "definitions.h"
0009 #include "keyframemodel.hpp"
0010 #include "undohelper.hpp"
0011 #include "utils/gentime.h"
0012 
0013 #include <QReadWriteLock>
0014 
0015 #include <QObject>
0016 #include <map>
0017 #include <memory>
0018 #include <unordered_map>
0019 
0020 class AssetParameterModel;
0021 class DocUndoStack;
0022 
0023 /** @class KeyframeModelList
0024     @brief This class is a container for the keyframe models.
0025    If an asset has several keyframable parameters, each one has its own keyframeModel,
0026    but we regroup all of these in a common class to provide unified access.
0027  */
0028 class KeyframeModelList : public QObject
0029 {
0030     Q_OBJECT
0031 
0032 public:
0033     /** @brief Construct a keyframe list bound to the given asset
0034        @param init_value and index correspond to the first parameter
0035      */
0036     explicit KeyframeModelList(std::weak_ptr<AssetParameterModel> model, const QModelIndex &index, std::weak_ptr<DocUndoStack> undo_stack, int in, int out);
0037 
0038     /** @brief Add a keyframable parameter to be managed by this model */
0039     void addParameter(const QModelIndex &index, int in, int out);
0040 
0041     /** @brief Adds a keyframe at the given position. If there is already one then we update it.
0042        @param pos defines the position of the keyframe, relative to the clip
0043        @param type is the type of the keyframe.
0044      */
0045     bool addKeyframe(GenTime pos, KeyframeType type);
0046     bool addKeyframe(int frame, double val);
0047 
0048     /** @brief Removes the keyframe at the given position. */
0049     bool removeKeyframe(GenTime pos);
0050     bool removeKeyframeWithUndo(GenTime pos, Fun &undo, Fun &redo);
0051 
0052     /** @brief Duplicate a keyframe at the given position. */
0053     bool duplicateKeyframeWithUndo(GenTime srcPos, GenTime destPos, Fun &undo, Fun &redo);
0054     /** @brief Delete all the keyframes of the model (except first) */
0055     bool removeAllKeyframes();
0056     /** @brief Delete all the keyframes after a certain position (except first) */
0057     bool removeNextKeyframes(GenTime pos);
0058 
0059     /** @brief moves a keyframe
0060        @param oldPos is the old position of the keyframe
0061        @param pos defines the new position of the keyframe, relative to the clip
0062        @param logUndo if true, then an undo object is created
0063     */
0064     bool moveKeyframe(GenTime oldPos, GenTime pos, bool logUndo, bool updateView = true);
0065     bool moveKeyframeWithUndo(GenTime oldPos, GenTime pos, Fun &undo, Fun &redo);
0066 
0067     /** @brief updates the value of a keyframe
0068        @param pos is the position of the keyframe
0069        @param value is the new value of the param
0070        @param index is the index of the wanted keyframe
0071     */
0072     bool updateKeyframe(GenTime pos, const QVariant &value, const QPersistentModelIndex &index, QUndoCommand *parentCommand = nullptr);
0073     /** @brief updates the value of a keyframe which contains multiple params, like Lift/Gamma/Gain
0074        @param pos is the position of the keyframe
0075        @param sourceValues is the list of previous values (used when undoing)
0076        @param values is the new values list
0077        @param indexes is the index list of the wanted keyframe
0078     */
0079     bool updateMultiKeyframe(GenTime pos, const QStringList &sourceValues, const QStringList &values, const QList<QModelIndex> &indexes,
0080                              QUndoCommand *parentCommand = nullptr);
0081     bool updateKeyframeType(GenTime pos, int type, const QPersistentModelIndex &index);
0082     bool updateKeyframe(GenTime oldPos, GenTime pos, const QVariant &normalizedVal, bool logUndo = true);
0083     KeyframeType keyframeType(GenTime pos) const;
0084     /** @brief Returns a keyframe data at given pos
0085        ok is a return parameter, set to true if everything went good
0086      */
0087     Keyframe getKeyframe(const GenTime &pos, bool *ok) const;
0088 
0089     /** @brief Returns true if we only have 1 keyframe
0090      */
0091     bool singleKeyframe() const;
0092     /** @brief Returns true if we only have no keyframe
0093      */
0094     bool isEmpty() const;
0095     /** @brief Returns the number of keyframes
0096      */
0097     int count() const;
0098 
0099     /** @brief Returns the keyframe located after given position.
0100        If there is a keyframe at given position it is ignored.
0101        @param ok is a return parameter to tell if a keyframe was found.
0102     */
0103     Keyframe getNextKeyframe(const GenTime &pos, bool *ok) const;
0104 
0105     /** @brief Returns the keyframe located before given position.
0106        If there is a keyframe at given position it is ignored.
0107        @param ok is a return parameter to tell if a keyframe was found.
0108     */
0109     Keyframe getPrevKeyframe(const GenTime &pos, bool *ok) const;
0110 
0111     /** @brief Returns the closest keyframe from given position.
0112        @param ok is a return parameter to tell if a keyframe was found.
0113     */
0114     Keyframe getClosestKeyframe(const GenTime &pos, bool *ok) const;
0115 
0116     /** @brief Returns true if a keyframe exists at given pos
0117        Notice that add/remove queries are done in real time (gentime), but this request is made in frame
0118      */
0119     Q_INVOKABLE bool hasKeyframe(int frame) const;
0120 
0121     /** @brief Return the interpolated value of a parameter.
0122        @param pos is the position where we interpolate
0123        @param index is the index of the queried parameter. */
0124     QVariant getInterpolatedValue(int pos, const QPersistentModelIndex &index) const;
0125     /** @brief Return the interpolated value of a parameter.
0126        @param pos is the position where we interpolate
0127        @param index is the index of the queried parameter. */
0128     QVariant getInterpolatedValue(const GenTime &pos, const QPersistentModelIndex &index) const;
0129 
0130     /** @brief Load keyframes from the current parameter value. */
0131     void refresh();
0132     void setParametersFromTask(const paramVector &params);
0133     /** @brief Reset all keyframes and add a default one */
0134     void reset();
0135     Q_INVOKABLE KeyframeModel *getKeyModel();
0136     KeyframeModel *getKeyModel(const QPersistentModelIndex &index);
0137     /** @brief Returns parent asset owner id*/
0138     ObjectId getOwnerId() const;
0139     /** @brief Returns parent asset id*/
0140     const QString getAssetId();
0141     const QString getAssetRow();
0142 
0143     /** @brief Returns the list of selected keyframes */
0144     QVector<int> selectedKeyframes() const;
0145     /** @brief Remove a position from selected keyframes */
0146     void removeFromSelected(int pos);
0147     /** @brief Replace list of selected keyframes */
0148     void setSelectedKeyframes(const QVector<int> &list);
0149     /** @brief Append a keyframe to selection */
0150     void appendSelectedKeyframe(int frame);
0151 
0152     /** @brief Get the currently active keyframe */
0153     int activeKeyframe() const;
0154     /** @brief Set the currently active keyframe */
0155     void setActiveKeyframe(int pos);
0156 
0157     /** @brief Parent item size change, update keyframes*/
0158     void resizeKeyframes(int oldIn, int oldOut, int in, int out, int offset, bool adjustFromEnd, Fun &undo, Fun &redo);
0159 
0160     /** @brief Parent item size change, update keyframes*/
0161     void moveKeyframes(int oldIn, int in, Fun &undo, Fun &redo);
0162 
0163     /** @brief Return position of the nth keyframe (ix = nth)*/
0164     GenTime getPosAtIndex(int ix);
0165     int getIndexForPos(GenTime pos);
0166     QModelIndex getIndexAtRow(int row);
0167 
0168     /** @brief Check that all keyframable parameters have the same keyframes on loading
0169      *  (that's how our model works) */
0170     void checkConsistency();
0171     /** @brief Returns the indexes of all parameters */
0172     std::vector<QPersistentModelIndex> getIndexes();
0173 
0174 protected:
0175     /** @brief Helper function to apply a given operation on all parameters */
0176     bool applyOperation(const std::function<bool(std::shared_ptr<KeyframeModel>, Fun &, Fun &)> &op, const QString &undoString);
0177 
0178 Q_SIGNALS:
0179     void modelChanged();
0180     void modelDisplayChanged();
0181 
0182 private:
0183     std::weak_ptr<AssetParameterModel> m_model;
0184     std::weak_ptr<DocUndoStack> m_undoStack;
0185     std::unordered_map<QPersistentModelIndex, std::shared_ptr<KeyframeModel>> m_parameters;
0186     /** @brief Index of the parameter that is displayed in timeline */
0187     QModelIndex m_inTimelineIndex;
0188     mutable QReadWriteLock m_lock; // This is a lock that ensures safety in case of concurrent access
0189 
0190 private Q_SLOTS:
0191     void slotUpdateModels(const QModelIndex &ix1, const QModelIndex &ix2, const QVector<int> &roles);
0192 
0193 public:
0194     // this is to enable for range loops
0195     auto begin() -> decltype(m_parameters.begin()->second->begin()) { return m_parameters.begin()->second->begin(); }
0196     auto end() -> decltype(m_parameters.begin()->second->end()) { return m_parameters.begin()->second->end(); }
0197 };