timeline: implemented some base ripple delete functionality
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
virtual void DeleteSelected() override;
|
||||
|
||||
virtual void RippleDelete() override;
|
||||
|
||||
virtual void IncreaseTrackHeight() override;
|
||||
|
||||
virtual void DecreaseTrackHeight() override;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user