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 a1d958e635..fa126f0a3b 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 @@ -1,5 +1,5 @@ use super::node_properties; -use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendNode}; +use super::utility_types::{BoxSelection, ContextMenuInformation, FrontendNode}; use crate::consts::GRID_SIZE; use crate::messages::clipboard::utility_types::ClipboardContent; use crate::messages::input_mapper::utility_types::macros::{action_shortcut, action_shortcut_manual}; @@ -56,11 +56,10 @@ pub struct NodeGraphMessageHandler { pub network: Vec, has_selection: bool, widgets: [LayoutGroup; 2], + /// This stores the coordinate of the click relative to the top left selected node. + pub drag_start: Option, /// Used to add a transaction for the first node move when dragging. - /// Used to prevent entering a nested network if the node is dragged after double clicking - node_has_moved_in_drag: bool, - /// See DragStart for notes - pub drag_start: Option, + pub node_has_moved_in_drag: bool, // Store the selected chain nodes on drag start so they can be reconnected if shaken pub drag_start_chain_nodes: Vec, /// If dragging the background to create a box selection, this stores its starting point in node graph coordinates, @@ -936,6 +935,7 @@ impl<'a> MessageHandler> for NodeG return; }; let mut updated_selected = selected_nodes.selected_nodes().cloned().collect::>(); + log::debug!("updated_selected: {:?}", updated_selected); let mut modified_selected = false; // Add to/remove from selection if holding Shift or Ctrl @@ -963,9 +963,12 @@ impl<'a> MessageHandler> for NodeG // If this node is selected (whether from before or just now), prepare it for dragging if updated_selected.contains(&clicked_id) { - if let Some(selected_top_left) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path) { - self.drag_start = Some(DragStart::new(node_graph_point - selected_top_left[0])); + let Some(selected_top_left) = network_interface.nodes_bounding_box(&updated_selected, selection_network_path) else { + log::error!("Could not get selected nodes bounding box in PointerDown"); + return; }; + self.drag_start = Some(node_graph_point - selected_top_left[0]); + self.node_has_moved_in_drag = false; let selected_chain_nodes = updated_selected .iter() .filter(|node_id| network_interface.is_chain(node_id, selection_network_path)) @@ -980,7 +983,6 @@ impl<'a> MessageHandler> for NodeG .filter(|node_id| network_interface.is_chain(node_id, selection_network_path)) }) .collect::>(); - self.node_has_moved_in_drag = false; self.update_node_graph_hints(responses); } @@ -1099,8 +1101,8 @@ impl<'a> MessageHandler> for NodeG } } else if let Some(drag_start) = &mut self.drag_start { let moved = sync_selected_node_position_with_mouse(network_interface, breadcrumb_network_path, drag_start, point, responses); - if !drag_start.dragged && moved { - drag_start.dragged = true; + if !self.node_has_moved_in_drag && moved { + self.node_has_moved_in_drag = true; if ipp.keyboard.get(Key::Alt as usize) { responses.add(NodeGraphMessage::DuplicateSelectedNodes); // Duplicating sets a 2x2 offset, so shift the nodes back to the original position @@ -1179,7 +1181,7 @@ impl<'a> MessageHandler> for NodeG self.preview_on_mouse_up = None; } if let Some(node_to_deselect) = self.deselect_on_pointer_up.take() - && self.drag_start.as_ref().is_some_and(|start| !start.dragged) + && self.node_has_moved_in_drag { let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone(); new_selected_nodes.remove(node_to_deselect); @@ -1243,7 +1245,7 @@ impl<'a> MessageHandler> for NodeG } } // End of dragging a node - else if let Some(drag_start) = &self.drag_start { + else if self.drag_start.is_some() { self.shift_without_push = false; // Reset all offsets to end the rubber banding while dragging @@ -1254,16 +1256,15 @@ impl<'a> MessageHandler> for NodeG }; // Only select clicked node if multiple are selected and they were not dragged - if let Some(select_if_not_dragged) = self.select_if_not_dragged { - if !drag_start.dragged - && (selected_nodes.selected_nodes_ref().len() != 1 - || selected_nodes - .selected_nodes_ref() - .first() - .is_some_and(|first_selected_node| *first_selected_node != select_if_not_dragged)) - { - responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![select_if_not_dragged] }) - } + if let Some(select_if_not_dragged) = self.select_if_not_dragged + && !self.node_has_moved_in_drag + && (selected_nodes.selected_nodes_ref().len() != 1 + || selected_nodes + .selected_nodes_ref() + .first() + .is_some_and(|first_selected_node| *first_selected_node != select_if_not_dragged)) + { + responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![select_if_not_dragged] }) } // Try expand the upstream chain for all layers if there is an eligible node @@ -1284,7 +1285,7 @@ impl<'a> MessageHandler> for NodeG return; }; // Check if a single node was dragged onto a wire and that the node was dragged onto the wire - if selected_nodes.selected_nodes_ref().len() == 1 && self.drag_start.as_ref().is_some_and(|drag_start| drag_start.dragged) { + if selected_nodes.selected_nodes_ref().len() == 1 && self.node_has_moved_in_drag { let selected_node_id = selected_nodes.selected_nodes_ref()[0]; let has_primary_output_connection = network_interface .outward_wires(selection_network_path) @@ -2728,8 +2729,8 @@ impl NodeGraphMessageHandler { // A wire is in progress and its start and end connectors are set let wiring = self.wire_in_progress_from_connector.is_some(); - // Node dragging is in progress (having already moved at least one pixel from the mouse down position) - let dragging_nodes = self.drag_start.as_ref().is_some_and(|drag_start| drag_start.dragged); + // Node dragging is in progress (having already moved one grid space) + let dragging_nodes = self.node_has_moved_in_drag; // A box selection is in progress let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged); @@ -2820,19 +2821,19 @@ impl PartialEq for NodeGraphMessageHandler { fn sync_selected_node_position_with_mouse( network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId], - drag_start: &DragStart, + drag_start: &DVec2, mouse_position_node_graph_space: DVec2, responses: &mut VecDeque, ) -> bool { - let Some(selected_nodes_bbox) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path) else { - log::error!("Could not get selected_nodes_bounding_box when dragging"); - return false; - }; - let target_center = selected_nodes_bbox[0] + drag_start.drag_start_offset; - let offset = mouse_position_node_graph_space - target_center; - let graph_delta = IVec2::new((offset.x / 24.).round() as i32, (offset.y / 24.).round() as i32); - if graph_delta != IVec2::ZERO { - responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true }); - }; - graph_delta != IVec2::ZERO + if let Some(selected_nodes_bbox) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path) { + let target_center = selected_nodes_bbox[0] + drag_start; + let offset = mouse_position_node_graph_space - target_center; + let graph_delta = IVec2::new((offset.x / 24.).round() as i32, (offset.y / 24.).round() as i32); + if graph_delta != IVec2::ZERO { + responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true }); + }; + graph_delta != IVec2::ZERO + } else { + false + } } diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index d05f005657..846cca3955 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -110,23 +110,6 @@ pub struct FrontendNodeType { pub input_types: Vec, } -/// If dragging the selected nodes, this stores the coordinate of the click relative to the top left selected node. -/// Once the nodes have been dragged, it is toggled to the Yes variant. -#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct DragStart { - pub drag_start_offset: DVec2, - pub dragged: bool, -} - -impl DragStart { - pub fn new(drag_start: DVec2) -> Self { - DragStart { - drag_start_offset: drag_start, - dragged: false, - } - } -} - #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct Transform { pub scale: f64, diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 22680231e5..8abf943715 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -3011,10 +3011,13 @@ impl NodeNetworkInterface { log::error!("Could not get selected nodes in selected_nodes_bounding_box_viewport"); return None; }; - selected_nodes - .selected_nodes() - .cloned() - .collect::>() + let nodes = selected_nodes.selected_nodes().cloned().collect::>(); + + self.nodes_bounding_box(&nodes, network_path) + } + + pub fn nodes_bounding_box(&mut self, nodes: &Vec, network_path: &[NodeId]) -> Option<[DVec2; 2]> { + nodes .iter() .filter_map(|node_id| { self.node_click_targets(node_id, network_path)