CuteLogger
Fast and simple logging solution for Qt based applications
timelinedock.h
1 /*
2  * Copyright (c) 2013-2025 Meltytech, LLC
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef TIMELINEDOCK_H
19 #define TIMELINEDOCK_H
20 
21 #include "jobs/ffmpegjob.h"
22 #include "models/markersmodel.h"
23 #include "models/multitrackmodel.h"
24 #include "models/subtitlesmodel.h"
25 #include "models/subtitlesselectionmodel.h"
26 #include "sharedframe.h"
27 
28 #include <QApplication>
29 #include <QDateTime>
30 #include <QDockWidget>
31 #include <QQuickWidget>
32 #include <QTimer>
33 
34 namespace Timeline {
35 class UpdateCommand;
36 class TrimCommand;
37 } // namespace Timeline
38 class UndoHelper;
39 class QMenu;
40 
41 class TimelineDock : public QDockWidget
42 {
43  Q_OBJECT
44  Q_PROPERTY(int position READ position WRITE setPosition NOTIFY positionChanged)
45  Q_PROPERTY(int currentTrack READ currentTrack WRITE setCurrentTrack NOTIFY currentTrackChanged)
46  Q_PROPERTY(
47  QVariantList selection READ selectionForJS WRITE setSelectionFromJS NOTIFY selectionChanged)
48  Q_PROPERTY(bool isRecording READ isRecording NOTIFY isRecordingChanged)
49  Q_PROPERTY(int loopStart READ loopStart NOTIFY loopChanged)
50  Q_PROPERTY(int loopEnd READ loopEnd NOTIFY loopChanged)
51 
52 public:
53  explicit TimelineDock(QWidget *parent = 0);
54  ~TimelineDock();
55 
56  enum TrimLocation { TrimInPoint, TrimOutPoint };
57 
58  MultitrackModel *model() { return &m_model; }
59  MarkersModel *markersModel() { return &m_markersModel; }
60  SubtitlesModel *subtitlesModel() { return &m_subtitlesModel; }
61  SubtitlesSelectionModel *subtitlesSelectionModel() { return &m_subtitlesSelectionModel; }
62  int position() const { return m_position; }
63  void setPosition(int position);
64  Mlt::Producer producerForClip(int trackIndex, int clipIndex);
65  int clipIndexAtPlayhead(int trackIndex = -1);
66  int clipIndexAtPosition(int trackIndex, int position);
67  void chooseClipAtPosition(int position, int &trackIndex, int &clipIndex);
68  void setCurrentTrack(int currentTrack);
69  int currentTrack() const;
70  int clipCount(int trackIndex) const;
71  void setSelectionFromJS(const QVariantList &list);
72  void setSelection(QList<QPoint> selection = QList<QPoint>(),
73  int trackIndex = -1,
74  bool isMultitrack = false);
75  QVariantList selectionForJS() const;
76  const QList<QPoint> selection() const;
77  const QVector<QUuid> selectionUuids();
78  const QList<QPoint> uuidsToSelection(QVector<QUuid> uuids) const;
79  void saveAndClearSelection();
80  Q_INVOKABLE void restoreSelection();
81  Q_INVOKABLE QVariantList getGroupForClip(int trackIndex, int clipIndex);
82  void selectClipUnderPlayhead();
83  int centerOfClip(int trackIndex, int clipIndex);
84  bool isTrackLocked(int trackIndex) const;
85  void trimClipAtPlayhead(TrimLocation location, bool ripple);
86  Q_INVOKABLE bool isMultitrackSelected() const { return m_selection.isMultitrackSelected; }
87  Q_INVOKABLE int selectedTrack() const { return m_selection.selectedTrack; }
88  Q_INVOKABLE bool isFloating() const { return QDockWidget::isFloating(); }
89  Q_INVOKABLE static void openProperties();
90  void emitSelectedChanged(const QVector<int> &roles);
91  void replaceClipsWithHash(const QString &hash, Mlt::Producer &producer);
92  Q_INVOKABLE void recordAudio();
93  Q_INVOKABLE void stopRecording();
94  bool isRecording() const { return m_isRecording; }
95  int addTrackIfNeeded(TrackType trackType);
96  void getSelectionRange(int *start, int *end);
97  int loopStart() const { return m_loopStart; }
98  int loopEnd() const { return m_loopEnd; }
99 
100 signals:
101  void currentTrackChanged();
102  void selectionChanged();
103  void seeked(int position);
104  void positionChanged(int position);
105  void loopChanged();
106  void clipOpened(Mlt::Producer *producer);
107  void dragging(const QPointF &pos, int duration);
108  void dropped();
109  void dropAccepted(const QString &xml);
110  void fadeInChanged(int duration);
111  void fadeOutChanged(int duration);
112  void selected(Mlt::Producer *producer);
113  void clipClicked();
114  void showStatusMessage(QString);
115  void clipCopied();
116  void clipMoved(int fromTrack, int toTrack, int clipIndex, int position, bool ripple);
117  void filteredClicked();
118  void durationChanged();
119  void transitionAdded(int trackIndex, int clipIndex, int position, bool ripple);
120  void zoomIn();
121  void zoomOut();
122  void zoomToFit();
123  void setZoom(double value);
124  void markerRangesChanged();
125  void markerSeeked(int markerIndex);
126  void isRecordingChanged(bool);
127  void multitrackSelected();
128  void warnTrackLocked(int trackIndex);
129  void refreshWaveforms();
130  void updateThumbnails(int trackIndex, int clipIndex);
131  void trimStarted();
132  void trimEnded();
133 
134 public slots:
135  int addAudioTrack();
136  int addVideoTrack();
137  void alignSelectedClips();
138  void onShowFrame(const SharedFrame &frame);
139  void onSeeked(int position);
140  void append(int trackIndex);
141  void remove(int trackIndex, int clipIndex, bool ignoreTransition = false);
142  bool mergeClipWithNext(int trackIndex, int clipIndex, bool dryrun);
143  void lift(int trackIndex, int clipIndex, bool ignoreTransition = false);
144  void removeSelection(bool withCopy = false);
145  void liftSelection();
146  void incrementCurrentTrack(int by);
147  void selectTrackHead(int trackIndex);
148  void selectMultitrack();
149  void copy(int trackIndex, int clipIndex);
150  void setTrackName(int trackIndex, const QString &value);
151  void toggleTrackMute(int trackIndex);
152  void toggleTrackHidden(int trackIndex);
153  void setTrackComposite(int trackIndex, bool composite);
154  void setTrackLock(int trackIndex, bool lock);
155  bool moveClip(int fromTrack, int toTrack, int clipIndex, int position, bool ripple);
156  void onClipMoved(int fromTrack, int toTrack, int clipIndex, int position, bool ripple);
157  bool trimClipIn(int trackIndex, int clipIndex, int oldClipIndex, int delta, bool ripple);
158  bool trimClipOut(int trackIndex, int clipIndex, int delta, bool ripple);
159  void insert(int trackIndex, int position = -1, const QString &xml = QString(), bool seek = true);
160  void overwrite(int trackIndex,
161  int position = -1,
162  const QString &xml = QString(),
163  bool seek = true);
164  void appendFromPlaylist(Mlt::Playlist *playlist, bool skipProxy, bool emptyTrack);
165  void fadeIn(int trackIndex, int clipIndex = -1, int duration = -1);
166  void fadeOut(int trackIndex, int clipIndex = -1, int duration = -1);
167  void seekPreviousEdit();
168  void seekNextEdit();
169  void seekInPoint(int clipIndex);
170  void clearSelectionIfInvalid();
171  void insertTrack();
172  void insertAudioTrack();
173  void insertVideoTrack();
174  void removeTrack();
175  void moveTrack(int fromTrackIndex, int toTrackIndex);
176  void moveTrackUp();
177  void moveTrackDown();
178  void onProducerChanged(Mlt::Producer *);
179  void emitSelectedFromSelection();
180  void remakeAudioLevels(int trackIndex, int clipIndex, bool force = true);
181  void commitTrimCommand();
182  void onRowsInserted(const QModelIndex &parent, int first, int last);
183  void onRowsRemoved(const QModelIndex &parent, int first, int last);
184  void onRowsMoved(
185  const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row);
186  void detachAudio(int trackIndex, int clipIndex);
187  void selectAll();
188  void selectAllOnCurrentTrack();
189  void onProducerModified();
190  void replace(int trackIndex, int clipIndex, const QString &xml = QString());
191  void createOrEditMarker();
192  void createOrEditSelectionMarker();
193  void createMarker();
194  void editMarker(int markerIndex);
195  void deleteMarker(int markerIndex = -1);
196  void seekNextMarker();
197  void seekPrevMarker();
198  void onFilterModelChanged();
199  void trimClipIn(bool ripple = false);
200  void trimClipOut(bool ripple = false);
201  void initLoad();
202  void handleDrop(int trackIndex, int position, QString xml);
203  void onLoopChanged(int start, int end);
204 
205 protected:
206  void dragEnterEvent(QDragEnterEvent *event);
207  void dragMoveEvent(QDragMoveEvent *event);
208  void dragLeaveEvent(QDragLeaveEvent *event);
209  void dropEvent(QDropEvent *event);
210  bool event(QEvent *event);
211  void keyPressEvent(QKeyEvent *event);
212  void keyReleaseEvent(QKeyEvent *event);
213 
214 private:
215  bool isBlank(int trackIndex, int clipIndex);
216  bool clipsAreSelected();
217  bool blankIsSelected();
218  bool nothingIsSelected();
219  bool isTransition(int trackIndex, int clipIndex);
220  void emitNonSeekableWarning();
221  void addTrackIfNeeded(int mltTrackIndex, Mlt::Producer *srcTrack);
222  void setupActions();
223  bool isMultitrackValid() { return m_model.tractor() && !m_model.trackList().empty(); }
224  void reportSelectionChange();
225  void applyCopiedFiltersToSelectdClips();
226  void insertOrOverwriteDrop(int trackIndex, int position, const QString &xml);
227  void freezeFrame();
228  void addGenerator(QWidget *widget);
229 
230  QQuickWidget m_quickView;
231  MultitrackModel m_model;
232  MarkersModel m_markersModel;
233  SubtitlesModel m_subtitlesModel;
234  SubtitlesSelectionModel m_subtitlesSelectionModel;
235  int m_position{-1};
236  std::unique_ptr<Timeline::UpdateCommand> m_updateCommand;
237  bool m_ignoreNextPositionChange{false};
238  struct Selection
239  {
240  QList<QPoint> selectedClips; // x is the clip index, y is the track index
241  int selectedTrack;
242  bool isMultitrackSelected;
243  };
244  Selection m_selection;
245  int m_savedSelectedTrack{-1};
246  bool m_savedIsMultitrackSelected{false};
247  QVector<QUuid> m_savedSelectionUuids;
248  QTimer m_selectionSignalTimer;
249  std::unique_ptr<Timeline::TrimCommand> m_trimCommand;
250  std::unique_ptr<UndoHelper> m_undoHelper;
251  int m_trimDelta{0};
252  int m_transitionDelta{0};
253  bool m_isRecording{false};
254  std::unique_ptr<AbstractJob> m_recordJob;
255  QTimer m_recordingTimer;
256  QDateTime m_recordingTime;
257  int m_recordingTrackIndex{-1};
258  int m_recordingClipIndex{-1};
259  int m_currentTrack{0};
260  QMenu *m_mainMenu{nullptr};
261  QMenu *m_clipMenu{nullptr};
262  int m_loopStart{-1};
263  int m_loopEnd{-1};
264 
265 private slots:
266  void load(bool force);
267  void onTopLevelChanged(bool floating);
268  void onTransitionAdded(int trackIndex, int clipIndex, int position, bool ripple);
269  void selectClip(int trackIndex, int clipIndex);
270  void onMultitrackClosed();
271  void reloadTimelineModels();
272  void onRecordStarted();
273  void updateRecording();
274  void onRecordFinished(AbstractJob *, bool);
275  void onWarnTrackLocked();
276  void onTimelineRightClicked();
277  void onClipRightClicked();
278  void onNoMoreEmptyTracks(bool isAudio);
279  void addGenerator();
280 };
281 
282 #endif // TIMELINEDOCK_H
The SharedFrame provides thread safe access to Mlt::Frame data.
Definition: sharedframe.h:50