timeline: optimized pointer tool ctrl+drop

This commit is contained in:
itsmattkc
2020-06-06 17:50:23 +10:00
parent aaee2ab9ed
commit be784591fc
4 changed files with 158 additions and 67 deletions
+5 -44
View File
@@ -824,50 +824,11 @@ QList<TimelineViewBlockItem *> TimelineWidget::GetSelectedBlocks()
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, QUndoCommand *command)
{
QVector<Block*> blocks_to_split;
QList<Block*> blocks_to_append_gap_to;
QList<Block*> gaps_to_extend;
foreach (TrackOutput* track, GetConnectedNode()->GetTracks()) {
if (track->IsLocked()) {
continue;
}
foreach (Block* b, track->Blocks()) {
if (b->out() >= earliest_point) {
if (b->type() == Block::kClip) {
if (b->out() > earliest_point) {
blocks_to_split.append(b);
}
blocks_to_append_gap_to.append(b);
} else if (b->type() == Block::kGap) {
gaps_to_extend.append(b);
}
break;
}
}
}
// Extend gaps that already exist
foreach (Block* gap, gaps_to_extend) {
new BlockResizeCommand(gap, gap->length() + insert_length, command);
}
// Split clips here
new BlockSplitPreservingLinksCommand(blocks_to_split, {earliest_point}, command);
// Insert gaps that don't exist yet
foreach (Block* b, blocks_to_append_gap_to) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(insert_length);
new NodeAddCommand(static_cast<NodeGraph*>(GetConnectedNode()->parent()), gap, command);
new TrackInsertBlockAfterCommand(TrackOutput::TrackFromBlock(b), gap, b, command);
for (int i=0;i<Timeline::kTrackTypeCount;i++) {
new TrackListInsertGaps(GetConnectedNode()->track_list(static_cast<Timeline::TrackType>(i)),
earliest_point,
insert_length,
command);
}
}
@@ -248,21 +248,11 @@ void TimelineWidget::PointerTool::FinishDrag(TimelineViewMouseEvent *event)
InsertGapsAtGhostDestination(parent()->ghost_items_, command);
}
/*
QList<TrackReference> tracks_affected;
*/
// Now we can re-add each clip
for (int i=0;i<ghosts_moving.size();i++) {
TimelineViewGhostItem* ghost = ghosts_moving.at(i);
Block* block = blocks_moving.at(i);
/*
if (!tracks_affected.contains(ghost->GetAdjustedTrack())) {
tracks_affected.append(ghost->GetAdjustedTrack());
}
*/
if (duplicate_clips) {
// Duplicate rather than move
Node* copy = block->copy();
@@ -275,11 +265,6 @@ void TimelineWidget::PointerTool::FinishDrag(TimelineViewMouseEvent *event)
// Place the copy instead of the original block
block = static_cast<Block*>(copy);
/*
} else if (!tracks_affected.contains(ghost->Track())) {
// Block moved from its original position. Mark its track as affected.
tracks_affected.append(ghost->Track());
*/
}
const TrackReference& track_ref = ghost->GetAdjustedTrack();
@@ -290,14 +275,6 @@ void TimelineWidget::PointerTool::FinishDrag(TimelineViewMouseEvent *event)
command);
}
/*
foreach (const TrackReference& t, tracks_affected) {
new TrackCleanGapsCommand(parent()->GetConnectedNode()->track_list(t.type()),
t.index(),
command);
}
*/
// FIXME: Heavy optimization since MOST of the timeline does NOT change in this time
}
+124
View File
@@ -1444,4 +1444,128 @@ void TrackListRippleToolCommand::undo_internal()
}
}
TrackListInsertGaps::TrackListInsertGaps(TrackList *track_list, const rational &point, const rational &length, QUndoCommand *parent) :
UndoCommand(parent),
track_list_(track_list),
point_(point),
length_(length),
split_command_(nullptr)
{
all_tracks_unlocked_ = true;
foreach (TrackOutput* track, track_list_->GetTracks()) {
if (track->IsLocked()) {
all_tracks_unlocked_ = false;
continue;
}
working_tracks_.append(track);
}
}
Project *TrackListInsertGaps::GetRelevantProject() const
{
return static_cast<Sequence*>(static_cast<ViewerOutput*>(track_list_->parent())->parent())->project();
}
void TrackListInsertGaps::redo_internal()
{
if (all_tracks_unlocked_) {
// Optimize by shifting over since we have a constant amount of time being inserted
if (track_list_->type() == Timeline::kTrackTypeVideo) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftVideoCache(point_, point_ + length_);
} else if (track_list_->type() == Timeline::kTrackTypeAudio) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftAudioCache(point_, point_ + length_);
}
foreach (TrackOutput* track, working_tracks_) {
track->BlockInvalidateCache();
}
}
QVector<Block*> blocks_to_split;
QList<Block*> blocks_to_append_gap_to;
foreach (TrackOutput* track, working_tracks_) {
foreach (Block* b, track->Blocks()) {
if (b->type() == Block::kGap && b->in() <= point_ && b->out() >= point_) {
gaps_to_extend_.append(b);
} else if (b->type() == Block::kClip && b->out() >= point_) {
if (b->out() > point_) {
blocks_to_split.append(b);
}
blocks_to_append_gap_to.append(b);
}
}
}
foreach (Block* gap, gaps_to_extend_) {
gap->set_length_and_media_out(gap->length() + length_);
}
if (!blocks_to_split.isEmpty()) {
split_command_ = new BlockSplitPreservingLinksCommand(blocks_to_split, {point_});
split_command_->redo();
}
foreach (Block* block, blocks_to_append_gap_to) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(length_);
static_cast<NodeGraph*>(block->parent())->AddNode(gap);
TrackOutput::TrackFromBlock(block)->InsertBlockAfter(gap, block);
gaps_added_.append(gap);
}
if (all_tracks_unlocked_) {
foreach (TrackOutput* track, working_tracks_) {
track->UnblockInvalidateCache();
track->PushLengthChangeSignal(false);
}
}
}
void TrackListInsertGaps::undo_internal()
{
if (all_tracks_unlocked_) {
// Optimize by shifting over since we have a constant amount of time being inserted
if (track_list_->type() == Timeline::kTrackTypeVideo) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftVideoCache(point_ + length_, point_);
} else if (track_list_->type() == Timeline::kTrackTypeAudio) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftAudioCache(point_ + length_, point_);
}
foreach (TrackOutput* track, working_tracks_) {
track->BlockInvalidateCache();
}
}
// Remove added gaps
foreach (GapBlock* gap, gaps_added_) {
TrackOutput::TrackFromBlock(gap)->RippleRemoveBlock(gap);
delete TakeNodeFromParentGraph(gap);
}
gaps_added_.clear();
// Un-split blocks
if (split_command_) {
split_command_->undo();
delete split_command_;
split_command_ = nullptr;
}
// Restore original length of gaps
foreach (Block* gap, gaps_to_extend_) {
gap->set_length_and_media_out(gap->length() - length_);
}
gaps_to_extend_.clear();
if (all_tracks_unlocked_) {
foreach (TrackOutput* track, working_tracks_) {
track->UnblockInvalidateCache();
track->PushLengthChangeSignal(false);
}
}
}
OLIVE_NAMESPACE_EXIT
+29
View File
@@ -574,6 +574,35 @@ private:
};
class TrackListInsertGaps : public UndoCommand {
public:
TrackListInsertGaps(TrackList* track_list, const rational& point, const rational& length, QUndoCommand* parent = nullptr);
virtual Project* GetRelevantProject() const override;
protected:
virtual void redo_internal() override;
virtual void undo_internal() override;
private:
TrackList* track_list_;
rational point_;
rational length_;
QList<TrackOutput*> working_tracks_;
bool all_tracks_unlocked_;
QList<Block*> gaps_to_extend_;
QList<GapBlock*> gaps_added_;
BlockSplitPreservingLinksCommand* split_command_;
};
OLIVE_NAMESPACE_EXIT
#endif // TIMELINEUNDOABLE_H