change: change code style to Linux style except indent.
This commit is contained in:
+371
-363
@@ -22,159 +22,165 @@
|
||||
|
||||
#include "timelineundocommon.h"
|
||||
|
||||
namespace olive {
|
||||
namespace olive
|
||||
{
|
||||
|
||||
//
|
||||
// TrackRippleRemoveAreaCommand
|
||||
//
|
||||
TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(Track* track, const TimeRange& range) :
|
||||
track_(track),
|
||||
range_(range),
|
||||
allow_splitting_gaps_(false),
|
||||
splice_split_command_(nullptr)
|
||||
TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(
|
||||
Track *track, const TimeRange &range)
|
||||
: track_(track)
|
||||
, range_(range)
|
||||
, allow_splitting_gaps_(false)
|
||||
, splice_split_command_(nullptr)
|
||||
{
|
||||
trim_out_.block = nullptr;
|
||||
trim_in_.block = nullptr;
|
||||
trim_out_.block = nullptr;
|
||||
trim_in_.block = nullptr;
|
||||
}
|
||||
|
||||
TrackRippleRemoveAreaCommand::~TrackRippleRemoveAreaCommand()
|
||||
{
|
||||
delete splice_split_command_;
|
||||
qDeleteAll(remove_block_commands_);
|
||||
delete splice_split_command_;
|
||||
qDeleteAll(remove_block_commands_);
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::prepare()
|
||||
{
|
||||
// Determine precisely what will be happening to these tracks
|
||||
Block* first_block = track_->NearestBlockBeforeOrAt(range_.in());
|
||||
// Determine precisely what will be happening to these tracks
|
||||
Block *first_block = track_->NearestBlockBeforeOrAt(range_.in());
|
||||
|
||||
if (!first_block) {
|
||||
// No blocks at this time, nothing to be done on this track
|
||||
return;
|
||||
}
|
||||
if (!first_block) {
|
||||
// No blocks at this time, nothing to be done on this track
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if this first block is getting trimmed or removed
|
||||
bool first_block_is_out_trimmed = first_block->in() < range_.in();
|
||||
bool first_block_is_in_trimmed = first_block->out() > range_.out();
|
||||
// Determine if this first block is getting trimmed or removed
|
||||
bool first_block_is_out_trimmed = first_block->in() < range_.in();
|
||||
bool first_block_is_in_trimmed = first_block->out() > range_.out();
|
||||
|
||||
// Set's the block that any insert command should insert AFTER. If the first block is not
|
||||
// getting out-trimmed, that means first block is either getting removed or in-trimmed, which
|
||||
// means any insert should happen before it
|
||||
insert_previous_ = first_block_is_out_trimmed ? first_block : first_block->previous();
|
||||
// Set's the block that any insert command should insert AFTER. If the first block is not
|
||||
// getting out-trimmed, that means first block is either getting removed or in-trimmed, which
|
||||
// means any insert should happen before it
|
||||
insert_previous_ = first_block_is_out_trimmed ? first_block :
|
||||
first_block->previous();
|
||||
|
||||
// If it's getting trimmed, determine if it's actually getting spliced
|
||||
if (first_block_is_out_trimmed && first_block_is_in_trimmed) {
|
||||
if (!allow_splitting_gaps_ && dynamic_cast<GapBlock*>(first_block)) {
|
||||
// As a rule, we don't split gaps, so we just treat it as a trim of the range requested
|
||||
trim_out_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - range_.length()};
|
||||
} else {
|
||||
// This block is getting spliced, so we'll handle that later
|
||||
splice_split_command_ = new BlockSplitCommand(first_block, range_.in());
|
||||
}
|
||||
} else {
|
||||
// It's just getting trimmed or removed, so we'll append that operation
|
||||
if (first_block_is_out_trimmed) {
|
||||
trim_out_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - (first_block->out() - range_.in())};
|
||||
} else if (first_block_is_in_trimmed) {
|
||||
// Block is getting in trimmed
|
||||
trim_in_ = {first_block,
|
||||
first_block->length(),
|
||||
first_block->length() - (range_.out() - first_block->in())};
|
||||
} else {
|
||||
// We know for sure this block is within the range so it will be removed
|
||||
removals_.append(RemoveOperation({first_block, first_block->previous()}));
|
||||
}
|
||||
// If it's getting trimmed, determine if it's actually getting spliced
|
||||
if (first_block_is_out_trimmed && first_block_is_in_trimmed) {
|
||||
if (!allow_splitting_gaps_ && dynamic_cast<GapBlock *>(first_block)) {
|
||||
// As a rule, we don't split gaps, so we just treat it as a trim of the range requested
|
||||
trim_out_ = { first_block, first_block->length(),
|
||||
first_block->length() - range_.length() };
|
||||
} else {
|
||||
// This block is getting spliced, so we'll handle that later
|
||||
splice_split_command_ =
|
||||
new BlockSplitCommand(first_block, range_.in());
|
||||
}
|
||||
} else {
|
||||
// It's just getting trimmed or removed, so we'll append that operation
|
||||
if (first_block_is_out_trimmed) {
|
||||
trim_out_ = { first_block, first_block->length(),
|
||||
first_block->length() -
|
||||
(first_block->out() - range_.in()) };
|
||||
} else if (first_block_is_in_trimmed) {
|
||||
// Block is getting in trimmed
|
||||
trim_in_ = { first_block, first_block->length(),
|
||||
first_block->length() -
|
||||
(range_.out() - first_block->in()) };
|
||||
} else {
|
||||
// We know for sure this block is within the range so it will be removed
|
||||
removals_.append(
|
||||
RemoveOperation({ first_block, first_block->previous() }));
|
||||
}
|
||||
|
||||
// If the first block is getting in trimmed, we're already at the end of our range
|
||||
if (!first_block_is_in_trimmed) {
|
||||
// Loop through the rest of the blocks and determine what to do with those
|
||||
for (Block* next=first_block->next(); next; next=next->next()) {
|
||||
bool trimming = (next->out() > range_.out());
|
||||
// If the first block is getting in trimmed, we're already at the end of our range
|
||||
if (!first_block_is_in_trimmed) {
|
||||
// Loop through the rest of the blocks and determine what to do with those
|
||||
for (Block *next = first_block->next(); next; next = next->next()) {
|
||||
bool trimming = (next->out() > range_.out());
|
||||
|
||||
if (trimming) {
|
||||
trim_in_ = {next,
|
||||
next->length(),
|
||||
next->length() - (range_.out() - next->in())};
|
||||
break;
|
||||
} else {
|
||||
removals_.append(RemoveOperation({next, next->previous()}));
|
||||
if (trimming) {
|
||||
trim_in_ = { next, next->length(),
|
||||
next->length() - (range_.out() - next->in()) };
|
||||
break;
|
||||
} else {
|
||||
removals_.append(
|
||||
RemoveOperation({ next, next->previous() }));
|
||||
|
||||
if (next->out() == range_.out()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next->out() == range_.out()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::redo()
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
// We're just splicing
|
||||
splice_split_command_->redo_now();
|
||||
if (splice_split_command_) {
|
||||
// We're just splicing
|
||||
splice_split_command_->redo_now();
|
||||
|
||||
// Trim the in of the split
|
||||
Block* split = splice_split_command_->new_block();
|
||||
split->set_length_and_media_in(split->length() - (range_.out() - split->in()));
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.new_length);
|
||||
}
|
||||
// Trim the in of the split
|
||||
Block *split = splice_split_command_->new_block();
|
||||
split->set_length_and_media_in(split->length() -
|
||||
(range_.out() - split->in()));
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.new_length);
|
||||
}
|
||||
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.new_length);
|
||||
}
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.new_length);
|
||||
}
|
||||
|
||||
// Perform removals
|
||||
if (!removals_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
// Ripple remove them all first
|
||||
track_->RippleRemoveBlock(op.block);
|
||||
}
|
||||
// Perform removals
|
||||
if (!removals_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
// Ripple remove them all first
|
||||
track_->RippleRemoveBlock(op.block);
|
||||
}
|
||||
|
||||
// Create undo commands for node removals where possible
|
||||
if (remove_block_commands_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
if (NodeCanBeRemoved(op.block)) {
|
||||
remove_block_commands_.append(CreateRemoveCommand(op.block));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create undo commands for node removals where possible
|
||||
if (remove_block_commands_.isEmpty()) {
|
||||
foreach (auto op, removals_) {
|
||||
if (NodeCanBeRemoved(op.block)) {
|
||||
remove_block_commands_.append(
|
||||
CreateRemoveCommand(op.block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (UndoCommand* c, remove_block_commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (UndoCommand *c, remove_block_commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrackRippleRemoveAreaCommand::undo()
|
||||
{
|
||||
if (splice_split_command_) {
|
||||
splice_split_command_->undo_now();
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.old_length);
|
||||
}
|
||||
if (splice_split_command_) {
|
||||
splice_split_command_->undo_now();
|
||||
} else {
|
||||
if (trim_out_.block) {
|
||||
trim_out_.block->set_length_and_media_out(trim_out_.old_length);
|
||||
}
|
||||
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.old_length);
|
||||
}
|
||||
if (trim_in_.block) {
|
||||
trim_in_.block->set_length_and_media_in(trim_in_.old_length);
|
||||
}
|
||||
|
||||
// Un-remove any blocks
|
||||
for (int i=remove_block_commands_.size()-1; i>=0; i--) {
|
||||
remove_block_commands_.at(i)->undo_now();
|
||||
}
|
||||
// Un-remove any blocks
|
||||
for (int i = remove_block_commands_.size() - 1; i >= 0; i--) {
|
||||
remove_block_commands_.at(i)->undo_now();
|
||||
}
|
||||
|
||||
foreach (auto op, removals_) {
|
||||
track_->InsertBlockAfter(op.block, op.before);
|
||||
}
|
||||
}
|
||||
foreach (auto op, removals_) {
|
||||
track_->InsertBlockAfter(op.block, op.before);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -182,199 +188,197 @@ void TrackRippleRemoveAreaCommand::undo()
|
||||
//
|
||||
void TrackListRippleRemoveAreaCommand::prepare()
|
||||
{
|
||||
foreach (Track* track, list_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
foreach (Track *track, list_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackRippleRemoveAreaCommand* c = new TrackRippleRemoveAreaCommand(track, range_);
|
||||
commands_.append(c);
|
||||
working_tracks_.append(track);
|
||||
}
|
||||
TrackRippleRemoveAreaCommand *c =
|
||||
new TrackRippleRemoveAreaCommand(track, range_);
|
||||
commands_.append(c);
|
||||
working_tracks_.append(track);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListRippleRemoveAreaCommand::redo()
|
||||
{
|
||||
foreach (TrackRippleRemoveAreaCommand* c, commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
foreach (TrackRippleRemoveAreaCommand *c, commands_) {
|
||||
c->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackListRippleRemoveAreaCommand::undo()
|
||||
{
|
||||
foreach (TrackRippleRemoveAreaCommand* c, commands_) {
|
||||
c->undo_now();
|
||||
}
|
||||
foreach (TrackRippleRemoveAreaCommand *c, commands_) {
|
||||
c->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TimelineRippleRemoveAreaCommand
|
||||
//
|
||||
TimelineRippleRemoveAreaCommand::TimelineRippleRemoveAreaCommand(Sequence* timeline, rational in, rational out) :
|
||||
timeline_(timeline)
|
||||
TimelineRippleRemoveAreaCommand::TimelineRippleRemoveAreaCommand(
|
||||
Sequence *timeline, rational in, rational out)
|
||||
: timeline_(timeline)
|
||||
{
|
||||
for (int i=0; i<Track::kCount; i++) {
|
||||
add_child(new TrackListRippleRemoveAreaCommand(timeline->track_list(static_cast<Track::Type>(i)),
|
||||
in,
|
||||
out));
|
||||
}
|
||||
for (int i = 0; i < Track::kCount; i++) {
|
||||
add_child(new TrackListRippleRemoveAreaCommand(
|
||||
timeline->track_list(static_cast<Track::Type>(i)), in, out));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TrackListRippleToolCommand
|
||||
//
|
||||
TrackListRippleToolCommand::TrackListRippleToolCommand(TrackList* track_list,
|
||||
const QHash<Track*, RippleInfo>& info,
|
||||
const rational& ripple_movement,
|
||||
const Timeline::MovementMode& movement_mode) :
|
||||
track_list_(track_list),
|
||||
info_(info),
|
||||
ripple_movement_(ripple_movement),
|
||||
movement_mode_(movement_mode)
|
||||
TrackListRippleToolCommand::TrackListRippleToolCommand(
|
||||
TrackList *track_list, const QHash<Track *, RippleInfo> &info,
|
||||
const rational &ripple_movement,
|
||||
const Timeline::MovementMode &movement_mode)
|
||||
: track_list_(track_list)
|
||||
, info_(info)
|
||||
, ripple_movement_(ripple_movement)
|
||||
, movement_mode_(movement_mode)
|
||||
{
|
||||
}
|
||||
|
||||
void TrackListRippleToolCommand::ripple(bool redo)
|
||||
{
|
||||
if (info_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (info_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The following variables are used to determine how much of the cache to invalidate
|
||||
// The following variables are used to determine how much of the cache to invalidate
|
||||
|
||||
// If we can shift, we will shift from the latest out before the ripple to the latest out after,
|
||||
// since those sections will be unchanged by this ripple
|
||||
rational pre_latest_out = RATIONAL_MIN;
|
||||
rational post_latest_out = RATIONAL_MIN;
|
||||
// If we can shift, we will shift from the latest out before the ripple to the latest out after,
|
||||
// since those sections will be unchanged by this ripple
|
||||
rational pre_latest_out = RATIONAL_MIN;
|
||||
rational post_latest_out = RATIONAL_MIN;
|
||||
|
||||
// Make timeline changes
|
||||
for (auto it=info_.cbegin(); it!=info_.cend(); it++) {
|
||||
Track* track = it.key();
|
||||
const RippleInfo& info = it.value();
|
||||
WorkingData working_data = working_data_.value(track);
|
||||
Block* b = info.block;
|
||||
// Make timeline changes
|
||||
for (auto it = info_.cbegin(); it != info_.cend(); it++) {
|
||||
Track *track = it.key();
|
||||
const RippleInfo &info = it.value();
|
||||
WorkingData working_data = working_data_.value(track);
|
||||
Block *b = info.block;
|
||||
|
||||
// Generate block length
|
||||
rational new_block_length;
|
||||
rational operation_movement = ripple_movement_;
|
||||
// Generate block length
|
||||
rational new_block_length;
|
||||
rational operation_movement = ripple_movement_;
|
||||
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
|
||||
if (!redo) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
if (!redo) {
|
||||
operation_movement = -operation_movement;
|
||||
}
|
||||
|
||||
if (b) {
|
||||
new_block_length = b->length() + operation_movement;
|
||||
}
|
||||
if (b) {
|
||||
new_block_length = b->length() + operation_movement;
|
||||
}
|
||||
|
||||
rational pre_shift;
|
||||
rational post_shift;
|
||||
rational pre_shift;
|
||||
rational post_shift;
|
||||
|
||||
if (info.append_gap) {
|
||||
if (info.append_gap) {
|
||||
// Rather than rippling the referenced block, we'll insert a gap and ripple with that
|
||||
GapBlock *gap = working_data.created_gap;
|
||||
|
||||
// Rather than rippling the referenced block, we'll insert a gap and ripple with that
|
||||
GapBlock* gap = working_data.created_gap;
|
||||
if (redo) {
|
||||
if (!gap) {
|
||||
gap = new GapBlock();
|
||||
gap->set_length_and_media_out(qAbs(ripple_movement_));
|
||||
working_data.created_gap = gap;
|
||||
}
|
||||
|
||||
if (redo) {
|
||||
if (!gap) {
|
||||
gap = new GapBlock();
|
||||
gap->set_length_and_media_out(qAbs(ripple_movement_));
|
||||
working_data.created_gap = gap;
|
||||
}
|
||||
gap->setParent(track->parent());
|
||||
track->InsertBlockBefore(gap, b);
|
||||
|
||||
gap->setParent(track->parent());
|
||||
track->InsertBlockBefore(gap, b);
|
||||
// As an insertion, we will shift from the gap's in to the gap's out
|
||||
pre_shift = gap->in();
|
||||
post_shift = gap->out();
|
||||
working_data.earliest_point_of_change = gap->in();
|
||||
} else {
|
||||
// As a removal, we will shift from the gap's out to the gap's in
|
||||
pre_shift = gap->out();
|
||||
post_shift = gap->in();
|
||||
|
||||
// As an insertion, we will shift from the gap's in to the gap's out
|
||||
pre_shift = gap->in();
|
||||
post_shift = gap->out();
|
||||
working_data.earliest_point_of_change = gap->in();
|
||||
} else {
|
||||
// As a removal, we will shift from the gap's out to the gap's in
|
||||
pre_shift = gap->out();
|
||||
post_shift = gap->in();
|
||||
track->RippleRemoveBlock(gap);
|
||||
gap->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
track->RippleRemoveBlock(gap);
|
||||
gap->setParent(&memory_manager_);
|
||||
}
|
||||
} else if ((redo && new_block_length.isNull()) ||
|
||||
(!redo && !b->track())) {
|
||||
// The ripple is the length of this block. We assume that for this to happen, it must have
|
||||
// been a gap that we will now remove.
|
||||
|
||||
} else if ((redo && new_block_length.isNull()) || (!redo && !b->track())) {
|
||||
if (redo) {
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
// The ripple is the length of this block. We assume that for this to happen, it must have
|
||||
// been a gap that we will now remove.
|
||||
// As a removal, we will be shifting from the out point to the in point
|
||||
pre_shift = b->out();
|
||||
post_shift = b->in();
|
||||
|
||||
if (redo) {
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
// Remove gap from track and from graph
|
||||
working_data.removed_gap_after = b->previous();
|
||||
track->RippleRemoveBlock(b);
|
||||
b->setParent(&memory_manager_);
|
||||
} else {
|
||||
// Restore gap to graph and track
|
||||
b->setParent(track->parent());
|
||||
track->InsertBlockAfter(b, working_data.removed_gap_after);
|
||||
|
||||
// As a removal, we will be shifting from the out point to the in point
|
||||
pre_shift = b->out();
|
||||
post_shift = b->in();
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
// Remove gap from track and from graph
|
||||
working_data.removed_gap_after = b->previous();
|
||||
track->RippleRemoveBlock(b);
|
||||
b->setParent(&memory_manager_);
|
||||
} else {
|
||||
// Restore gap to graph and track
|
||||
b->setParent(track->parent());
|
||||
track->InsertBlockAfter(b, working_data.removed_gap_after);
|
||||
// As an insert, we will be shifting from the block's in point to its out point
|
||||
pre_shift = b->in();
|
||||
post_shift = b->out();
|
||||
}
|
||||
|
||||
// The earliest point changes will happen is at the start of this block
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
} else {
|
||||
// Store old length
|
||||
working_data.old_length = b->length();
|
||||
|
||||
// As an insert, we will be shifting from the block's in point to its out point
|
||||
pre_shift = b->in();
|
||||
post_shift = b->out();
|
||||
}
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
// The earliest point changes will occur is in point of this bloc
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
|
||||
} else {
|
||||
// Undo the trim in inversion we do above, this will still be inverted accurately for
|
||||
// undoing where appropriate
|
||||
rational inverted = -operation_movement;
|
||||
if (inverted > 0) {
|
||||
pre_shift = b->in() + inverted;
|
||||
post_shift = b->in();
|
||||
} else {
|
||||
pre_shift = b->in();
|
||||
post_shift = b->in() - inverted;
|
||||
}
|
||||
|
||||
// Store old length
|
||||
working_data.old_length = b->length();
|
||||
// Update length
|
||||
b->set_length_and_media_in(new_block_length);
|
||||
} else {
|
||||
// The earliest point changes will occur is the out point if trimming out or the in point
|
||||
// if trimming in
|
||||
working_data.earliest_point_of_change = b->out();
|
||||
|
||||
if (movement_mode_ == Timeline::kTrimIn) {
|
||||
// The earliest point changes will occur is in point of this bloc
|
||||
working_data.earliest_point_of_change = b->in();
|
||||
// The latest out before the ripple is this block's current out point
|
||||
pre_shift = b->out();
|
||||
|
||||
// Undo the trim in inversion we do above, this will still be inverted accurately for
|
||||
// undoing where appropriate
|
||||
rational inverted = -operation_movement;
|
||||
if (inverted > 0) {
|
||||
pre_shift = b->in() + inverted;
|
||||
post_shift = b->in();
|
||||
} else {
|
||||
pre_shift = b->in();
|
||||
post_shift = b->in() - inverted;
|
||||
}
|
||||
// Update length
|
||||
b->set_length_and_media_out(new_block_length);
|
||||
|
||||
// Update length
|
||||
b->set_length_and_media_in(new_block_length);
|
||||
} else {
|
||||
// The earliest point changes will occur is the out point if trimming out or the in point
|
||||
// if trimming in
|
||||
working_data.earliest_point_of_change = b->out();
|
||||
// The latest out after the ripple is this block's out point after the length change
|
||||
post_shift = b->out();
|
||||
}
|
||||
}
|
||||
|
||||
// The latest out before the ripple is this block's current out point
|
||||
pre_shift = b->out();
|
||||
working_data_.insert(it.key(), working_data);
|
||||
|
||||
// Update length
|
||||
b->set_length_and_media_out(new_block_length);
|
||||
|
||||
// The latest out after the ripple is this block's out point after the length change
|
||||
post_shift = b->out();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
working_data_.insert(it.key(), working_data);
|
||||
|
||||
pre_latest_out = qMax(pre_latest_out, pre_shift);
|
||||
post_latest_out = qMax(post_latest_out, post_shift);
|
||||
}
|
||||
pre_latest_out = qMax(pre_latest_out, pre_shift);
|
||||
post_latest_out = qMax(post_latest_out, post_shift);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -382,140 +386,144 @@ void TrackListRippleToolCommand::ripple(bool redo)
|
||||
//
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::prepare()
|
||||
{
|
||||
int max_gaps = 0;
|
||||
QHash<Track*, QVector<RemovalRequest> > requested_gaps;
|
||||
int max_gaps = 0;
|
||||
QHash<Track *, QVector<RemovalRequest>> requested_gaps;
|
||||
|
||||
// Convert regions to gaps
|
||||
for (const QPair<Track*, TimeRange> ®ion : qAsConst(regions_)) {
|
||||
Track *track = region.first;
|
||||
const TimeRange &range = region.second;
|
||||
// Convert regions to gaps
|
||||
for (const QPair<Track *, TimeRange> ®ion : qAsConst(regions_)) {
|
||||
Track *track = region.first;
|
||||
const TimeRange &range = region.second;
|
||||
|
||||
GapBlock *gap = dynamic_cast<GapBlock*>(track->NearestBlockBeforeOrAt(range.in()));
|
||||
GapBlock *gap =
|
||||
dynamic_cast<GapBlock *>(track->NearestBlockBeforeOrAt(range.in()));
|
||||
|
||||
if (gap) {
|
||||
QVector<RemovalRequest> &gaps_on_track = requested_gaps[track];
|
||||
if (gap) {
|
||||
QVector<RemovalRequest> &gaps_on_track = requested_gaps[track];
|
||||
|
||||
RemovalRequest this_req = {gap, range};
|
||||
RemovalRequest this_req = { gap, range };
|
||||
|
||||
// Insertion sort
|
||||
bool inserted = false;
|
||||
for (int i=0; i<gaps_on_track.size(); i++) {
|
||||
if (gaps_on_track.at(i).range.in() < range.in()) {
|
||||
gaps_on_track.insert(i, this_req);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
gaps_on_track.append(this_req);
|
||||
}
|
||||
// Insertion sort
|
||||
bool inserted = false;
|
||||
for (int i = 0; i < gaps_on_track.size(); i++) {
|
||||
if (gaps_on_track.at(i).range.in() < range.in()) {
|
||||
gaps_on_track.insert(i, this_req);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
gaps_on_track.append(this_req);
|
||||
}
|
||||
|
||||
max_gaps = qMax(max_gaps, gaps_on_track.size());
|
||||
} else {
|
||||
qWarning() << "Failed to find corresponding gap to region";
|
||||
}
|
||||
}
|
||||
max_gaps = qMax(max_gaps, gaps_on_track.size());
|
||||
} else {
|
||||
qWarning() << "Failed to find corresponding gap to region";
|
||||
}
|
||||
}
|
||||
|
||||
// For each gap on each track, find a corresponding gap on every other track (which may include
|
||||
// a requested gap) to ripple in order to keep everything synchronized
|
||||
QHash<GapBlock*, rational> gap_lengths;
|
||||
for (int gap_index=0; gap_index<max_gaps; gap_index++) {
|
||||
rational earliest_point = RATIONAL_MAX;
|
||||
rational ripple_length = RATIONAL_MAX;
|
||||
rational latest_point = RATIONAL_MIN;
|
||||
// For each gap on each track, find a corresponding gap on every other track (which may include
|
||||
// a requested gap) to ripple in order to keep everything synchronized
|
||||
QHash<GapBlock *, rational> gap_lengths;
|
||||
for (int gap_index = 0; gap_index < max_gaps; gap_index++) {
|
||||
rational earliest_point = RATIONAL_MAX;
|
||||
rational ripple_length = RATIONAL_MAX;
|
||||
rational latest_point = RATIONAL_MIN;
|
||||
|
||||
foreach (const QVector<RemovalRequest> &gaps_on_track, requested_gaps) {
|
||||
if (gap_index < gaps_on_track.size()) {
|
||||
const RemovalRequest &gap = gaps_on_track.at(gap_index);
|
||||
earliest_point = qMin(earliest_point, gap.range.in());
|
||||
ripple_length = qMin(ripple_length, gap.range.length());
|
||||
latest_point = qMax(latest_point, gap.range.out());
|
||||
}
|
||||
}
|
||||
foreach (const QVector<RemovalRequest> &gaps_on_track, requested_gaps) {
|
||||
if (gap_index < gaps_on_track.size()) {
|
||||
const RemovalRequest &gap = gaps_on_track.at(gap_index);
|
||||
earliest_point = qMin(earliest_point, gap.range.in());
|
||||
ripple_length = qMin(ripple_length, gap.range.length());
|
||||
latest_point = qMax(latest_point, gap.range.out());
|
||||
}
|
||||
}
|
||||
|
||||
// Determine which gaps will be involved in this operation
|
||||
QVector<GapBlock*> gaps;
|
||||
// Determine which gaps will be involved in this operation
|
||||
QVector<GapBlock *> gaps;
|
||||
|
||||
foreach (Track* track, timeline_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
foreach (Track *track, timeline_->GetTracks()) {
|
||||
if (track->IsLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QVector<RemovalRequest> &requested_gaps_on_track = requested_gaps.value(track);
|
||||
GapBlock *gap = nullptr;
|
||||
if (gap_index < requested_gaps_on_track.size()) {
|
||||
// A requested gap was at this index, use it
|
||||
gap = requested_gaps_on_track.at(gap_index).gap;
|
||||
} else {
|
||||
// No requested gap was at this index, find one
|
||||
Block *block = track->NearestBlockAfterOrAt(earliest_point);
|
||||
const QVector<RemovalRequest> &requested_gaps_on_track =
|
||||
requested_gaps.value(track);
|
||||
GapBlock *gap = nullptr;
|
||||
if (gap_index < requested_gaps_on_track.size()) {
|
||||
// A requested gap was at this index, use it
|
||||
gap = requested_gaps_on_track.at(gap_index).gap;
|
||||
} else {
|
||||
// No requested gap was at this index, find one
|
||||
Block *block = track->NearestBlockAfterOrAt(earliest_point);
|
||||
|
||||
if (block) {
|
||||
// Found a block, test if it's a gap
|
||||
gap = dynamic_cast<GapBlock*>(block);
|
||||
if (block) {
|
||||
// Found a block, test if it's a gap
|
||||
gap = dynamic_cast<GapBlock *>(block);
|
||||
|
||||
if (!gap) {
|
||||
if (block->in() == earliest_point) {
|
||||
if (block->next()) {
|
||||
gap = dynamic_cast<GapBlock*>(block->next());
|
||||
if (!gap) {
|
||||
if (block->in() == earliest_point) {
|
||||
if (block->next()) {
|
||||
gap = dynamic_cast<GapBlock *>(block->next());
|
||||
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gap = dynamic_cast<GapBlock*>(block->previous());
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gap = dynamic_cast<GapBlock *>(block->previous());
|
||||
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assume track finishes here and track won't be affected by this operation
|
||||
}
|
||||
}
|
||||
if (!gap) {
|
||||
ripple_length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Assume track finishes here and track won't be affected by this operation
|
||||
}
|
||||
}
|
||||
|
||||
if (gap) {
|
||||
gaps.append(gap);
|
||||
if (gap) {
|
||||
gaps.append(gap);
|
||||
|
||||
if (!gap_lengths.contains(gap)) {
|
||||
gap_lengths.insert(gap, gap->length());
|
||||
}
|
||||
if (!gap_lengths.contains(gap)) {
|
||||
gap_lengths.insert(gap, gap->length());
|
||||
}
|
||||
|
||||
ripple_length = qMin(ripple_length, gap_lengths.value(gap));
|
||||
}
|
||||
ripple_length = qMin(ripple_length, gap_lengths.value(gap));
|
||||
}
|
||||
|
||||
if (ripple_length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ripple_length == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ripple_length > 0) {
|
||||
foreach (GapBlock *gap, gaps) {
|
||||
if (gap_lengths.value(gap) == ripple_length) {
|
||||
commands_.append(new TrackRippleRemoveBlockCommand(gap->track(), gap));
|
||||
} else {
|
||||
gap_lengths[gap] -= ripple_length;
|
||||
commands_.append(new BlockResizeCommand(gap, gap_lengths.value(gap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ripple_length > 0) {
|
||||
foreach (GapBlock *gap, gaps) {
|
||||
if (gap_lengths.value(gap) == ripple_length) {
|
||||
commands_.append(
|
||||
new TrackRippleRemoveBlockCommand(gap->track(), gap));
|
||||
} else {
|
||||
gap_lengths[gap] -= ripple_length;
|
||||
commands_.append(
|
||||
new BlockResizeCommand(gap, gap_lengths.value(gap)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::redo()
|
||||
{
|
||||
for (auto it=commands_.cbegin(); it!=commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
for (auto it = commands_.cbegin(); it != commands_.cend(); it++) {
|
||||
(*it)->redo_now();
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineRippleDeleteGapsAtRegionsCommand::undo()
|
||||
{
|
||||
for (auto it=commands_.crbegin(); it!=commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
for (auto it = commands_.crbegin(); it != commands_.crend(); it++) {
|
||||
(*it)->undo_now();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user