diff --git a/app/node/node.cpp b/app/node/node.cpp index 6acfa5294..70d6b1907 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -1105,6 +1105,71 @@ void Node::CopyDependencyGraph(const QVector &src, const QVector } } +Node *Node::CopyNodeAndDependencyGraphMinusItemsInternal(QMap& created, const Node *node, MultiUndoCommand *command) +{ + // Make a new node of the same type + Node* copy = node->copy(); + + // Add to map + created.insert(node, copy); + + // Copy values to the clone + CopyInputs(node, copy, false); + + // Add it to the same graph + command->add_child(new NodeAddCommand(node->parent(), copy)); + + // Go through input connections and copy if non-item and connect if item + for (auto it=node->input_connections_.cbegin(); it!=node->input_connections_.cend(); it++) { + NodeInput input = it->first; + NodeOutput output = it->second; + Node* connected = output.node(); + Node* connected_copy; + + if (dynamic_cast(connected)) { + // This is an item and we avoid copying those and just connect to them directly + connected_copy = connected; + } else { + // Non-item, we want to clone this too + connected_copy = created.value(connected, nullptr); + + if (!connected_copy) { + connected_copy = CopyNodeAndDependencyGraphMinusItemsInternal(created, connected, command); + } + } + + command->add_child(new NodeEdgeAddCommand(NodeOutput(connected_copy, output.output()), + NodeInput(copy, input.input(), input.element()))); + } + + return copy; +} + +Node *Node::CopyNodeAndDependencyGraphMinusItems(const Node *node, MultiUndoCommand *command) +{ + QMap created; + + return CopyNodeAndDependencyGraphMinusItemsInternal(created, node, command); +} + +Node *Node::CopyNodeInGraph(const Node *node, MultiUndoCommand *command) +{ + Node* copy; + + if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + copy = Node::CopyNodeAndDependencyGraphMinusItems(node, command); + } else { + copy = node->copy(); + + command->add_child(new NodeAddCommand(static_cast(node->parent()), + copy)); + + command->add_child(new NodeCopyInputsCommand(node, copy, true)); + } + + return copy; +} + void Node::SendInvalidateCache(const TimeRange &range, qint64 job_time) { for (const OutputConnection& conn : output_connections_) { @@ -1376,7 +1441,7 @@ void Node::Hash(const QString &output, QCryptographicHash &hash, const rational& } } -void Node::CopyInputs(Node *source, Node *destination, bool include_connections) +void Node::CopyInputs(const Node *source, Node *destination, bool include_connections) { Q_ASSERT(source->id() == destination->id()); @@ -1388,7 +1453,7 @@ void Node::CopyInputs(Node *source, Node *destination, bool include_connections) destination->SetLabel(source->GetLabel()); } -void Node::CopyInput(Node *src, Node *dst, const QString &input, bool include_connections, bool traverse_arrays) +void Node::CopyInput(const Node *src, Node *dst, const QString &input, bool include_connections, bool traverse_arrays) { Q_ASSERT(src->id() == dst->id()); @@ -1419,7 +1484,7 @@ void Node::CopyInput(Node *src, Node *dst, const QString &input, bool include_co } } -void Node::CopyValuesOfElement(Node *src, Node *dst, const QString &input, int src_element, int dst_element) +void Node::CopyValuesOfElement(const Node *src, Node *dst, const QString &input, int src_element, int dst_element) { if (dst_element >= dst->GetInternalInputArraySize(input)) { qDebug() << "Ignored destination element that was out of array bounds"; diff --git a/app/node/node.h b/app/node/node.h index 42aff2586..dc4f4f664 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -640,12 +640,12 @@ public: * * Nodes must be of the same types (i.e. have the same ID) */ - static void CopyInputs(Node* source, Node* destination, bool include_connections = true); + static void CopyInputs(const Node *source, Node* destination, bool include_connections = true); - static void CopyInput(Node* src, Node* dst, const QString& input, bool include_connections, bool traverse_arrays); + static void CopyInput(const Node *src, Node* dst, const QString& input, bool include_connections, bool traverse_arrays); - static void CopyValuesOfElement(Node* src, Node* dst, const QString& input, int src_element, int dst_element); - static void CopyValuesOfElement(Node* src, Node* dst, const QString& input, int element) + static void CopyValuesOfElement(const Node* src, Node* dst, const QString& input, int src_element, int dst_element); + static void CopyValuesOfElement(const Node* src, Node* dst, const QString& input, int element) { return CopyValuesOfElement(src, dst, input, element, element); } @@ -656,6 +656,10 @@ public: static QVector CopyDependencyGraph(const QVector& nodes, MultiUndoCommand *command); static void CopyDependencyGraph(const QVector& src, const QVector& dst, MultiUndoCommand *command); + static Node* CopyNodeAndDependencyGraphMinusItems(const Node* node, MultiUndoCommand* command); + + static Node* CopyNodeInGraph(const Node* node, MultiUndoCommand* command); + /** * @brief Return whether this Node can be deleted or not */ @@ -1048,6 +1052,8 @@ private: void ArrayResizeInternal(const QString& id, int size); + static Node *CopyNodeAndDependencyGraphMinusItemsInternal(QMap& created, const Node *node, MultiUndoCommand *command); + /** * @brief Immediates aren't deleted, so the actual array size may be larger than ArraySize() */ diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 977e6a9d7..d5135fd71 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -112,7 +112,7 @@ Project *NodeAddCommand::GetRelevantProject() const return dynamic_cast(graph_); } -NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, bool include_connections) : +NodeCopyInputsCommand::NodeCopyInputsCommand(const Node *src, Node *dest, bool include_connections) : src_(src), dest_(dest), include_connections_(include_connections) diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 2d97cff6e..205987894 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -203,7 +203,7 @@ private: class NodeCopyInputsCommand : public UndoCommand { public: - NodeCopyInputsCommand(Node* src, + NodeCopyInputsCommand(const Node* src, Node* dest, bool include_connections); @@ -214,7 +214,7 @@ public: virtual Project* GetRelevantProject() const override {return nullptr;} private: - Node* src_; + const Node* src_; Node* dest_; diff --git a/app/widget/timelinewidget/timelineundo.h b/app/widget/timelinewidget/timelineundo.h index fc2587006..10dab5ef6 100644 --- a/app/widget/timelinewidget/timelineundo.h +++ b/app/widget/timelinewidget/timelineundo.h @@ -488,6 +488,7 @@ class BlockSplitCommand : public UndoCommand { public: BlockSplitCommand(Block* block, rational point) : block_(block), + new_block_(nullptr), point_(point), reconnect_tree_command_(nullptr) { @@ -508,7 +509,7 @@ public: */ Block* new_block() { - return static_cast(added_nodes_.first()); + return new_block_; } virtual void redo() override @@ -517,47 +518,9 @@ public: Q_ASSERT(point_ > block_->in() && point_ < block_->out()); - // Determine if we're copying the dependencies as part of this command - bool copy_dependencies_too = Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool(); - - // Copy nodes if we haven't already done it - if (added_nodes_.isEmpty()) { - if (copy_dependencies_too) { - src_nodes_.append(block_); - src_nodes_.append(block_->GetDependencies()); - - added_nodes_.resize(src_nodes_.size()); - for (int i=0; icopy(); - - // Copy inputs - Node::CopyInputs(src_nodes_[i], copy, false); - - // Keep in array - added_nodes_[i] = copy; - - } - } else { - // Just copy the block itself - added_nodes_.append(block_->copy()); - } - } - - // Add all new nodes to the graph - foreach (Node* n, added_nodes_) { - n->setParent(block_->parent()); - } - if (!reconnect_tree_command_) { - if (copy_dependencies_too) { - // Create equivalent connections among our copied dependency tree - reconnect_tree_command_ = new MultiUndoCommand(); - Node::CopyDependencyGraph(src_nodes_, added_nodes_, static_cast(reconnect_tree_command_)); - } else { - reconnect_tree_command_ = new NodeCopyInputsCommand(block_, new_block(), true); - } + reconnect_tree_command_ = new MultiUndoCommand(); + new_block_ = static_cast(Node::CopyNodeInGraph(block_, reconnect_tree_command_)); } reconnect_tree_command_->redo(); @@ -612,29 +575,20 @@ public: // If we ran a reconnect command, disconnect now reconnect_tree_command_->undo(); - foreach (Node* n, added_nodes_) { - // Remove nodes - n->setParent(&memory_manager_); - } - track->EndOperation(); } private: Block* block_; + Block* new_block_; rational old_length_; rational point_; - QObject memory_manager_; - - UndoCommand* reconnect_tree_command_; + MultiUndoCommand* reconnect_tree_command_; NodeInput moved_transition_; - QVector src_nodes_; - QVector added_nodes_; - }; class BlockSplitPreservingLinksCommand : public UndoCommand { diff --git a/app/widget/timelinewidget/tool/pointer.cpp b/app/widget/timelinewidget/tool/pointer.cpp index 5a131e0c9..065c486c8 100644 --- a/app/widget/timelinewidget/tool/pointer.cpp +++ b/app/widget/timelinewidget/tool/pointer.cpp @@ -622,25 +622,8 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event) if (duplicate_clips) { // Duplicate rather than move - Node* copy; - - if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { - QVector nodes_to_clone; - nodes_to_clone.append(block); - nodes_to_clone.append(block->GetDependencies()); - QVector duplicated = Node::CopyDependencyGraph(nodes_to_clone, command); - copy = duplicated.first(); - } else { - copy = block->copy(); - - command->add_child(new NodeAddCommand(static_cast(block->parent()), - copy)); - - command->add_child(new NodeCopyInputsCommand(block, copy, true)); - } - // Place the copy instead of the original block - block = static_cast(copy); + block = static_cast(Node::CopyNodeInGraph(block, command)); } const Track::Reference& track_ref = p.ghost->GetAdjustedTrack();