/*** Olive - Non-Linear Video Editor Copyright (C) 2021 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 . ***/ #include "timelineundo.h" namespace olive { BlockTrimCommand::BlockTrimCommand(Track *track, Block* block, rational new_length, Timeline::MovementMode mode) : prepped_(false), track_(track), block_(block), new_length_(new_length), mode_(mode), deleted_adjacent_command_(nullptr), trim_is_a_roll_edit_(false) { } void BlockTrimCommand::redo() { if (!prepped_) { prep(); prepped_ = true; } if (doing_nothing_) { return; } // Begin an operation since we'll be doing a lot track_->BeginOperation(); // Determine how much time to invalidate TimeRange invalidate_range; if (mode_ == Timeline::kTrimIn) { invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_); block_->set_length_and_media_in(new_length_); } else { invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_); block_->set_length_and_media_out(new_length_); } if (needs_adjacent_) { if (we_created_adjacent_) { // Add adjacent and insert it adjacent_->setParent(track_->parent()); if (mode_ == Timeline::kTrimIn) { track_->InsertBlockBefore(adjacent_, block_); } else { track_->InsertBlockAfter(adjacent_, block_); } } else if (we_removed_adjacent_) { track_->RippleRemoveBlock(adjacent_); // It no longer inputs/outputs anything, remove it if (remove_block_from_graph_ && NodeCanBeRemoved(adjacent_)) { if (!deleted_adjacent_command_) { deleted_adjacent_command_ = CreateAndRunRemoveCommand(adjacent_); } else { deleted_adjacent_command_->redo(); } } } else { rational adjacent_length = adjacent_->length() + trim_diff_; if (mode_ == Timeline::kTrimIn) { adjacent_->set_length_and_media_out(adjacent_length); } else { adjacent_->set_length_and_media_in(adjacent_length); } } } track_->EndOperation(); if (dynamic_cast(block_)) { // Whole transition needs to be invalidated invalidate_range = block_->range(); } track_->Node::InvalidateCache(invalidate_range, Track::kBlockInput); } void BlockTrimCommand::undo() { if (doing_nothing_) { return; } track_->BeginOperation(); // Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer if (needs_adjacent_) { if (we_created_adjacent_) { // Adjacent is ours, just delete it track_->RippleRemoveBlock(adjacent_); adjacent_->setParent(&memory_manager_); } else { if (we_removed_adjacent_) { if (deleted_adjacent_command_) { // We deleted adjacent, restore it now deleted_adjacent_command_->undo(); } if (mode_ == Timeline::kTrimIn) { track_->InsertBlockBefore(adjacent_, block_); } else { track_->InsertBlockAfter(adjacent_, block_); } } else { rational adjacent_length = adjacent_->length() - trim_diff_; if (mode_ == Timeline::kTrimIn) { adjacent_->set_length_and_media_out(adjacent_length); } else { adjacent_->set_length_and_media_in(adjacent_length); } } } } TimeRange invalidate_range; if (mode_ == Timeline::kTrimIn) { block_->set_length_and_media_in(old_length_); invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff_); } else { block_->set_length_and_media_out(old_length_); invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff_); } if (dynamic_cast(block_)) { // Whole transition needs to be invalidated invalidate_range = block_->range(); } track_->EndOperation(); track_->Node::InvalidateCache(invalidate_range, Track::kBlockInput); } void BlockTrimCommand::prep() { // Store old length old_length_ = block_->length(); // Determine if the length isn't changing, in which case we set a flag to do nothing if ((doing_nothing_ = (old_length_ == new_length_))) { return; } // Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer trim_diff_ = old_length_ - new_length_; // Retrieve our adjacent block (or nullptr if none) if (mode_ == Timeline::kTrimIn) { adjacent_ = block_->previous(); } else { adjacent_ = block_->next(); } // Ignore when trimming the out with no adjacent, because the user must have trimmed the end // of the last block in the track, so we don't need to do anything elses needs_adjacent_ = (mode_ == Timeline::kTrimIn || adjacent_); if (needs_adjacent_) { // If we're trimming shorter, we need an adjacent, so check if we have a viable one. we_created_adjacent_ = (trim_diff_ > 0 && (!adjacent_ || (!dynamic_cast(adjacent_) && !trim_is_a_roll_edit_))); if (we_created_adjacent_) { // We shortened but don't have a viable adjacent to lengthen, so we create one adjacent_ = new GapBlock(); adjacent_->set_length_and_media_out(trim_diff_); } else { // Determine if we're removing the adjacent rational adjacent_length = adjacent_->length() + trim_diff_; we_removed_adjacent_ = adjacent_length.isNull(); } } } }