diff --git a/app/node/input.cpp b/app/node/input.cpp index 0eec3baaf..a793186be 100644 --- a/app/node/input.cpp +++ b/app/node/input.cpp @@ -293,7 +293,7 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn NodeInputArray* src_array = static_cast(source); NodeInputArray* dst_array = static_cast(dest); - dst_array->SetSize(src_array->GetSize()); + dst_array->SetSize(src_array->GetSize(), lock_connections); for (int i=0;iGetSize();i++) { CopyValues(src_array->At(i), dst_array->At(i), include_connections); diff --git a/app/node/inputarray.cpp b/app/node/inputarray.cpp index d86a39a4f..af5680bb7 100644 --- a/app/node/inputarray.cpp +++ b/app/node/inputarray.cpp @@ -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;iLockUserInput(); + 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;iIsConnected()) { // 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); + } } } diff --git a/app/node/inputarray.h b/app/node/inputarray.h index faf29f2de..51035d7df 100644 --- a/app/node/inputarray.h +++ b/app/node/inputarray.h @@ -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; diff --git a/app/node/node.cpp b/app/node/node.cpp index e0c6955e9..22974b504 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -324,33 +324,36 @@ QList Node::GetDependencies() const QList Node::GetExclusiveDependencies() const { - QList deps = GetDependencies(); + QList dependency_tree = GetDependencies(); - // Filter out any dependencies that are used elsewhere - for (int i=0;i params = deps.at(i)->params_; + QList exclusive_deps; - // See if any of this Node's outputs are used outside of this dep list - for (int j=0;jtype() == 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::GetImmediateDependencies() const diff --git a/app/node/param.cpp b/app/node/param.cpp index 8f5f3d7aa..bdb531bd6 100644 --- a/app/node/param.cpp +++ b/app/node/param.cpp @@ -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); } diff --git a/app/node/param.h b/app/node/param.h index f7ac48dd4..d8a438968 100644 --- a/app/node/param.h +++ b/app/node/param.h @@ -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 diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index d35399fa3..d3f4041df 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -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) { diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index f5dce2aa5..d4c107bde 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -62,6 +62,8 @@ public: virtual void GoToNextCut() override; + virtual void DeleteSelected() override; + public slots: void SetTimebase(const rational& timebase); diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 5dc1047e2..dbf9bdc20 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -383,16 +383,96 @@ void TimelineWidget::SplitAtPlayhead() } } +void TimelineWidget::DeleteSelectedInternal(const QList 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(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 block_and_its_exclusive_deps; + + block_and_its_exclusive_deps.append(b); + block_and_its_exclusive_deps.append(b->GetExclusiveDependencies()); + + new NodeRemoveCommand(static_cast(b->parent()), block_and_its_exclusive_deps, command); + } + } +} + void TimelineWidget::DeleteSelected() { - QList list = GetSelectedBlocks(); + QList selected_list = GetSelectedBlocks(); + QList 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 TimelineWidget::GetSelectedBlocks() diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index caa0649e7..23df7e4d4 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -319,6 +319,8 @@ private: bool dual_transition_; }; + void DeleteSelectedInternal(const QList blocks, bool remove_from_graph, QUndoCommand* command); + void SetBlockLinksSelected(Block *block, bool selected); QPoint drag_origin_; diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 91da510c3..835b705a2 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -161,6 +161,8 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e QUndoCommand* command = new QUndoCommand(); + QList 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;ighost_items_.size();i++) { @@ -173,52 +175,11 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e Block* b = Node::ValueToPtr(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(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;ighost_items_.size();i++) { diff --git a/app/widget/timelinewidget/undo/undo.cpp b/app/widget/timelinewidget/undo/undo.cpp index 2314ad1d7..6f35be343 100644 --- a/app/widget/timelinewidget/undo/undo.cpp +++ b/app/widget/timelinewidget/undo/undo.cpp @@ -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_);