timeline: optimized pointer tool ctrl+drop
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user