timeline: heavily optimized and improved nearly all timeline optimizations

Features a lot of timeline-related cache optimizations as well as general
optimizations and improvements in timeline behavior. Should improve
usability significantly.
This commit is contained in:
itsmattkc
2020-06-01 04:42:59 +10:00
parent 93f8b4f79c
commit c2e47a296c
35 changed files with 1496 additions and 939 deletions
+88 -46
View File
@@ -30,65 +30,107 @@ TimelineWidget::SlideTool::SlideTool(TimelineWidget* parent) :
{
SetTrimmingAllowed(false);
SetTrackMovementAllowed(false);
SetTrimOverwriteAllowed(true);
}
void TimelineWidget::SlideTool::MouseReleaseInternal(TimelineViewMouseEvent *event)
{
Q_UNUSED(event)
struct TrackBlockListPair {
TrackReference track;
QList<Block*> blocks;
};
QUndoCommand* command = new QUndoCommand();
// Find earliest point to ripple around
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
Block* b = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
if (ghost->mode() == Timeline::kTrimIn) {
new BlockResizeWithMediaInCommand(b, ghost->AdjustedLength(), command);
} else if (ghost->mode() == Timeline::kTrimOut) {
new BlockResizeCommand(b, ghost->AdjustedLength(), command);
} else if (ghost->mode() == Timeline::kMove && b->previous() == nullptr) {
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(ghost->InAdjustment());
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()), gap, command);
new TrackPrependBlockCommand(parent()->GetTrackFromReference(ghost->Track()), gap, command);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
rational TimelineWidget::SlideTool::FrameValidateInternal(rational time_movement, const QVector<TimelineViewGhostItem *> &ghosts)
{
// Only validate trimming, and we don't care about "overwriting" since the rolling tool is designed to trim at collisions
time_movement = ValidateInTrimming(time_movement, ghosts, false);
time_movement = ValidateOutTrimming(time_movement, ghosts, false);
return time_movement;
}
void TimelineWidget::SlideTool::InitiateGhosts(TimelineViewBlockItem *clicked_item,
Timeline::MovementMode trim_mode,
bool allow_gap_trimming)
void TimelineWidget::SlideTool::InitiateDrag(TimelineViewBlockItem *clicked_item,
Timeline::MovementMode trim_mode,
bool allow_gap_trimming)
{
Q_UNUSED(allow_gap_trimming)
PointerTool::InitiateGhosts(clicked_item, trim_mode, true);
PointerTool::InitiateDrag(clicked_item, trim_mode, true);
// For each ghost, we make an equivalent Ghost on the next/previous block
// Sort blocks into tracks
QList<TrackBlockListPair> blocks_per_track;
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
Block* ghost_block = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
Block* b = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
bool found = false;
// Add trimming ghosts for each side of the Block
if (ghost_block->previous() != nullptr) {
// Add an extra Ghost for the previous block
AddGhostFromBlock(ghost_block->previous(), ghost->Track(), Timeline::kTrimOut);
for (int i=0;i<blocks_per_track.size();i++) {
if (blocks_per_track.at(i).track == ghost->Track()) {
blocks_per_track[i].blocks.append(b);
found = true;
break;
}
}
if (ghost_block->next() != nullptr) {
AddGhostFromBlock(ghost_block->next(), ghost->Track(), Timeline::kTrimIn);
if (!found) {
blocks_per_track.append({ghost->Track(), {b}});
}
}
// Make contiguous runs of blocks per each track
foreach (const TrackBlockListPair& p, blocks_per_track) {
// Blocks must be merged if any are non-adjacent
const TrackReference& track = p.track;
const QList<Block*>& blocks = p.blocks;
Block* earliest_block = blocks.first();
Block* latest_block = blocks.first();
// Find the earliest and latest selected blocks
for (int j=1;j<blocks.size();j++) {
Block* compare = blocks.at(j);
if (compare->in() < earliest_block->in()) {
earliest_block = compare;
}
if (compare->in() > latest_block->in()) {
latest_block = compare;
}
}
// Add any blocks between these blocks that aren't already in the list
if (earliest_block != latest_block) {
Block* b = earliest_block;
while ((b = b->next()) != latest_block) {
if (!blocks.contains(b)) {
AddGhostFromBlock(b, track, Timeline::kMove);
}
}
}
// Add surrounding blocks that will be trimming instead of moving
if (earliest_block->previous()) {
AddGhostFromBlock(earliest_block->previous(), track, Timeline::kTrimOut);
}
if (latest_block->next()) {
AddGhostFromBlock(latest_block->next(), track, Timeline::kTrimIn);
}
}
}
void TimelineWidget::SlideTool::FinishDrag(TimelineViewMouseEvent *event)
{
Q_UNUSED(event)
QVector<TrackSlideCommand::BlockSlideInfo> info;
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
if (!ghost->HasBeenAdjusted()) {
continue;
}
Block* b = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
info.append({parent()->GetTrackFromReference(ghost->Track()),
b,
ghost->mode(),
ghost->mode() == Timeline::kMove ? ghost->GetAdjustedIn() : ghost->AdjustedLength(),
ghost->mode() == Timeline::kMove ? ghost->In() : ghost->Length()});
}
if (!info.isEmpty()) {
Core::instance()->undo_stack()->push(new TrackSlideCommand(info));
}
}
OLIVE_NAMESPACE_EXIT