File indexing completed on 2024-05-19 04:54:24
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 "abstractmodel/abstracttreemodel.hpp" 0009 #include "definitions.h" 0010 #include "undohelper.hpp" 0011 0012 #include <QReadWriteLock> 0013 #include <QUuid> 0014 #include <memory> 0015 #include <mlt++/Mlt.h> 0016 #include <unordered_set> 0017 0018 /** @brief This class an effect stack as viewed by the back-end. 0019 It is responsible for planting and managing effects into the list of producer it holds a pointer to. 0020 It can contains more than one producer for example if it represents the effect stack of a projectClip: this clips contains several producers (audio, video, 0021 ...) 0022 */ 0023 class AbstractEffectItem; 0024 class AssetParameterModel; 0025 class DocUndoStack; 0026 class EffectItemModel; 0027 class TreeItem; 0028 class KeyframeModel; 0029 0030 class EffectStackModel : public AbstractTreeModel 0031 { 0032 Q_OBJECT 0033 0034 public: 0035 /** @brief Constructs an effect stack and returns a shared ptr to the constructed object 0036 @param service is the mlt object on which we will plant the effects 0037 @param ownerId is some information about the actual object to which the effects are applied 0038 */ 0039 static std::shared_ptr<EffectStackModel> construct(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack); 0040 0041 protected: 0042 EffectStackModel(std::weak_ptr<Mlt::Service> service, ObjectId ownerId, std::weak_ptr<DocUndoStack> undo_stack); 0043 0044 public: 0045 /** @brief Add an effect at the bottom of the stack */ 0046 bool appendEffect(const QString &effectId, bool makeCurrent = false, stringMap params = {}); 0047 bool appendEffectWithUndo(const QString &effectId, Fun &undo, Fun &redo); 0048 /** @brief Copy an existing effect and append it at the bottom of the stack 0049 */ 0050 bool copyEffect(const std::shared_ptr<AbstractEffectItem> &sourceItem, PlaylistState::ClipState state, bool logUndo = true); 0051 bool copyXmlEffect(const QDomElement &effect); 0052 bool copyXmlEffectWithUndo(const QDomElement &effect, Fun &undo, Fun &redo); 0053 /** @brief Import all effects from the given effect stack 0054 */ 0055 bool importEffects(const std::shared_ptr<EffectStackModel> &sourceStack, PlaylistState::ClipState state); 0056 void importEffects(const std::weak_ptr<Mlt::Service> &service, PlaylistState::ClipState state, bool alreadyExist = false, 0057 const QString &originalDecimalPoint = QString(), const QUuid &uuid = QUuid()); 0058 bool removeFade(bool fromStart); 0059 0060 /** @brief This function change the global (timeline-wise) enabled state of the effects 0061 */ 0062 void setEffectStackEnabled(bool enabled); 0063 0064 /** @brief Returns an effect or group from the stack (at the given row) */ 0065 std::shared_ptr<AbstractEffectItem> getEffectStackRow(int row, const std::shared_ptr<TreeItem> &parentItem = nullptr); 0066 std::shared_ptr<AssetParameterModel> getAssetModelById(const QString &effectId); 0067 0068 /** @brief Move an effect in the stack */ 0069 void moveEffect(int destRow, const std::shared_ptr<AbstractEffectItem> &item); 0070 0071 /** @brief Set effect in row as current one */ 0072 void setActiveEffect(int ix); 0073 /** @brief Get currently active effect row */ 0074 int getActiveEffect() const; 0075 /** @brief Adjust an effect duration (useful for fades) */ 0076 bool adjustFadeLength(int duration, bool fromStart, bool audioFade, bool videoFade, bool logUndo); 0077 bool adjustStackLength(bool adjustFromEnd, int oldIn, int oldDuration, int newIn, int duration, int offset, Fun &undo, Fun &redo, bool logUndo); 0078 0079 void slotCreateGroup(const std::shared_ptr<EffectItemModel> &childEffect); 0080 0081 /** @brief Returns the id of the owner of the stack */ 0082 ObjectId getOwnerId() const; 0083 0084 int getFadePosition(bool fromStart); 0085 Q_INVOKABLE void adjust(const QString &effectId, const QString &effectName, double value); 0086 0087 /** @brief Returns true if the stack contains an effect with the given Id */ 0088 Q_INVOKABLE bool hasFilter(const QString &effectId) const; 0089 // TODO: this break the encapsulation, remove 0090 Q_INVOKABLE double getFilterParam(const QString &effectId, const QString ¶mName); 0091 /** @brief get the active effect's keyframe model */ 0092 Q_INVOKABLE KeyframeModel *getEffectKeyframeModel(); 0093 /** Add a keyframe in all model parameters */ 0094 bool addEffectKeyFrame(int frame, double normalisedVal); 0095 /** @brief Remove a keyframe in all model parameters */ 0096 bool removeKeyFrame(int frame); 0097 /** Update a keyframe in all model parameters (with value updated only in first parameter)*/ 0098 bool updateKeyFrame(int oldFrame, int newFrame, QVariant normalisedVal); 0099 /** @brief Returns true if active effect has a keyframe at pos p*/ 0100 bool hasKeyFrame(int frame); 0101 /** @brief Remove unwanted fade effects, mostly after a cut operation */ 0102 void cleanFadeEffects(bool outEffects, Fun &undo, Fun &redo); 0103 0104 /** @brief Remove all the services associated with this stack and replace them with the given one */ 0105 void resetService(std::weak_ptr<Mlt::Service> service); 0106 0107 /** @brief Append a new service to be managed by this stack */ 0108 void addService(std::weak_ptr<Mlt::Service> service); 0109 /** @brief Append an existing service to be managed by this stack (on document load)*/ 0110 void loadService(std::weak_ptr<Mlt::Service> service); 0111 0112 /** @brief Remove a service from those managed by this stack */ 0113 void removeService(const std::shared_ptr<Mlt::Service> &service); 0114 0115 /** @brief Returns a comma separated list of effect names */ 0116 const QString effectNames() const; 0117 0118 /** @brief Returns a list of external file urls used by the effects (e.g. LUTs) */ 0119 QStringList externalFiles() const; 0120 0121 bool isStackEnabled() const; 0122 0123 /** @brief Returns an XML representation of the effect stack with all parameters */ 0124 QDomElement toXml(QDomDocument &document); 0125 /** @brief Returns an XML representation of one of the effect in the stack with all parameters */ 0126 QDomElement rowToXml(const QUuid &uuid, int row, QDomDocument &document); 0127 /** @brief Load an effect stack from an XML representation */ 0128 bool fromXml(const QDomElement &effectsXml, Fun &undo, Fun &redo); 0129 /** @brief Delete active effect from stack */ 0130 void removeCurrentEffect(); 0131 0132 /** @brief This is a convenience function that helps check if the tree is in a valid state */ 0133 bool checkConsistency() override; 0134 0135 /** @brief Return true if an asset id is already added to this effect stack */ 0136 bool hasEffect(const QString &assetId) const; 0137 0138 /** @brief Remove all effects for this stack */ 0139 void removeAllEffects(Fun &undo, Fun &redo); 0140 0141 /** @brief Returns a list of zones for all effects */ 0142 QVariantList getEffectZones() const; 0143 0144 /** @brief Copy all Kdenlive effects of this track on a producer */ 0145 void passEffects(Mlt::Producer *producer, const QString &exception = QString()); 0146 0147 public Q_SLOTS: 0148 /** @brief Delete an effect from the stack */ 0149 void removeEffect(const std::shared_ptr<EffectItemModel> &effect); 0150 /** @brief Move an effect in the stack */ 0151 void moveEffectByRow(int destRow, int srcRow); 0152 0153 protected: 0154 /** @brief Register the existence of a new element 0155 */ 0156 void registerItem(const std::shared_ptr<TreeItem> &item) override; 0157 /** @brief Deregister the existence of a new element*/ 0158 void deregisterItem(int id, TreeItem *item) override; 0159 0160 std::weak_ptr<Mlt::Service> m_masterService; 0161 std::vector<std::weak_ptr<Mlt::Service>> m_childServices; 0162 bool m_effectStackEnabled; 0163 ObjectId m_ownerId; 0164 0165 std::weak_ptr<DocUndoStack> m_undoStack; 0166 0167 private: 0168 mutable QReadWriteLock m_lock; 0169 std::unordered_set<int> m_fadeIns; 0170 std::unordered_set<int> m_fadeOuts; 0171 0172 /** @brief: When loading a project, we load filters/effects that are already planted 0173 * in the producer, so we shouldn't plant them again. Setting this value to 0174 * true will prevent planting in the producer */ 0175 bool m_loadingExisting; 0176 bool doAppendEffect(const QString &effectId, bool makeCurrent, stringMap params, Fun &undo, Fun &redo); 0177 0178 private Q_SLOTS: 0179 /** @brief: Some effects do not support dynamic changes like sox, and need to be unplugged / replugged on each param change 0180 */ 0181 void replugEffect(const std::shared_ptr<AssetParameterModel> &asset); 0182 /** @brief: Some effect zones changed, ensure to update master effect zones 0183 */ 0184 void updateEffectZones(); 0185 0186 Q_SIGNALS: 0187 /** @brief: This signal is connected to the project clip for bin clips and activates the reload of effects on child (timeline) producers 0188 */ 0189 void modelChanged(); 0190 void enabledStateChanged(); 0191 /** @brief: The master effect stack zones changed, update */ 0192 void updateMasterZones(); 0193 /** @brief: Currently active effect changed */ 0194 void currentChanged(QModelIndex ix, bool active); 0195 };