/*** Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***/ #ifndef TIMELINEUNDOGENERAL_H #define TIMELINEUNDOGENERAL_H #include "config/config.h" #include "node/block/clip/clip.h" #include "node/block/gap/gap.h" #include "node/output/track/track.h" #include "node/output/track/tracklist.h" #include "node/output/viewer/viewer.h" #include "node/project/sequence/sequence.h" #include "timelineundosplit.h" namespace olive { class BlockResizeCommand : public UndoCommand { public: BlockResizeCommand(Block* block, rational new_length) : block_(block), new_length_(new_length) { } virtual Project* GetRelevantProject() const override { return block_->project(); } protected: virtual void redo() override; virtual void undo() override; private: Block* block_; rational old_length_; rational new_length_; }; class BlockResizeWithMediaInCommand : public UndoCommand { public: BlockResizeWithMediaInCommand(Block* block, rational new_length) : block_(block), new_length_(new_length) { } virtual Project* GetRelevantProject() const { return block_->project(); } protected: virtual void redo(); virtual void undo(); private: Block* block_; rational old_length_; rational new_length_; }; class BlockSetMediaInCommand : public UndoCommand { public: BlockSetMediaInCommand(ClipBlock* block, rational new_media_in) : block_(block), new_media_in_(new_media_in) { } virtual Project* GetRelevantProject() const { return block_->project(); } protected: virtual void redo(); virtual void undo(); private: ClipBlock* block_; rational old_media_in_; rational new_media_in_; }; class TimelineAddTrackCommand : public UndoCommand { public: TimelineAddTrackCommand(TrackList *timeline) : TimelineAddTrackCommand(timeline, OLIVE_CONFIG("AutoMergeTracks").toBool()) { } TimelineAddTrackCommand(TrackList *timeline, bool automerge_tracks); static Track* RunImmediately(TrackList *timeline) { TimelineAddTrackCommand c(timeline); c.redo(); return c.track(); } static Track* RunImmediately(TrackList *timeline, bool automerge) { TimelineAddTrackCommand c(timeline, automerge); c.redo(); return c.track(); } virtual ~TimelineAddTrackCommand() override { delete position_command_; } Track* track() const { return track_; } virtual Project* GetRelevantProject() const override { return timeline_->parent()->project(); } protected: virtual void redo() override; virtual void undo() override; private: TrackList* timeline_; Track* track_; Node* merge_; NodeInput base_; NodeInput blend_; NodeInput direct_; MultiUndoCommand* position_command_; QObject memory_manager_; }; class TimelineRemoveTrackCommand : public UndoCommand { public: TimelineRemoveTrackCommand(Track *track) : track_(track), remove_command_(nullptr) {} virtual ~TimelineRemoveTrackCommand() { delete remove_command_; } virtual Project* GetRelevantProject() const override { return track_->project(); } protected: virtual void prepare() override; virtual void redo() override; virtual void undo() override; private: Track *track_; TrackList *list_; int index_; UndoCommand *remove_command_; }; class TransitionRemoveCommand : public UndoCommand { public: TransitionRemoveCommand(TransitionBlock* block, bool remove_from_graph) : block_(block), remove_from_graph_(remove_from_graph), remove_command_(nullptr) { } virtual Project* GetRelevantProject() const override { return track_->project(); } protected: virtual void redo() override; virtual void undo() override; private: TransitionBlock* block_; Track* track_; Block* out_block_; Block* in_block_; bool remove_from_graph_; UndoCommand* remove_command_; }; class TrackReplaceBlockWithGapCommand : public UndoCommand { public: TrackReplaceBlockWithGapCommand(Track* track, Block* block, bool handle_transitions = true) : track_(track), block_(block), existing_gap_(nullptr), existing_merged_gap_(nullptr), our_gap_(nullptr), handle_transitions_(handle_transitions) { } virtual Project* GetRelevantProject() const override { return block_->project(); } protected: virtual void redo() override; virtual void undo() override; private: void CreateRemoveTransitionCommandIfNecessary(bool next); Track* track_; Block* block_; GapBlock* existing_gap_; GapBlock* existing_merged_gap_; bool existing_gap_precedes_; GapBlock* our_gap_; bool handle_transitions_; QObject memory_manager_; QVector transition_remove_commands_; }; class BlockEnableDisableCommand : public UndoCommand { public: BlockEnableDisableCommand(Block* block, bool enabled) : block_(block), old_enabled_(block_->is_enabled()), new_enabled_(enabled) { } virtual Project* GetRelevantProject() const override { return block_->project(); } protected: virtual void redo() override { block_->set_enabled(new_enabled_); } virtual void undo() override { block_->set_enabled(old_enabled_); } private: Block* block_; bool old_enabled_; bool new_enabled_; }; class TrackListInsertGaps : public UndoCommand { public: TrackListInsertGaps(TrackList* track_list, const rational& point, const rational& length) : track_list_(track_list), point_(point), length_(length), split_command_(nullptr) { } virtual ~TrackListInsertGaps() override { delete split_command_; } virtual Project* GetRelevantProject() const override { return track_list_->parent()->project(); } protected: virtual void prepare() override; virtual void redo() override; virtual void undo() override; private: TrackList* track_list_; rational point_; rational length_; QVector working_tracks_; QVector gaps_to_extend_; struct AddGap { GapBlock* gap; Block* before; Track* track; }; QVector gaps_added_; BlockSplitPreservingLinksCommand* split_command_; QObject memory_manager_; }; class TimelineAddDefaultTransitionCommand : public UndoCommand { public: TimelineAddDefaultTransitionCommand(const QVector &clips, const rational &timebase) : clips_(clips), timebase_(timebase) {} virtual ~TimelineAddDefaultTransitionCommand() override { qDeleteAll(commands_); } virtual Project* GetRelevantProject() const override { return clips_.empty() ? nullptr : clips_.first()->project(); } protected: virtual void prepare() override; virtual void redo() override { for (auto it=commands_.cbegin(); it!=commands_.cend(); it++) { (*it)->redo_now(); } } virtual void undo() override { for (auto it=commands_.crbegin(); it!=commands_.crend(); it++) { (*it)->undo_now(); } } private: enum CreateTransitionMode { kIn, kOut, kOutDual }; void AddTransition(ClipBlock *c, CreateTransitionMode mode); void AdjustClipLength(ClipBlock *c, const rational &transition_length, bool out); void ValidateTransitionLength(ClipBlock *c, rational &transition_length); QVector clips_; rational timebase_; QVector commands_; QHash lengths_; }; } #endif // TIMELINEUNDOGENERAL_H