1 /*
2     SPDX-FileCopyrightText: 2021 Jean-Baptiste Mardelle <jb@kdenlive.org>
3 
4 SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6 
7 #ifndef TIMEREMAP_H
8 #define TIMEREMAP_H
9 
10 #include "ui_timeremap_ui.h"
11 
12 #include "definitions.h"
13 #include "timecode.h"
14 
15 #include <QWidget>
16 #include <QTimer>
17 #include <QMutex>
18 
19 #include "mlt++/Mlt.h"
20 
21 class ProjectClip;
22 class TimecodeDisplay;
23 
24 
25 /**
26  * @class RemapView
27  * @brief A widget to view remap keyframes.
28  * @author Jean-Baptiste Mardelle
29  */
30 
31 class RemapView : public QWidget
32 {
33     Q_OBJECT
34 
35 public:
36     friend class TimeRemap;
37     explicit RemapView(QWidget *parent = nullptr);
38     void setBinClipDuration(std::shared_ptr<ProjectClip> clip, int duration);
39     void setDuration(std::shared_ptr<Mlt::Producer> service, int duration, int sourceDuration = 0);
40     void loadKeyframes(const QString &mapData);
41     const QString getKeyframesData(QMap<int,int> keyframes = {}) const;
42     int position() const;
43     int remapDuration() const;
44     int remapMax() const;
45     bool movingKeyframe() const;
46     void refreshOnDurationChanged(int remapDuration);
47     /** @brief Returns true if timeline cursor is inside the remapped clip */
48     bool isInRange() const;
49     QTimer timer;
50 
51 protected:
52     void resizeEvent(QResizeEvent *event) override;
53     void paintEvent(QPaintEvent *event) override;
54     void mouseMoveEvent(QMouseEvent *event) override;
55     void mousePressEvent(QMouseEvent *event) override;
56     void mouseReleaseEvent(QMouseEvent *event) override;
57     void wheelEvent(QWheelEvent *event) override;
58     std::shared_ptr<Mlt::Link> m_remapLink;
59     /** @brief The position of the clip in timeline, used to seek to correct place */
60     int m_startPos;
61     /** @brief The in frame of the clip in timeline, used to correctly offset keyframes */
62     int m_inFrame;
63     int m_oldInFrame;
64     /** @brief the original in/out of the clip when opening the remap widget, used to snap to ends */
65     std::pair<int,int> m_originalRange;
66 
67 public slots:
68     void updateInPos(int pos);
69     void updateOutPos(int pos);
70     void slotSetPosition(int pos);
71     void slotSetBottomPosition(int pos);
72     void addKeyframe();
73     void goNext();
74     void goPrev();
75     void updateBeforeSpeed(double speed);
76     void updateAfterSpeed(double speed);
77     void toggleMoveNext(bool moveNext);
78     void reloadProducer();
79     void centerCurrentKeyframe();
80     void centerCurrentTopKeyframe();
81 
82 private:
83     enum MOVEMODE {NoMove, TopMove, BottomMove, CursorMove, CursorMoveBottom};
84     int m_duration;
85     int m_sourceDuration;
86     int m_lastMaxDuration;
87     int m_position;
88     /** @brief the maximum duration of the parent (bin) clip */
89     int m_maxLength;
90     int m_bottomPosition;
91     double m_scale;
92     QColor m_colSelected;
93     QColor m_colKeyframe;
94     int m_zoomHeight;
95     int m_centerPos;
96     int m_lineHeight;
97     double m_zoomFactor;
98     double m_zoomStart;
99     /** @brief The zoom factor (start, end - between 0 and 1) */
100     QPointF m_zoomHandle;
101     /** @brief the keyframes for the remap effect. first value is output, second is source time */
102     QMap<int, int>m_keyframes;
103     QMap<int, int>m_keyframesOrigin;
104     std::shared_ptr<ProjectClip> m_clip;
105     std::shared_ptr<Mlt::Producer> m_service;
106     QPointF m_lastZoomHandle;
107     /** @brief Mouse is the zoom left handle */
108     bool m_hoverZoomIn;
109     /** @brief Mouse is the zoom right handle */
110     bool m_hoverZoomOut;
111     /** @brief Mouse is over the zoom bar */
112     bool m_hoverZoom;
113     int m_bottomView;
114     std::pair<int, int> m_currentKeyframe;
115     std::pair<int,int> m_currentKeyframeOriginal;
116     MOVEMODE m_moveKeyframeMode;
117     double m_clickOffset;
118     int m_clickPoint;
119     bool m_moveNext;
120     int m_clickEnd;
121     int m_offset;
122     QMutex m_kfrMutex;
123     QMap <int,int>m_selectedKeyframes;
124     QMap<int,int>m_previousSelection;
125     std::pair<int,int> getClosestKeyframe(int pos, bool bottomKeyframe = false) const;
126     std::pair<double,double> getSpeed(std::pair<int,int>kf);
127 
128 signals:
129     void seekToPos(int,int);
130     void selectedKf(std::pair<int,int>, std::pair<double,double>, std::pair<bool,bool>atEnd = {true,true});
131     void updateSpeeds(std::pair<double,double>);
132     /** When the cursor position changes inform parent if we are on a keyframe or not. */
133     void atKeyframe(bool isKeyframe, bool last);
134     void updateKeyframes(bool resize);
135     void updateKeyframesWithUndo(QMap<int,int>updatedKeyframes, QMap<int,int>previousKeyframes);
136     void updateMaxDuration();
137 };
138 
139  /**
140  * @class TimeRemap
141  * @brief A dialog for editing time remap effect.
142  * @author Jean-Baptiste Mardelle
143  */
144 class TimeRemap : public QWidget, public Ui::TimeRemap_UI
145 {
146     Q_OBJECT
147 
148 public:
149     explicit TimeRemap(QWidget *parent = nullptr);
150     ~TimeRemap() override;
151     void selectedClip(int cid);
152     void setClip(std::shared_ptr<ProjectClip> clip, int in = -1, int out = -1);
153     /** @brief the bin id of the clip currently active in remap widget */
154     const QString &currentClip() const;
155     /** @brief Returns true if timeline cursor is inside the remapped clip */
156     bool isInRange() const;
157 
158 private slots:
159     void updateKeyframes(bool resize = true);
160     void updateKeyframesWithUndo(QMap<int,int>updatedKeyframes, QMap<int,int>previousKeyframes);
161     void checkClipUpdate(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int>& roles);
162     void switchRemapParam();
163 
164 private:
165     std::shared_ptr<Mlt::Link> m_splitRemap;
166     TimecodeDisplay *m_in;
167     TimecodeDisplay *m_out;
168     RemapView *m_view;
169     int m_lastLength;
170     int m_cid;
171     int m_splitId;
172     QString m_binId;
173     QMetaObject::Connection m_seekConnection1;
174     QMetaObject::Connection m_seekConnection2;
175     QMetaObject::Connection m_seekConnection3;
176 
177 };
178 
179 #endif
180