1 /*
2     SPDX-FileCopyrightText: 2017 Nicolas Carion
3     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4 */
5 
6 #ifndef ASSETPARAMETERMODEL_H
7 #define ASSETPARAMETERMODEL_H
8 
9 #include "definitions.h"
10 #include "klocalizedstring.h"
11 #include <QAbstractListModel>
12 #include <QDomElement>
13 #include <QJsonDocument>
14 #include <unordered_map>
15 
16 #include <memory>
17 #include <mlt++/MltProperties.h>
18 
19 class KeyframeModelList;
20 
21 typedef QVector<QPair<QString, QVariant>> paramVector;
22 
23 enum class ParamType {
24     Double,
25     List, // Value can be chosen from a list of pre-defined ones
26     ListWithDependency,  // Value can be chosen from a list of pre-defined ones. Some values might not be available due to missing dependencies
27     UrlList, // File can be chosen from a list of pre-defined ones or a custom file can be used (like url)
28     Bool,
29     Switch,
30     MultiSwitch,
31     RestrictedAnim, // animated 1 dimensional param with linear support only
32     Animated,
33     AnimatedRect, // Animated rects have X, Y, width, height, and opacity (in [0,1])
34     Geometry,
35     Addedgeometry,
36     KeyframeParam,
37     Color,
38     ColorWheel,
39     Position,
40     Curve,
41     Bezier_spline,
42     Roto_spline,
43     Wipe,
44     Url,
45     Keywords,
46     Fontfamily,
47     Filterjob,
48     Readonly,
49     Hidden
50 };
51 Q_DECLARE_METATYPE(ParamType)
52 
53 /** @class AssetParameterModel
54     @brief This class is the model for a list of parameters.
55    The behaviour of a transition or an effect is typically  controlled by several parameters. This class exposes this parameters as a list that can be rendered
56    using the relevant widgets.
57    Note that internally parameters are not sorted in any ways, because some effects like sox need a precise order
58     */
59 class AssetParameterModel : public QAbstractListModel, public enable_shared_from_this_virtual<AssetParameterModel>
60 {
61     Q_OBJECT
62 
63 friend class KeyframeModelList;
64 friend class KeyframeModel;
65 
66 public:
67     /**
68      *
69      * @param asset
70      * @param assetXml XML to parse, from project file
71      * @param assetId
72      * @param ownerId
73      * @param originalDecimalPoint If a decimal point other than “.” was used, try to replace all occurrences by a “.”
74      * so numbers are parsed correctly.
75      * @param parent
76      */
77     explicit AssetParameterModel(std::unique_ptr<Mlt::Properties> asset, const QDomElement &assetXml, const QString &assetId, ObjectId ownerId,
78                                  const QString& originalDecimalPoint = QString(),
79                                  QObject *parent = nullptr);
80     ~AssetParameterModel() override;
81     enum DataRoles {
82         NameRole = Qt::UserRole + 1,
83         TypeRole,
84         CommentRole,
85         AlternateNameRole,
86         MinRole,
87         VisualMinRole,
88         VisualMaxRole,
89         MaxRole,
90         DefaultRole,
91         SuffixRole,
92         DecimalsRole,
93         OddRole,
94         ValueRole,
95         AlphaRole,
96         ListValuesRole,
97         InstalledValuesRole,
98         ListNamesRole,
99         ListDependenciesRole,
100         NewStuffRole,
101         ModeRole,
102         FactorRole,
103         FilterRole,
104         FilterJobParamsRole,
105         FilterProgressRole,
106         FilterParamsRole,
107         FilterConsumerParamsRole,
108         ScaleRole,
109         OpacityRole,
110         RelativePosRole,
111         // Don't display this param in timeline keyframes
112         ShowInTimelineRole,
113         InRole,
114         OutRole,
115         ParentInRole,
116         ParentPositionRole,
117         ParentDurationRole,
118         HideKeyframesFirstRole,
119         List1Role,
120         List2Role,
121         Enum1Role,
122         Enum2Role,
123         Enum3Role,
124         Enum4Role,
125         Enum5Role,
126         Enum6Role,
127         Enum7Role,
128         Enum8Role,
129         Enum9Role,
130         Enum10Role,
131         Enum11Role,
132         Enum12Role,
133         Enum13Role,
134         Enum14Role,
135         Enum15Role,
136         Enum16Role
137     };
138 
139     /** @brief Returns the id of the asset represented by this object */
140     QString getAssetId() const;
141     const QString getAssetMltId();
142     void setActive(bool active);
143     bool isActive() const;
144 
145     /** @brief Set the parameter with given name to the given value
146      */
147     Q_INVOKABLE void setParameter(const QString &name, const QString &paramValue, bool update = true, const QModelIndex &paramIndex = QModelIndex());
148     void setParameter(const QString &name, int value, bool update = true);
149 
150     /** @brief Return all the parameters as pairs (parameter name, parameter value) */
151     QVector<QPair<QString, QVariant>> getAllParameters() const;
152     /** @brief Get a parameter value from its name */
153     const QVariant getParamFromName(const QString &paramName);
154     /** @brief Returns a json definition of the effect with all param values */
155     QJsonDocument toJson(bool includeFixed = true) const;
156     /** @brief Returns the interpolated value at the given position with all param values as json*/
157     QJsonDocument valueAsJson(int pos, bool includeFixed = true) const;
158 
159     void savePreset(const QString &presetFile, const QString &presetName);
160     void deletePreset(const QString &presetFile, const QString &presetName);
161     const QStringList getPresetList(const QString &presetFile) const;
162     const QVector<QPair<QString, QVariant>> loadPreset(const QString &presetFile, const QString &presetName);
163 
164     /* Which monitor is attached to this asset (clip/project)
165      */
166     Kdenlive::MonitorId monitorId;
167 
168     QVariant data(const QModelIndex &index, int role) const override;
169     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
170 
171     /** @brief Returns the id of the actual object associated with this asset */
172     ObjectId getOwnerId() const;
173 
174     /** @brief Returns the keyframe model associated with this asset
175        Return empty ptr if there is no keyframable parameter in the asset or if prepareKeyframes was not called
176      */
177     Q_INVOKABLE std::shared_ptr<KeyframeModelList> getKeyframeModel();
178 
179     /** @brief Must be called before using the keyframes of this model */
180     void prepareKeyframes();
181     void resetAsset(std::unique_ptr<Mlt::Properties> asset);
182     /** @brief Returns true if the effect has more than one keyframe */
183     bool hasMoreThanOneKeyframe() const;
184     int time_to_frames(const QString &time);
185     void passProperties(Mlt::Properties &target);
186     /** @brief Returns a list of the parameter names that are keyframable */
187     QStringList getKeyframableParameters() const;
188 
189     /** @brief Returns the current value of an effect parameter */
190     const QString getParam(const QString &paramName);
191     /** @brief Returns the current asset */
192     Mlt::Properties *getAsset();
193     /** @brief Returns a frame time as click time (00:00:00.000) */
194     const QString framesToTime(int t) const;
195 
196 public slots:
197     /** @brief Sets the value of a list of parameters
198        @param params contains the pairs (parameter name, parameter value)
199      */
200     void setParameters(const paramVector &params, bool update = true);
201     /** @brief Set a filter job's progress */
202     void setProgress(int progress);
203 
204 protected:
205     /** @brief Helper function to retrieve the type of a parameter given the string corresponding to it*/
206     static ParamType paramTypeFromStr(const QString &type);
207 
208     static QString getDefaultKeyframes(int start, const QString &defaultValue, bool linearOnly);
209 
210     /** @brief Helper function to get an attribute from a dom element, given its name.
211        The function additionally parses following keywords:
212        - %width and %height that are replaced with profile's height and width.
213        If keywords are found, mathematical operations are supported for double type params. For example "%width -1" is a valid value.
214     */
215     static QVariant parseAttribute(const ObjectId &owner, const QString &attribute, const QDomElement &element, QVariant defaultValue = QVariant());
216     QVariant parseSubAttributes(const QString &attribute, const QDomElement &element) const;
217 
218     /** @brief Helper function to register one more parameter that is keyframable.
219        @param index is the index corresponding to this parameter
220     */
221     void addKeyframeParam(const QModelIndex &index);
222 
223     struct ParamRow
224     {
225         ParamType type;
226         QDomElement xml;
227         QVariant value;
228         QString name;
229     };
230 
231     QString m_assetId;
232     ObjectId m_ownerId;
233     bool m_active;
234     /** @brief Keep track of parameter order, important for sox */
235     std::vector<QString> m_paramOrder;
236     /** @brief Store all parameters by name */
237     std::unordered_map<QString, ParamRow> m_params;
238     /** @brief We store values of fixed parameters aside */
239     std::unordered_map<QString, QVariant> m_fixedParams;
240     /** @brief We store the params name in order of parsing. The order is important (cf some effects like sox) */
241     QVector<QString> m_rows;
242 
243     std::unique_ptr<Mlt::Properties> m_asset;
244 
245     std::shared_ptr<KeyframeModelList> m_keyframes;
246     QVector<int>m_selectedKeyframes;
247     int m_activeKeyframe;
248     /** @brief if true, keyframe tools will be hidden by default */
249     bool m_hideKeyframesByDefault;
250     /** @brief true if this is an audio effect, used to prevent unnecessary monitor refresh / timeline invalidate */
251     bool m_isAudio;
252     /** @brief Store a filter's job progress */
253     int m_filterProgress;
254 
255     /** @brief Set the parameter with given name to the given value. This should be called when first
256      *  building an effect in the constructor, so that we don't call shared_from_this
257      */
258     void internalSetParameter(const QString &name, const QString &paramValue, const QModelIndex &paramIndex = QModelIndex());
259 
260 signals:
261     void modelChanged();
262     /** @brief inform child effects (in case of bin effect with timeline producers)
263      *  that a change occurred and a param update is needed **/
264     void updateChildren(const QStringList &names);
265     void compositionTrackChanged();
266     void replugEffect(std::shared_ptr<AssetParameterModel> asset);
267     void rebuildEffect(std::shared_ptr<AssetParameterModel> asset);
268     void enabledChange(bool);
269     void showEffectZone(ObjectId id, QPair <int, int>inOut, bool checked);
270 };
271 
272 #endif
273