implemented deleting clips in the timeline
Also fixed bugs in the Node::GetExclusiveDependencies function and in the NodeInputArray::RemoveAt function to make this functionality work.
This commit is contained in:
+1
-1
@@ -293,7 +293,7 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
|
||||
NodeInputArray* src_array = static_cast<NodeInputArray*>(source);
|
||||
NodeInputArray* dst_array = static_cast<NodeInputArray*>(dest);
|
||||
|
||||
dst_array->SetSize(src_array->GetSize());
|
||||
dst_array->SetSize(src_array->GetSize(), lock_connections);
|
||||
|
||||
for (int i=0;i<dst_array->GetSize();i++) {
|
||||
CopyValues(src_array->At(i), dst_array->At(i), include_connections);
|
||||
|
||||
+21
-14
@@ -22,7 +22,7 @@ void NodeInputArray::Prepend()
|
||||
InsertAt(0);
|
||||
}
|
||||
|
||||
void NodeInputArray::SetSize(int size)
|
||||
void NodeInputArray::SetSize(int size, bool lock)
|
||||
{
|
||||
int old_size = GetSize();
|
||||
|
||||
@@ -33,10 +33,14 @@ void NodeInputArray::SetSize(int size)
|
||||
if (size < old_size) {
|
||||
// If the new size is less, delete all extraneous parameters
|
||||
for (int i=size;i<old_size;i++) {
|
||||
delete sub_params_.at(i);
|
||||
NodeInput* sub_param = sub_params_.at(i);
|
||||
delete sub_param;
|
||||
}
|
||||
}
|
||||
|
||||
if (lock)
|
||||
parentNode()->LockUserInput();
|
||||
|
||||
sub_params_.resize(size);
|
||||
|
||||
if (size > old_size) {
|
||||
@@ -57,6 +61,9 @@ void NodeInputArray::SetSize(int size)
|
||||
}
|
||||
}
|
||||
|
||||
if (lock)
|
||||
parentNode()->UnlockUserInput();
|
||||
|
||||
emit SizeChanged(size);
|
||||
}
|
||||
|
||||
@@ -126,28 +133,28 @@ void NodeInputArray::RemoveLast()
|
||||
|
||||
void NodeInputArray::RemoveAt(int index)
|
||||
{
|
||||
int limit = sub_params_.size() - 1;
|
||||
|
||||
// Shift all connections from index down
|
||||
for (int i=index;i<limit;i++) {
|
||||
for (int i=index;i<sub_params_.size();i++) {
|
||||
NodeInput* this_param = sub_params_.at(i);
|
||||
NodeInput* next_param = sub_params_.at(i + 1);
|
||||
|
||||
if (this_param->IsConnected()) {
|
||||
// Disconnect current edge
|
||||
NodeParam::DisconnectEdge(this_param->edges().first());
|
||||
}
|
||||
|
||||
if (next_param->IsConnected()) {
|
||||
// Get edge from next param
|
||||
NodeEdgePtr edge = next_param->edges().first();
|
||||
if (i < sub_params_.size() - 1) {
|
||||
NodeInput* next_param = sub_params_.at(i + 1);
|
||||
if (next_param->IsConnected()) {
|
||||
// Get edge from next param
|
||||
NodeEdgePtr edge = next_param->edges().first();
|
||||
|
||||
// Disconnect it
|
||||
NodeParam::DisconnectEdge(edge);
|
||||
// Disconnect it
|
||||
NodeParam::DisconnectEdge(edge);
|
||||
|
||||
// Reconnect it to this param
|
||||
NodeParam::ConnectEdge(edge->output(),
|
||||
this_param);
|
||||
// Reconnect it to this param
|
||||
NodeParam::ConnectEdge(edge->output(),
|
||||
this_param);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
void InsertAt(int index);
|
||||
void RemoveLast();
|
||||
void RemoveAt(int index);
|
||||
void SetSize(int size);
|
||||
void SetSize(int size, bool lock = true);
|
||||
|
||||
int IndexOfSubParameter(NodeInput* input) const;
|
||||
|
||||
|
||||
+21
-18
@@ -324,33 +324,36 @@ QList<Node *> Node::GetDependencies() const
|
||||
|
||||
QList<Node *> Node::GetExclusiveDependencies() const
|
||||
{
|
||||
QList<Node*> deps = GetDependencies();
|
||||
QList<Node*> dependency_tree = GetDependencies();
|
||||
|
||||
// Filter out any dependencies that are used elsewhere
|
||||
for (int i=0;i<deps.size();i++) {
|
||||
QList<NodeParam*> params = deps.at(i)->params_;
|
||||
QList<Node*> exclusive_deps;
|
||||
|
||||
// See if any of this Node's outputs are used outside of this dep list
|
||||
for (int j=0;j<params.size();j++) {
|
||||
NodeParam* p = params.at(j);
|
||||
// See if any nodes in the list output somewhere else
|
||||
foreach (Node* dep, dependency_tree) {
|
||||
bool is_exclusive = true;
|
||||
|
||||
if (p->type() == NodeParam::kOutput) {
|
||||
foreach (NodeEdgePtr edge, p->edges()) {
|
||||
// If any edge goes to from an output here to an input of a Node that isn't in this dep list, it's NOT an
|
||||
// exclusive dependency
|
||||
if (deps.contains(edge->input()->parentNode())) {
|
||||
deps.removeAt(i);
|
||||
|
||||
i--; // -1 since we just removed a Node in this list
|
||||
j = params.size(); // No need to keep looking at this Node's params
|
||||
break; // Or this param's edges
|
||||
foreach (NodeParam* param, dep->parameters()) {
|
||||
if (param->type() == NodeParam::kOutput) {
|
||||
foreach (NodeEdgePtr edge, param->edges()) {
|
||||
Node* node_param_outputs_to = edge->input()->parentNode();
|
||||
if (node_param_outputs_to != this && !dependency_tree.contains(node_param_outputs_to)) {
|
||||
is_exclusive = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_exclusive) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_exclusive) {
|
||||
exclusive_deps.append(dep);
|
||||
}
|
||||
}
|
||||
|
||||
return deps;
|
||||
return exclusive_deps;
|
||||
}
|
||||
|
||||
QList<Node *> Node::GetImmediateDependencies() const
|
||||
|
||||
+9
-5
@@ -143,19 +143,23 @@ NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input, bool lo
|
||||
return edge;
|
||||
}
|
||||
|
||||
void NodeParam::DisconnectEdge(NodeEdgePtr edge)
|
||||
void NodeParam::DisconnectEdge(NodeEdgePtr edge, bool lock)
|
||||
{
|
||||
NodeOutput* output = edge->output();
|
||||
NodeInput* input = edge->input();
|
||||
|
||||
output->parentNode()->LockUserInput();
|
||||
input->parentNode()->LockUserInput();
|
||||
if (lock) {
|
||||
output->parentNode()->LockUserInput();
|
||||
input->parentNode()->LockUserInput();
|
||||
}
|
||||
|
||||
output->edges_.removeOne(edge);
|
||||
input->edges_.removeOne(edge);
|
||||
|
||||
output->parentNode()->UnlockUserInput();
|
||||
input->parentNode()->UnlockUserInput();
|
||||
if (lock) {
|
||||
output->parentNode()->UnlockUserInput();
|
||||
input->parentNode()->UnlockUserInput();
|
||||
}
|
||||
|
||||
emit input->EdgeRemoved(edge);
|
||||
}
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ public:
|
||||
*
|
||||
* Edge to disconnect.
|
||||
*/
|
||||
static void DisconnectEdge(NodeEdgePtr edge);
|
||||
static void DisconnectEdge(NodeEdgePtr edge, bool lock = true);
|
||||
|
||||
/**
|
||||
* @brief Disconnect an edge
|
||||
|
||||
@@ -114,6 +114,11 @@ void TimelinePanel::GoToNextCut()
|
||||
timeline_widget_->GoToNextCut();
|
||||
}
|
||||
|
||||
void TimelinePanel::DeleteSelected()
|
||||
{
|
||||
timeline_widget_->DeleteSelected();
|
||||
}
|
||||
|
||||
void TimelinePanel::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
|
||||
virtual void GoToNextCut() override;
|
||||
|
||||
virtual void DeleteSelected() override;
|
||||
|
||||
public slots:
|
||||
void SetTimebase(const rational& timebase);
|
||||
|
||||
|
||||
@@ -383,16 +383,96 @@ void TimelineWidget::SplitAtPlayhead()
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::DeleteSelectedInternal(const QList<Block *> blocks, bool remove_from_graph, QUndoCommand *command)
|
||||
{
|
||||
foreach (Block* b, blocks) {
|
||||
// All this function does is replace blocks with gaps, nothing to do if the block is already a gap
|
||||
if (b->type() == Block::kGap) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool previous_is_gap = (b->previous() && b->previous()->type() == Block::kGap);
|
||||
bool next_is_gap = (b->next() && b->next()->type() == Block::kGap);
|
||||
|
||||
TrackOutput* original_track = TrackOutput::TrackFromBlock(b);
|
||||
|
||||
if (!b->next()) {
|
||||
// If the block has no next, presumably it's the last block and doesn't actually need a gap
|
||||
new TrackRippleRemoveBlockCommand(original_track,
|
||||
b,
|
||||
command);
|
||||
} else if (!previous_is_gap && !next_is_gap) {
|
||||
// Make new gap and replace old Block with it for now
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(b->length());
|
||||
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
|
||||
gap,
|
||||
command);
|
||||
|
||||
new TrackReplaceBlockCommand(original_track,
|
||||
b,
|
||||
gap,
|
||||
command);
|
||||
} else {
|
||||
// Remove the block from the track
|
||||
new TrackRippleRemoveBlockCommand(original_track,
|
||||
b,
|
||||
command);
|
||||
|
||||
if (previous_is_gap && next_is_gap) {
|
||||
// Clip is surrounded by gaps, merge both together
|
||||
|
||||
// Remove one of the gaps
|
||||
new TrackRippleRemoveBlockCommand(original_track,
|
||||
b->next(),
|
||||
command);
|
||||
|
||||
// Resize the other to match both
|
||||
new BlockResizeCommand(b->previous(),
|
||||
b->previous()->length() + b->length() + b->next()->length(),
|
||||
command);
|
||||
} else {
|
||||
// Resize the surrounding block to take its place
|
||||
Block* gap_to_resize = previous_is_gap ? b->previous() : b->next();
|
||||
new BlockResizeCommand(gap_to_resize,
|
||||
gap_to_resize->length() + b->length(),
|
||||
command);
|
||||
}
|
||||
}
|
||||
|
||||
if (remove_from_graph) {
|
||||
QList<Node*> block_and_its_exclusive_deps;
|
||||
|
||||
block_and_its_exclusive_deps.append(b);
|
||||
block_and_its_exclusive_deps.append(b->GetExclusiveDependencies());
|
||||
|
||||
new NodeRemoveCommand(static_cast<NodeGraph*>(b->parent()), block_and_its_exclusive_deps, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::DeleteSelected()
|
||||
{
|
||||
QList<TimelineViewBlockItem *> list = GetSelectedBlocks();
|
||||
QList<TimelineViewBlockItem *> selected_list = GetSelectedBlocks();
|
||||
QList<Block*> blocks_to_delete;
|
||||
|
||||
foreach (TimelineViewBlockItem* item, selected_list) {
|
||||
Block* b = item->block();
|
||||
|
||||
blocks_to_delete.append(b);
|
||||
}
|
||||
|
||||
// No-op if nothing is selected
|
||||
if (list.isEmpty()) {
|
||||
if (blocks_to_delete.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
DeleteSelectedInternal(blocks_to_delete, true, command);
|
||||
|
||||
olive::undo_stack.pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
QList<TimelineViewBlockItem *> TimelineWidget::GetSelectedBlocks()
|
||||
|
||||
@@ -319,6 +319,8 @@ private:
|
||||
bool dual_transition_;
|
||||
};
|
||||
|
||||
void DeleteSelectedInternal(const QList<Block*> blocks, bool remove_from_graph, QUndoCommand* command);
|
||||
|
||||
void SetBlockLinksSelected(Block *block, bool selected);
|
||||
|
||||
QPoint drag_origin_;
|
||||
|
||||
@@ -161,6 +161,8 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
QList<Block*> blocks_to_temp_remove;
|
||||
|
||||
// Since all the ghosts will be leaving their old position in some way, we replace all of them with gaps here so the
|
||||
// entire timeline isn't disrupted in the process
|
||||
for (int i=0;i<parent()->ghost_items_.size();i++) {
|
||||
@@ -173,52 +175,11 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
|
||||
|
||||
Block* b = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kAttachedBlock));
|
||||
|
||||
bool previous_is_gap = (b->previous() && b->previous()->type() == Block::kGap);
|
||||
bool next_is_gap = (b->next() && b->next()->type() == Block::kGap);
|
||||
|
||||
TrackOutput* original_track = parent()->GetTrackFromReference(ghost->Track());
|
||||
|
||||
if (!previous_is_gap && !next_is_gap) {
|
||||
// Make new gap and replace old Block with it for now
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(b->length());
|
||||
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
|
||||
gap,
|
||||
command);
|
||||
|
||||
new TrackReplaceBlockCommand(original_track,
|
||||
b,
|
||||
gap,
|
||||
command);
|
||||
} else {
|
||||
// Remove the block from the track (this does NOT remove the block from the graph however)
|
||||
new TrackRippleRemoveBlockCommand(original_track,
|
||||
b,
|
||||
command);
|
||||
|
||||
if (previous_is_gap && next_is_gap) {
|
||||
// Clip is surrounded by gaps, merge both together
|
||||
|
||||
// Remove one of the gaps
|
||||
new TrackRippleRemoveBlockCommand(original_track,
|
||||
b->next(),
|
||||
command);
|
||||
|
||||
// Resize the other to match both
|
||||
new BlockResizeCommand(b->previous(),
|
||||
b->previous()->length() + b->length() + b->next()->length(),
|
||||
command);
|
||||
} else {
|
||||
// Resize the surrounding block to take its place
|
||||
Block* gap_to_resize = previous_is_gap ? b->previous() : b->next();
|
||||
new BlockResizeCommand(gap_to_resize,
|
||||
gap_to_resize->length() + b->length(),
|
||||
command);
|
||||
}
|
||||
}
|
||||
blocks_to_temp_remove.append(b);
|
||||
}
|
||||
|
||||
parent()->DeleteSelectedInternal(blocks_to_temp_remove, 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
|
||||
for (int i=0;i<parent()->ghost_items_.size();i++) {
|
||||
|
||||
@@ -107,7 +107,11 @@ void TrackRippleRemoveBlockCommand::redo()
|
||||
|
||||
void TrackRippleRemoveBlockCommand::undo()
|
||||
{
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
if (before_) {
|
||||
track_->InsertBlockAfter(block_, before_);
|
||||
} else {
|
||||
track_->AppendBlock(block_);
|
||||
}
|
||||
}
|
||||
|
||||
TrackInsertBlockBetweenBlocksCommand::TrackInsertBlockBetweenBlocksCommand(TrackOutput *track,
|
||||
@@ -224,7 +228,6 @@ void TrackRippleRemoveAreaCommand::redo()
|
||||
|
||||
// If we were given a block to insert, insert it here
|
||||
if (insert_) {
|
||||
qDebug() << "Insert is" << insert_ << ", parent is" << insert_->parent();
|
||||
if (!trim_out_) {
|
||||
// This is the start of the Sequence
|
||||
track_->PrependBlock(insert_);
|
||||
|
||||
Reference in New Issue
Block a user