timeline: implemented some base ripple delete functionality

This commit is contained in:
itsmattkc
2020-03-07 18:07:55 +11:00
parent d5fdc555e1
commit 38a30b584a
7 changed files with 148 additions and 20 deletions
+30 -4
View File
@@ -150,7 +150,19 @@ Block *TrackOutput::NearestBlockBefore(const rational &time) const
return nullptr;
}
Block *TrackOutput::NearestBlockAfter(const rational &time) const
Block *TrackOutput::NearestBlockBeforeOrAt(const rational &time) const
{
foreach (Block* block, block_cache_) {
// Blocks are sorted by time, so the first Block who's out point is at/after this time is the correct Block
if (block->out() > time) {
return block;
}
}
return nullptr;
}
Block *TrackOutput::NearestBlockAfterOrAt(const rational &time) const
{
foreach (Block* block, block_cache_) {
// Blocks are sorted by time, so the first Block after this time is the correct Block
@@ -162,6 +174,18 @@ Block *TrackOutput::NearestBlockAfter(const rational &time) const
return nullptr;
}
Block *TrackOutput::NearestBlockAfter(const rational &time) const
{
foreach (Block* block, block_cache_) {
// Blocks are sorted by time, so the first Block after this time is the correct Block
if (block->in() > time) {
return block;
}
}
return nullptr;
}
Block *TrackOutput::BlockAtTime(const rational &time) const
{
if (IsMuted()) {
@@ -288,8 +312,6 @@ void TrackOutput::RippleRemoveBlock(Block *block)
void TrackOutput::ReplaceBlock(Block *old, Block *replace)
{
Q_ASSERT(old->length() == replace->length());
BlockInvalidateCache();
int index_of_old_block = block_cache_.indexOf(old);
@@ -302,7 +324,11 @@ void TrackOutput::ReplaceBlock(Block *old, Block *replace)
UnblockInvalidateCache();
InvalidateCache(replace->in(), replace->out());
if (old->length() == replace->length()) {
InvalidateCache(replace->in(), replace->out());
} else {
InvalidateCache(replace->in(), RATIONAL_MAX);
}
}
TrackOutput *TrackOutput::TrackFromBlock(Block *block)
+16
View File
@@ -57,8 +57,24 @@ public:
Block* BlockContainingTime(const rational& time) const;
/**
* @brief Returns the block that starts BEFORE a given time and ends some time AFTER or precisely AT that time
*/
Block* NearestBlockBefore(const rational& time) const;
/**
* @brief Returns the block that starts BEFORE a given time OR the block that starts precisely at that time
*/
Block* NearestBlockBeforeOrAt(const rational& time) const;
/**
* @brief Returns the block that starts either precisely AT a given time or the soonest block AFTER
*/
Block* NearestBlockAfterOrAt(const rational& time) const;
/**
* @brief Returns the block that starts AFTER the given time (but never AT the given time)
*/
Block* NearestBlockAfter(const rational& time) const;
Block* BlockAtTime(const rational& time) const;
+6 -1
View File
@@ -79,7 +79,12 @@ void TimelinePanel::EditToOut()
void TimelinePanel::DeleteSelected()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteSelected();
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteSelected(false);
}
void TimelinePanel::RippleDelete()
{
static_cast<TimelineWidget*>(GetTimeBasedWidget())->DeleteSelected(true);
}
void TimelinePanel::IncreaseTrackHeight()
+2
View File
@@ -51,6 +51,8 @@ public:
virtual void DeleteSelected() override;
virtual void RippleDelete() override;
virtual void IncreaseTrackHeight() override;
virtual void DecreaseTrackHeight() override;
+87 -8
View File
@@ -335,8 +335,92 @@ void TimelineWidget::SplitAtPlayhead()
}
}
void TimelineWidget::DeleteSelectedInternal(const QList<Block *> blocks, bool transition_aware, bool remove_from_graph, QUndoCommand *command)
void TimelineWidget::DeleteSelectedInternal(QList<Block *> blocks,
bool transition_aware,
bool remove_from_graph,
bool ripple,
QUndoCommand *command)
{
if (ripple) {
for (int i=0;i<blocks.size();i++) {
Block* b = blocks.at(i);
TrackOutput* b_track = TrackOutput::TrackFromBlock(b);
// See if we can ripple the length of this block from all tracks
rational max_ripple_length = b->length();
QList<Block*> blocks_at_time;
foreach (TrackOutput* track, GetConnectedNode()->Tracks()) {
// Ignore our track since we've already taking account of the block at this time on our track
if (track == b_track) {
continue;
}
// Get the block from every other track that is either at or just before our block's in point
Block* block_at_time = track->NearestBlockBeforeOrAt(b->in());
// If we found a block, see what it is
if (block_at_time) {
// If it's a gap, or we're deleting it (which means it will soon become a gap), it's viable for removing
// or resizing
if (block_at_time->type() == Block::kGap || blocks.contains(block_at_time)) {
// In an effort to keep all tracks synchronized, we can only ripple a maximum of the smallest gap we find
max_ripple_length = qMin(max_ripple_length, block_at_time->length());
} else {
// If there is no gap here, we cannot ripple at all and must abort this ripple
max_ripple_length = 0;
break;
}
blocks_at_time.append(block_at_time);
}
}
// If we can ripple all the tracks
if (max_ripple_length > 0) {
// Ripple everything including the main block
blocks_at_time.append(b);
foreach (Block* resize, blocks_at_time) {
// If we can remove this whole block, remove the whole block
if (resize->length() == max_ripple_length) {
new TrackRippleRemoveBlockCommand(TrackOutput::TrackFromBlock(resize), resize, command);
// Also remove this block from our block list so we don't bother replacing it with a gap later
int resize_index = blocks.indexOf(resize);
if (resize_index >= 0) {
blocks.removeOne(resize);
// Ensure our iteration remain correct after removing blocks
if (resize_index <= i) {
i--;
}
}
} else {
// Otherwise, we'll simply shorten the gap/clip
BlockResizeCommand* brc = new BlockResizeCommand(resize, resize->length() - max_ripple_length, command);
// Perform the resize NOW so that if it's a clip that we're replacing with a gap later, the gap will have
// the correct length
brc->redo();
}
}
}
}
}
foreach (Block* b, blocks) {
TrackOutput* original_track = TrackOutput::TrackFromBlock(b);
@@ -382,7 +466,7 @@ void TimelineWidget::DeleteSelectedInternal(const QList<Block *> blocks, bool tr
}
}
void TimelineWidget::DeleteSelected()
void TimelineWidget::DeleteSelected(bool ripple)
{
QList<TimelineViewBlockItem *> selected_list = GetSelectedBlocks();
QList<Block*> blocks_to_delete;
@@ -406,7 +490,7 @@ void TimelineWidget::DeleteSelected()
QUndoCommand* command = new QUndoCommand();
// Replace blocks with gaps (effectively deleting them)
DeleteSelectedInternal(blocks_to_delete, true, true, command);
DeleteSelectedInternal(blocks_to_delete, true, true, ripple, command);
// Clean each track
foreach (const TrackReference& track, tracks_affected) {
@@ -418,11 +502,6 @@ void TimelineWidget::DeleteSelected()
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void TimelineWidget::RippleDelete()
{
}
void TimelineWidget::IncreaseTrackHeight()
{
if (!GetConnectedNode()) {
+2 -4
View File
@@ -47,9 +47,7 @@ public:
void SplitAtPlayhead();
void DeleteSelected();
void RippleDelete();
void DeleteSelected(bool ripple = false);
void IncreaseTrackHeight();
@@ -351,7 +349,7 @@ private:
bool dual_transition_;
};
void DeleteSelectedInternal(const QList<Block*> blocks, bool transition_aware, bool remove_from_graph, QUndoCommand* command);
void DeleteSelectedInternal(QList<Block *> blocks, bool transition_aware, bool remove_from_graph, bool ripple, QUndoCommand* command);
void SetBlockLinksSelected(Block *block, bool selected);
+5 -3
View File
@@ -216,10 +216,12 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
}
}
// If there are any blocks to remove, remove them
parent()->DeleteSelectedInternal(blocks_to_temp_remove, false, false, command);
bool inserting = (event->GetModifiers() & Qt::ControlModifier);
if (event->GetModifiers() & Qt::ControlModifier) {
// If there are any blocks to remove, remove them
parent()->DeleteSelectedInternal(blocks_to_temp_remove, false, false, inserting, command);
if (inserting) {
// Make room to insert clips to
InsertGapsAtGhostDestination(parent()->ghost_items_, command);
}