implemented support for trimming transitions

This commit is contained in:
itsmattkc
2020-01-07 01:47:58 +11:00
parent e71697f693
commit 5d8be03970
10 changed files with 140 additions and 43 deletions
+4 -4
View File
@@ -52,8 +52,8 @@ rational TransitionBlock::in_offset() const
return length();
}
// Assume both are connected, in which case the in offset will be <= length
return length() / 2 + media_in();
// Assume both are connected
return length() + media_in();
}
rational TransitionBlock::out_offset() const
@@ -68,8 +68,8 @@ rational TransitionBlock::out_offset() const
return length();
}
// Assume both are connected, in which case the in offset will be <= length
return length() / 2 - media_in();
// Assume both are connected
return -media_in();
}
Block *TransitionBlock::connected_out_block() const
+5
View File
@@ -68,6 +68,11 @@ void NodeInputArray::SetSize(int size, bool lock)
emit SizeChanged(size);
}
bool NodeInputArray::ContainsSubParameter(NodeInput *input) const
{
return sub_params_.contains(input);
}
int NodeInputArray::IndexOfSubParameter(NodeInput *input) const
{
return sub_params_.indexOf(input);
+1
View File
@@ -20,6 +20,7 @@ public:
void RemoveAt(int index);
void SetSize(int size, bool lock = true);
bool ContainsSubParameter(NodeInput* input) const;
int IndexOfSubParameter(NodeInput* input) const;
NodeInput* First() const;
+3 -4
View File
@@ -91,10 +91,9 @@ TrackOutput* TrackList::AddTrack()
track_input_->Append();
NodeInput* assoc_input = track_input_->At(track_input_->GetSize() - 1);
// Connect this track directly to this output
NodeParam::ConnectEdge(track->output(), assoc_input);
NodeParam::ConnectEdge(track->output(),
track_input_->At(track_input_->GetSize() - 1));
// FIXME: Test code only
if (track_input_->GetSize() > 1) {
@@ -111,7 +110,7 @@ TrackOutput* TrackList::AddTrack()
if (last_track && last_track->output()->IsConnected()) {
foreach (NodeEdgePtr edge, last_track->output()->edges()) {
if (edge->input()->parentNode() != track_input_->parentNode()) {
if (!track_input_->ContainsSubParameter(edge->input())) {
Node* blend = NodeFactory::CreateFromID("org.olivevideoeditor.Olive.alphaoverblend");
GetParentGraph()->AddNode(blend);
+36 -12
View File
@@ -7,6 +7,7 @@
#include "core.h"
#include "common/timecodefunctions.h"
#include "dialog/speedduration/speedduration.h"
#include "node/block/transition/transition.h"
#include "tool/tool.h"
#include "trackview/trackview.h"
#include "widget/menu/menu.h"
@@ -394,23 +395,46 @@ void TimelineWidget::SplitAtPlayhead()
}
}
void TimelineWidget::DeleteSelectedInternal(const QList<Block *> blocks, bool remove_from_graph, QUndoCommand *command)
void TimelineWidget::DeleteSelectedInternal(const QList<Block *> blocks, bool transition_aware, bool remove_from_graph, QUndoCommand *command)
{
foreach (Block* b, blocks) {
TrackOutput* original_track = TrackOutput::TrackFromBlock(b);
// Make new gap and replace old Block with it for now
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(b->length());
if (transition_aware && b->type() == Block::kTransition) {
// Deleting transitions restores their in/out offsets to their attached blocks
TransitionBlock* transition = static_cast<TransitionBlock*>(b);
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
gap,
command);
// Ripple remove transition
new TrackRippleRemoveBlockCommand(original_track,
transition,
command);
new TrackReplaceBlockCommand(original_track,
b,
gap,
command);
// Resize attached blocks to make up length
if (transition->connected_in_block()) {
new BlockResizeWithMediaInCommand(transition->connected_in_block(),
transition->connected_in_block()->length() + transition->in_offset(),
command);
}
if (transition->connected_out_block()) {
new BlockResizeCommand(transition->connected_out_block(),
transition->connected_out_block()->length() + transition->out_offset(),
command);
}
} else {
// Make new gap and replace old Block with it for now
GapBlock* gap = new GapBlock();
gap->set_length_and_media_out(b->length());
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
gap,
command);
new TrackReplaceBlockCommand(original_track,
b,
gap,
command);
}
if (remove_from_graph) {
new NodeRemoveWithExclusiveDeps(static_cast<NodeGraph*>(b->parent()), b, command);
@@ -442,7 +466,7 @@ void TimelineWidget::DeleteSelected()
QUndoCommand* command = new QUndoCommand();
// Replace blocks with gaps (effectively deleting them)
DeleteSelectedInternal(blocks_to_delete, true, command);
DeleteSelectedInternal(blocks_to_delete, true, true, command);
// Clean each track
foreach (const TrackReference& track, tracks_affected) {
+1 -1
View File
@@ -331,7 +331,7 @@ private:
bool dual_transition_;
};
void DeleteSelectedInternal(const QList<Block*> blocks, bool remove_from_graph, QUndoCommand* command);
void DeleteSelectedInternal(const QList<Block*> blocks, bool transition_aware, bool remove_from_graph, QUndoCommand* command);
void SetBlockLinksSelected(Block *block, bool selected);
+65 -11
View File
@@ -31,6 +31,7 @@
#include "config/config.h"
#include "core.h"
#include "node/block/gap/gap.h"
#include "node/block/transition/transition.h"
#include "widget/nodeview/nodeviewundo.h"
TimelineWidget::PointerTool::PointerTool(TimelineWidget *parent) :
@@ -216,7 +217,7 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
}
// If there are any blocks to remove, remove them
parent()->DeleteSelectedInternal(blocks_to_temp_remove, false, command);
parent()->DeleteSelectedInternal(blocks_to_temp_remove, false, false, command);
// Now we place the clips back in the timeline where the user moved them. It's legal for them to overwrite parts or
// all of the gaps we inserted earlier
@@ -459,8 +460,19 @@ void TimelineWidget::PointerTool::InitiateGhosts(TimelineViewBlockItem* clicked_
block_mode = FlipTrimMode(trim_mode);
}
if (block != nullptr) {
if (block) {
AddGhostFromBlock(block, clip_item->Track(), block_mode);
if (block->type() == Block::kTransition) {
TransitionBlock* transition = static_cast<TransitionBlock*>(block);
// Create a rolling effect with the attached block
if (transition->connected_in_block() && block_mode == Timeline::kTrimOut) {
AddGhostFromBlock(transition->connected_in_block(), clip_item->Track(), Timeline::kTrimIn);
} else if (transition->connected_out_block() && block_mode == Timeline::kTrimIn) {
AddGhostFromBlock(transition->connected_out_block(), clip_item->Track(), Timeline::kTrimOut);
}
}
}
}
}
@@ -531,6 +543,11 @@ bool TimelineWidget::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip,
return true;
}
rational GetEarliestPointForClip(Block* block)
{
return qMax(rational(0), block->in() - block->media_in());
}
rational TimelineWidget::PointerTool::ValidateInTrimming(rational movement,
const QVector<TimelineViewGhostItem *> ghosts,
bool prevent_overwriting)
@@ -542,8 +559,34 @@ rational TimelineWidget::PointerTool::ValidateInTrimming(rational movement,
Block* block = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
// Determine the earliest in point this block could have
rational earliest_in = qMax(rational(0), block->in() - block->media_in());
rational earliest_in = RATIONAL_MIN;
rational latest_in = ghost->Out();
if (block->type() == Block::kTransition) {
// For transitions, validate with the attached block
TransitionBlock* transition = static_cast<TransitionBlock*>(block);
if (transition->connected_in_block() && transition->connected_out_block()) {
// Here, we try to get the latest earliest point for both the in and out blocks, we do in here and out will
// be calculated later
earliest_in = GetEarliestPointForClip(transition->connected_in_block());
// We set the block to the out block since that will be before the in block and will be the one we use to
// prevent overwriting since we're trimming the in side of this transition
block = transition->connected_out_block();
latest_in = transition->in() + transition->out_offset();
} else {
// Use whatever block is attached
block = transition->connected_in_block() ? transition->connected_in_block() : transition->connected_out_block();
}
}
earliest_in = qMax(earliest_in, GetEarliestPointForClip(block));
if (!ghost->CanHaveZeroLength()) {
latest_in -= parent()->timebase();
}
if (prevent_overwriting) {
// Look for a Block in the way
@@ -557,13 +600,6 @@ rational TimelineWidget::PointerTool::ValidateInTrimming(rational movement,
}
}
// Determine the latest point this block could have
rational latest_in = ghost->Out();
if (!ghost->CanHaveZeroLength()) {
latest_in -= parent()->timebase();
}
// Clamp adjusted value between the earliest and latest values
rational adjusted = ghost->In() + movement;
rational clamped = clamp(adjusted, earliest_in, latest_in);
@@ -596,6 +632,24 @@ rational TimelineWidget::PointerTool::ValidateOutTrimming(rational movement,
rational latest_out = RATIONAL_MAX;
if (block->type() == Block::kTransition) {
// For transitions, validate with the attached block
TransitionBlock* transition = static_cast<TransitionBlock*>(block);
if (transition->connected_in_block() && transition->connected_out_block()) {
// We set the block to the out block since that will be before the in block and will be the one we use to
// prevent overwriting since we're trimming the in side of this transition
// FIXME: At some point we may add some better logic to `latest_out` akin to the logic in ValidateInTrimming
// which is why this hasn't yet been collapsed into the ternary below.
block = transition->connected_in_block();
earliest_out = transition->out() - transition->in_offset();
} else {
block = transition->connected_in_block() ? transition->connected_in_block() : transition->connected_out_block();
}
}
if (prevent_overwriting) {
// Determine if there's a block in the way
Block* next = block->next();
@@ -97,6 +97,7 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
new NodeAddCommand(static_cast<NodeGraph*>(parent()->timeline_node_->parent()),
transition,
command);
new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()),
track.index(),
transition,
@@ -104,8 +105,8 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
command);
if (dual_transition_) {
//transition->set_in_and_out_offset(ghost_->AdjustedLength()/2, ghost_->AdjustedLength()/2);
transition->set_length_and_media_out(ghost_->AdjustedLength());
transition->set_media_in(-ghost_->AdjustedLength()/2);
// Block mouse is hovering over
Block* active_block = Node::ValueToPtr<Block>(ghost_->data(TimelineViewGhostItem::kAttachedBlock));
+4
View File
@@ -546,6 +546,7 @@ void TrackCleanGapsCommand::redo()
rational new_gap_length = on_gap->length();
foreach (GapBlock* gap, consecutive_gaps) {
track->RippleRemoveBlock(gap);
static_cast<NodeGraph*>(gap->parent())->TakeNode(gap, &memory_manager_);
new_gap_length += gap->length();
}
@@ -566,6 +567,7 @@ void TrackCleanGapsCommand::redo()
foreach (GapBlock* gap, removed_end_gaps_) {
track->RippleRemoveBlock(gap);
static_cast<NodeGraph*>(gap->parent())->TakeNode(gap, &memory_manager_);
}
}
}
@@ -576,6 +578,7 @@ void TrackCleanGapsCommand::undo()
// Restored removed end gaps
foreach (GapBlock* gap, removed_end_gaps_) {
static_cast<NodeGraph*>(gap->parent())->AddNode(gap);
track->AppendBlock(gap);
}
removed_end_gaps_.clear();
@@ -590,6 +593,7 @@ void TrackCleanGapsCommand::undo()
GapBlock* last_gap_added = merge_info.merged;
foreach (GapBlock* gap, merge_info.removed) {
static_cast<NodeGraph*>(gap->parent())->AddNode(gap);
track->InsertBlockAfter(gap, last_gap_added);
last_gap_added = gap;
}
@@ -146,17 +146,8 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
TransitionBlock* t = static_cast<TransitionBlock*>(block_);
if (t->connected_out_block()) {
// Transition fades something out, we'll draw a line
painter->drawLine(rect().topLeft(), rect().bottomRight());
}
if (t->connected_in_block()) {
// Transition fades something in, we'll draw a line
painter->drawLine(rect().bottomLeft(), rect().topRight());
}
if (t->connected_out_block() && t->connected_in_block()) {
// Draw line between out offset and in offset
qreal crossover_line = rect().left();
crossover_line += TimeToScene(t->out_offset());
@@ -164,6 +155,24 @@ void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsI
qRound(rect().top()),
qRound(crossover_line),
qRound(rect().bottom()));
// Draw lines to mid point
QPointF mid_point(crossover_line, rect().center().y());
painter->drawLine(rect().topLeft(), mid_point);
painter->drawLine(rect().bottomLeft(), mid_point);
painter->drawLine(rect().topRight(), mid_point);
painter->drawLine(rect().bottomRight(), mid_point);
} else if (t->connected_out_block()) {
// Transition fades something out, we'll draw a line
painter->drawLine(rect().topLeft(), rect().bottomRight());
} else if (t->connected_in_block()) {
// Transition fades something in, we'll draw a line
painter->drawLine(rect().bottomLeft(), rect().topRight());
}
break;
}