diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 7ffceb9f5a..3926205e75 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -540,12 +540,12 @@ impl MessageHandler> for DocumentMes responses.add(NodeGraphMessage::UpdateNodeGraphWidth); } DocumentMessage::Escape => { - // Abort dragging nodes - if self.node_graph_handler.drag_start.is_some() { - responses.add(DocumentMessage::AbortTransaction); - self.node_graph_handler.drag_start = None; - self.node_graph_handler.select_if_not_dragged = None; - } + // Abort dragging nodes + if self.node_graph_handler.drag_start.is_some() { + responses.add(DocumentMessage::AbortTransaction); + self.node_graph_handler.drag_start = None; + self.node_graph_handler.select_if_not_dragged = None; + } // Abort box selection else if self.node_graph_handler.box_selection_start.is_some() { self.node_graph_handler.box_selection_start = None; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 3ac4622911..6e91eca119 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -1172,7 +1172,17 @@ impl<'a> MessageHandler> for NodeG if self.begin_dragging { self.begin_dragging = false; if ipp.keyboard.get(Key::Alt as usize) { - responses.add(NodeGraphMessage::DuplicateSelectedNodes); + // Duplicate nodes inline within the existing PointerDown transaction. + // This means a completed Alt-drag is one undo step, and aborting (right-click / Escape) + // rolls back both the duplication and the move with a single plain AbortTransaction. + let all_selected_nodes = network_interface.upstream_chain_nodes(selection_network_path); + let copy_ids = all_selected_nodes.iter().enumerate().map(|(new, id)| (*id, NodeId(new as u64))).collect::>(); + let nodes = network_interface.copy_nodes(©_ids, selection_network_path).collect::>(); + let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>(); + responses.add(NodeGraphMessage::AddNodes { nodes, new_ids: new_ids.clone() }); + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: new_ids.values().cloned().collect(), + }); // Duplicating sets a 2x2 offset, so shift the nodes back to the original position responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta: IVec2::new(-2, -2),