From b3c30f466ebdae57c7fc04747b2a805d48fc1e55 Mon Sep 17 00:00:00 2001 From: krVatsal Date: Sun, 15 Feb 2026 20:23:36 +0530 Subject: [PATCH 1/2] added feature to snap at midpoint while using path tool --- .../messages/tool/tool_messages/path_tool.rs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 542a6f0a8c..d691f270b7 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -1974,7 +1974,7 @@ impl Fsm for PathToolFsmState { // Draw the snapping axis lines if tool_data.snapping_axis.is_some() { let Some(axis) = tool_data.snapping_axis else { return self }; - let origin = tool_data.drag_start_pos; + let origin = tool_data.snap_manager.indicator_pos().unwrap_or(tool_data.drag_start_pos); let viewport_diagonal = viewport.size().into_dvec2().length(); let faded = |color: &str| { @@ -2116,16 +2116,32 @@ impl Fsm for PathToolFsmState { } let break_molding = input.keyboard.get(break_colinear_molding as usize); + let snap_axis_state = input.keyboard.get(snap_angle as usize); // Logic for molding segment if let Some(segment) = &mut tool_data.segment && let Some(molding_segment_handles) = tool_data.molding_info { + // Constrain molding to a single axis when Shift is held + let mouse_position = if snap_axis_state { + let delta = input.mouse.position - tool_data.drag_start_pos; + let axis = if delta.x.abs() >= delta.y.abs() { Axis::X } else { Axis::Y }; + tool_data.snapping_axis = Some(axis); + match axis { + Axis::X => DVec2::new(input.mouse.position.x, tool_data.drag_start_pos.y), + Axis::Y => DVec2::new(tool_data.drag_start_pos.x, input.mouse.position.y), + _ => input.mouse.position, + } + } else { + tool_data.snapping_axis = None; + input.mouse.position + }; + tool_data.temporary_adjacent_handles_while_molding = segment.mold_handle_positions( document, responses, molding_segment_handles, - input.mouse.position, + mouse_position, break_molding, tool_data.temporary_adjacent_handles_while_molding, ); @@ -2380,6 +2396,7 @@ impl Fsm for PathToolFsmState { tool_data.molding_segment = false; tool_data.temporary_adjacent_handles_while_molding = None; tool_data.angle_locked = false; + tool_data.snapping_axis = None; responses.add(DocumentMessage::AbortTransaction); tool_data.snap_manager.cleanup(responses); PathToolFsmState::Ready From 939e091a9068e864e145abf7dbb2314cdb913cb2 Mon Sep 17 00:00:00 2001 From: krVatsal Date: Tue, 17 Feb 2026 10:55:03 +0530 Subject: [PATCH 2/2] fix axes to be at midpoint of vertices --- .../messages/tool/tool_messages/path_tool.rs | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index d691f270b7..d689367732 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -590,6 +590,7 @@ struct PathToolData { last_clicked_point_was_selected: bool, last_clicked_segment_was_selected: bool, snapping_axis: Option, + snap_axis_origin: Option, alt_clicked_on_anchor: bool, alt_dragging_from_anchor: bool, angle_locked: bool, @@ -1974,7 +1975,7 @@ impl Fsm for PathToolFsmState { // Draw the snapping axis lines if tool_data.snapping_axis.is_some() { let Some(axis) = tool_data.snapping_axis else { return self }; - let origin = tool_data.snap_manager.indicator_pos().unwrap_or(tool_data.drag_start_pos); + let origin = tool_data.snap_axis_origin.or_else(|| tool_data.snap_manager.indicator_pos()).unwrap_or(tool_data.drag_start_pos); let viewport_diagonal = viewport.size().into_dvec2().length(); let faded = |color: &str| { @@ -2124,16 +2125,35 @@ impl Fsm for PathToolFsmState { { // Constrain molding to a single axis when Shift is held let mouse_position = if snap_axis_state { - let delta = input.mouse.position - tool_data.drag_start_pos; + // Calculate the midpoint between the segment's two anchor endpoints for the axis overlay + let midpoint = if let Some(vector) = document.network_interface.compute_modified_vector(segment.layer()) { + let transform = document.metadata().transform_to_viewport(segment.layer()); + let points = segment.points(); + let pos1 = vector.point_domain.position_from_id(points[0]); + let pos2 = vector.point_domain.position_from_id(points[1]); + if let (Some(p1), Some(p2)) = (pos1, pos2) { + (transform.transform_point2(p1) + transform.transform_point2(p2)) / 2.0 + } else { + tool_data.drag_start_pos + } + } else { + tool_data.drag_start_pos + }; + tool_data.snap_axis_origin = Some(midpoint); + + // Constrain mouse movement relative to drag start so molding delta stays correct + let drag_start = tool_data.drag_start_pos; + let delta = input.mouse.position - drag_start; let axis = if delta.x.abs() >= delta.y.abs() { Axis::X } else { Axis::Y }; tool_data.snapping_axis = Some(axis); match axis { - Axis::X => DVec2::new(input.mouse.position.x, tool_data.drag_start_pos.y), - Axis::Y => DVec2::new(tool_data.drag_start_pos.x, input.mouse.position.y), + Axis::X => DVec2::new(input.mouse.position.x, drag_start.y), + Axis::Y => DVec2::new(drag_start.x, input.mouse.position.y), _ => input.mouse.position, } } else { tool_data.snapping_axis = None; + tool_data.snap_axis_origin = None; input.mouse.position }; @@ -2397,6 +2417,7 @@ impl Fsm for PathToolFsmState { tool_data.temporary_adjacent_handles_while_molding = None; tool_data.angle_locked = false; tool_data.snapping_axis = None; + tool_data.snap_axis_origin = None; responses.add(DocumentMessage::AbortTransaction); tool_data.snap_manager.cleanup(responses); PathToolFsmState::Ready @@ -2645,6 +2666,7 @@ impl Fsm for PathToolFsmState { } tool_data.snapping_axis = None; + tool_data.snap_axis_origin = None; tool_data.sliding_point_info = None; if drag_occurred || extend_selection {