Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,10 @@ pub struct NodeGraphMessageHandler {
has_selection: bool,
widgets: [LayoutGroup; 2],
/// Used to add a transaction for the first node move when dragging.
begin_dragging: bool,
/// Used to prevent entering a nested network if the node is dragged after double clicking
node_has_moved_in_drag: bool,
/// If dragging the selected nodes, this stores the starting position both in viewport and node graph coordinates,
/// plus a flag indicating if it has been dragged since the mousedown began.
pub drag_start: Option<(DragStart, bool)>,
/// See DragStart for notes
pub drag_start: Option<DragStart>,
// Store the selected chain nodes on drag start so they can be reconnected if shaken
pub drag_start_chain_nodes: Vec<NodeId>,
/// If dragging the background to create a box selection, this stores its starting point in node graph coordinates,
Expand Down Expand Up @@ -963,14 +961,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG

// If this node is selected (whether from before or just now), prepare it for dragging
if updated_selected.contains(&clicked_id) {
let drag_start = DragStart {
start_x: node_graph_point.x,
start_y: node_graph_point.y,
round_x: 0,
round_y: 0,
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]));
};

self.drag_start = Some((drag_start, false));
let selected_chain_nodes = updated_selected
.iter()
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
Expand All @@ -985,7 +978,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
.filter(|node_id| network_interface.is_chain(node_id, selection_network_path))
})
.collect::<Vec<_>>();
self.begin_dragging = true;
self.node_has_moved_in_drag = false;
self.update_node_graph_hints(responses);
}
Expand Down Expand Up @@ -1103,14 +1095,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
};
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) });
}
} else if let Some((drag_start, dragged)) = &mut self.drag_start {
if drag_start.start_x != point.x || drag_start.start_y != point.y {
*dragged = true;
}

self.node_has_moved_in_drag = true;
if self.begin_dragging {
self.begin_dragging = false;
} 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 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
Expand All @@ -1121,19 +1109,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
self.preview_on_mouse_up = None;
}
}

let mut graph_delta = IVec2::new(((point.x - drag_start.start_x) / 24.).round() as i32, ((point.y - drag_start.start_y) / 24.).round() as i32);
let previous_round_x = drag_start.round_x;
let previous_round_y = drag_start.round_y;

drag_start.round_x = graph_delta.x;
drag_start.round_y = graph_delta.y;

graph_delta.x -= previous_round_x;
graph_delta.y -= previous_round_y;

responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: true });

self.update_node_graph_hints(responses);
} else if let Some((_, box_selection_dragged)) = &mut self.box_selection_start {
*box_selection_dragged = true;
Expand Down Expand Up @@ -1202,7 +1177,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> 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(|t| t.1)
&& self.drag_start.as_ref().is_some_and(|start| !start.dragged)
{
let mut new_selected_nodes = selected_nodes.selected_nodes_ref().clone();
new_selected_nodes.remove(node_to_deselect);
Expand Down Expand Up @@ -1266,7 +1241,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}
}
// End of dragging a node
else if let Some((drag_start, _)) = &self.drag_start {
else if let Some(drag_start) = &self.drag_start {
self.shift_without_push = false;

// Reset all offsets to end the rubber banding while dragging
Expand All @@ -1278,8 +1253,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> 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 {
let not_dragged = drag_start.start_x == point.x && drag_start.start_y == point.y;
if not_dragged
if !drag_start.dragged
&& (selected_nodes.selected_nodes_ref().len() != 1
|| selected_nodes
.selected_nodes_ref()
Expand Down Expand Up @@ -1308,7 +1282,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> 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.begin_dragging {
if selected_nodes.selected_nodes_ref().len() == 1 && self.drag_start.as_ref().is_some_and(|drag_start| drag_start.dragged) {
let selected_node_id = selected_nodes.selected_nodes_ref()[0];
let has_primary_output_connection = network_interface
.outward_wires(selection_network_path)
Expand Down Expand Up @@ -1420,7 +1394,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}

self.drag_start = None;
self.begin_dragging = false;
self.box_selection_start = None;

self.wire_in_progress_from_connector = None;
Expand All @@ -1447,11 +1420,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}
}
NodeGraphMessage::ShakeNode => {
let Some(drag_start) = &self.drag_start else {
log::error!("Drag start should be initialized when shaking a node");
return;
};

let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
return;
};
Expand All @@ -1464,9 +1432,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
.inverse()
.transform_point2(viewport_location);

// Collect the distance to move the shaken nodes after the undo
let graph_delta = IVec2::new(((point.x - drag_start.0.start_x) / 24.).round() as i32, ((point.y - drag_start.0.start_y) / 24.).round() as i32);

// Undo to the state of the graph before shaking
responses.add(DocumentMessage::AbortTransaction);

Expand Down Expand Up @@ -1571,7 +1536,9 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
}
}
}
responses.add(NodeGraphMessage::ShiftSelectedNodesByAmount { graph_delta, rubber_band: false });
if let Some(drag_start) = self.drag_start.as_ref() {
sync_selected_node_position_with_mouse(network_interface, breadcrumb_network_path, drag_start, point, responses);
}
responses.add(NodeGraphMessage::RunDocumentGraph);
responses.add(NodeGraphMessage::SendGraph);
}
Expand Down Expand Up @@ -2749,8 +2716,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 gragging 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(|(_, dragged)| *dragged);
// 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);

// A box selection is in progress
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
Expand Down Expand Up @@ -2796,7 +2763,6 @@ impl Default for NodeGraphMessageHandler {
has_selection: false,
widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: Vec::new() }],
drag_start: None,
begin_dragging: false,
node_has_moved_in_drag: false,
shift_without_push: false,
box_selection_start: None,
Expand Down Expand Up @@ -2827,7 +2793,6 @@ impl PartialEq for NodeGraphMessageHandler {
&& self.has_selection == other.has_selection
&& self.widgets == other.widgets
&& self.drag_start == other.drag_start
&& self.begin_dragging == other.begin_dragging
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
&& self.box_selection_start == other.box_selection_start
&& self.initial_disconnecting == other.initial_disconnecting
Expand All @@ -2837,3 +2802,24 @@ impl PartialEq for NodeGraphMessageHandler {
&& self.context_menu == other.context_menu
}
}

/// Returns whether the nodes have been moved
fn sync_selected_node_position_with_mouse(
network_interface: &mut NodeNetworkInterface,
breadcrumb_network_path: &[NodeId],
drag_start: &DragStart,
mouse_position_node_graph_space: DVec2,
responses: &mut VecDeque<Message>,
) -> 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
}
17 changes: 13 additions & 4 deletions editor/src/messages/portfolio/document/node_graph/utility_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,21 @@ pub struct FrontendNodeType {
pub input_types: Vec<String>,
}

/// 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 start_x: f64,
pub start_y: f64,
pub round_x: i32,
pub round_y: i32,
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)]
Expand Down