From 274998c9cdef54ace41e03404701974be6aab71e Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Wed, 12 Mar 2025 22:35:48 +0530
Subject: [PATCH 01/21] added handle_types and refactored the
 handle_adjustments

---
 .../messages/tool/tool_messages/pen_tool.rs   | 211 ++++++++----------
 1 file changed, 95 insertions(+), 116 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 50e06ef16c..5f4e497adc 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -263,6 +263,15 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
+#[derive(Clone, Debug, Default)]
+enum TargetHandle {
+	HandleEnd,
+	PrimaryHandle(SegmentId),
+	EndHandle(SegmentId),
+	#[default]
+	None,
+}
+
 #[derive(Clone, Debug, Default)]
 struct PenToolData {
 	snap_manager: SnapManager,
@@ -290,6 +299,7 @@ struct PenToolData {
 	end_point: Option<PointId>,
 	end_point_segment: Option<SegmentId>,
 	draw_mode: DrawMode,
+	handle_type: TargetHandle,
 }
 impl PenToolData {
 	fn latest_point(&self) -> Option<&LastPoint> {
@@ -306,6 +316,53 @@ impl PenToolData {
 		self.latest_points.push(point);
 	}
 
+	fn update_handle_custom(&mut self, vector_data: &VectorData) {
+		let Some((point, segment)) = self.end_point.zip(self.end_point_segment) else {
+			self.update_handle_type(TargetHandle::None);
+			return;
+		};
+
+		if vector_data.segment_start_from_id(segment) == Some(point) {
+			self.update_handle_type(TargetHandle::PrimaryHandle(segment));
+			return;
+		}
+		self.update_handle_type(TargetHandle::EndHandle(segment));
+	}
+
+	fn update_handle_type(&mut self, handle_type: TargetHandle) {
+		self.handle_type = handle_type;
+	}
+
+	fn update_target_handle_pos(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
+		match self.handle_type {
+			TargetHandle::PrimaryHandle(segment) => {
+				let relative_position = delta - self.next_point;
+				let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position };
+				responses.add(GraphOperationMessage::Vector { layer, modification_type });
+			}
+			TargetHandle::HandleEnd => {
+				if let Some(handle) = self.handle_end.as_mut() {
+					*handle = delta;
+				}
+			}
+			TargetHandle::EndHandle(segment) => {
+				let relative_position = delta - self.next_point;
+				let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
+				responses.add(GraphOperationMessage::Vector { layer, modification_type });
+			}
+			TargetHandle::None => {}
+		}
+	}
+
+	fn target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
+		match self.handle_type {
+			TargetHandle::PrimaryHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(&vector_data),
+			TargetHandle::EndHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(&vector_data),
+			TargetHandle::HandleEnd => self.handle_end,
+			TargetHandle::None => None,
+		}
+	}
+
 	// When the vector data transform changes, the positions of the points must be recalculated.
 	fn recalculate_latest_points_position(&mut self, document: &DocumentMessageHandler) {
 		let selected_nodes = document.network_interface.selected_nodes();
@@ -336,6 +393,7 @@ impl PenToolData {
 
 		let transform = document.metadata().document_to_viewport * transform;
 		let on_top = transform.transform_point2(self.next_point).distance_squared(transform.transform_point2(last_pos)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2);
+		self.update_handle_type(TargetHandle::HandleEnd);
 		if on_top {
 			self.handle_end = None;
 			self.handle_mode = HandleMode::Free;
@@ -435,17 +493,12 @@ impl PenToolData {
 		self.next_handle_start = self.compute_snapped_angle(snap_data, transform, colinear, mouse, Some(self.next_point), false);
 		let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
-		// Check if the handle is the start of the segment
-		let mut is_start = false;
-		if let Some((anchor, segment)) = self.end_point.zip(self.end_point_segment) {
-			is_start = vector_data.segment_start_from_id(segment) == Some(anchor);
-		}
 
 		match self.handle_mode {
 			HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => {
 				self.g1_continuous = true;
-				self.colinear(responses, layer, self.next_handle_start, self.next_point, &vector_data, is_start);
-				self.adjust_handle_length(responses, layer, &vector_data, is_start);
+				self.apply_colinear_constraint(responses, layer, self.next_handle_start, self.next_point, &vector_data);
+				self.adjust_handle_length(responses, layer, &vector_data);
 			}
 			HandleMode::Free => {
 				self.g1_continuous = false;
@@ -458,127 +511,50 @@ impl PenToolData {
 	}
 
 	/// Makes the opposite handle equidistant or locks its length.
-	fn adjust_handle_length(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData, is_start: bool) {
-		let Some(latest) = self.latest_point() else { return };
-		let anchor_pos = latest.pos;
-
+	fn adjust_handle_length(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData) {
 		match self.handle_mode {
-			HandleMode::ColinearEquidistant => self.adjust_equidistant_handle(anchor_pos, responses, layer, vector_data, is_start),
-			HandleMode::ColinearLocked => self.adjust_locked_length_handle(anchor_pos, responses, layer, is_start),
+			HandleMode::ColinearEquidistant => {
+				if self.modifiers.break_handle {
+					// Store handle for later restoration only when Alt is first pressed
+					if !self.alt_press {
+						self.previous_handle_end_pos = self.target_handle_position(vector_data);
+						self.alt_press = true;
+					}
+
+					// Set handle to opposite position of the other handle
+					let new_position = self.next_point * 2. - self.next_handle_start;
+					self.update_target_handle_pos(responses, new_position, layer);
+				} else if self.alt_press {
+					// Restore the previous handle position when Alt is released
+					if let Some(previous_handle) = self.previous_handle_end_pos {
+						self.update_target_handle_pos(responses, previous_handle, layer);
+					}
+					self.alt_press = false;
+					self.previous_handle_end_pos = None;
+				}
+			}
+			HandleMode::ColinearLocked => {
+				if !self.modifiers.break_handle {
+					let new_position = self.next_point * 2. - self.next_handle_start;
+					self.update_target_handle_pos(responses, new_position, layer);
+				}
+			}
 			HandleMode::Free => {} // No adjustments needed in free mode
 		}
 	}
 
-	fn colinear(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, handle_start: DVec2, anchor_pos: DVec2, vector_data: &VectorData, is_start: bool) {
+	fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, handle_start: DVec2, anchor_pos: DVec2, vector_data: &VectorData) {
 		let Some(direction) = (anchor_pos - handle_start).try_normalize() else {
 			log::trace!("Skipping colinear adjustment: handle_start and anchor_point are too close!");
 			return;
 		};
 
-		let Some(handle_offset) = self.get_handle_offset(anchor_pos, vector_data, is_start) else { return };
-		let new_handle_position = anchor_pos + handle_offset * direction;
-
-		self.update_handle_position(new_handle_position, anchor_pos, responses, layer, is_start);
-	}
-
-	fn get_handle_offset(&self, anchor_pos: DVec2, vector_data: &VectorData, is_start: bool) -> Option<f64> {
-		if is_start {
-			let segment = self.end_point_segment?;
-			let handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data)?;
-			return Some((handle - anchor_pos).length());
-		}
-
-		if self.draw_mode == DrawMode::ContinuePath {
-			return self.handle_end.map(|handle| (handle - anchor_pos).length()).or_else(|| {
-				self.end_point_segment
-					.and_then(|segment| Some((ManipulatorPointId::EndHandle(segment).get_position(vector_data)? - anchor_pos).length()))
-			});
-		}
-
-		let handle = ManipulatorPointId::EndHandle(self.end_point_segment?).get_position(vector_data);
-		if let Some(handle) = handle {
-			return Some((handle - anchor_pos).length());
-		}
-		None
-	}
-
-	fn adjust_equidistant_handle(&mut self, anchor_pos: DVec2, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData, is_start: bool) {
-		if self.modifiers.break_handle {
-			self.store_handle(vector_data, is_start);
-			self.alt_press = true;
-			let new_position = self.next_point * 2. - self.next_handle_start;
-			self.update_handle_position(new_position, anchor_pos, responses, layer, is_start);
-		} else {
-			self.restore_previous_handle(anchor_pos, responses, layer, is_start);
-		}
-	}
-
-	fn adjust_locked_length_handle(&mut self, anchor_pos: DVec2, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, is_start: bool) {
-		if !self.modifiers.break_handle {
-			let new_position = self.next_point * 2. - self.next_handle_start;
-			self.update_handle_position(new_position, anchor_pos, responses, layer, is_start);
-		}
-	}
-
-	/// Temporarily stores the opposite handle position to revert back when Alt is released in equidistant mode.
-	fn store_handle(&mut self, vector_data: &VectorData, is_start: bool) {
-		if !self.alt_press {
-			self.previous_handle_end_pos = if is_start {
-				let Some(segment) = self.end_point_segment else { return };
-				ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data)
-			} else if self.draw_mode == DrawMode::ContinuePath {
-				self.handle_end.or_else(|| {
-					let segment = self.end_point_segment?;
-					ManipulatorPointId::EndHandle(segment).get_position(vector_data)
-				})
-			} else {
-				let Some(segment) = self.end_point_segment else { return };
-				let end_handle = ManipulatorPointId::EndHandle(segment);
-				end_handle.get_position(vector_data)
-			};
-		}
-	}
-
-	fn restore_previous_handle(&mut self, anchor_pos: DVec2, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, is_start: bool) {
-		if self.alt_press {
-			self.alt_press = false;
-			if let Some(previous_handle) = self.previous_handle_end_pos {
-				self.update_handle_position(previous_handle, anchor_pos, responses, layer, is_start);
-			}
-			self.previous_handle_end_pos = None; // Reset storage
-		}
-	}
-
-	fn update_handle_position(&mut self, new_position: DVec2, anchor_pos: DVec2, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, is_start: bool) {
-		let relative_position = new_position - anchor_pos;
-
-		if is_start {
-			let modification_type = VectorModificationType::SetPrimaryHandle {
-				segment: self
-					.end_point_segment
-					.expect("In update_handle_position(), if `is_start` is true then `end_point_segment` should exist"),
-				relative_position,
-			};
-			responses.add(GraphOperationMessage::Vector { layer, modification_type });
+		let Some(handle_offset) = self.target_handle_position(vector_data).map(|handle| (handle - anchor_pos).length()) else {
 			return;
-		}
-
-		if self.draw_mode == DrawMode::ContinuePath {
-			if let Some(handle) = self.handle_end.as_mut() {
-				*handle = new_position;
-				return;
-			}
-
-			let Some(segment) = self.end_point_segment else { return };
-			let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
-			responses.add(GraphOperationMessage::Vector { layer, modification_type });
-			return;
-		}
-
-		let Some(segment) = self.end_point_segment else { return };
+		};
 
-		let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
-		responses.add(GraphOperationMessage::Vector { layer, modification_type });
+		let new_handle_position = anchor_pos + handle_offset * direction;
+		self.update_target_handle_pos(responses, new_handle_position, layer);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
@@ -740,6 +716,7 @@ impl PenToolData {
 		tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
 		self.end_point_segment = None;
 		self.draw_mode = DrawMode::ContinuePath;
+		self.handle_type = TargetHandle::HandleEnd;
 		responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
 
 		// This causes the following message to be run only after the next graph evaluation runs and the transforms are updated
@@ -820,6 +797,7 @@ impl PenToolData {
 			let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 			let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 			self.end_point_segment = segment;
+			self.update_handle_custom(&vector_data);
 		}
 	}
 
@@ -1235,6 +1213,7 @@ impl Fsm for PenToolFsmState {
 					colinear,
 				},
 			) => {
+				log::info!("{:?}", tool_data.handle_type);
 				tool_data.modifiers = ModifierState {
 					snap_angle: input.keyboard.key(snap_angle),
 					lock_angle: input.keyboard.key(lock_angle),

From 32581403ea3e59f6df90c0d2050addcf37f8018f Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Thu, 13 Mar 2025 10:31:33 +0530
Subject: [PATCH 02/21] anchor move refactor

---
 .../messages/tool/tool_messages/pen_tool.rs   | 78 ++++---------------
 1 file changed, 13 insertions(+), 65 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index ffed73964c..161ce3960e 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -528,8 +528,8 @@ impl PenToolData {
 		mouse: &DVec2,
 		vector_data: &VectorData,
 		input: &InputPreprocessorMessageHandler,
-		is_start: bool,
 	) -> Option<DVec2> {
+		let handle_pos = self.target_handle_position(vector_data);
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
@@ -543,34 +543,14 @@ impl PenToolData {
 		let snapped_near_handle_start = snap.free_snap(&snap_data, &handle_start, SnapTypeConfiguration::default());
 		let snapped_anchor = snap.free_snap(&snap_data, &anchor, SnapTypeConfiguration::default());
 
-		let handle_snap_option = if let Some(handle_end) = self.handle_end {
-			let handle_offset = transform.transform_point2(handle_end - self.next_handle_start);
-			let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
-			Some((handle_end, handle_snap))
-		} else {
-			// Otherwise use either primary or end handle based on is_start flag
-			if is_start {
-				let primary_handle_id = ManipulatorPointId::PrimaryHandle(self.end_point_segment.unwrap());
-				match primary_handle_id.get_position(vector_data) {
-					Some(primary_handle) => {
-						let handle_offset = transform.transform_point2(primary_handle - self.next_handle_start);
-						let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
-						Some((primary_handle, handle_snap))
-					}
-					None => None,
-				}
-			} else {
-				let end_handle = self.end_point_segment.and_then(|handle| ManipulatorPointId::EndHandle(handle).get_position(vector_data));
-				match end_handle {
-					Some(end_handle) => {
-						let handle_offset = transform.transform_point2(end_handle - self.next_handle_start);
-						let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
-						Some((end_handle, handle_snap))
-					}
-					None => None,
-				}
+		let handle_snap_option = handle_pos.and_then(|handle| match self.handle_type {
+			TargetHandle::None => None,
+			_ => {
+				let handle_offset = transform.transform_point2(handle - self.next_handle_start);
+				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
+				Some((handle, handle_snap))
 			}
-		};
+		});
 
 		let mut delta: DVec2;
 		let best_snapped = if snapped_near_handle_start.other_snap_better(&snapped_anchor) {
@@ -609,53 +589,27 @@ impl PenToolData {
 		};
 
 		latest.pos += delta;
-
 		let modification_type = VectorModificationType::ApplyPointDelta { point: latest.id, delta };
-
 		responses.add(GraphOperationMessage::Vector { layer, modification_type });
 
 		responses.add(OverlaysMessage::Draw);
 		Some(PenToolFsmState::DraggingHandle(self.handle_mode))
 	}
 
-	fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>, is_start: bool, vector_data: &VectorData) {
+	fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>, vector_data: &VectorData) {
 		if let Some(latest_pt) = self.latest_point_mut() {
 			latest_pt.pos += delta;
 		}
 
 		let Some(end_point) = self.end_point else { return };
-
-		// Move anchor point
 		let modification_type_anchor = VectorModificationType::ApplyPointDelta { point: end_point, delta };
-
 		responses.add(GraphOperationMessage::Vector {
 			layer,
 			modification_type: modification_type_anchor,
 		});
 
-		// Check if the opposite handle exist and move it
-		let Some(segment) = self.end_point_segment else { return };
-		// Get handle positions
-		let handle_end = ManipulatorPointId::EndHandle(segment).get_position(vector_data);
-		let handle_start = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data);
-
-		let handle_modification_type: Option<VectorModificationType> = if is_start {
-			let Some(handle_start) = handle_start else { return };
-			Some(VectorModificationType::SetPrimaryHandle {
-				segment,
-				relative_position: handle_start + delta - self.next_point,
-			})
-		} else {
-			let Some(handle_end) = handle_end else { return };
-			Some(VectorModificationType::SetEndHandle {
-				segment,
-				relative_position: handle_end + delta - self.next_point,
-			})
-		};
-
-		if let Some(modification_type) = handle_modification_type {
-			responses.add(GraphOperationMessage::Vector { layer, modification_type });
-		}
+		let Some(handle_pos) = self.target_handle_position(vector_data) else { return };
+		self.update_target_handle_pos(responses, handle_pos + delta, layer);
 	}
 
 	fn drag_handle(
@@ -673,14 +627,8 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
 
-		// Check if the handle is the start of the segment
-		let mut is_start = false;
-		if let Some((anchor, segment)) = self.end_point.zip(self.end_point_segment) {
-			is_start = vector_data.segment_start_from_id(segment) == Some(anchor);
-		}
-
 		if self.modifiers.move_anchor_with_handles {
-			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input, is_start) else {
+			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
 				return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 			};
 
@@ -694,7 +642,7 @@ impl PenToolData {
 			if let Some(handle) = self.handle_end.as_mut() {
 				*handle += delta;
 			} else {
-				self.move_anchor_and_handles(delta, layer, responses, is_start, &vector_data);
+				self.move_anchor_and_handles(delta, layer, responses, &vector_data);
 			}
 			responses.add(OverlaysMessage::Draw);
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));

From 308031bae545bb48d6d2611b0106a897ef3a5036 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Thu, 13 Mar 2025 17:35:32 +0530
Subject: [PATCH 03/21] code-todo-fix

---
 editor/src/messages/input_mapper/input_mappings.rs | 4 ++--
 editor/src/messages/tool/tool_messages/pen_tool.rs | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs
index 939e85353f..0ac3ee419c 100644
--- a/editor/src/messages/input_mapper/input_mappings.rs
+++ b/editor/src/messages/input_mapper/input_mappings.rs
@@ -255,8 +255,8 @@ pub fn input_mappings() -> Mapping {
 		entry!(PointerMove; refresh_keys=[Control, Alt, Shift, KeyC], action_dispatch=PenToolMessage::PointerMove { snap_angle: Shift, break_handle: Alt, lock_angle: Control, colinear: KeyC, move_anchor_with_handles: Space }),
 		entry!(KeyDown(MouseLeft); action_dispatch=PenToolMessage::DragStart { append_to_selected: Shift }),
 		entry!(KeyUp(MouseLeft); action_dispatch=PenToolMessage::DragStop),
-		entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Confirm),
-		entry!(KeyDown(Escape); action_dispatch=PenToolMessage::Confirm),
+		entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Abort),
+		entry!(KeyDown(Escape); action_dispatch=PenToolMessage::Abort),
 		entry!(KeyDown(Enter); action_dispatch=PenToolMessage::Confirm),
 		entry!(KeyDown(Delete); action_dispatch=PenToolMessage::RemovePreviousHandle),
 		entry!(KeyDown(Backspace); action_dispatch=PenToolMessage::RemovePreviousHandle),
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 161ce3960e..b2b8abcdc5 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -695,7 +695,7 @@ impl PenToolData {
 					self.update_target_handle_pos(responses, new_position, layer);
 				}
 			}
-			HandleMode::Free => {} // No adjustments needed in free mode
+			HandleMode::Free => {}
 		}
 	}
 

From 34f6f4359e608ee984d28dcd6606497ee0646e70 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Fri, 14 Mar 2025 09:41:42 +0530
Subject: [PATCH 04/21] removed-draw-mode

---
 editor/src/messages/tool/tool_messages/pen_tool.rs | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index b2b8abcdc5..26ec1e3e76 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -266,14 +266,6 @@ struct LastPoint {
 	in_segment: Option<SegmentId>,
 	handle_start: DVec2,
 }
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-enum DrawMode {
-	#[default]
-	/// Modifies the clicked endpoint segment, once you go to the ready mode you need to modify the handles of the next clicked endpoint segment
-	BreakPath,
-	/// Modifies the handle_end
-	ContinuePath,
-}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 enum HandleMode {
@@ -321,7 +313,6 @@ struct PenToolData {
 	/// The point that is being dragged
 	end_point: Option<PointId>,
 	end_point_segment: Option<SegmentId>,
-	draw_mode: DrawMode,
 	handle_type: TargetHandle,
 
 	snap_cache: SnapCache,
@@ -871,7 +862,6 @@ impl PenToolData {
 		tool_options.fill.apply_fill(layer, responses);
 		tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
 		self.end_point_segment = None;
-		self.draw_mode = DrawMode::ContinuePath;
 		self.handle_type = TargetHandle::HandleEnd;
 		responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
 
@@ -1370,7 +1360,6 @@ impl Fsm for PenToolFsmState {
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
 				tool_data.end_point = None;
-				tool_data.draw_mode = DrawMode::ContinuePath;
 				tool_data
 					.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
 					.unwrap_or(PenToolFsmState::PlacingAnchor)
@@ -1547,7 +1536,6 @@ impl Fsm for PenToolFsmState {
 			(PenToolFsmState::DraggingHandle(..) | PenToolFsmState::PlacingAnchor, PenToolMessage::Confirm) => {
 				responses.add(DocumentMessage::EndTransaction);
 				tool_data.handle_end = None;
-				tool_data.draw_mode = DrawMode::BreakPath;
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
 				tool_data.snap_manager.cleanup(responses);
@@ -1559,7 +1547,6 @@ impl Fsm for PenToolFsmState {
 				tool_data.handle_end = None;
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
-				tool_data.draw_mode = DrawMode::BreakPath;
 				tool_data.snap_manager.cleanup(responses);
 
 				responses.add(OverlaysMessage::Draw);

From 3e86424d79dac3cbbb4707f5346a17640812d6a3 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Sat, 15 Mar 2025 12:01:57 +0530
Subject: [PATCH 05/21] kind of works need to figure out snapping

---
 .../messages/input_mapper/input_mappings.rs   |   1 +
 .../messages/tool/tool_messages/pen_tool.rs   | 155 +++++++++++++-----
 2 files changed, 115 insertions(+), 41 deletions(-)

diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs
index 0ac3ee419c..201200ed11 100644
--- a/editor/src/messages/input_mapper/input_mappings.rs
+++ b/editor/src/messages/input_mapper/input_mappings.rs
@@ -253,6 +253,7 @@ pub fn input_mappings() -> Mapping {
 		//
 		// PenToolMessage
 		entry!(PointerMove; refresh_keys=[Control, Alt, Shift, KeyC], action_dispatch=PenToolMessage::PointerMove { snap_angle: Shift, break_handle: Alt, lock_angle: Control, colinear: KeyC, move_anchor_with_handles: Space }),
+		entry!(KeyDownNoRepeat(Tab);action_dispatch=PenToolMessage::SwapHandles),
 		entry!(KeyDown(MouseLeft); action_dispatch=PenToolMessage::DragStart { append_to_selected: Shift }),
 		entry!(KeyUp(MouseLeft); action_dispatch=PenToolMessage::DragStop),
 		entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Abort),
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 26ec1e3e76..f2b29661a4 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -88,6 +88,7 @@ pub enum PenToolMessage {
 	FinalPosition {
 		final_position: DVec2,
 	},
+	SwapHandles,
 }
 
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
@@ -186,9 +187,36 @@ impl LayoutHolder for PenTool {
 impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool {
 	fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
 		let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
-			self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
-			return;
+			match message {
+				ToolMessage::Pen(PenToolMessage::SwapHandles) => {
+					let document = &tool_data.document;
+					let selected_nodes = document.network_interface.selected_nodes();
+					let mut selected_layers = selected_nodes.selected_layers(document.metadata());
+					let layer = selected_layers.next().filter(|_| selected_layers.next().is_none());
+					let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
+						return;
+					};
+					match self.tool_data.handle_type {
+						TargetHandle::None => {}
+						TargetHandle::HandleStart => {
+							self.tool_data.update_handle_custom(&vector_data);
+						}
+						_ => {
+							let offset: Option<DVec2> = self.tool_data.target_handle_position(&vector_data).map(|handle| handle - self.tool_data.next_handle_start);
+							self.tool_data.offset_position = offset;
+							self.tool_data.update_handle_type(TargetHandle::HandleStart);
+						}
+					}
+					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
+					return;
+				}
+				_ => {
+					self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
+					return;
+				}
+			}
 		};
+
 		match action {
 			PenOptionsUpdate::OverlayModeType(overlay_mode_type) => {
 				self.options.pen_overlay_mode = overlay_mode_type;
@@ -235,6 +263,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
 				Abort,
 				RemovePreviousHandle,
 				GRS,
+				SwapHandles
 			),
 		}
 	}
@@ -278,9 +307,10 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, PartialEq)]
 enum TargetHandle {
 	HandleEnd,
+	HandleStart,
 	PrimaryHandle(SegmentId),
 	EndHandle(SegmentId),
 	#[default]
@@ -314,6 +344,7 @@ struct PenToolData {
 	end_point: Option<PointId>,
 	end_point_segment: Option<SegmentId>,
 	handle_type: TargetHandle,
+	offset_position: Option<DVec2>,
 
 	snap_cache: SnapCache,
 }
@@ -333,49 +364,77 @@ impl PenToolData {
 	}
 
 	fn update_handle_custom(&mut self, vector_data: &VectorData) {
-		let Some((point, segment)) = self.end_point.zip(self.end_point_segment) else {
-			self.update_handle_type(TargetHandle::None);
-			return;
+		let target_handle = match (self.handle_end, self.end_point, self.end_point_segment) {
+			(Some(_), _, _) => TargetHandle::HandleEnd,
+			(None, Some(point), Some(segment)) => {
+				if vector_data.segment_start_from_id(segment) == Some(point) {
+					TargetHandle::PrimaryHandle(segment)
+				} else {
+					TargetHandle::EndHandle(segment)
+				}
+			}
+			_ => TargetHandle::None,
 		};
 
-		if vector_data.segment_start_from_id(segment) == Some(point) {
-			self.update_handle_type(TargetHandle::PrimaryHandle(segment));
-			return;
-		}
-		self.update_handle_type(TargetHandle::EndHandle(segment));
+		self.update_handle_type(target_handle);
 	}
 
 	fn update_handle_type(&mut self, handle_type: TargetHandle) {
 		self.handle_type = handle_type;
 	}
 
-	fn update_target_handle_pos(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
+	fn update_target_handle_pos(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
 		match self.handle_type {
-			TargetHandle::PrimaryHandle(segment) => {
-				let relative_position = delta - self.next_point;
-				let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position };
-				responses.add(GraphOperationMessage::Vector { layer, modification_type });
-			}
-			TargetHandle::HandleEnd => {
-				if let Some(handle) = self.handle_end.as_mut() {
-					*handle = delta;
-				}
-			}
-			TargetHandle::EndHandle(segment) => {
-				let relative_position = delta - self.next_point;
-				let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
-				responses.add(GraphOperationMessage::Vector { layer, modification_type });
+			TargetHandle::HandleStart => {
+				self.next_handle_start = delta;
 			}
 			TargetHandle::None => {}
+			_ => {
+				self.update_end_targets(responses, delta, layer, vector_data);
+			}
+		}
+	}
+
+	fn update_end_targets(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
+		if let Some(handle) = self.handle_end.as_mut() {
+			*handle = delta;
+			return;
+		}
+
+		if let Some((segment, anchor_point)) = self.end_point_segment.zip(self.end_point) {
+			let relative_position = delta - self.next_point;
+			let modification_type = if vector_data.segment_start_from_id(segment) == Some(anchor_point) {
+				VectorModificationType::SetPrimaryHandle { segment, relative_position }
+			} else {
+				VectorModificationType::SetEndHandle { segment, relative_position }
+			};
+			responses.add(GraphOperationMessage::Vector { layer, modification_type });
 		}
 	}
 
 	fn target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
 		match self.handle_type {
-			TargetHandle::PrimaryHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(&vector_data),
-			TargetHandle::EndHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(&vector_data),
+			TargetHandle::PrimaryHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data),
+			TargetHandle::EndHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data),
 			TargetHandle::HandleEnd => self.handle_end,
+			TargetHandle::HandleStart => Some(self.next_handle_start),
+			TargetHandle::None => None,
+		}
+	}
+
+	fn opposite_target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
+		match self.handle_type {
 			TargetHandle::None => None,
+			TargetHandle::HandleStart => self.handle_end.or_else(|| {
+				self.end_point_segment.zip(self.end_point).and_then(|(segment, anchor_point)| {
+					if vector_data.segment_start_from_id(segment) == Some(anchor_point) {
+						ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data)
+					} else {
+						ManipulatorPointId::EndHandle(segment).get_position(vector_data)
+					}
+				})
+			}),
+			_ => Some(self.next_handle_start),
 		}
 	}
 
@@ -441,6 +500,7 @@ impl PenToolData {
 		let next_handle_start = self.next_handle_start;
 		let handle_start = self.latest_point()?.handle_start;
 		let mouse = snap_data.input.mouse.position;
+		self.offset_position = None;
 		let Some(handle_end) = self.handle_end else {
 			responses.add(DocumentMessage::EndTransaction);
 			self.handle_end = Some(next_handle_start);
@@ -600,7 +660,7 @@ impl PenToolData {
 		});
 
 		let Some(handle_pos) = self.target_handle_position(vector_data) else { return };
-		self.update_target_handle_pos(responses, handle_pos + delta, layer);
+		self.update_target_handle_pos(responses, handle_pos + delta, layer, vector_data);
 	}
 
 	fn drag_handle(
@@ -617,6 +677,7 @@ impl PenToolData {
 		let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
+		let viewport = document.metadata().transform_to_viewport(layer);
 
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
@@ -638,13 +699,18 @@ impl PenToolData {
 			responses.add(OverlaysMessage::Draw);
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 		}
-
-		self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
+		if self.handle_type == TargetHandle::HandleStart {
+			let mouse_offset = mouse + viewport.transform_point2(self.offset_position.unwrap());
+			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
+			self.update_end_targets(responses, mouse_pos, layer, &vector_data);
+		} else {
+			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
+		}
 
 		match self.handle_mode {
 			HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => {
 				self.g1_continuous = true;
-				self.apply_colinear_constraint(responses, layer, self.next_handle_start, self.next_point, &vector_data);
+				self.apply_colinear_constraint(responses, layer, self.next_point, &vector_data);
 				self.adjust_handle_length(responses, layer, &vector_data);
 			}
 			HandleMode::Free => {
@@ -669,12 +735,14 @@ impl PenToolData {
 					}
 
 					// Set handle to opposite position of the other handle
-					let new_position = self.next_point * 2. - self.next_handle_start;
-					self.update_target_handle_pos(responses, new_position, layer);
+					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
+						return;
+					};
+					self.update_target_handle_pos(responses, new_position, layer, vector_data);
 				} else if self.alt_press {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
-						self.update_target_handle_pos(responses, previous_handle, layer);
+						self.update_target_handle_pos(responses, previous_handle, layer, vector_data);
 					}
 					self.alt_press = false;
 					self.previous_handle_end_pos = None;
@@ -682,16 +750,22 @@ impl PenToolData {
 			}
 			HandleMode::ColinearLocked => {
 				if !self.modifiers.break_handle {
-					let new_position = self.next_point * 2. - self.next_handle_start;
-					self.update_target_handle_pos(responses, new_position, layer);
+					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
+						return;
+					};
+					self.update_target_handle_pos(responses, new_position, layer, vector_data);
 				}
 			}
 			HandleMode::Free => {}
 		}
 	}
 
-	fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, handle_start: DVec2, anchor_pos: DVec2, vector_data: &VectorData) {
-		let Some(direction) = (anchor_pos - handle_start).try_normalize() else {
+	fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, anchor_pos: DVec2, vector_data: &VectorData) {
+		let Some(handle) = self.opposite_target_handle_position(vector_data) else {
+			return;
+		};
+
+		let Some(direction) = (anchor_pos - handle).try_normalize() else {
 			log::trace!("Skipping colinear adjustment: handle_start and anchor_point are too close!");
 			return;
 		};
@@ -701,7 +775,7 @@ impl PenToolData {
 		};
 
 		let new_handle_position = anchor_pos + handle_offset * direction;
-		self.update_target_handle_pos(responses, new_handle_position, layer);
+		self.update_target_handle_pos(responses, new_handle_position, layer, vector_data);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
@@ -1374,7 +1448,6 @@ impl Fsm for PenToolFsmState {
 					move_anchor_with_handles,
 				},
 			) => {
-				log::info!("{:?}", tool_data.handle_type);
 				tool_data.modifiers = ModifierState {
 					snap_angle: input.keyboard.key(snap_angle),
 					lock_angle: input.keyboard.key(lock_angle),

From 6b7ba1149f127c0be7529f91da9c0ad59d5b0c68 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Sat, 15 Mar 2025 13:10:31 +0530
Subject: [PATCH 06/21] some refactoring

---
 .../messages/tool/tool_messages/pen_tool.rs   | 101 +++++++++---------
 1 file changed, 53 insertions(+), 48 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index f2b29661a4..22d738463b 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -202,7 +202,10 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
 							self.tool_data.update_handle_custom(&vector_data);
 						}
 						_ => {
-							let offset: Option<DVec2> = self.tool_data.target_handle_position(&vector_data).map(|handle| handle - self.tool_data.next_handle_start);
+							let offset: Option<DVec2> = self
+								.tool_data
+								.target_handle_position(self.tool_data.handle_type, &vector_data)
+								.map(|handle| handle - self.tool_data.next_handle_start);
 							self.tool_data.offset_position = offset;
 							self.tool_data.update_handle_type(TargetHandle::HandleStart);
 						}
@@ -307,7 +310,7 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	HandleEnd,
 	HandleStart,
@@ -363,8 +366,8 @@ impl PenToolData {
 		self.latest_points.push(point);
 	}
 
-	fn update_handle_custom(&mut self, vector_data: &VectorData) {
-		let target_handle = match (self.handle_end, self.end_point, self.end_point_segment) {
+	fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
+		match (self.handle_end, self.end_point, self.end_point_segment) {
 			(Some(_), _, _) => TargetHandle::HandleEnd,
 			(None, Some(point), Some(segment)) => {
 				if vector_data.segment_start_from_id(segment) == Some(point) {
@@ -374,46 +377,52 @@ impl PenToolData {
 				}
 			}
 			_ => TargetHandle::None,
-		};
+		}
+	}
 
+	fn update_handle_custom(&mut self, vector_data: &VectorData) {
+		let target_handle = self.check_end_handle_type(vector_data);
 		self.update_handle_type(target_handle);
 	}
 
+	fn get_opposite_handle_type(&mut self, vector_data: &VectorData) -> TargetHandle {
+		match self.handle_type {
+			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
+			TargetHandle::None => TargetHandle::None,
+			_ => TargetHandle::HandleStart,
+		}
+	}
+
 	fn update_handle_type(&mut self, handle_type: TargetHandle) {
 		self.handle_type = handle_type;
 	}
 
-	fn update_target_handle_pos(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
-		match self.handle_type {
+	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
+		match handle_type {
 			TargetHandle::HandleStart => {
 				self.next_handle_start = delta;
 			}
-			TargetHandle::None => {}
-			_ => {
-				self.update_end_targets(responses, delta, layer, vector_data);
+			TargetHandle::HandleEnd => {
+				if let Some(handle) = self.handle_end.as_mut() {
+					*handle = delta;
+				}
 			}
+			TargetHandle::EndHandle(segment) => {
+				let relative_position = delta - self.next_point;
+				let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
+				responses.add(GraphOperationMessage::Vector { layer, modification_type });
+			}
+			TargetHandle::PrimaryHandle(segment) => {
+				let relative_position = delta - self.next_point;
+				let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position };
+				responses.add(GraphOperationMessage::Vector { layer, modification_type });
+			}
+			TargetHandle::None => {}
 		}
 	}
 
-	fn update_end_targets(&mut self, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
-		if let Some(handle) = self.handle_end.as_mut() {
-			*handle = delta;
-			return;
-		}
-
-		if let Some((segment, anchor_point)) = self.end_point_segment.zip(self.end_point) {
-			let relative_position = delta - self.next_point;
-			let modification_type = if vector_data.segment_start_from_id(segment) == Some(anchor_point) {
-				VectorModificationType::SetPrimaryHandle { segment, relative_position }
-			} else {
-				VectorModificationType::SetEndHandle { segment, relative_position }
-			};
-			responses.add(GraphOperationMessage::Vector { layer, modification_type });
-		}
-	}
-
-	fn target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
-		match self.handle_type {
+	fn target_handle_position(&self, handle_type: TargetHandle, vector_data: &VectorData) -> Option<DVec2> {
+		match handle_type {
 			TargetHandle::PrimaryHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data),
 			TargetHandle::EndHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data),
 			TargetHandle::HandleEnd => self.handle_end,
@@ -425,15 +434,10 @@ impl PenToolData {
 	fn opposite_target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
 		match self.handle_type {
 			TargetHandle::None => None,
-			TargetHandle::HandleStart => self.handle_end.or_else(|| {
-				self.end_point_segment.zip(self.end_point).and_then(|(segment, anchor_point)| {
-					if vector_data.segment_start_from_id(segment) == Some(anchor_point) {
-						ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data)
-					} else {
-						ManipulatorPointId::EndHandle(segment).get_position(vector_data)
-					}
-				})
-			}),
+			TargetHandle::HandleStart => {
+				let opposite_target_handle = self.check_end_handle_type(vector_data);
+				self.target_handle_position(opposite_target_handle, vector_data)
+			}
 			_ => Some(self.next_handle_start),
 		}
 	}
@@ -580,7 +584,7 @@ impl PenToolData {
 		vector_data: &VectorData,
 		input: &InputPreprocessorMessageHandler,
 	) -> Option<DVec2> {
-		let handle_pos = self.target_handle_position(vector_data);
+		let handle_pos = self.target_handle_position(self.handle_type, vector_data);
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
@@ -659,8 +663,8 @@ impl PenToolData {
 			modification_type: modification_type_anchor,
 		});
 
-		let Some(handle_pos) = self.target_handle_position(vector_data) else { return };
-		self.update_target_handle_pos(responses, handle_pos + delta, layer, vector_data);
+		let Some(handle_pos) = self.target_handle_position(self.handle_type, vector_data) else { return };
+		self.update_target_handle_pos(self.handle_type, responses, handle_pos + delta, layer, vector_data);
 	}
 
 	fn drag_handle(
@@ -702,7 +706,8 @@ impl PenToolData {
 		if self.handle_type == TargetHandle::HandleStart {
 			let mouse_offset = mouse + viewport.transform_point2(self.offset_position.unwrap());
 			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
-			self.update_end_targets(responses, mouse_pos, layer, &vector_data);
+			let opposite_target = self.get_opposite_handle_type(&vector_data);
+			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer, &vector_data);
 		} else {
 			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
 		}
@@ -730,7 +735,7 @@ impl PenToolData {
 				if self.modifiers.break_handle {
 					// Store handle for later restoration only when Alt is first pressed
 					if !self.alt_press {
-						self.previous_handle_end_pos = self.target_handle_position(vector_data);
+						self.previous_handle_end_pos = self.target_handle_position(self.handle_type, vector_data);
 						self.alt_press = true;
 					}
 
@@ -738,11 +743,11 @@ impl PenToolData {
 					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(responses, new_position, layer, vector_data);
+					self.update_target_handle_pos(self.handle_type, responses, new_position, layer, vector_data);
 				} else if self.alt_press {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
-						self.update_target_handle_pos(responses, previous_handle, layer, vector_data);
+						self.update_target_handle_pos(self.handle_type, responses, previous_handle, layer, vector_data);
 					}
 					self.alt_press = false;
 					self.previous_handle_end_pos = None;
@@ -753,7 +758,7 @@ impl PenToolData {
 					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(responses, new_position, layer, vector_data);
+					self.update_target_handle_pos(self.handle_type, responses, new_position, layer, vector_data);
 				}
 			}
 			HandleMode::Free => {}
@@ -770,12 +775,12 @@ impl PenToolData {
 			return;
 		};
 
-		let Some(handle_offset) = self.target_handle_position(vector_data).map(|handle| (handle - anchor_pos).length()) else {
+		let Some(handle_offset) = self.target_handle_position(self.handle_type, vector_data).map(|handle| (handle - anchor_pos).length()) else {
 			return;
 		};
 
 		let new_handle_position = anchor_pos + handle_offset * direction;
-		self.update_target_handle_pos(responses, new_handle_position, layer, vector_data);
+		self.update_target_handle_pos(self.handle_type, responses, new_handle_position, layer, vector_data);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {

From 7cabb159d126d1083fb5127abc3edb2559a4918b Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Sun, 16 Mar 2025 12:14:46 +0530
Subject: [PATCH 07/21] refactor+overlays..need to fix the snapping and
 dragging

---
 .../messages/tool/tool_messages/pen_tool.rs   | 72 +++++++++++++------
 1 file changed, 51 insertions(+), 21 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 22d738463b..c8ec9534c3 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -7,6 +7,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
 use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
 use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
 use crate::messages::tool::common_functionality::graph_modification_utils::{self, merge_layers};
+use crate::messages::tool::common_functionality::shape_editor::ShapeState;
 use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
 use crate::messages::tool::common_functionality::utility_functions::{closest_point, should_extend};
 use bezier_rs::{Bezier, BezierHandles};
@@ -200,16 +201,16 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
 						TargetHandle::None => {}
 						TargetHandle::HandleStart => {
 							self.tool_data.update_handle_custom(&vector_data);
+							self.tool_data.cleanup_target_selections(tool_data.shape_editor, layer, tool_data.document);
 						}
 						_ => {
-							let offset: Option<DVec2> = self
-								.tool_data
-								.target_handle_position(self.tool_data.handle_type, &vector_data)
-								.map(|handle| handle - self.tool_data.next_handle_start);
-							self.tool_data.offset_position = offset;
+							self.tool_data.add_target_selections(tool_data.shape_editor, layer);
 							self.tool_data.update_handle_type(TargetHandle::HandleStart);
+							let offset = self.tool_data.opposite_target_handle_position(&vector_data).map(|opposite| opposite - self.tool_data.next_handle_start);
+							self.tool_data.offset_position = offset;
 						}
 					}
+					responses.add(OverlaysMessage::Draw);
 					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 					return;
 				}
@@ -385,7 +386,7 @@ impl PenToolData {
 		self.update_handle_type(target_handle);
 	}
 
-	fn get_opposite_handle_type(&mut self, vector_data: &VectorData) -> TargetHandle {
+	fn get_opposite_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
 		match self.handle_type {
 			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
 			TargetHandle::None => TargetHandle::None,
@@ -397,7 +398,7 @@ impl PenToolData {
 		self.handle_type = handle_type;
 	}
 
-	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier, vector_data: &VectorData) {
+	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
 		match handle_type {
 			TargetHandle::HandleStart => {
 				self.next_handle_start = delta;
@@ -432,13 +433,36 @@ impl PenToolData {
 	}
 
 	fn opposite_target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
+		let opposite_handle_type = self.get_opposite_handle_type(vector_data);
+		self.target_handle_position(opposite_handle_type, vector_data)
+	}
+
+	/// Remove the handles selected when swapping handles
+	fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) {
+		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
+			return;
+		};
+
+		let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
+			return;
+		};
+
+		match self.check_end_handle_type(&vector_data) {
+			TargetHandle::EndHandle(segment) => shape_state.deselect_point(ManipulatorPointId::EndHandle(segment)),
+			TargetHandle::PrimaryHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)),
+			_ => {}
+		}
+	}
+
+	fn add_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>) {
+		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
+			return;
+		};
+
 		match self.handle_type {
-			TargetHandle::None => None,
-			TargetHandle::HandleStart => {
-				let opposite_target_handle = self.check_end_handle_type(vector_data);
-				self.target_handle_position(opposite_target_handle, vector_data)
-			}
-			_ => Some(self.next_handle_start),
+			TargetHandle::EndHandle(segment) => shape_state.select_point(ManipulatorPointId::EndHandle(segment)),
+			TargetHandle::PrimaryHandle(segment) => shape_state.select_point(ManipulatorPointId::PrimaryHandle(segment)),
+			_ => {}
 		}
 	}
 
@@ -664,7 +688,7 @@ impl PenToolData {
 		});
 
 		let Some(handle_pos) = self.target_handle_position(self.handle_type, vector_data) else { return };
-		self.update_target_handle_pos(self.handle_type, responses, handle_pos + delta, layer, vector_data);
+		self.update_target_handle_pos(self.handle_type, responses, handle_pos + delta, layer);
 	}
 
 	fn drag_handle(
@@ -707,7 +731,7 @@ impl PenToolData {
 			let mouse_offset = mouse + viewport.transform_point2(self.offset_position.unwrap());
 			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
 			let opposite_target = self.get_opposite_handle_type(&vector_data);
-			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer, &vector_data);
+			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer);
 		} else {
 			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
 		}
@@ -743,11 +767,11 @@ impl PenToolData {
 					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(self.handle_type, responses, new_position, layer, vector_data);
+					self.update_target_handle_pos(self.handle_type, responses, new_position, layer);
 				} else if self.alt_press {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
-						self.update_target_handle_pos(self.handle_type, responses, previous_handle, layer, vector_data);
+						self.update_target_handle_pos(self.handle_type, responses, previous_handle, layer);
 					}
 					self.alt_press = false;
 					self.previous_handle_end_pos = None;
@@ -758,7 +782,7 @@ impl PenToolData {
 					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(self.handle_type, responses, new_position, layer, vector_data);
+					self.update_target_handle_pos(self.handle_type, responses, new_position, layer);
 				}
 			}
 			HandleMode::Free => {}
@@ -780,7 +804,7 @@ impl PenToolData {
 		};
 
 		let new_handle_position = anchor_pos + handle_offset * direction;
-		self.update_target_handle_pos(self.handle_type, responses, new_handle_position, layer, vector_data);
+		self.update_target_handle_pos(self.handle_type, responses, new_handle_position, layer);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
@@ -1328,7 +1352,8 @@ impl Fsm for PenToolFsmState {
 
 					if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, handle_end) {
 						// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
-						overlay_context.manipulator_handle(handle_end, false, None);
+						let selected = tool_data.handle_type == TargetHandle::HandleStart;
+						overlay_context.manipulator_handle(handle_end, selected, None);
 					}
 
 					if valid(anchor_start, handle_start) {
@@ -1349,7 +1374,8 @@ impl Fsm for PenToolFsmState {
 
 				if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, next_handle_start) {
 					// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
-					overlay_context.manipulator_handle(next_handle_start, false, None);
+					let selected = tool_data.handle_type != TargetHandle::HandleStart;
+					overlay_context.manipulator_handle(next_handle_start, selected, None);
 				}
 
 				if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) {
@@ -1439,6 +1465,8 @@ impl Fsm for PenToolFsmState {
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
 				tool_data.end_point = None;
+
+				tool_data.cleanup_target_selections(shape_editor, layer, document);
 				tool_data
 					.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
 					.unwrap_or(PenToolFsmState::PlacingAnchor)
@@ -1617,6 +1645,7 @@ impl Fsm for PenToolFsmState {
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
 				tool_data.snap_manager.cleanup(responses);
+				tool_data.cleanup_target_selections(shape_editor, layer, document);
 
 				PenToolFsmState::Ready
 			}
@@ -1626,6 +1655,7 @@ impl Fsm for PenToolFsmState {
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
 				tool_data.snap_manager.cleanup(responses);
+				tool_data.cleanup_target_selections(shape_editor, layer, document);
 
 				responses.add(OverlaysMessage::Draw);
 

From f4515103cc187dff8ba9f7230f4123839f60e9c7 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Sun, 16 Mar 2025 22:30:57 +0530
Subject: [PATCH 08/21] added docs

---
 .../messages/tool/tool_messages/pen_tool.rs   | 70 ++++++++++---------
 1 file changed, 38 insertions(+), 32 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index c8ec9534c3..0427d5a56d 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -188,37 +188,8 @@ impl LayoutHolder for PenTool {
 impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool {
 	fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, tool_data: &mut ToolActionHandlerData<'a>) {
 		let ToolMessage::Pen(PenToolMessage::UpdateOptions(action)) = message else {
-			match message {
-				ToolMessage::Pen(PenToolMessage::SwapHandles) => {
-					let document = &tool_data.document;
-					let selected_nodes = document.network_interface.selected_nodes();
-					let mut selected_layers = selected_nodes.selected_layers(document.metadata());
-					let layer = selected_layers.next().filter(|_| selected_layers.next().is_none());
-					let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
-						return;
-					};
-					match self.tool_data.handle_type {
-						TargetHandle::None => {}
-						TargetHandle::HandleStart => {
-							self.tool_data.update_handle_custom(&vector_data);
-							self.tool_data.cleanup_target_selections(tool_data.shape_editor, layer, tool_data.document);
-						}
-						_ => {
-							self.tool_data.add_target_selections(tool_data.shape_editor, layer);
-							self.tool_data.update_handle_type(TargetHandle::HandleStart);
-							let offset = self.tool_data.opposite_target_handle_position(&vector_data).map(|opposite| opposite - self.tool_data.next_handle_start);
-							self.tool_data.offset_position = offset;
-						}
-					}
-					responses.add(OverlaysMessage::Draw);
-					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
-					return;
-				}
-				_ => {
-					self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
-					return;
-				}
-			}
+			self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &self.options, responses, true);
+			return;
 		};
 
 		match action {
@@ -311,6 +282,7 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
+/// The handle which is opposite to the currently dragged handle under the cursor
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	HandleEnd,
@@ -367,6 +339,7 @@ impl PenToolData {
 		self.latest_points.push(point);
 	}
 
+	/// Check whether target handle is primary,end or 'self.handle_end'
 	fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
 		match (self.handle_end, self.end_point, self.end_point_segment) {
 			(Some(_), _, _) => TargetHandle::HandleEnd,
@@ -454,6 +427,7 @@ impl PenToolData {
 		}
 	}
 
+	/// Selects the handle which is currently dragged by the user  
 	fn add_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>) {
 		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
 			return;
@@ -728,10 +702,14 @@ impl PenToolData {
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 		}
 		if self.handle_type == TargetHandle::HandleStart {
-			let mouse_offset = mouse + viewport.transform_point2(self.offset_position.unwrap());
+			let mouse_offset = mouse + self.offset_position.unwrap();
+			log::info!("{:?}", mouse_offset);
+			log::info!("{:?}", self.handle_end.map(|handle| viewport.transform_point2(handle)));
+
 			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
 			let opposite_target = self.get_opposite_handle_type(&vector_data);
 			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer);
+			responses.add(OverlaysMessage::Draw);
 		} else {
 			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
 		}
@@ -1573,6 +1551,34 @@ impl Fsm for PenToolFsmState {
 
 				state
 			}
+			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
+				let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
+					return self;
+				};
+				match tool_data.handle_type {
+					TargetHandle::None => {}
+					TargetHandle::HandleStart => {
+						tool_data.offset_position = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
+
+						tool_data.update_handle_custom(&vector_data);
+						tool_data.cleanup_target_selections(shape_editor, layer, document);
+					}
+					_ => {
+						tool_data.add_target_selections(shape_editor, layer);
+
+						let viewport = layer.map(|layer| document.metadata().transform_to_viewport(layer));
+						let offset = tool_data
+							.target_handle_position(tool_data.handle_type, &vector_data)
+							.zip(viewport)
+							.map(|(opposite, transform)| transform.transform_point2(opposite - tool_data.next_handle_start));
+						tool_data.offset_position = offset;
+						tool_data.update_handle_type(TargetHandle::HandleStart);
+					}
+				}
+				responses.add(OverlaysMessage::Draw);
+				responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
+				self
+			}
 			(
 				PenToolFsmState::Ready,
 				PenToolMessage::PointerMove {

From ca346bc11050c0c6cb6a179ec7a830ac4778f260 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Mon, 17 Mar 2025 19:45:12 +0530
Subject: [PATCH 09/21] got stuck in space move

---
 .../messages/tool/tool_messages/pen_tool.rs   | 45 +++++++++++--------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 0427d5a56d..fd028ae4c6 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -320,8 +320,8 @@ struct PenToolData {
 	end_point: Option<PointId>,
 	end_point_segment: Option<SegmentId>,
 	handle_type: TargetHandle,
-	offset_position: Option<DVec2>,
-
+	handle_start_offset: Option<DVec2>,
+	handle_end_offset: Option<DVec2>,
 	snap_cache: SnapCache,
 }
 impl PenToolData {
@@ -502,7 +502,8 @@ impl PenToolData {
 		let next_handle_start = self.next_handle_start;
 		let handle_start = self.latest_point()?.handle_start;
 		let mouse = snap_data.input.mouse.position;
-		self.offset_position = None;
+		self.handle_end_offset = None;
+		self.handle_start_offset = None;
 		let Some(handle_end) = self.handle_end else {
 			responses.add(DocumentMessage::EndTransaction);
 			self.handle_end = Some(next_handle_start);
@@ -582,25 +583,33 @@ impl PenToolData {
 		vector_data: &VectorData,
 		input: &InputPreprocessorMessageHandler,
 	) -> Option<DVec2> {
-		let handle_pos = self.target_handle_position(self.handle_type, vector_data);
+		let end_handle = self.check_end_handle_type(vector_data);
+		let end_handle_pos = self.target_handle_position(end_handle, vector_data);
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
 		let document_pos = viewport_to_document.transform_point2(*mouse);
 
-		let offset = transform.transform_point2(self.next_point - self.next_handle_start);
+		let offset = transform.transform_point2(self.next_point) - transform.transform_point2(self.next_handle_start);
+
+		let start_offset = self
+			.handle_start_offset
+			.map(|offset| viewport_to_document.transform_point2(offset))
+			.filter(|vec| !vec.abs().cmple(DVec2::splat(10.0)).all())
+			.unwrap_or(DVec2::ZERO);
 
-		let handle_start = SnapCandidatePoint::handle(document_pos);
-		let anchor = SnapCandidatePoint::handle(document_pos + offset);
+		let handle_start = SnapCandidatePoint::handle(document_pos + start_offset);
+		let anchor = SnapCandidatePoint::handle(document_pos + offset + start_offset);
 
 		let snapped_near_handle_start = snap.free_snap(&snap_data, &handle_start, SnapTypeConfiguration::default());
 		let snapped_anchor = snap.free_snap(&snap_data, &anchor, SnapTypeConfiguration::default());
 
-		let handle_snap_option = handle_pos.and_then(|handle| match self.handle_type {
+		let handle_snap_option = end_handle_pos.and_then(|handle| match end_handle {
 			TargetHandle::None => None,
+			TargetHandle::HandleStart => None,
 			_ => {
 				let handle_offset = transform.transform_point2(handle - self.next_handle_start);
-				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
+				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset + start_offset);
 				Some((handle, handle_snap))
 			}
 		});
@@ -679,7 +688,6 @@ impl PenToolData {
 		let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
-		let viewport = document.metadata().transform_to_viewport(layer);
 
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
@@ -702,16 +710,14 @@ impl PenToolData {
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 		}
 		if self.handle_type == TargetHandle::HandleStart {
-			let mouse_offset = mouse + self.offset_position.unwrap();
-			log::info!("{:?}", mouse_offset);
-			log::info!("{:?}", self.handle_end.map(|handle| viewport.transform_point2(handle)));
+			let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
 
 			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
 			let opposite_target = self.get_opposite_handle_type(&vector_data);
 			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer);
-			responses.add(OverlaysMessage::Draw);
 		} else {
-			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse, Some(self.next_point), false);
+			let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
+			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
 		}
 
 		match self.handle_mode {
@@ -1558,7 +1564,8 @@ impl Fsm for PenToolFsmState {
 				match tool_data.handle_type {
 					TargetHandle::None => {}
 					TargetHandle::HandleStart => {
-						tool_data.offset_position = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
+						// will be moving the `next_handle_start` need to check the offset
+						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
 
 						tool_data.update_handle_custom(&vector_data);
 						tool_data.cleanup_target_selections(shape_editor, layer, document);
@@ -1566,12 +1573,14 @@ impl Fsm for PenToolFsmState {
 					_ => {
 						tool_data.add_target_selections(shape_editor, layer);
 
+						// The handle which will be dragged will be the handle end ,need to offset the mouse position
 						let viewport = layer.map(|layer| document.metadata().transform_to_viewport(layer));
 						let offset = tool_data
 							.target_handle_position(tool_data.handle_type, &vector_data)
 							.zip(viewport)
-							.map(|(opposite, transform)| transform.transform_point2(opposite - tool_data.next_handle_start));
-						tool_data.offset_position = offset;
+							.map(|(opposite, transform)| transform.transform_point2(opposite) - input.mouse.position);
+
+						tool_data.handle_end_offset = offset;
 						tool_data.update_handle_type(TargetHandle::HandleStart);
 					}
 				}

From 1b9ea0eb4177f3d09707af6bb28179f8bb86060c Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Wed, 19 Mar 2025 22:55:43 +0530
Subject: [PATCH 10/21] fixed all issues

---
 .../messages/tool/tool_messages/pen_tool.rs   | 63 ++++++++++++-------
 1 file changed, 39 insertions(+), 24 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index fd028ae4c6..f1142aaf71 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -314,6 +314,7 @@ struct PenToolData {
 	previous_handle_start_pos: DVec2,
 	previous_handle_end_pos: Option<DVec2>,
 	alt_press: bool,
+	space_press: bool,
 
 	handle_mode: HandleMode,
 	/// The point that is being dragged
@@ -411,7 +412,7 @@ impl PenToolData {
 	}
 
 	/// Remove the handles selected when swapping handles
-	fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler) {
+	fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
 		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
 			return;
 		};
@@ -425,6 +426,7 @@ impl PenToolData {
 			TargetHandle::PrimaryHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)),
 			_ => {}
 		}
+		responses.add(OverlaysMessage::Draw);
 	}
 
 	/// Selects the handle which is currently dragged by the user  
@@ -588,18 +590,13 @@ impl PenToolData {
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
-		let document_pos = viewport_to_document.transform_point2(*mouse);
-
-		let offset = transform.transform_point2(self.next_point) - transform.transform_point2(self.next_handle_start);
+		let handle_start_offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
+		let document_pos = viewport_to_document.transform_point2(*mouse + handle_start_offset);
 
-		let start_offset = self
-			.handle_start_offset
-			.map(|offset| viewport_to_document.transform_point2(offset))
-			.filter(|vec| !vec.abs().cmple(DVec2::splat(10.0)).all())
-			.unwrap_or(DVec2::ZERO);
+		let anchor_offset = transform.transform_point2(self.next_point - self.next_handle_start);
 
-		let handle_start = SnapCandidatePoint::handle(document_pos + start_offset);
-		let anchor = SnapCandidatePoint::handle(document_pos + offset + start_offset);
+		let handle_start = SnapCandidatePoint::handle(document_pos);
+		let anchor = SnapCandidatePoint::handle(document_pos + anchor_offset);
 
 		let snapped_near_handle_start = snap.free_snap(&snap_data, &handle_start, SnapTypeConfiguration::default());
 		let snapped_anchor = snap.free_snap(&snap_data, &anchor, SnapTypeConfiguration::default());
@@ -609,7 +606,7 @@ impl PenToolData {
 			TargetHandle::HandleStart => None,
 			_ => {
 				let handle_offset = transform.transform_point2(handle - self.next_handle_start);
-				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset + start_offset);
+				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
 				Some((handle, handle_snap))
 			}
 		});
@@ -670,8 +667,15 @@ impl PenToolData {
 			modification_type: modification_type_anchor,
 		});
 
-		let Some(handle_pos) = self.target_handle_position(self.handle_type, vector_data) else { return };
-		self.update_target_handle_pos(self.handle_type, responses, handle_pos + delta, layer);
+		// Move the end handle
+		let end_handle_type = self.check_end_handle_type(vector_data);
+		match end_handle_type {
+			TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..) => {
+				let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return };
+				self.update_target_handle_pos(end_handle_type, responses, handle_pos + delta, layer);
+			}
+			_ => {}
+		}
 	}
 
 	fn drag_handle(
@@ -689,6 +693,7 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
 
+		// Handles pressing `space` to drag anchor and its handles
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
 				return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
@@ -709,15 +714,15 @@ impl PenToolData {
 			responses.add(OverlaysMessage::Draw);
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 		}
-		if self.handle_type == TargetHandle::HandleStart {
-			let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
 
+		if self.handle_type != TargetHandle::HandleStart {
+			let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
+			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
+		} else {
+			let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
 			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
 			let opposite_target = self.get_opposite_handle_type(&vector_data);
 			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer);
-		} else {
-			let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
-			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
 		}
 
 		match self.handle_mode {
@@ -1450,7 +1455,7 @@ impl Fsm for PenToolFsmState {
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
 				tool_data.end_point = None;
 
-				tool_data.cleanup_target_selections(shape_editor, layer, document);
+				tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
 				tool_data
 					.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
 					.unwrap_or(PenToolFsmState::PlacingAnchor)
@@ -1481,6 +1486,16 @@ impl Fsm for PenToolFsmState {
 					tool_data.toggle_colinear_debounce = true;
 				}
 
+				if tool_data.modifiers.move_anchor_with_handles && !tool_data.space_press {
+					let handle_start = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start));
+					tool_data.handle_start_offset = handle_start.map(|start| start - input.mouse.position);
+					tool_data.space_press = true;
+				}
+
+				if !tool_data.modifiers.move_anchor_with_handles {
+					tool_data.space_press = false;
+				}
+
 				if !tool_data.modifiers.colinear {
 					tool_data.toggle_colinear_debounce = false;
 				}
@@ -1568,7 +1583,7 @@ impl Fsm for PenToolFsmState {
 						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
 
 						tool_data.update_handle_custom(&vector_data);
-						tool_data.cleanup_target_selections(shape_editor, layer, document);
+						tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
 					}
 					_ => {
 						tool_data.add_target_selections(shape_editor, layer);
@@ -1579,7 +1594,7 @@ impl Fsm for PenToolFsmState {
 							.target_handle_position(tool_data.handle_type, &vector_data)
 							.zip(viewport)
 							.map(|(opposite, transform)| transform.transform_point2(opposite) - input.mouse.position);
-
+						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
 						tool_data.handle_end_offset = offset;
 						tool_data.update_handle_type(TargetHandle::HandleStart);
 					}
@@ -1660,7 +1675,7 @@ impl Fsm for PenToolFsmState {
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
 				tool_data.snap_manager.cleanup(responses);
-				tool_data.cleanup_target_selections(shape_editor, layer, document);
+				tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
 
 				PenToolFsmState::Ready
 			}
@@ -1670,7 +1685,7 @@ impl Fsm for PenToolFsmState {
 				tool_data.latest_points.clear();
 				tool_data.point_index = 0;
 				tool_data.snap_manager.cleanup(responses);
-				tool_data.cleanup_target_selections(shape_editor, layer, document);
+				tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
 
 				responses.add(OverlaysMessage::Draw);
 

From 9493749f96af16ad0f76e176fd4ce35cd755eeaa Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Thu, 20 Mar 2025 08:45:38 +0530
Subject: [PATCH 11/21] comments and small fixes

---
 editor/src/messages/tool/tool_messages/pen_tool.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index f67272dcd5..c6df6ca097 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -363,7 +363,6 @@ impl PenToolData {
 	fn get_opposite_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
 		match self.handle_type {
 			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
-			TargetHandle::None => TargetHandle::None,
 			_ => TargetHandle::HandleStart,
 		}
 	}
@@ -1453,9 +1452,8 @@ impl Fsm for PenToolFsmState {
 				self
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
-				tool_data.end_point = None;
-
 				tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
+				tool_data.end_point = None;
 				tool_data
 					.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
 					.unwrap_or(PenToolFsmState::PlacingAnchor)
@@ -1579,7 +1577,7 @@ impl Fsm for PenToolFsmState {
 				match tool_data.handle_type {
 					TargetHandle::None => {}
 					TargetHandle::HandleStart => {
-						// will be moving the `next_handle_start` need to check the offset
+						// The hanlde which will be dragged will be the `next_handle_start` need to check the offset
 						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
 
 						tool_data.update_handle_custom(&vector_data);
@@ -1625,7 +1623,7 @@ impl Fsm for PenToolFsmState {
 				self
 			}
 			(PenToolFsmState::DraggingHandle(mode), PenToolMessage::PointerOutsideViewport { .. }) => {
-				// Auto-panning
+				// Auto-panningF
 				let _ = tool_data.auto_panning.shift_viewport(input, responses);
 
 				PenToolFsmState::DraggingHandle(mode)

From 43f9a7c3d2d0a07341c8017a45e96c7d48cd814e Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Fri, 21 Mar 2025 23:18:30 +0530
Subject: [PATCH 12/21] completed last issue and refactor

---
 .../messages/tool/tool_messages/pen_tool.rs   | 201 +++++++++++-------
 1 file changed, 130 insertions(+), 71 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index c6df6ca097..73f0dd0fd8 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -282,7 +282,7 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
-/// The handle which is opposite to the currently dragged handle under the cursor
+/// The type of handle which id dragged handle by the cursor (under the cursor)
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	HandleEnd,
@@ -315,14 +315,15 @@ struct PenToolData {
 	previous_handle_end_pos: Option<DVec2>,
 	alt_press: bool,
 	space_press: bool,
+	close_path: bool,
 
 	handle_mode: HandleMode,
-	/// The point that is being dragged
 	end_point: Option<PointId>,
 	end_point_segment: Option<SegmentId>,
 	handle_type: TargetHandle,
 	handle_start_offset: Option<DVec2>,
 	handle_end_offset: Option<DVec2>,
+
 	snap_cache: SnapCache,
 }
 impl PenToolData {
@@ -355,15 +356,32 @@ impl PenToolData {
 		}
 	}
 
-	fn update_handle_custom(&mut self, vector_data: &VectorData) {
-		let target_handle = self.check_end_handle_type(vector_data);
-		self.update_handle_type(target_handle);
-	}
-
-	fn get_opposite_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
-		match self.handle_type {
+	fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle {
+		match handle_type {
 			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
-			_ => TargetHandle::HandleStart,
+			TargetHandle::HandleEnd => {
+				if self.close_path {
+					match (self.end_point, self.end_point_segment) {
+						(Some(point), Some(segment)) => {
+							if vector_data.segment_start_from_id(segment) == Some(point) {
+								TargetHandle::PrimaryHandle(segment)
+							} else {
+								TargetHandle::EndHandle(segment)
+							}
+						}
+						_ => TargetHandle::None,
+					}
+				} else {
+					TargetHandle::HandleStart
+				}
+			}
+			_ => {
+				if self.close_path {
+					TargetHandle::HandleEnd
+				} else {
+					TargetHandle::HandleStart
+				}
+			}
 		}
 	}
 
@@ -404,12 +422,6 @@ impl PenToolData {
 			TargetHandle::None => None,
 		}
 	}
-
-	fn opposite_target_handle_position(&self, vector_data: &VectorData) -> Option<DVec2> {
-		let opposite_handle_type = self.get_opposite_handle_type(vector_data);
-		self.target_handle_position(opposite_handle_type, vector_data)
-	}
-
 	/// Remove the handles selected when swapping handles
 	fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
 		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
@@ -470,20 +482,17 @@ impl PenToolData {
 		let document = snap_data.document;
 		self.next_handle_start = self.next_point;
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
+		self.update_handle_type(TargetHandle::HandleStart);
 
 		// Break the control
 		let Some((last_pos, id)) = self.latest_point().map(|point| (point.pos, point.id)) else { return };
 
 		let transform = document.metadata().document_to_viewport * transform;
 		let on_top = transform.transform_point2(self.next_point).distance_squared(transform.transform_point2(last_pos)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2);
-		self.update_handle_type(TargetHandle::HandleEnd);
 		if on_top {
 			self.handle_end = None;
 			self.handle_mode = HandleMode::Free;
-
-			// Update `end_point_segment` that was clicked on
 			self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
-
 			if self.modifiers.lock_angle {
 				self.set_lock_angle(&vector_data, id, self.end_point_segment);
 				let last_segment = self.end_point_segment;
@@ -496,6 +505,20 @@ impl PenToolData {
 				point.in_segment = None;
 			}
 		}
+
+		for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != id) {
+			let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
+			let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point));
+			let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
+			if transformed_distance_between_squared < snap_point_tolerance_squared {
+				self.update_handle_type(TargetHandle::HandleEnd);
+				self.handle_end_offset = None;
+				self.close_path = true;
+				self.next_handle_start = self.next_point;
+				self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
+				self.handle_mode = HandleMode::Free;
+			}
+		}
 	}
 
 	fn finish_placing_handle(&mut self, snap_data: SnapData, transform: DAffine2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
@@ -569,6 +592,7 @@ impl PenToolData {
 				handle_start: next_handle_start,
 			});
 		}
+		self.close_path = false;
 		responses.add(DocumentMessage::EndTransaction);
 		Some(if close_subpath { PenToolFsmState::Ready } else { PenToolFsmState::PlacingAnchor })
 	}
@@ -584,15 +608,17 @@ impl PenToolData {
 		vector_data: &VectorData,
 		input: &InputPreprocessorMessageHandler,
 	) -> Option<DVec2> {
-		let end_handle = self.check_end_handle_type(vector_data);
+		let reference_handle = if self.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+		let end_handle = self.get_opposite_handle_type(reference_handle, vector_data);
 		let end_handle_pos = self.target_handle_position(end_handle, vector_data);
+		let ref_pos = self.target_handle_position(reference_handle, vector_data).unwrap();
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
 		let handle_start_offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
 		let document_pos = viewport_to_document.transform_point2(*mouse + handle_start_offset);
 
-		let anchor_offset = transform.transform_point2(self.next_point - self.next_handle_start);
+		let anchor_offset = transform.transform_point2(self.next_point - ref_pos);
 
 		let handle_start = SnapCandidatePoint::handle(document_pos);
 		let anchor = SnapCandidatePoint::handle(document_pos + anchor_offset);
@@ -604,7 +630,7 @@ impl PenToolData {
 			TargetHandle::None => None,
 			TargetHandle::HandleStart => None,
 			_ => {
-				let handle_offset = transform.transform_point2(handle - self.next_handle_start);
+				let handle_offset = transform.transform_point2(handle - ref_pos);
 				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
 				Some((handle, handle_snap))
 			}
@@ -615,7 +641,7 @@ impl PenToolData {
 			delta = snapped_anchor.snapped_point_document - transform.transform_point2(self.next_point);
 			snapped_anchor
 		} else {
-			delta = snapped_near_handle_start.snapped_point_document - transform.transform_point2(self.next_handle_start);
+			delta = snapped_near_handle_start.snapped_point_document - transform.transform_point2(ref_pos);
 			snapped_near_handle_start
 		};
 
@@ -655,8 +681,10 @@ impl PenToolData {
 	}
 
 	fn move_anchor_and_handles(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>, vector_data: &VectorData) {
-		if let Some(latest_pt) = self.latest_point_mut() {
-			latest_pt.pos += delta;
+		if self.handle_end.is_none() {
+			if let Some(latest_pt) = self.latest_point_mut() {
+				latest_pt.pos += delta;
+			}
 		}
 
 		let Some(end_point) = self.end_point else { return };
@@ -666,8 +694,10 @@ impl PenToolData {
 			modification_type: modification_type_anchor,
 		});
 
+		let reference_handle = if self.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+
 		// Move the end handle
-		let end_handle_type = self.check_end_handle_type(vector_data);
+		let end_handle_type = self.get_opposite_handle_type(reference_handle, vector_data);
 		match end_handle_type {
 			TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..) => {
 				let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return };
@@ -707,21 +737,23 @@ impl PenToolData {
 
 			if let Some(handle) = self.handle_end.as_mut() {
 				*handle += delta;
-			} else {
-				self.move_anchor_and_handles(delta, layer, responses, &vector_data);
 			}
+			self.move_anchor_and_handles(delta, layer, responses, &vector_data);
+
 			responses.add(OverlaysMessage::Draw);
 			return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
 		}
 
-		if self.handle_type != TargetHandle::HandleStart {
-			let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
-			self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
-		} else {
-			let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
-			let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
-			let opposite_target = self.get_opposite_handle_type(&vector_data);
-			self.update_target_handle_pos(opposite_target, responses, mouse_pos, layer);
+		match self.handle_type {
+			TargetHandle::HandleStart => {
+				let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
+				self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
+			}
+			_ => {
+				let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
+				let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
+				self.update_target_handle_pos(self.handle_type, responses, mouse_pos, layer);
+			}
 		}
 
 		match self.handle_mode {
@@ -742,24 +774,25 @@ impl PenToolData {
 
 	/// Makes the opposite handle equidistant or locks its length.
 	fn adjust_handle_length(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, vector_data: &VectorData) {
+		let opposite_handle_type = self.get_opposite_handle_type(self.handle_type, vector_data);
 		match self.handle_mode {
 			HandleMode::ColinearEquidistant => {
 				if self.modifiers.break_handle {
 					// Store handle for later restoration only when Alt is first pressed
 					if !self.alt_press {
-						self.previous_handle_end_pos = self.target_handle_position(self.handle_type, vector_data);
+						self.previous_handle_end_pos = self.target_handle_position(opposite_handle_type, vector_data);
 						self.alt_press = true;
 					}
 
 					// Set handle to opposite position of the other handle
-					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
+					let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(self.handle_type, responses, new_position, layer);
+					self.update_target_handle_pos(opposite_handle_type, responses, new_position, layer);
 				} else if self.alt_press {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
-						self.update_target_handle_pos(self.handle_type, responses, previous_handle, layer);
+						self.update_target_handle_pos(opposite_handle_type, responses, previous_handle, layer);
 					}
 					self.alt_press = false;
 					self.previous_handle_end_pos = None;
@@ -767,10 +800,10 @@ impl PenToolData {
 			}
 			HandleMode::ColinearLocked => {
 				if !self.modifiers.break_handle {
-					let Some(new_position) = self.opposite_target_handle_position(vector_data).map(|handle| self.next_point * 2. - handle) else {
+					let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(self.handle_type, responses, new_position, layer);
+					self.update_target_handle_pos(opposite_handle_type, responses, new_position, layer);
 				}
 			}
 			HandleMode::Free => {}
@@ -778,7 +811,7 @@ impl PenToolData {
 	}
 
 	fn apply_colinear_constraint(&mut self, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, anchor_pos: DVec2, vector_data: &VectorData) {
-		let Some(handle) = self.opposite_target_handle_position(vector_data) else {
+		let Some(handle) = self.target_handle_position(self.handle_type, vector_data) else {
 			return;
 		};
 
@@ -787,12 +820,13 @@ impl PenToolData {
 			return;
 		};
 
-		let Some(handle_offset) = self.target_handle_position(self.handle_type, vector_data).map(|handle| (handle - anchor_pos).length()) else {
+		let opposite_handle = self.get_opposite_handle_type(self.handle_type, vector_data);
+		let Some(handle_offset) = self.target_handle_position(opposite_handle, vector_data).map(|handle| (handle - anchor_pos).length()) else {
 			return;
 		};
 
 		let new_handle_position = anchor_pos + handle_offset * direction;
-		self.update_target_handle_pos(self.handle_type, responses, new_handle_position, layer);
+		self.update_target_handle_pos(opposite_handle, responses, new_handle_position, layer);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
@@ -904,6 +938,7 @@ impl PenToolData {
 		let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
 		let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
 		let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
+		self.handle_type = TargetHandle::HandleStart;
 
 		let selected_nodes = document.network_interface.selected_nodes();
 		self.handle_end = None;
@@ -953,7 +988,6 @@ impl PenToolData {
 		tool_options.fill.apply_fill(layer, responses);
 		tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
 		self.end_point_segment = None;
-		self.handle_type = TargetHandle::HandleEnd;
 		responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
 
 		// This causes the following message to be run only after the next graph evaluation runs and the transforms are updated
@@ -1038,7 +1072,6 @@ impl PenToolData {
 			let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 			let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 			self.end_point_segment = segment;
-			self.update_handle_custom(&vector_data);
 			layer_manipulators.insert(point);
 			for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
 				if id == point {
@@ -1340,7 +1373,7 @@ impl Fsm for PenToolFsmState {
 
 					if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, handle_end) {
 						// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
-						let selected = tool_data.handle_type == TargetHandle::HandleStart;
+						let selected = tool_data.handle_type == TargetHandle::HandleEnd;
 						overlay_context.manipulator_handle(handle_end, selected, None);
 					}
 
@@ -1362,7 +1395,7 @@ impl Fsm for PenToolFsmState {
 
 				if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, next_handle_start) {
 					// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
-					let selected = tool_data.handle_type != TargetHandle::HandleStart;
+					let selected = tool_data.handle_type == TargetHandle::HandleStart;
 					overlay_context.manipulator_handle(next_handle_start, selected, None);
 				}
 
@@ -1475,6 +1508,7 @@ impl Fsm for PenToolFsmState {
 					colinear: input.keyboard.key(colinear),
 					move_anchor_with_handles: input.keyboard.key(move_anchor_with_handles),
 				};
+
 				let snap_data = SnapData::new(document, input);
 				if tool_data.modifiers.colinear && !tool_data.toggle_colinear_debounce {
 					tool_data.handle_mode = match tool_data.handle_mode {
@@ -1484,8 +1518,18 @@ impl Fsm for PenToolFsmState {
 					tool_data.toggle_colinear_debounce = true;
 				}
 
+				let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
+					return self;
+				};
+
 				if tool_data.modifiers.move_anchor_with_handles && !tool_data.space_press {
-					let handle_start = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start));
+					let reference_handle = if tool_data.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+					let handle_start = layer.map(|layer| {
+						document
+							.metadata()
+							.transform_to_viewport(layer)
+							.transform_point2(tool_data.target_handle_position(reference_handle, &vector_data).unwrap())
+					});
 					tool_data.handle_start_offset = handle_start.map(|start| start - input.mouse.position);
 					tool_data.space_press = true;
 				}
@@ -1574,29 +1618,44 @@ impl Fsm for PenToolFsmState {
 				let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
 					return self;
 				};
-				match tool_data.handle_type {
-					TargetHandle::None => {}
-					TargetHandle::HandleStart => {
-						// The hanlde which will be dragged will be the `next_handle_start` need to check the offset
-						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
-
-						tool_data.update_handle_custom(&vector_data);
-						tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
+
+				let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else {
+					return self;
+				};
+
+				if tool_data.close_path {
+					match tool_data.handle_type {
+						TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..) => {
+							let opposite_type = tool_data.get_opposite_handle_type(tool_data.handle_type, &vector_data);
+							tool_data.handle_end_offset = tool_data
+								.target_handle_position(opposite_type, &vector_data)
+								.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
+							tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
+							tool_data.update_handle_type(opposite_type);
+							tool_data.add_target_selections(shape_editor, layer);
+						}
+						_ => {}
 					}
-					_ => {
-						tool_data.add_target_selections(shape_editor, layer);
-
-						// The handle which will be dragged will be the handle end ,need to offset the mouse position
-						let viewport = layer.map(|layer| document.metadata().transform_to_viewport(layer));
-						let offset = tool_data
-							.target_handle_position(tool_data.handle_type, &vector_data)
-							.zip(viewport)
-							.map(|(opposite, transform)| transform.transform_point2(opposite) - input.mouse.position);
-						tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
-						tool_data.handle_end_offset = offset;
-						tool_data.update_handle_type(TargetHandle::HandleStart);
+				} else {
+					// Store the offset and swap the handle_types
+					match tool_data.handle_type {
+						TargetHandle::None => {}
+						TargetHandle::HandleStart => {
+							let opposite_type = tool_data.get_opposite_handle_type(tool_data.handle_type, &vector_data);
+							tool_data.handle_end_offset = tool_data
+								.target_handle_position(opposite_type, &vector_data)
+								.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
+							tool_data.update_handle_type(opposite_type);
+							tool_data.add_target_selections(shape_editor, layer);
+						}
+						_ => {
+							tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
+							tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
+							tool_data.update_handle_type(TargetHandle::HandleStart);
+						}
 					}
 				}
+
 				responses.add(OverlaysMessage::Draw);
 				responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 				self

From 3a7369087bfa88aed4b0c4f796da27a4b107f091 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Thu, 27 Mar 2025 21:30:17 +0530
Subject: [PATCH 13/21] major fixes and improv

---
 .../document/overlays/utility_functions.rs    |   1 -
 .../messages/tool/tool_messages/pen_tool.rs   | 225 ++++++++++--------
 2 files changed, 131 insertions(+), 95 deletions(-)

diff --git a/editor/src/messages/portfolio/document/overlays/utility_functions.rs b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
index a6a77b1726..2c585d2afe 100644
--- a/editor/src/messages/portfolio/document/overlays/utility_functions.rs
+++ b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
@@ -121,7 +121,6 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
 		let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
 
 		let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.adjacent_segment(point_id)).collect();
-
 		match draw_handles {
 			DrawHandles::All => {
 				vector_data.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| {
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 73f0dd0fd8..2a006d2bf3 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -282,7 +282,7 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
-/// The type of handle which id dragged handle by the cursor (under the cursor)
+/// The type of handle which is dragged by the cursor (under the cursor)
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	HandleEnd,
@@ -356,6 +356,17 @@ impl PenToolData {
 		}
 	}
 
+	fn check_grs_end_handle(&self, vector_data: &VectorData) -> TargetHandle {
+		let Some(point) = self.latest_point().map(|point| point.id) else { return TargetHandle::None };
+		let Some(segment) = self.end_point_segment else { return TargetHandle::None };
+
+		if vector_data.segment_start_from_id(segment) == Some(point) {
+			TargetHandle::PrimaryHandle(segment)
+		} else {
+			TargetHandle::EndHandle(segment)
+		}
+	}
+
 	fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle {
 		match handle_type {
 			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
@@ -389,7 +400,7 @@ impl PenToolData {
 		self.handle_type = handle_type;
 	}
 
-	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
+	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, anchor_pos: DVec2, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
 		match handle_type {
 			TargetHandle::HandleStart => {
 				self.next_handle_start = delta;
@@ -400,12 +411,12 @@ impl PenToolData {
 				}
 			}
 			TargetHandle::EndHandle(segment) => {
-				let relative_position = delta - self.next_point;
+				let relative_position = delta - anchor_pos;
 				let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
 				responses.add(GraphOperationMessage::Vector { layer, modification_type });
 			}
 			TargetHandle::PrimaryHandle(segment) => {
-				let relative_position = delta - self.next_point;
+				let relative_position = delta - anchor_pos;
 				let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position };
 				responses.add(GraphOperationMessage::Vector { layer, modification_type });
 			}
@@ -517,6 +528,9 @@ impl PenToolData {
 				self.next_handle_start = self.next_point;
 				self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
 				self.handle_mode = HandleMode::Free;
+				if self.modifiers.lock_angle {
+					self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
+				}
 			}
 		}
 	}
@@ -568,6 +582,19 @@ impl PenToolData {
 
 		// Store the segment
 		let id = SegmentId::generate();
+		if self.close_path && self.handle_mode != HandleMode::Free {
+			if let Some(handles) = match self.get_opposite_handle_type(TargetHandle::HandleEnd, &vector_data) {
+				TargetHandle::PrimaryHandle(segment) => Some([HandleId::end(id), HandleId::primary(segment)]),
+				TargetHandle::EndHandle(segment) => Some([HandleId::end(id), HandleId::end(segment)]),
+				_ => None,
+			} {
+				responses.add(GraphOperationMessage::Vector {
+					layer,
+					modification_type: VectorModificationType::SetG1Continuous { handles, enabled: true },
+				});
+			}
+		}
+
 		self.end_point_segment = Some(id);
 
 		let points = [start, end];
@@ -575,13 +602,16 @@ impl PenToolData {
 		responses.add(GraphOperationMessage::Vector { layer, modification_type });
 
 		// Mirror
-		if let Some(last_segment) = self.latest_point().and_then(|point| point.in_segment) {
+		if let Some((last_segment, last_point)) = self.latest_point().and_then(|point| point.in_segment).zip(self.latest_point()) {
+			let end = vector_data.segment_end_from_id(last_segment) == Some(last_point.id);
+			let handles = if end {
+				[HandleId::end(last_segment), HandleId::primary(id)]
+			} else {
+				[HandleId::primary(last_segment), HandleId::primary(id)]
+			};
 			responses.add(GraphOperationMessage::Vector {
 				layer,
-				modification_type: VectorModificationType::SetG1Continuous {
-					handles: [HandleId::end(last_segment), HandleId::primary(id)],
-					enabled: true,
-				},
+				modification_type: VectorModificationType::SetG1Continuous { handles, enabled: true },
 			});
 		}
 		if !close_subpath {
@@ -593,6 +623,7 @@ impl PenToolData {
 			});
 		}
 		self.close_path = false;
+		self.end_point = None;
 		responses.add(DocumentMessage::EndTransaction);
 		Some(if close_subpath { PenToolFsmState::Ready } else { PenToolFsmState::PlacingAnchor })
 	}
@@ -663,6 +694,57 @@ impl PenToolData {
 		Some(transform.inverse().transform_vector2(delta))
 	}
 
+	// Calculates the offset from the mouse when swapping handles
+	fn update_offset(
+		&mut self,
+		layer: Option<LayerNodeIdentifier>,
+		document: &DocumentMessageHandler,
+		shape_editor: &mut ShapeState,
+		input: &InputPreprocessorMessageHandler,
+		responses: &mut VecDeque<Message>,
+	) {
+		let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
+			return;
+		};
+
+		let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else {
+			return;
+		};
+
+		if self.close_path {
+			match self.handle_type {
+				TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..) => {
+					let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
+					self.handle_end_offset = self
+						.target_handle_position(opposite_type, &vector_data)
+						.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
+					self.cleanup_target_selections(shape_editor, layer, document, responses);
+					self.update_handle_type(opposite_type);
+					self.add_target_selections(shape_editor, layer);
+				}
+				_ => {}
+			}
+		} else {
+			// Store the offset and swap the handle_types
+			match self.handle_type {
+				TargetHandle::None => {}
+				TargetHandle::HandleStart => {
+					let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
+					self.handle_end_offset = self
+						.target_handle_position(opposite_type, &vector_data)
+						.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
+					self.update_handle_type(opposite_type);
+					self.add_target_selections(shape_editor, layer);
+				}
+				_ => {
+					self.cleanup_target_selections(shape_editor, layer, document, responses);
+					self.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(self.next_handle_start) - input.mouse.position);
+					self.update_handle_type(TargetHandle::HandleStart);
+				}
+			}
+		}
+	}
+
 	/// Handles moving the initially created point
 	fn handle_single_point_path_drag(&mut self, delta: DVec2, layer: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
 		self.next_handle_start += delta;
@@ -701,7 +783,7 @@ impl PenToolData {
 		match end_handle_type {
 			TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..) => {
 				let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return };
-				self.update_target_handle_pos(end_handle_type, responses, handle_pos + delta, layer);
+				self.update_target_handle_pos(end_handle_type, self.next_point, responses, handle_pos + delta, layer);
 			}
 			_ => {}
 		}
@@ -721,7 +803,6 @@ impl PenToolData {
 		let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
-
 		// Handles pressing `space` to drag anchor and its handles
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
@@ -752,7 +833,7 @@ impl PenToolData {
 			_ => {
 				let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
 				let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
-				self.update_target_handle_pos(self.handle_type, responses, mouse_pos, layer);
+				self.update_target_handle_pos(self.handle_type, self.next_point, responses, mouse_pos, layer);
 			}
 		}
 
@@ -788,11 +869,11 @@ impl PenToolData {
 					let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(opposite_handle_type, responses, new_position, layer);
+					self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer);
 				} else if self.alt_press {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
-						self.update_target_handle_pos(opposite_handle_type, responses, previous_handle, layer);
+						self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, previous_handle, layer);
 					}
 					self.alt_press = false;
 					self.previous_handle_end_pos = None;
@@ -803,7 +884,7 @@ impl PenToolData {
 					let Some(new_position) = self.target_handle_position(self.handle_type, vector_data).map(|handle| self.next_point * 2. - handle) else {
 						return;
 					};
-					self.update_target_handle_pos(opposite_handle_type, responses, new_position, layer);
+					self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer);
 				}
 			}
 			HandleMode::Free => {}
@@ -826,13 +907,16 @@ impl PenToolData {
 		};
 
 		let new_handle_position = anchor_pos + handle_offset * direction;
-		self.update_target_handle_pos(opposite_handle, responses, new_handle_position, layer);
+		self.update_target_handle_pos(opposite_handle, self.next_point, responses, new_handle_position, layer);
 	}
 
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
 		let document = snap_data.document;
 
-		let relative = self.latest_point().map(|point| point.pos);
+		let mut relative = self.latest_point().map(|point| point.pos);
+		if self.close_path {
+			relative = None
+		};
 		self.next_point = self.compute_snapped_angle(snap_data, transform, false, mouse, relative, true);
 
 		let selected_nodes = document.network_interface.selected_nodes();
@@ -959,7 +1043,6 @@ impl PenToolData {
 					self.set_lock_angle(&vector_data, point, segment);
 				}
 			}
-			self.end_point_segment = None;
 			let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface);
 			let existing_layer = selected_layers_except_artboards.next().filter(|_| selected_layers_except_artboards.next().is_none());
 			if let Some(layer) = existing_layer {
@@ -974,8 +1057,8 @@ impl PenToolData {
 			let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 
 			if self.modifiers.lock_angle {
-				self.set_lock_angle(&vector_data, point, segment);
 				self.handle_mode = HandleMode::Free;
+				self.set_lock_angle(&vector_data, point, segment);
 			}
 		}
 
@@ -1048,10 +1131,10 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 		let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 
+		self.handle_mode = HandleMode::Free;
 		if self.modifiers.lock_angle {
 			self.set_lock_angle(&vector_data, point, segment);
 		}
-		self.handle_mode = HandleMode::Free;
 	}
 
 	// Stores the segment and point ID of the clicked endpoint
@@ -1191,14 +1274,10 @@ impl Fsm for PenToolFsmState {
 					responses.add(TransformLayerMessage::BeginScalePen { last_point, handle });
 				}
 
+				let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 				tool_data.previous_handle_start_pos = latest.handle_start;
-
-				// Store the handle_end position
-				let segment = tool_data.end_point_segment;
-				if let Some(segment) = segment {
-					let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
-					tool_data.previous_handle_end_pos = ManipulatorPointId::EndHandle(segment).get_position(&vector_data);
-				}
+				let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
+				tool_data.previous_handle_end_pos = tool_data.target_handle_position(opposite_handle, &vector_data);
 				PenToolFsmState::GRSHandle
 			}
 			(PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position }) => {
@@ -1218,7 +1297,7 @@ impl Fsm for PenToolFsmState {
 				match tool_data.handle_mode {
 					HandleMode::Free => {}
 					HandleMode::ColinearEquidistant | HandleMode::ColinearLocked => {
-						if let Some((latest, segment)) = tool_data.latest_point().zip(tool_data.end_point_segment) {
+						if let Some(latest) = tool_data.latest_point() {
 							let Some(direction) = (latest.pos - latest.handle_start).try_normalize() else {
 								return PenToolFsmState::GRSHandle;
 							};
@@ -1226,23 +1305,12 @@ impl Fsm for PenToolFsmState {
 							if (latest.pos - latest.handle_start).length_squared() < f64::EPSILON {
 								return PenToolFsmState::GRSHandle;
 							}
-
-							let is_start = vector_data.segment_start_from_id(segment) == Some(latest.id);
-
-							let handle = if is_start {
-								ManipulatorPointId::PrimaryHandle(segment).get_position(&vector_data)
-							} else {
-								ManipulatorPointId::EndHandle(segment).get_position(&vector_data)
-							};
+							let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
+							let handle = tool_data.target_handle_position(opposite_handle, &vector_data);
 							let Some(handle) = handle else { return PenToolFsmState::GRSHandle };
 							let relative_distance = (handle - latest.pos).length();
-							let relative_position = relative_distance * direction;
-							let modification_type = if is_start {
-								VectorModificationType::SetPrimaryHandle { segment, relative_position }
-							} else {
-								VectorModificationType::SetEndHandle { segment, relative_position }
-							};
-							responses.add(GraphOperationMessage::Vector { layer, modification_type });
+							let relative_position = relative_distance * direction + latest.pos;
+							tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, relative_position, layer);
 						}
 					}
 				}
@@ -1271,10 +1339,14 @@ impl Fsm for PenToolFsmState {
 				tool_data.next_handle_start = input.mouse.position;
 
 				let Some(layer) = layer else { return PenToolFsmState::GRSHandle };
+				let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
+				let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
 
 				let previous = tool_data.previous_handle_start_pos;
 				if let Some(latest) = tool_data.latest_point_mut() {
 					latest.handle_start = previous;
+				} else {
+					return PenToolFsmState::PlacingAnchor;
 				}
 
 				responses.add(OverlaysMessage::Draw);
@@ -1286,12 +1358,10 @@ impl Fsm for PenToolFsmState {
 					move_anchor_with_handles: Key::Space,
 				});
 
-				// Set the handle-end back to original position
-				if let Some(((latest, segment), handle_end)) = tool_data.latest_point().zip(tool_data.end_point_segment).zip(tool_data.previous_handle_end_pos) {
-					let relative = handle_end - latest.pos;
-					let modification_type = VectorModificationType::SetEndHandle { segment, relative_position: relative };
-					responses.add(GraphOperationMessage::Vector { layer, modification_type });
-				}
+				let Some((previous_pos, latest)) = tool_data.previous_handle_end_pos.zip(tool_data.latest_point()) else {
+					return PenToolFsmState::PlacingAnchor;
+				};
+				tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, previous_pos, layer);
 
 				PenToolFsmState::PlacingAnchor
 			}
@@ -1486,7 +1556,6 @@ impl Fsm for PenToolFsmState {
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::DragStop) => {
 				tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
-				tool_data.end_point = None;
 				tool_data
 					.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses)
 					.unwrap_or(PenToolFsmState::PlacingAnchor)
@@ -1512,7 +1581,13 @@ impl Fsm for PenToolFsmState {
 				let snap_data = SnapData::new(document, input);
 				if tool_data.modifiers.colinear && !tool_data.toggle_colinear_debounce {
 					tool_data.handle_mode = match tool_data.handle_mode {
-						HandleMode::Free => HandleMode::ColinearEquidistant,
+						HandleMode::Free => {
+							let last_segment = tool_data.end_point_segment;
+							if let Some(latest) = tool_data.latest_point_mut() {
+								latest.in_segment = last_segment;
+							}
+							HandleMode::ColinearEquidistant
+						}
 						HandleMode::ColinearEquidistant | HandleMode::ColinearLocked => HandleMode::Free,
 					};
 					tool_data.toggle_colinear_debounce = true;
@@ -1615,47 +1690,7 @@ impl Fsm for PenToolFsmState {
 				state
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
-				let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
-					return self;
-				};
-
-				let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else {
-					return self;
-				};
-
-				if tool_data.close_path {
-					match tool_data.handle_type {
-						TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..) => {
-							let opposite_type = tool_data.get_opposite_handle_type(tool_data.handle_type, &vector_data);
-							tool_data.handle_end_offset = tool_data
-								.target_handle_position(opposite_type, &vector_data)
-								.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
-							tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
-							tool_data.update_handle_type(opposite_type);
-							tool_data.add_target_selections(shape_editor, layer);
-						}
-						_ => {}
-					}
-				} else {
-					// Store the offset and swap the handle_types
-					match tool_data.handle_type {
-						TargetHandle::None => {}
-						TargetHandle::HandleStart => {
-							let opposite_type = tool_data.get_opposite_handle_type(tool_data.handle_type, &vector_data);
-							tool_data.handle_end_offset = tool_data
-								.target_handle_position(opposite_type, &vector_data)
-								.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
-							tool_data.update_handle_type(opposite_type);
-							tool_data.add_target_selections(shape_editor, layer);
-						}
-						_ => {
-							tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
-							tool_data.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(tool_data.next_handle_start) - input.mouse.position);
-							tool_data.update_handle_type(TargetHandle::HandleStart);
-						}
-					}
-				}
-
+				tool_data.update_offset(layer, document, shape_editor, input, responses);
 				responses.add(OverlaysMessage::Draw);
 				responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 				self
@@ -1796,7 +1831,7 @@ impl Fsm for PenToolFsmState {
 					HintInfo::keys([Key::Enter], "End Path").prepend_slash(),
 				]));
 
-				let toggle_group = match mode {
+				let mut toggle_group = match mode {
 					HandleMode::Free => {
 						vec![HintInfo::keys([Key::KeyC], "Make Handles Colinear")]
 					}
@@ -1804,9 +1839,10 @@ impl Fsm for PenToolFsmState {
 						vec![HintInfo::keys([Key::KeyC], "Break Colinear Handles")]
 					}
 				};
+				toggle_group.push(HintInfo::keys([Key::Tab], "Swap Selected Handles"));
 
 				let mut common_hints = vec![HintInfo::keys([Key::Shift], "15° Increments"), HintInfo::keys([Key::Control], "Lock Angle")];
-				let hold_group = match mode {
+				let mut hold_group = match mode {
 					HandleMode::Free => common_hints,
 					HandleMode::ColinearLocked => {
 						common_hints.push(HintInfo::keys([Key::Alt], "Non-Equidistant Handles"));
@@ -1817,6 +1853,7 @@ impl Fsm for PenToolFsmState {
 						common_hints
 					}
 				};
+				hold_group.push(HintInfo::keys([Key::Space], "Drag Anchor"));
 
 				dragging_hint_data.0.push(HintGroup(toggle_group));
 				dragging_hint_data.0.push(HintGroup(hold_group));

From b228ac905e41c98f925da8b54a7471a2257711bd Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Mon, 31 Mar 2025 04:18:32 +0530
Subject: [PATCH 14/21] fixed edge cases

---
 .../messages/tool/tool_messages/pen_tool.rs   | 240 +++++++++++-------
 node-graph/gcore/src/vector/vector_data.rs    |  12 +-
 2 files changed, 156 insertions(+), 96 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 2a006d2bf3..e48560cfd9 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -313,6 +313,7 @@ struct PenToolData {
 
 	previous_handle_start_pos: DVec2,
 	previous_handle_end_pos: Option<DVec2>,
+	colinear: bool,
 	alt_press: bool,
 	space_press: bool,
 	close_path: bool,
@@ -343,9 +344,9 @@ impl PenToolData {
 
 	/// Check whether target handle is primary,end or 'self.handle_end'
 	fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
-		match (self.handle_end, self.end_point, self.end_point_segment) {
-			(Some(_), _, _) => TargetHandle::HandleEnd,
-			(None, Some(point), Some(segment)) => {
+		match (self.handle_end, self.end_point, self.end_point_segment, self.close_path) {
+			(Some(_), _, _, false) => TargetHandle::HandleEnd,
+			(None, Some(point), Some(segment), false) | (Some(_), Some(point), Some(segment), true) => {
 				if vector_data.segment_start_from_id(segment) == Some(point) {
 					TargetHandle::PrimaryHandle(segment)
 				} else {
@@ -527,10 +528,10 @@ impl PenToolData {
 				self.close_path = true;
 				self.next_handle_start = self.next_point;
 				self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
-				self.handle_mode = HandleMode::Free;
 				if self.modifiers.lock_angle {
 					self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
 				}
+				self.handle_mode = HandleMode::Free;
 			}
 		}
 	}
@@ -582,15 +583,26 @@ impl PenToolData {
 
 		// Store the segment
 		let id = SegmentId::generate();
-		if self.close_path && self.handle_mode != HandleMode::Free {
-			if let Some(handles) = match self.get_opposite_handle_type(TargetHandle::HandleEnd, &vector_data) {
-				TargetHandle::PrimaryHandle(segment) => Some([HandleId::end(id), HandleId::primary(segment)]),
-				TargetHandle::EndHandle(segment) => Some([HandleId::end(id), HandleId::end(segment)]),
+		if self.close_path {
+			if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::HandleEnd, &vector_data) {
+				TargetHandle::PrimaryHandle(segment) => {
+					let handles = [HandleId::end(id), HandleId::primary(segment)];
+					let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
+					handle1_pos.map(|pos| (handles, pos))
+				}
+				TargetHandle::EndHandle(segment) => {
+					let handles = [HandleId::end(id), HandleId::end(segment)];
+					let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
+					handle1_pos.map(|pos| (handles, pos))
+				}
 				_ => None,
 			} {
+				let angle = (handle_end - next_point).angle_to(handle1_pos - next_point);
+				let pi = std::f64::consts::PI;
+				let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6;
 				responses.add(GraphOperationMessage::Vector {
 					layer,
-					modification_type: VectorModificationType::SetG1Continuous { handles, enabled: true },
+					modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear },
 				});
 			}
 		}
@@ -609,10 +621,16 @@ impl PenToolData {
 			} else {
 				[HandleId::primary(last_segment), HandleId::primary(id)]
 			};
-			responses.add(GraphOperationMessage::Vector {
-				layer,
-				modification_type: VectorModificationType::SetG1Continuous { handles, enabled: true },
-			});
+
+			if let Some(h1) = handles[0].to_manipulator_point().get_position(&vector_data) {
+				let angle = (h1 - last_point.pos).angle_to(last_point.handle_start - last_point.pos);
+				let pi = std::f64::consts::PI;
+				let colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6;
+				responses.add(GraphOperationMessage::Vector {
+					layer,
+					modification_type: VectorModificationType::SetG1Continuous { handles, enabled: colinear },
+				});
+			}
 		}
 		if !close_subpath {
 			self.add_point(LastPoint {
@@ -694,8 +712,8 @@ impl PenToolData {
 		Some(transform.inverse().transform_vector2(delta))
 	}
 
-	// Calculates the offset from the mouse when swapping handles
-	fn update_offset(
+	// Calculates the offset from the mouse when swapping handles and swaps the handles
+	fn swap_handles(
 		&mut self,
 		layer: Option<LayerNodeIdentifier>,
 		document: &DocumentMessageHandler,
@@ -703,6 +721,7 @@ impl PenToolData {
 		input: &InputPreprocessorMessageHandler,
 		responses: &mut VecDeque<Message>,
 	) {
+		// Validate necessary data exists
 		let Some(vector_data) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)) else {
 			return;
 		};
@@ -710,39 +729,41 @@ impl PenToolData {
 		let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else {
 			return;
 		};
+		// Determine if we need to swap to opposite handle
+		let should_swap_to_opposite = self.close_path && matches!(self.handle_type, TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..))
+			|| !self.close_path && matches!(self.handle_type, TargetHandle::HandleStart);
 
-		if self.close_path {
-			match self.handle_type {
-				TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..) => {
-					let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
-					self.handle_end_offset = self
-						.target_handle_position(opposite_type, &vector_data)
-						.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
-					self.cleanup_target_selections(shape_editor, layer, document, responses);
-					self.update_handle_type(opposite_type);
-					self.add_target_selections(shape_editor, layer);
-				}
-				_ => {}
+		// Determine if we need to swap to start handle
+		let should_swap_to_start = !self.close_path && !matches!(self.handle_type, TargetHandle::None | TargetHandle::HandleStart);
+
+		if should_swap_to_opposite {
+			let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
+			// Update offset
+			let Some(handle_pos) = self.target_handle_position(opposite_type, &vector_data) else {
+				return;
+			};
+			if (handle_pos - self.next_point).length() < 1e-6 {
+				return;
 			}
-		} else {
-			// Store the offset and swap the handle_types
-			match self.handle_type {
-				TargetHandle::None => {}
-				TargetHandle::HandleStart => {
-					let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
-					self.handle_end_offset = self
-						.target_handle_position(opposite_type, &vector_data)
-						.map(|handle| viewport.transform_point2(handle) - input.mouse.position);
-					self.update_handle_type(opposite_type);
-					self.add_target_selections(shape_editor, layer);
-				}
-				_ => {
-					self.cleanup_target_selections(shape_editor, layer, document, responses);
-					self.handle_start_offset = layer.map(|layer| document.metadata().transform_to_viewport(layer).transform_point2(self.next_handle_start) - input.mouse.position);
-					self.update_handle_type(TargetHandle::HandleStart);
-				}
+			self.handle_end_offset = Some(viewport.transform_point2(handle_pos) - input.mouse.position);
+			// Update selections if in closed path mode
+			if self.close_path {
+				self.cleanup_target_selections(shape_editor, layer, document, responses);
 			}
+			self.update_handle_type(opposite_type);
+			self.add_target_selections(shape_editor, layer);
+		} else if should_swap_to_start {
+			self.cleanup_target_selections(shape_editor, layer, document, responses);
+
+			// Calculate offset from mouse position to next handle start
+			if let Some(layer_id) = layer {
+				let transform = document.metadata().transform_to_viewport(layer_id);
+				self.handle_start_offset = Some(transform.transform_point2(self.next_handle_start) - input.mouse.position);
+			}
+
+			self.update_handle_type(TargetHandle::HandleStart);
 		}
+		responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 	}
 
 	/// Handles moving the initially created point
@@ -803,6 +824,7 @@ impl PenToolData {
 		let Some(layer) = layer else { return Some(PenToolFsmState::DraggingHandle(self.handle_mode)) };
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
+		let mut mouse_pos = mouse;
 		// Handles pressing `space` to drag anchor and its handles
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
@@ -828,11 +850,12 @@ impl PenToolData {
 		match self.handle_type {
 			TargetHandle::HandleStart => {
 				let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
-				self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse + offset, Some(self.next_point), false);
+				mouse_pos += offset;
+				self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_pos, Some(self.next_point), false);
 			}
 			_ => {
-				let mouse_offset = mouse + self.handle_end_offset.unwrap_or(DVec2::ZERO);
-				let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_offset, Some(self.next_point), false);
+				mouse_pos += self.handle_end_offset.unwrap_or(DVec2::ZERO);
+				let mouse_pos = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_pos, Some(self.next_point), false);
 				self.update_target_handle_pos(self.handle_type, self.next_point, responses, mouse_pos, layer);
 			}
 		}
@@ -848,8 +871,20 @@ impl PenToolData {
 			}
 		}
 
-		responses.add(OverlaysMessage::Draw);
+		let mouse_pos = viewport_to_document.transform_point2(mouse_pos);
+		let anchor = transform.transform_point2(self.next_point);
+		let distance = (mouse_pos - anchor).length();
+
+		if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle {
+			self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
+			self.handle_mode = HandleMode::Free;
+			let last_segment = self.end_point_segment;
+			if let Some(latest) = self.latest_point_mut() {
+				latest.in_segment = last_segment;
+			}
+		}
 
+		responses.add(OverlaysMessage::Draw);
 		Some(PenToolFsmState::DraggingHandle(self.handle_mode))
 	}
 
@@ -1131,10 +1166,10 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 		let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 
-		self.handle_mode = HandleMode::Free;
 		if self.modifiers.lock_angle {
 			self.set_lock_angle(&vector_data, point, segment);
 		}
+		self.handle_mode = HandleMode::Free;
 	}
 
 	// Stores the segment and point ID of the clicked endpoint
@@ -1174,35 +1209,45 @@ impl PenToolData {
 			self.handle_mode = HandleMode::Free;
 			return;
 		};
+		match (self.handle_type, self.close_path) {
+			(TargetHandle::HandleStart, _) | (TargetHandle::HandleEnd, true) => {
+				let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point);
 
-		// Closure to check if a point is the start or end of a segment
-		let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point);
+				let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector_data);
+				let start_handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data);
 
-		let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector_data);
-		let start_handle = ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data);
-
-		let start_point = if is_start(anchor, segment) {
-			vector_data.segment_end_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
-		} else {
-			vector_data.segment_start_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
-		};
+				let start_point = if is_start(anchor, segment) {
+					vector_data.segment_end_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
+				} else {
+					vector_data.segment_start_from_id(segment).and_then(|id| vector_data.point_domain.position_from_id(id))
+				};
 
-		let required_handle = if is_start(anchor, segment) {
-			start_handle
-				.filter(|&handle| handle != anchor_position)
-				.or(end_handle.filter(|&handle| Some(handle) != start_point))
-				.or(start_point)
-		} else {
-			end_handle
-				.filter(|&handle| handle != anchor_position)
-				.or(start_handle.filter(|&handle| Some(handle) != start_point))
-				.or(start_point)
-		};
+				let required_handle = if is_start(anchor, segment) {
+					start_handle
+						.filter(|&handle| handle != anchor_position)
+						.or(end_handle.filter(|&handle| Some(handle) != start_point))
+						.or(start_point)
+				} else {
+					end_handle
+						.filter(|&handle| handle != anchor_position)
+						.or(start_handle.filter(|&handle| Some(handle) != start_point))
+						.or(start_point)
+				};
 
-		if let Some(required_handle) = required_handle {
-			self.angle = -(required_handle - anchor_position).angle_to(DVec2::X);
-			self.handle_mode = HandleMode::ColinearEquidistant;
+				if let Some(required_handle) = required_handle {
+					self.angle = -(required_handle - anchor_position).angle_to(DVec2::X);
+					self.handle_mode = HandleMode::ColinearEquidistant;
+				}
+			}
+			(TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..), true) => {
+				self.angle = -(self.handle_end.unwrap() - anchor_position).angle_to(DVec2::X);
+			}
+			_ => {
+				self.angle = -(self.next_handle_start - anchor_position).angle_to(DVec2::X);
+			}
 		}
+
+		// Closure to check if a point is the start or end of a segment
 	}
 
 	fn add_point_layer_position(&mut self, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>, layer: LayerNodeIdentifier, viewport: DVec2) {
@@ -1262,6 +1307,9 @@ impl Fsm for PenToolFsmState {
 					return PenToolFsmState::PlacingAnchor;
 				}
 
+				let latest_pos = latest.pos;
+				let latest_handle_start = latest.handle_start;
+
 				let viewport = document.metadata().transform_to_viewport(layer);
 				let last_point = viewport.transform_point2(latest.pos);
 				let handle = viewport.transform_point2(latest.handle_start);
@@ -1278,6 +1326,14 @@ impl Fsm for PenToolFsmState {
 				tool_data.previous_handle_start_pos = latest.handle_start;
 				let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
 				tool_data.previous_handle_end_pos = tool_data.target_handle_position(opposite_handle, &vector_data);
+				let handle1 = latest_handle_start - latest_pos;
+				let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else {
+					return PenToolFsmState::GRSHandle;
+				};
+				let handle2 = opposite_handle_pos - latest_pos;
+				let pi = std::f64::consts::PI;
+				let angle = handle1.angle_to(handle2);
+				tool_data.colinear = angle.abs() < 1e-6 || (angle % pi).abs() < 1e-6;
 				PenToolFsmState::GRSHandle
 			}
 			(PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position }) => {
@@ -1292,27 +1348,24 @@ impl Fsm for PenToolFsmState {
 				}
 
 				responses.add(OverlaysMessage::Draw);
+				let Some(latest) = tool_data.latest_point() else {
+					return PenToolFsmState::GRSHandle;
+				};
+				let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
+				let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else {
+					return PenToolFsmState::GRSHandle;
+				};
+				if tool_data.colinear {
+					let Some(direction) = (latest.pos - latest.handle_start).try_normalize() else {
+						return PenToolFsmState::GRSHandle;
+					};
 
-				// Making the end handle colinear
-				match tool_data.handle_mode {
-					HandleMode::Free => {}
-					HandleMode::ColinearEquidistant | HandleMode::ColinearLocked => {
-						if let Some(latest) = tool_data.latest_point() {
-							let Some(direction) = (latest.pos - latest.handle_start).try_normalize() else {
-								return PenToolFsmState::GRSHandle;
-							};
-
-							if (latest.pos - latest.handle_start).length_squared() < f64::EPSILON {
-								return PenToolFsmState::GRSHandle;
-							}
-							let opposite_handle = tool_data.check_grs_end_handle(&vector_data);
-							let handle = tool_data.target_handle_position(opposite_handle, &vector_data);
-							let Some(handle) = handle else { return PenToolFsmState::GRSHandle };
-							let relative_distance = (handle - latest.pos).length();
-							let relative_position = relative_distance * direction + latest.pos;
-							tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, relative_position, layer);
-						}
+					if (latest.pos - latest.handle_start).length_squared() < f64::EPSILON {
+						return PenToolFsmState::GRSHandle;
 					}
+					let relative_distance = (opposite_handle_pos - latest.pos).length();
+					let relative_position = relative_distance * direction + latest.pos;
+					tool_data.update_target_handle_pos(opposite_handle, latest.pos, responses, relative_position, layer);
 				}
 
 				responses.add(OverlaysMessage::Draw);
@@ -1690,9 +1743,8 @@ impl Fsm for PenToolFsmState {
 				state
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
-				tool_data.update_offset(layer, document, shape_editor, input, responses);
+				tool_data.swap_handles(layer, document, shape_editor, input, responses);
 				responses.add(OverlaysMessage::Draw);
-				responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 				self
 			}
 			(
diff --git a/node-graph/gcore/src/vector/vector_data.rs b/node-graph/gcore/src/vector/vector_data.rs
index a141655fe8..add5b68690 100644
--- a/node-graph/gcore/src/vector/vector_data.rs
+++ b/node-graph/gcore/src/vector/vector_data.rs
@@ -334,14 +334,22 @@ impl VectorData {
 				let (start_point_id, _, _) = self.segment_points_from_id(*segment_id)?;
 				let start_index = self.point_domain.resolve_id(start_point_id)?;
 
-				self.segment_domain.end_connected(start_index).find(|&id| id != *segment_id).map(|id| (start_point_id, id))
+				self.segment_domain.end_connected(start_index).find(|&id| id != *segment_id).map(|id| (start_point_id, id)).or(self
+					.segment_domain
+					.start_connected(start_index)
+					.find(|&id| id != *segment_id)
+					.map(|id| (start_point_id, id)))
 			}
 			ManipulatorPointId::EndHandle(segment_id) => {
 				// For end handle, find segments starting at our end point
 				let (_, end_point_id, _) = self.segment_points_from_id(*segment_id)?;
 				let end_index = self.point_domain.resolve_id(end_point_id)?;
 
-				self.segment_domain.start_connected(end_index).find(|&id| id != *segment_id).map(|id| (end_point_id, id))
+				self.segment_domain.start_connected(end_index).find(|&id| id != *segment_id).map(|id| (end_point_id, id)).or(self
+					.segment_domain
+					.end_connected(end_index)
+					.find(|&id| id != *segment_id)
+					.map(|id| (end_point_id, id)))
 			}
 			ManipulatorPointId::Anchor(_) => None,
 		}

From a25c0d903f703c5cb5549816bd128c4aec4a0263 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Mon, 31 Mar 2025 17:51:28 +0530
Subject: [PATCH 15/21] edge cases fixed

---
 .../messages/tool/tool_messages/pen_tool.rs   | 56 +++++++++++++++----
 1 file changed, 44 insertions(+), 12 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index e48560cfd9..38e78259bb 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -303,7 +303,6 @@ struct PenToolData {
 	next_handle_start: DVec2,
 
 	g1_continuous: bool,
-	toggle_colinear_debounce: bool,
 
 	angle: f64,
 	auto_panning: AutoPanning,
@@ -313,9 +312,13 @@ struct PenToolData {
 
 	previous_handle_start_pos: DVec2,
 	previous_handle_end_pos: Option<DVec2>,
+	toggle_colinear_debounce: bool,
 	colinear: bool,
 	alt_press: bool,
 	space_press: bool,
+	lock_toggle: bool,
+	handle_swap: bool,
+	angle_locked: bool,
 	close_path: bool,
 
 	handle_mode: HandleMode,
@@ -495,6 +498,7 @@ impl PenToolData {
 		self.next_handle_start = self.next_point;
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 		self.update_handle_type(TargetHandle::HandleStart);
+		self.handle_mode = HandleMode::ColinearLocked;
 
 		// Break the control
 		let Some((last_pos, id)) = self.latest_point().map(|point| (point.pos, point.id)) else { return };
@@ -510,6 +514,7 @@ impl PenToolData {
 				let last_segment = self.end_point_segment;
 				let Some(point) = self.latest_point_mut() else { return };
 				point.in_segment = last_segment;
+				self.lock_toggle = true;
 				return;
 			}
 
@@ -518,6 +523,7 @@ impl PenToolData {
 			}
 		}
 
+		//Closing path
 		for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != id) {
 			let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
 			let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point));
@@ -528,10 +534,11 @@ impl PenToolData {
 				self.close_path = true;
 				self.next_handle_start = self.next_point;
 				self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
+				self.handle_mode = HandleMode::Free;
 				if self.modifiers.lock_angle {
 					self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
+					self.lock_toggle = true;
 				}
-				self.handle_mode = HandleMode::Free;
 			}
 		}
 	}
@@ -541,6 +548,7 @@ impl PenToolData {
 		let next_handle_start = self.next_handle_start;
 		let handle_start = self.latest_point()?.handle_start;
 		let mouse = snap_data.input.mouse.position;
+		self.handle_swap = false;
 		self.handle_end_offset = None;
 		self.handle_start_offset = None;
 		let Some(handle_end) = self.handle_end else {
@@ -860,6 +868,19 @@ impl PenToolData {
 			}
 		}
 
+		let mouse_pos = viewport_to_document.transform_point2(mouse_pos);
+		let anchor = transform.transform_point2(self.next_point);
+		let distance = (mouse_pos - anchor).length();
+
+		if self.lock_toggle && !self.modifiers.lock_angle {
+			self.lock_toggle = false;
+			self.handle_mode = HandleMode::Free;
+		}
+
+		if distance > 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked {
+			self.angle_locked = true
+		}
+
 		match self.handle_mode {
 			HandleMode::ColinearLocked | HandleMode::ColinearEquidistant => {
 				self.g1_continuous = true;
@@ -871,13 +892,9 @@ impl PenToolData {
 			}
 		}
 
-		let mouse_pos = viewport_to_document.transform_point2(mouse_pos);
-		let anchor = transform.transform_point2(self.next_point);
-		let distance = (mouse_pos - anchor).length();
-
-		if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle {
+		if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked {
 			self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
-			self.handle_mode = HandleMode::Free;
+			self.lock_toggle = true;
 			let last_segment = self.end_point_segment;
 			if let Some(latest) = self.latest_point_mut() {
 				latest.in_segment = last_segment;
@@ -1076,6 +1093,7 @@ impl PenToolData {
 
 				if self.modifiers.lock_angle {
 					self.set_lock_angle(&vector_data, point, segment);
+					self.lock_toggle = true;
 				}
 			}
 			let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface);
@@ -1090,10 +1108,10 @@ impl PenToolData {
 		if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
 			let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 			let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
-
+			self.handle_mode = HandleMode::Free;
 			if self.modifiers.lock_angle {
-				self.handle_mode = HandleMode::Free;
 				self.set_lock_angle(&vector_data, point, segment);
+				self.lock_toggle = true;
 			}
 		}
 
@@ -1165,11 +1183,11 @@ impl PenToolData {
 		self.next_handle_start = handle_start;
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 		let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
-
+		self.handle_mode = HandleMode::Free;
 		if self.modifiers.lock_angle {
 			self.set_lock_angle(&vector_data, point, segment);
+			self.lock_toggle = true;
 		}
-		self.handle_mode = HandleMode::Free;
 	}
 
 	// Stores the segment and point ID of the clicked endpoint
@@ -1241,9 +1259,11 @@ impl PenToolData {
 			}
 			(TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..), true) => {
 				self.angle = -(self.handle_end.unwrap() - anchor_position).angle_to(DVec2::X);
+				self.handle_mode = HandleMode::ColinearEquidistant;
 			}
 			_ => {
 				self.angle = -(self.next_handle_start - anchor_position).angle_to(DVec2::X);
+				self.handle_mode = HandleMode::ColinearEquidistant;
 			}
 		}
 
@@ -1670,10 +1690,19 @@ impl Fsm for PenToolFsmState {
 					tool_data.toggle_colinear_debounce = false;
 				}
 
+				if !tool_data.modifiers.lock_angle {
+					tool_data.angle_locked = false;
+				}
+
 				let state = tool_data
 					.drag_handle(snap_data, transform, input.mouse.position, responses, layer, input)
 					.unwrap_or(PenToolFsmState::Ready);
 
+				// To prevent showing cursor when KeyC is pressed when handles are swapped
+				if tool_data.handle_swap {
+					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
+				}
+
 				// Auto-panning
 				let messages = [
 					PenToolMessage::PointerOutsideViewport {
@@ -1744,6 +1773,9 @@ impl Fsm for PenToolFsmState {
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
 				tool_data.swap_handles(layer, document, shape_editor, input, responses);
+				if !tool_data.handle_swap {
+					tool_data.handle_swap = true
+				};
 				responses.add(OverlaysMessage::Draw);
 				self
 			}

From 8a445d747683334211b0bd744a90a884a684e747 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Mon, 7 Apr 2025 14:46:25 +0530
Subject: [PATCH 16/21] fix edge cases and add docs

---
 .../messages/tool/tool_messages/pen_tool.rs   | 47 +++++++++++++------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index bdd5a4e671..2e07ba3696 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -285,12 +285,18 @@ enum HandleMode {
 /// The type of handle which is dragged by the cursor (under the cursor)
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
-	HandleEnd,
+	#[default]
+	None,
+	/// The handle that is drawn when an anchor is placed and dragging begins usually `next__handle-_start`,
+	/// lasting until `Tab` is pressed to swap the handles.
 	HandleStart,
+	/// The opposite handle that is drawn after placing an anchor and starting to drag
+	/// the "next handle start", continuing until `Tab` is pressed to swap the handles.
+	HandleEnd,
+	/// In the bent handle case,or starting to drag handle from a different segment,the endpoint might be having handle a to it.
+	/// if the endpoint is a startpoint it would have ManipulatorPointId::PrimaryHandle attached to it if not then ManipulatorPointId::EndHandle
 	PrimaryHandle(SegmentId),
 	EndHandle(SegmentId),
-	#[default]
-	None,
 }
 
 #[derive(Clone, Debug, Default)]
@@ -316,8 +322,14 @@ struct PenToolData {
 	colinear: bool,
 	alt_press: bool,
 	space_press: bool,
-	lock_toggle: bool,
+	/// Tracks whether to switch from `HandleMode::ColinearEquidistant` to `HandleMode::Free`
+	/// after releasing Ctrl, specifically when Ctrl was held before the handle was dragged from the anchor.
+	switch_to_free_on_ctrl_release: bool,
+	///// To prevent showing cursor when KeyC is pressed when handles are swapped
 	handle_swap: bool,
+	/// Prevents conflicts when the handle's angle is already locked and it passes near the anchor,
+	/// avoiding unintended direction changes. Specifically handles the case where a handle is being dragged,
+	/// and Ctrl is pressed near the anchor to make it colinear with its opposite handle.
 	angle_locked: bool,
 	close_path: bool,
 
@@ -515,7 +527,7 @@ impl PenToolData {
 				let last_segment = self.end_point_segment;
 				let Some(point) = self.latest_point_mut() else { return };
 				point.in_segment = last_segment;
-				self.lock_toggle = true;
+				self.switch_to_free_on_ctrl_release = true;
 				return;
 			}
 
@@ -538,7 +550,7 @@ impl PenToolData {
 				self.handle_mode = HandleMode::Free;
 				if self.modifiers.lock_angle {
 					self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
-					self.lock_toggle = true;
+					self.switch_to_free_on_ctrl_release = true;
 				}
 			}
 		}
@@ -749,9 +761,11 @@ impl PenToolData {
 			let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
 			// Update offset
 			let Some(handle_pos) = self.target_handle_position(opposite_type, &vector_data) else {
+				self.handle_swap = false;
 				return;
 			};
 			if (handle_pos - self.next_point).length() < 1e-6 {
+				self.handle_swap = false;
 				return;
 			}
 			self.handle_end_offset = Some(viewport.transform_point2(handle_pos) - input.mouse.position);
@@ -873,8 +887,8 @@ impl PenToolData {
 		let anchor = transform.transform_point2(self.next_point);
 		let distance = (mouse_pos - anchor).length();
 
-		if self.lock_toggle && !self.modifiers.lock_angle {
-			self.lock_toggle = false;
+		if self.switch_to_free_on_ctrl_release && !self.modifiers.lock_angle {
+			self.switch_to_free_on_ctrl_release = false;
 			self.handle_mode = HandleMode::Free;
 		}
 
@@ -895,7 +909,7 @@ impl PenToolData {
 
 		if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked {
 			self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
-			self.lock_toggle = true;
+			self.switch_to_free_on_ctrl_release = true;
 			let last_segment = self.end_point_segment;
 			if let Some(latest) = self.latest_point_mut() {
 				latest.in_segment = last_segment;
@@ -949,6 +963,10 @@ impl PenToolData {
 			return;
 		};
 
+		if (anchor_pos - handle).length() < 1e-6 {
+			return;
+		}
+
 		let Some(direction) = (anchor_pos - handle).try_normalize() else {
 			log::trace!("Skipping colinear adjustment: handle_start and anchor_point are too close!");
 			return;
@@ -1094,7 +1112,7 @@ impl PenToolData {
 
 				if self.modifiers.lock_angle {
 					self.set_lock_angle(&vector_data, point, segment);
-					self.lock_toggle = true;
+					self.switch_to_free_on_ctrl_release = true;
 				}
 			}
 			let mut selected_layers_except_artboards = selected_nodes.selected_layers_except_artboards(&document.network_interface);
@@ -1112,7 +1130,7 @@ impl PenToolData {
 			self.handle_mode = HandleMode::Free;
 			if self.modifiers.lock_angle {
 				self.set_lock_angle(&vector_data, point, segment);
-				self.lock_toggle = true;
+				self.switch_to_free_on_ctrl_release = true;
 			}
 		}
 
@@ -1187,7 +1205,7 @@ impl PenToolData {
 		self.handle_mode = HandleMode::Free;
 		if self.modifiers.lock_angle {
 			self.set_lock_angle(&vector_data, point, segment);
-			self.lock_toggle = true;
+			self.switch_to_free_on_ctrl_release = true;
 		}
 	}
 
@@ -1354,7 +1372,7 @@ impl Fsm for PenToolFsmState {
 				let handle2 = opposite_handle_pos - latest_pos;
 				let pi = std::f64::consts::PI;
 				let angle = handle1.angle_to(handle2);
-				tool_data.colinear = angle.abs() < 1e-6 || (angle % pi).abs() < 1e-6;
+				tool_data.colinear = (angle - pi).abs() < 1e-6 || (angle + pi).abs() < 1e-6;
 				PenToolFsmState::GRSHandle
 			}
 			(PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position }) => {
@@ -1699,7 +1717,6 @@ impl Fsm for PenToolFsmState {
 					.drag_handle(snap_data, transform, input.mouse.position, responses, layer, input)
 					.unwrap_or(PenToolFsmState::Ready);
 
-				// To prevent showing cursor when KeyC is pressed when handles are swapped
 				if tool_data.handle_swap {
 					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 				}
@@ -1773,10 +1790,10 @@ impl Fsm for PenToolFsmState {
 				state
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
-				tool_data.swap_handles(layer, document, shape_editor, input, responses);
 				if !tool_data.handle_swap {
 					tool_data.handle_swap = true
 				};
+				tool_data.swap_handles(layer, document, shape_editor, input, responses);
 				responses.add(OverlaysMessage::Draw);
 				self
 			}

From 2b987e764f1b10ff9ffef9ac2cea4f720885b2e6 Mon Sep 17 00:00:00 2001
From: Keavon Chambers <keavon@keavon.com>
Date: Mon, 7 Apr 2025 04:12:54 -0700
Subject: [PATCH 17/21] Code review pass

---
 .../messages/input_mapper/input_mappings.rs   |  2 +-
 .../document/overlays/utility_functions.rs    |  1 +
 .../messages/tool/tool_messages/pen_tool.rs   | 85 ++++++++++++-------
 3 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs
index 3e05c4efe9..eb264dfb3a 100644
--- a/editor/src/messages/input_mapper/input_mappings.rs
+++ b/editor/src/messages/input_mapper/input_mappings.rs
@@ -254,7 +254,7 @@ pub fn input_mappings() -> Mapping {
 		//
 		// PenToolMessage
 		entry!(PointerMove; refresh_keys=[Control, Alt, Shift, KeyC], action_dispatch=PenToolMessage::PointerMove { snap_angle: Shift, break_handle: Alt, lock_angle: Control, colinear: KeyC, move_anchor_with_handles: Space }),
-		entry!(KeyDownNoRepeat(Tab);action_dispatch=PenToolMessage::SwapHandles),
+		entry!(KeyDownNoRepeat(Tab); action_dispatch=PenToolMessage::SwapHandles),
 		entry!(KeyDown(MouseLeft); action_dispatch=PenToolMessage::DragStart { append_to_selected: Shift }),
 		entry!(KeyUp(MouseLeft); action_dispatch=PenToolMessage::DragStop),
 		entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Abort),
diff --git a/editor/src/messages/portfolio/document/overlays/utility_functions.rs b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
index 2c585d2afe..a6a77b1726 100644
--- a/editor/src/messages/portfolio/document/overlays/utility_functions.rs
+++ b/editor/src/messages/portfolio/document/overlays/utility_functions.rs
@@ -121,6 +121,7 @@ pub fn path_overlays(document: &DocumentMessageHandler, draw_handles: DrawHandle
 		let is_selected = |point: ManipulatorPointId| selected.is_some_and(|selected| selected.is_selected(point));
 
 		let opposite_handles_data: Vec<(PointId, SegmentId)> = shape_editor.selected_points().filter_map(|point_id| vector_data.adjacent_segment(point_id)).collect();
+
 		match draw_handles {
 			DrawHandles::All => {
 				vector_data.segment_bezier_iter().for_each(|(segment_id, bezier, _start, _end)| {
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 2e07ba3696..6cbeb3bec7 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -282,20 +282,33 @@ enum HandleMode {
 	ColinearEquidistant,
 }
 
-/// The type of handle which is dragged by the cursor (under the cursor)
+/// The type of handle which is dragged by the cursor (under the cursor).
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	#[default]
 	None,
-	/// The handle that is drawn when an anchor is placed and dragging begins usually `next__handle-_start`,
-	/// lasting until `Tab` is pressed to swap the handles.
+	/// This is the handle being dragged and represents the primary handle
+	/// of the next segment that will be placed after the current handle and next anchor are placed.
+	/// Its position is stored in `tool_data.next_handle_start`.
+	///
+	/// Pressing Tab swaps to the opposite handle type. The swapped handle can be either `HandleEnd` or,
+	/// in the case of a bent segment, [`ManipulatorPointId::PrimaryHandle`] or [`ManipulatorPointId::EndHandle`].
+	///
+	/// When closing a path, the handle being dragged becomes the end handle of the currently placed anchor.
 	HandleStart,
 	/// The opposite handle that is drawn after placing an anchor and starting to drag
-	/// the "next handle start", continuing until `Tab` is pressed to swap the handles.
+	/// the "next handle start", continuing until Tab is pressed to swap the handles.
 	HandleEnd,
-	/// In the bent handle case,or starting to drag handle from a different segment,the endpoint might be having handle a to it.
-	/// if the endpoint is a startpoint it would have ManipulatorPointId::PrimaryHandle attached to it if not then ManipulatorPointId::EndHandle
+	/// This is the primary handle of the segment from whose endpoint a new handle is being drawn.
+	/// When closing the path, the handle being dragged will be the [`TargetHandle::HandleEnd`] (see its documentation);
+	/// otherwise, it will be [`TargetHandle::HandleStart`].
+	///
+	/// If a handle is dragged from a different endpoint within the same layer, the opposite handle will be
+	/// `ManipulatorPoint::Primary` if that point is the starting point of its path.
 	PrimaryHandle(SegmentId),
+	/// This is the end handle of the segment from whose endpoint a new handle is being drawn (same cases apply
+	/// as mentioned in [`TargetHandle::PrimaryHandle`]). If a handle is dragged from a different endpoint within the same
+	/// layer, the opposite handle will be `ManipulatorPoint::EndHandle` if that point is the end point of its path.
 	EndHandle(SegmentId),
 }
 
@@ -325,7 +338,7 @@ struct PenToolData {
 	/// Tracks whether to switch from `HandleMode::ColinearEquidistant` to `HandleMode::Free`
 	/// after releasing Ctrl, specifically when Ctrl was held before the handle was dragged from the anchor.
 	switch_to_free_on_ctrl_release: bool,
-	///// To prevent showing cursor when KeyC is pressed when handles are swapped
+	/// To prevent showing cursor when `KeyC` is pressed when handles are swapped.
 	handle_swap: bool,
 	/// Prevents conflicts when the handle's angle is already locked and it passes near the anchor,
 	/// avoiding unintended direction changes. Specifically handles the case where a handle is being dragged,
@@ -358,7 +371,7 @@ impl PenToolData {
 		self.latest_points.push(point);
 	}
 
-	/// Check whether target handle is primary,end or 'self.handle_end'
+	/// Check whether target handle is primary, end, or `self.handle_end`
 	fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
 		match (self.handle_end, self.end_point, self.end_point_segment, self.close_path) {
 			(Some(_), _, _, false) => TargetHandle::HandleEnd,
@@ -387,22 +400,17 @@ impl PenToolData {
 	fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle {
 		match handle_type {
 			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
-			TargetHandle::HandleEnd => {
-				if self.close_path {
-					match (self.end_point, self.end_point_segment) {
-						(Some(point), Some(segment)) => {
-							if vector_data.segment_start_from_id(segment) == Some(point) {
-								TargetHandle::PrimaryHandle(segment)
-							} else {
-								TargetHandle::EndHandle(segment)
-							}
-						}
-						_ => TargetHandle::None,
+			TargetHandle::HandleEnd => match (self.close_path, self.end_point, self.end_point_segment) {
+				(true, _, _) => TargetHandle::HandleStart,
+				(false, Some(point), Some(segment)) => {
+					if vector_data.segment_start_from_id(segment) == Some(point) {
+						TargetHandle::PrimaryHandle(segment)
+					} else {
+						TargetHandle::EndHandle(segment)
 					}
-				} else {
-					TargetHandle::HandleStart
 				}
-			}
+				_ => TargetHandle::None,
+			},
 			_ => {
 				if self.close_path {
 					TargetHandle::HandleEnd
@@ -450,6 +458,7 @@ impl PenToolData {
 			TargetHandle::None => None,
 		}
 	}
+
 	/// Remove the handles selected when swapping handles
 	fn cleanup_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
 		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
@@ -468,7 +477,7 @@ impl PenToolData {
 		responses.add(OverlaysMessage::Draw);
 	}
 
-	/// Selects the handle which is currently dragged by the user  
+	/// Selects the handle which is currently dragged by the user.
 	fn add_target_selections(&self, shape_editor: &mut ShapeState, layer: Option<LayerNodeIdentifier>) {
 		let Some(shape_state) = layer.and_then(|layer| shape_editor.selected_shape_state.get_mut(&layer)) else {
 			return;
@@ -521,7 +530,9 @@ impl PenToolData {
 		if on_top {
 			self.handle_end = None;
 			self.handle_mode = HandleMode::Free;
+
 			self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
+
 			if self.modifiers.lock_angle {
 				self.set_lock_angle(&vector_data, id, self.end_point_segment);
 				let last_segment = self.end_point_segment;
@@ -536,11 +547,12 @@ impl PenToolData {
 			}
 		}
 
-		//Closing path
+		// Closing path
 		for id in vector_data.extendable_points(preferences.vector_meshes).filter(|&point| point != id) {
 			let Some(pos) = vector_data.point_domain.position_from_id(id) else { continue };
 			let transformed_distance_between_squared = transform.transform_point2(pos).distance_squared(transform.transform_point2(self.next_point));
 			let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
+
 			if transformed_distance_between_squared < snap_point_tolerance_squared {
 				self.update_handle_type(TargetHandle::HandleEnd);
 				self.handle_end_offset = None;
@@ -733,7 +745,7 @@ impl PenToolData {
 		Some(transform.inverse().transform_vector2(delta))
 	}
 
-	// Calculates the offset from the mouse when swapping handles and swaps the handles
+	/// Calculates the offset from the mouse when swapping handles, and swaps the handles.
 	fn swap_handles(
 		&mut self,
 		layer: Option<LayerNodeIdentifier>,
@@ -750,6 +762,7 @@ impl PenToolData {
 		let Some(viewport) = layer.map(|layer| document.metadata().transform_to_viewport(layer)) else {
 			return;
 		};
+
 		// Determine if we need to swap to opposite handle
 		let should_swap_to_opposite = self.close_path && matches!(self.handle_type, TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..))
 			|| !self.close_path && matches!(self.handle_type, TargetHandle::HandleStart);
@@ -769,6 +782,7 @@ impl PenToolData {
 				return;
 			}
 			self.handle_end_offset = Some(viewport.transform_point2(handle_pos) - input.mouse.position);
+
 			// Update selections if in closed path mode
 			if self.close_path {
 				self.cleanup_target_selections(shape_editor, layer, document, responses);
@@ -786,6 +800,7 @@ impl PenToolData {
 
 			self.update_handle_type(TargetHandle::HandleStart);
 		}
+
 		responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 	}
 
@@ -799,7 +814,9 @@ impl PenToolData {
 		};
 
 		latest.pos += delta;
+
 		let modification_type = VectorModificationType::ApplyPointDelta { point: latest.id, delta };
+
 		responses.add(GraphOperationMessage::Vector { layer, modification_type });
 
 		responses.add(OverlaysMessage::Draw);
@@ -814,6 +831,7 @@ impl PenToolData {
 		}
 
 		let Some(end_point) = self.end_point else { return };
+
 		let modification_type_anchor = VectorModificationType::ApplyPointDelta { point: end_point, delta };
 		responses.add(GraphOperationMessage::Vector {
 			layer,
@@ -848,7 +866,8 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer)?;
 		let viewport_to_document = document.metadata().document_to_viewport.inverse();
 		let mut mouse_pos = mouse;
-		// Handles pressing `space` to drag anchor and its handles
+
+		// Handles pressing Space to drag anchor and its handles
 		if self.modifiers.move_anchor_with_handles {
 			let Some(delta) = self.space_anchor_handle_snap(&viewport_to_document, &transform, &snap_data, &mouse, &vector_data, input) else {
 				return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
@@ -864,6 +883,7 @@ impl PenToolData {
 			if let Some(handle) = self.handle_end.as_mut() {
 				*handle += delta;
 			}
+
 			self.move_anchor_and_handles(delta, layer, responses, &vector_data);
 
 			responses.add(OverlaysMessage::Draw);
@@ -917,6 +937,7 @@ impl PenToolData {
 		}
 
 		responses.add(OverlaysMessage::Draw);
+
 		Some(PenToolFsmState::DraggingHandle(self.handle_mode))
 	}
 
@@ -984,10 +1005,7 @@ impl PenToolData {
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
 		let document = snap_data.document;
 
-		let mut relative = self.latest_point().map(|point| point.pos);
-		if self.close_path {
-			relative = None
-		};
+		let relative = if self.close_path { None } else { self.latest_point().map(|point| point.pos) };
 		self.next_point = self.compute_snapped_angle(snap_data, transform, false, mouse, relative, true);
 
 		let selected_nodes = document.network_interface.selected_nodes();
@@ -1203,6 +1221,7 @@ impl PenToolData {
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 		let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
 		self.handle_mode = HandleMode::Free;
+
 		if self.modifiers.lock_angle {
 			self.set_lock_angle(&vector_data, point, segment);
 			self.switch_to_free_on_ctrl_release = true;
@@ -1246,6 +1265,7 @@ impl PenToolData {
 			self.handle_mode = HandleMode::Free;
 			return;
 		};
+
 		match (self.handle_type, self.close_path) {
 			(TargetHandle::HandleStart, _) | (TargetHandle::HandleEnd, true) => {
 				let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point);
@@ -1394,6 +1414,7 @@ impl Fsm for PenToolFsmState {
 				let Some(opposite_handle_pos) = tool_data.target_handle_position(opposite_handle, &vector_data) else {
 					return PenToolFsmState::GRSHandle;
 				};
+
 				if tool_data.colinear {
 					let Some(direction) = (latest.pos - latest.handle_start).try_normalize() else {
 						return PenToolFsmState::GRSHandle;
@@ -1792,7 +1813,7 @@ impl Fsm for PenToolFsmState {
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
 				if !tool_data.handle_swap {
 					tool_data.handle_swap = true
-				};
+				}
 				tool_data.swap_handles(layer, document, shape_editor, input, responses);
 				responses.add(OverlaysMessage::Draw);
 				self
@@ -1819,7 +1840,7 @@ impl Fsm for PenToolFsmState {
 				self
 			}
 			(PenToolFsmState::DraggingHandle(mode), PenToolMessage::PointerOutsideViewport { .. }) => {
-				// Auto-panningF
+				// Auto-panning
 				let _ = tool_data.auto_panning.shift_viewport(input, responses);
 
 				PenToolFsmState::DraggingHandle(mode)

From ff344547c1e0e854916e750481744a44ddba0425 Mon Sep 17 00:00:00 2001
From: 0SlowPoke0 <govindpratyush@gmail.com>
Date: Tue, 8 Apr 2025 07:03:59 +0530
Subject: [PATCH 18/21] rename ,bug fixes

---
 .../messages/tool/tool_messages/pen_tool.rs   | 215 +++++++++---------
 1 file changed, 112 insertions(+), 103 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 6cbeb3bec7..3ee6bb9652 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -291,25 +291,25 @@ enum TargetHandle {
 	/// of the next segment that will be placed after the current handle and next anchor are placed.
 	/// Its position is stored in `tool_data.next_handle_start`.
 	///
-	/// Pressing Tab swaps to the opposite handle type. The swapped handle can be either `HandleEnd` or,
-	/// in the case of a bent segment, [`ManipulatorPointId::PrimaryHandle`] or [`ManipulatorPointId::EndHandle`].
+	/// Pressing Tab swaps to the opposite handle type. The swapped handle can be either `PreviewInHandle` or,
+	/// in the case of a bent segment, [`ManipulatorPointId::EndHandle`] or [`ManipulatorPointId::PrimaryHandle`].
 	///
 	/// When closing a path, the handle being dragged becomes the end handle of the currently placed anchor.
-	HandleStart,
+	FuturePreviewOutHandle,
 	/// The opposite handle that is drawn after placing an anchor and starting to drag
 	/// the "next handle start", continuing until Tab is pressed to swap the handles.
-	HandleEnd,
+	PreviewInHandle,
 	/// This is the primary handle of the segment from whose endpoint a new handle is being drawn.
-	/// When closing the path, the handle being dragged will be the [`TargetHandle::HandleEnd`] (see its documentation);
-	/// otherwise, it will be [`TargetHandle::HandleStart`].
+	/// When closing the path, the handle being dragged will be the [`TargetHandle::PreviewInHandle`] (see its documentation);
+	/// otherwise, it will be [`TargetHandle::FuturePreviewOutHandle`].
 	///
 	/// If a handle is dragged from a different endpoint within the same layer, the opposite handle will be
 	/// `ManipulatorPoint::Primary` if that point is the starting point of its path.
-	PrimaryHandle(SegmentId),
+	PriorOutHandle(SegmentId),
 	/// This is the end handle of the segment from whose endpoint a new handle is being drawn (same cases apply
-	/// as mentioned in [`TargetHandle::PrimaryHandle`]). If a handle is dragged from a different endpoint within the same
+	/// as mentioned in [`TargetHandle::PriorOutHandle`]). If a handle is dragged from a different endpoint within the same
 	/// layer, the opposite handle will be `ManipulatorPoint::EndHandle` if that point is the end point of its path.
-	EndHandle(SegmentId),
+	PriorInHandle(SegmentId),
 }
 
 #[derive(Clone, Debug, Default)]
@@ -333,22 +333,22 @@ struct PenToolData {
 	previous_handle_end_pos: Option<DVec2>,
 	toggle_colinear_debounce: bool,
 	colinear: bool,
-	alt_press: bool,
-	space_press: bool,
+	alt_pressed: bool,
+	space_pressed: bool,
 	/// Tracks whether to switch from `HandleMode::ColinearEquidistant` to `HandleMode::Free`
 	/// after releasing Ctrl, specifically when Ctrl was held before the handle was dragged from the anchor.
 	switch_to_free_on_ctrl_release: bool,
 	/// To prevent showing cursor when `KeyC` is pressed when handles are swapped.
-	handle_swap: bool,
+	handle_swapped: bool,
 	/// Prevents conflicts when the handle's angle is already locked and it passes near the anchor,
 	/// avoiding unintended direction changes. Specifically handles the case where a handle is being dragged,
 	/// and Ctrl is pressed near the anchor to make it colinear with its opposite handle.
 	angle_locked: bool,
-	close_path: bool,
+	path_closed: bool,
 
 	handle_mode: HandleMode,
-	end_point: Option<PointId>,
-	end_point_segment: Option<SegmentId>,
+	prior_segment_endpoint: Option<PointId>,
+	prior_segment: Option<SegmentId>,
 	handle_type: TargetHandle,
 	handle_start_offset: Option<DVec2>,
 	handle_end_offset: Option<DVec2>,
@@ -373,13 +373,13 @@ impl PenToolData {
 
 	/// Check whether target handle is primary, end, or `self.handle_end`
 	fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
-		match (self.handle_end, self.end_point, self.end_point_segment, self.close_path) {
-			(Some(_), _, _, false) => TargetHandle::HandleEnd,
+		match (self.handle_end, self.prior_segment_endpoint, self.prior_segment, self.path_closed) {
+			(Some(_), _, _, false) => TargetHandle::PreviewInHandle,
 			(None, Some(point), Some(segment), false) | (Some(_), Some(point), Some(segment), true) => {
 				if vector_data.segment_start_from_id(segment) == Some(point) {
-					TargetHandle::PrimaryHandle(segment)
+					TargetHandle::PriorOutHandle(segment)
 				} else {
-					TargetHandle::EndHandle(segment)
+					TargetHandle::PriorInHandle(segment)
 				}
 			}
 			_ => TargetHandle::None,
@@ -388,34 +388,34 @@ impl PenToolData {
 
 	fn check_grs_end_handle(&self, vector_data: &VectorData) -> TargetHandle {
 		let Some(point) = self.latest_point().map(|point| point.id) else { return TargetHandle::None };
-		let Some(segment) = self.end_point_segment else { return TargetHandle::None };
+		let Some(segment) = self.prior_segment else { return TargetHandle::None };
 
 		if vector_data.segment_start_from_id(segment) == Some(point) {
-			TargetHandle::PrimaryHandle(segment)
+			TargetHandle::PriorOutHandle(segment)
 		} else {
-			TargetHandle::EndHandle(segment)
+			TargetHandle::PriorInHandle(segment)
 		}
 	}
 
 	fn get_opposite_handle_type(&self, handle_type: TargetHandle, vector_data: &VectorData) -> TargetHandle {
 		match handle_type {
-			TargetHandle::HandleStart => self.check_end_handle_type(vector_data),
-			TargetHandle::HandleEnd => match (self.close_path, self.end_point, self.end_point_segment) {
-				(true, _, _) => TargetHandle::HandleStart,
-				(false, Some(point), Some(segment)) => {
+			TargetHandle::FuturePreviewOutHandle => self.check_end_handle_type(vector_data),
+			TargetHandle::PreviewInHandle => match (self.path_closed, self.prior_segment_endpoint, self.prior_segment) {
+				(false, _, _) => TargetHandle::FuturePreviewOutHandle,
+				(true, Some(point), Some(segment)) => {
 					if vector_data.segment_start_from_id(segment) == Some(point) {
-						TargetHandle::PrimaryHandle(segment)
+						TargetHandle::PriorOutHandle(segment)
 					} else {
-						TargetHandle::EndHandle(segment)
+						TargetHandle::PriorInHandle(segment)
 					}
 				}
 				_ => TargetHandle::None,
 			},
 			_ => {
-				if self.close_path {
-					TargetHandle::HandleEnd
+				if self.path_closed {
+					TargetHandle::PreviewInHandle
 				} else {
-					TargetHandle::HandleStart
+					TargetHandle::FuturePreviewOutHandle
 				}
 			}
 		}
@@ -427,20 +427,20 @@ impl PenToolData {
 
 	fn update_target_handle_pos(&mut self, handle_type: TargetHandle, anchor_pos: DVec2, responses: &mut VecDeque<Message>, delta: DVec2, layer: LayerNodeIdentifier) {
 		match handle_type {
-			TargetHandle::HandleStart => {
+			TargetHandle::FuturePreviewOutHandle => {
 				self.next_handle_start = delta;
 			}
-			TargetHandle::HandleEnd => {
+			TargetHandle::PreviewInHandle => {
 				if let Some(handle) = self.handle_end.as_mut() {
 					*handle = delta;
 				}
 			}
-			TargetHandle::EndHandle(segment) => {
+			TargetHandle::PriorInHandle(segment) => {
 				let relative_position = delta - anchor_pos;
 				let modification_type = VectorModificationType::SetEndHandle { segment, relative_position };
 				responses.add(GraphOperationMessage::Vector { layer, modification_type });
 			}
-			TargetHandle::PrimaryHandle(segment) => {
+			TargetHandle::PriorOutHandle(segment) => {
 				let relative_position = delta - anchor_pos;
 				let modification_type = VectorModificationType::SetPrimaryHandle { segment, relative_position };
 				responses.add(GraphOperationMessage::Vector { layer, modification_type });
@@ -451,10 +451,10 @@ impl PenToolData {
 
 	fn target_handle_position(&self, handle_type: TargetHandle, vector_data: &VectorData) -> Option<DVec2> {
 		match handle_type {
-			TargetHandle::PrimaryHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data),
-			TargetHandle::EndHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data),
-			TargetHandle::HandleEnd => self.handle_end,
-			TargetHandle::HandleStart => Some(self.next_handle_start),
+			TargetHandle::PriorOutHandle(segment) => ManipulatorPointId::PrimaryHandle(segment).get_position(vector_data),
+			TargetHandle::PriorInHandle(segment) => ManipulatorPointId::EndHandle(segment).get_position(vector_data),
+			TargetHandle::PreviewInHandle => self.handle_end,
+			TargetHandle::FuturePreviewOutHandle => Some(self.next_handle_start),
 			TargetHandle::None => None,
 		}
 	}
@@ -470,8 +470,8 @@ impl PenToolData {
 		};
 
 		match self.check_end_handle_type(&vector_data) {
-			TargetHandle::EndHandle(segment) => shape_state.deselect_point(ManipulatorPointId::EndHandle(segment)),
-			TargetHandle::PrimaryHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)),
+			TargetHandle::PriorInHandle(segment) => shape_state.deselect_point(ManipulatorPointId::EndHandle(segment)),
+			TargetHandle::PriorOutHandle(segment) => shape_state.deselect_point(ManipulatorPointId::PrimaryHandle(segment)),
 			_ => {}
 		}
 		responses.add(OverlaysMessage::Draw);
@@ -484,8 +484,8 @@ impl PenToolData {
 		};
 
 		match self.handle_type {
-			TargetHandle::EndHandle(segment) => shape_state.select_point(ManipulatorPointId::EndHandle(segment)),
-			TargetHandle::PrimaryHandle(segment) => shape_state.select_point(ManipulatorPointId::PrimaryHandle(segment)),
+			TargetHandle::PriorInHandle(segment) => shape_state.select_point(ManipulatorPointId::EndHandle(segment)),
+			TargetHandle::PriorOutHandle(segment) => shape_state.select_point(ManipulatorPointId::PrimaryHandle(segment)),
 			_ => {}
 		}
 	}
@@ -519,7 +519,7 @@ impl PenToolData {
 		let document = snap_data.document;
 		self.next_handle_start = self.next_point;
 		let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
-		self.update_handle_type(TargetHandle::HandleStart);
+		self.update_handle_type(TargetHandle::FuturePreviewOutHandle);
 		self.handle_mode = HandleMode::ColinearLocked;
 
 		// Break the control
@@ -534,8 +534,8 @@ impl PenToolData {
 			self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
 
 			if self.modifiers.lock_angle {
-				self.set_lock_angle(&vector_data, id, self.end_point_segment);
-				let last_segment = self.end_point_segment;
+				self.set_lock_angle(&vector_data, id, self.prior_segment);
+				let last_segment = self.prior_segment;
 				let Some(point) = self.latest_point_mut() else { return };
 				point.in_segment = last_segment;
 				self.switch_to_free_on_ctrl_release = true;
@@ -554,14 +554,14 @@ impl PenToolData {
 			let snap_point_tolerance_squared = crate::consts::SNAP_POINT_TOLERANCE.powi(2);
 
 			if transformed_distance_between_squared < snap_point_tolerance_squared {
-				self.update_handle_type(TargetHandle::HandleEnd);
+				self.update_handle_type(TargetHandle::PreviewInHandle);
 				self.handle_end_offset = None;
-				self.close_path = true;
+				self.path_closed = true;
 				self.next_handle_start = self.next_point;
 				self.store_clicked_endpoint(document, &transform, snap_data.input, preferences);
 				self.handle_mode = HandleMode::Free;
-				if self.modifiers.lock_angle {
-					self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
+				if let (true, Some(prior_endpoint)) = (self.modifiers.lock_angle, self.prior_segment_endpoint) {
+					self.set_lock_angle(&vector_data, prior_endpoint, self.prior_segment);
 					self.switch_to_free_on_ctrl_release = true;
 				}
 			}
@@ -573,7 +573,7 @@ impl PenToolData {
 		let next_handle_start = self.next_handle_start;
 		let handle_start = self.latest_point()?.handle_start;
 		let mouse = snap_data.input.mouse.position;
-		self.handle_swap = false;
+		self.handle_swapped = false;
 		self.handle_end_offset = None;
 		self.handle_start_offset = None;
 		let Some(handle_end) = self.handle_end else {
@@ -616,14 +616,14 @@ impl PenToolData {
 
 		// Store the segment
 		let id = SegmentId::generate();
-		if self.close_path {
-			if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::HandleEnd, &vector_data) {
-				TargetHandle::PrimaryHandle(segment) => {
+		if self.path_closed {
+			if let Some((handles, handle1_pos)) = match self.get_opposite_handle_type(TargetHandle::PreviewInHandle, &vector_data) {
+				TargetHandle::PriorOutHandle(segment) => {
 					let handles = [HandleId::end(id), HandleId::primary(segment)];
 					let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
 					handle1_pos.map(|pos| (handles, pos))
 				}
-				TargetHandle::EndHandle(segment) => {
+				TargetHandle::PriorInHandle(segment) => {
 					let handles = [HandleId::end(id), HandleId::end(segment)];
 					let handle1_pos = handles[1].to_manipulator_point().get_position(&vector_data);
 					handle1_pos.map(|pos| (handles, pos))
@@ -640,7 +640,7 @@ impl PenToolData {
 			}
 		}
 
-		self.end_point_segment = Some(id);
+		self.prior_segment = Some(id);
 
 		let points = [start, end];
 		let modification_type = VectorModificationType::InsertSegment { id, points, handles };
@@ -673,8 +673,8 @@ impl PenToolData {
 				handle_start: next_handle_start,
 			});
 		}
-		self.close_path = false;
-		self.end_point = None;
+		self.path_closed = false;
+		self.prior_segment_endpoint = None;
 		responses.add(DocumentMessage::EndTransaction);
 		Some(if close_subpath { PenToolFsmState::Ready } else { PenToolFsmState::PlacingAnchor })
 	}
@@ -690,10 +690,10 @@ impl PenToolData {
 		vector_data: &VectorData,
 		input: &InputPreprocessorMessageHandler,
 	) -> Option<DVec2> {
-		let reference_handle = if self.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+		let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle };
 		let end_handle = self.get_opposite_handle_type(reference_handle, vector_data);
 		let end_handle_pos = self.target_handle_position(end_handle, vector_data);
-		let ref_pos = self.target_handle_position(reference_handle, vector_data).unwrap();
+		let ref_pos = self.target_handle_position(reference_handle, vector_data)?;
 		let snap = &mut self.snap_manager;
 		let snap_data = SnapData::new_snap_cache(snap_data.document, input, &self.snap_cache);
 
@@ -710,7 +710,7 @@ impl PenToolData {
 
 		let handle_snap_option = end_handle_pos.and_then(|handle| match end_handle {
 			TargetHandle::None => None,
-			TargetHandle::HandleStart => None,
+			TargetHandle::FuturePreviewOutHandle => None,
 			_ => {
 				let handle_offset = transform.transform_point2(handle - ref_pos);
 				let handle_snap = SnapCandidatePoint::handle(document_pos + handle_offset);
@@ -764,27 +764,27 @@ impl PenToolData {
 		};
 
 		// Determine if we need to swap to opposite handle
-		let should_swap_to_opposite = self.close_path && matches!(self.handle_type, TargetHandle::HandleEnd | TargetHandle::PrimaryHandle(..) | TargetHandle::EndHandle(..))
-			|| !self.close_path && matches!(self.handle_type, TargetHandle::HandleStart);
+		let should_swap_to_opposite = self.path_closed && matches!(self.handle_type, TargetHandle::PreviewInHandle | TargetHandle::PriorOutHandle(..) | TargetHandle::PriorInHandle(..))
+			|| !self.path_closed && matches!(self.handle_type, TargetHandle::FuturePreviewOutHandle);
 
 		// Determine if we need to swap to start handle
-		let should_swap_to_start = !self.close_path && !matches!(self.handle_type, TargetHandle::None | TargetHandle::HandleStart);
+		let should_swap_to_start = !self.path_closed && !matches!(self.handle_type, TargetHandle::None | TargetHandle::FuturePreviewOutHandle);
 
 		if should_swap_to_opposite {
 			let opposite_type = self.get_opposite_handle_type(self.handle_type, &vector_data);
 			// Update offset
 			let Some(handle_pos) = self.target_handle_position(opposite_type, &vector_data) else {
-				self.handle_swap = false;
+				self.handle_swapped = false;
 				return;
 			};
 			if (handle_pos - self.next_point).length() < 1e-6 {
-				self.handle_swap = false;
+				self.handle_swapped = false;
 				return;
 			}
 			self.handle_end_offset = Some(viewport.transform_point2(handle_pos) - input.mouse.position);
 
 			// Update selections if in closed path mode
-			if self.close_path {
+			if self.path_closed {
 				self.cleanup_target_selections(shape_editor, layer, document, responses);
 			}
 			self.update_handle_type(opposite_type);
@@ -798,7 +798,7 @@ impl PenToolData {
 				self.handle_start_offset = Some(transform.transform_point2(self.next_handle_start) - input.mouse.position);
 			}
 
-			self.update_handle_type(TargetHandle::HandleStart);
+			self.update_handle_type(TargetHandle::FuturePreviewOutHandle);
 		}
 
 		responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
@@ -830,7 +830,7 @@ impl PenToolData {
 			}
 		}
 
-		let Some(end_point) = self.end_point else { return };
+		let Some(end_point) = self.prior_segment_endpoint else { return };
 
 		let modification_type_anchor = VectorModificationType::ApplyPointDelta { point: end_point, delta };
 		responses.add(GraphOperationMessage::Vector {
@@ -838,12 +838,12 @@ impl PenToolData {
 			modification_type: modification_type_anchor,
 		});
 
-		let reference_handle = if self.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+		let reference_handle = if self.path_closed { TargetHandle::PreviewInHandle } else { TargetHandle::FuturePreviewOutHandle };
 
 		// Move the end handle
 		let end_handle_type = self.get_opposite_handle_type(reference_handle, vector_data);
 		match end_handle_type {
-			TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..) => {
+			TargetHandle::PriorInHandle(..) | TargetHandle::PriorOutHandle(..) => {
 				let Some(handle_pos) = self.target_handle_position(end_handle_type, vector_data) else { return };
 				self.update_target_handle_pos(end_handle_type, self.next_point, responses, handle_pos + delta, layer);
 			}
@@ -882,6 +882,10 @@ impl PenToolData {
 
 			if let Some(handle) = self.handle_end.as_mut() {
 				*handle += delta;
+				if !self.path_closed {
+					responses.add(OverlaysMessage::Draw);
+					return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
+				};
 			}
 
 			self.move_anchor_and_handles(delta, layer, responses, &vector_data);
@@ -891,7 +895,7 @@ impl PenToolData {
 		}
 
 		match self.handle_type {
-			TargetHandle::HandleStart => {
+			TargetHandle::FuturePreviewOutHandle => {
 				let offset = self.handle_start_offset.unwrap_or(DVec2::ZERO);
 				mouse_pos += offset;
 				self.next_handle_start = self.compute_snapped_angle(snap_data.clone(), transform, colinear, mouse_pos, Some(self.next_point), false);
@@ -928,9 +932,12 @@ impl PenToolData {
 		}
 
 		if distance < 20. && self.handle_mode == HandleMode::Free && self.modifiers.lock_angle && !self.angle_locked {
-			self.set_lock_angle(&vector_data, self.end_point.unwrap(), self.end_point_segment);
+			let Some(endpoint) = self.prior_segment_endpoint else {
+				return Some(PenToolFsmState::DraggingHandle(self.handle_mode));
+			};
+			self.set_lock_angle(&vector_data, endpoint, self.prior_segment);
 			self.switch_to_free_on_ctrl_release = true;
-			let last_segment = self.end_point_segment;
+			let last_segment = self.prior_segment;
 			if let Some(latest) = self.latest_point_mut() {
 				latest.in_segment = last_segment;
 			}
@@ -948,9 +955,9 @@ impl PenToolData {
 			HandleMode::ColinearEquidistant => {
 				if self.modifiers.break_handle {
 					// Store handle for later restoration only when Alt is first pressed
-					if !self.alt_press {
+					if !self.alt_pressed {
 						self.previous_handle_end_pos = self.target_handle_position(opposite_handle_type, vector_data);
-						self.alt_press = true;
+						self.alt_pressed = true;
 					}
 
 					// Set handle to opposite position of the other handle
@@ -958,12 +965,12 @@ impl PenToolData {
 						return;
 					};
 					self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, new_position, layer);
-				} else if self.alt_press {
+				} else if self.alt_pressed {
 					// Restore the previous handle position when Alt is released
 					if let Some(previous_handle) = self.previous_handle_end_pos {
 						self.update_target_handle_pos(opposite_handle_type, self.next_point, responses, previous_handle, layer);
 					}
-					self.alt_press = false;
+					self.alt_pressed = false;
 					self.previous_handle_end_pos = None;
 				}
 			}
@@ -984,20 +991,17 @@ impl PenToolData {
 			return;
 		};
 
-		if (anchor_pos - handle).length() < 1e-6 {
+		if (anchor_pos - handle).length() < 1e-6 && self.modifiers.lock_angle {
 			return;
 		}
 
 		let Some(direction) = (anchor_pos - handle).try_normalize() else {
-			log::trace!("Skipping colinear adjustment: handle_start and anchor_point are too close!");
 			return;
 		};
-
 		let opposite_handle = self.get_opposite_handle_type(self.handle_type, vector_data);
 		let Some(handle_offset) = self.target_handle_position(opposite_handle, vector_data).map(|handle| (handle - anchor_pos).length()) else {
 			return;
 		};
-
 		let new_handle_position = anchor_pos + handle_offset * direction;
 		self.update_target_handle_pos(opposite_handle, self.next_point, responses, new_handle_position, layer);
 	}
@@ -1005,7 +1009,7 @@ impl PenToolData {
 	fn place_anchor(&mut self, snap_data: SnapData, transform: DAffine2, mouse: DVec2, preferences: &PreferencesMessageHandler, responses: &mut VecDeque<Message>) -> Option<PenToolFsmState> {
 		let document = snap_data.document;
 
-		let relative = if self.close_path { None } else { self.latest_point().map(|point| point.pos) };
+		let relative = if self.path_closed { None } else { self.latest_point().map(|point| point.pos) };
 		self.next_point = self.compute_snapped_angle(snap_data, transform, false, mouse, relative, true);
 
 		let selected_nodes = document.network_interface.selected_nodes();
@@ -1111,7 +1115,7 @@ impl PenToolData {
 		let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));
 		let snapped = self.snap_manager.free_snap(&SnapData::new(document, input), &point, SnapTypeConfiguration::default());
 		let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
-		self.handle_type = TargetHandle::HandleStart;
+		self.handle_type = TargetHandle::FuturePreviewOutHandle;
 
 		let selected_nodes = document.network_interface.selected_nodes();
 		self.handle_end = None;
@@ -1160,7 +1164,7 @@ impl PenToolData {
 		let layer = graph_modification_utils::new_custom(NodeId::new(), nodes, parent, responses);
 		tool_options.fill.apply_fill(layer, responses);
 		tool_options.stroke.apply_stroke(tool_options.line_weight, layer, responses);
-		self.end_point_segment = None;
+		self.prior_segment = None;
 		responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
 
 		// This causes the following message to be run only after the next graph evaluation runs and the transforms are updated
@@ -1205,7 +1209,7 @@ impl PenToolData {
 			(position, None)
 		};
 
-		let in_segment = if self.modifiers.lock_angle { self.end_point_segment } else { in_segment };
+		let in_segment = if self.modifiers.lock_angle { self.prior_segment } else { in_segment };
 
 		self.add_point(LastPoint {
 			id: point,
@@ -1242,10 +1246,10 @@ impl PenToolData {
 		let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
 
 		if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) {
-			self.end_point = Some(point);
+			self.prior_segment_endpoint = Some(point);
 			let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
 			let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
-			self.end_point_segment = segment;
+			self.prior_segment = segment;
 			layer_manipulators.insert(point);
 			for (&id, &position) in vector_data.point_domain.ids().iter().zip(vector_data.point_domain.positions()) {
 				if id == point {
@@ -1266,8 +1270,8 @@ impl PenToolData {
 			return;
 		};
 
-		match (self.handle_type, self.close_path) {
-			(TargetHandle::HandleStart, _) | (TargetHandle::HandleEnd, true) => {
+		match (self.handle_type, self.path_closed) {
+			(TargetHandle::FuturePreviewOutHandle, _) | (TargetHandle::PreviewInHandle, true) => {
 				let is_start = |point: PointId, segment: SegmentId| vector_data.segment_start_from_id(segment) == Some(point);
 
 				let end_handle = ManipulatorPointId::EndHandle(segment).get_position(vector_data);
@@ -1296,7 +1300,7 @@ impl PenToolData {
 					self.handle_mode = HandleMode::ColinearEquidistant;
 				}
 			}
-			(TargetHandle::EndHandle(..) | TargetHandle::PrimaryHandle(..), true) => {
+			(TargetHandle::PriorInHandle(..) | TargetHandle::PriorOutHandle(..), true) => {
 				self.angle = -(self.handle_end.unwrap() - anchor_position).angle_to(DVec2::X);
 				self.handle_mode = HandleMode::ColinearEquidistant;
 			}
@@ -1529,7 +1533,7 @@ impl Fsm for PenToolFsmState {
 						path_overlays(document, DrawHandles::All, shape_editor, &mut overlay_context);
 					}
 					PenOverlayMode::FrontierHandles => {
-						if let Some(latest_segment) = tool_data.end_point_segment {
+						if let Some(latest_segment) = tool_data.prior_segment {
 							path_overlays(document, DrawHandles::SelectedAnchors(vec![latest_segment]), shape_editor, &mut overlay_context);
 						} else {
 							path_overlays(document, DrawHandles::None, shape_editor, &mut overlay_context);
@@ -1556,7 +1560,7 @@ impl Fsm for PenToolFsmState {
 
 					if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, handle_end) {
 						// Draw the handle circle for the currently-being-dragged-out incoming handle (opposite the one currently being dragged out)
-						let selected = tool_data.handle_type == TargetHandle::HandleEnd;
+						let selected = tool_data.handle_type == TargetHandle::PreviewInHandle;
 						overlay_context.manipulator_handle(handle_end, selected, None);
 					}
 
@@ -1578,7 +1582,7 @@ impl Fsm for PenToolFsmState {
 
 				if self == PenToolFsmState::DraggingHandle(tool_data.handle_mode) && valid(next_anchor, next_handle_start) {
 					// Draw the handle circle for the currently-being-dragged-out outgoing handle (the one currently being dragged out, under the user's cursor)
-					let selected = tool_data.handle_type == TargetHandle::HandleStart;
+					let selected = tool_data.handle_type == TargetHandle::FuturePreviewOutHandle;
 					overlay_context.manipulator_handle(next_handle_start, selected, None);
 				}
 
@@ -1695,7 +1699,7 @@ impl Fsm for PenToolFsmState {
 				if tool_data.modifiers.colinear && !tool_data.toggle_colinear_debounce {
 					tool_data.handle_mode = match tool_data.handle_mode {
 						HandleMode::Free => {
-							let last_segment = tool_data.end_point_segment;
+							let last_segment = tool_data.prior_segment;
 							if let Some(latest) = tool_data.latest_point_mut() {
 								latest.in_segment = last_segment;
 							}
@@ -1710,8 +1714,12 @@ impl Fsm for PenToolFsmState {
 					return self;
 				};
 
-				if tool_data.modifiers.move_anchor_with_handles && !tool_data.space_press {
-					let reference_handle = if tool_data.close_path { TargetHandle::HandleEnd } else { TargetHandle::HandleStart };
+				if tool_data.modifiers.move_anchor_with_handles && !tool_data.space_pressed {
+					let reference_handle = if tool_data.path_closed {
+						TargetHandle::PreviewInHandle
+					} else {
+						TargetHandle::FuturePreviewOutHandle
+					};
 					let handle_start = layer.map(|layer| {
 						document
 							.metadata()
@@ -1719,11 +1727,11 @@ impl Fsm for PenToolFsmState {
 							.transform_point2(tool_data.target_handle_position(reference_handle, &vector_data).unwrap())
 					});
 					tool_data.handle_start_offset = handle_start.map(|start| start - input.mouse.position);
-					tool_data.space_press = true;
+					tool_data.space_pressed = true;
 				}
 
 				if !tool_data.modifiers.move_anchor_with_handles {
-					tool_data.space_press = false;
+					tool_data.space_pressed = false;
 				}
 
 				if !tool_data.modifiers.colinear {
@@ -1738,7 +1746,7 @@ impl Fsm for PenToolFsmState {
 					.drag_handle(snap_data, transform, input.mouse.position, responses, layer, input)
 					.unwrap_or(PenToolFsmState::Ready);
 
-				if tool_data.handle_swap {
+				if tool_data.handle_swapped {
 					responses.add(FrontendMessage::UpdateMouseCursor { cursor: MouseCursorIcon::None });
 				}
 
@@ -1775,7 +1783,8 @@ impl Fsm for PenToolFsmState {
 					move_anchor_with_handles,
 				},
 			) => {
-				tool_data.alt_press = false;
+				tool_data.switch_to_free_on_ctrl_release = false;
+				tool_data.alt_pressed = false;
 				tool_data.modifiers = ModifierState {
 					snap_angle: input.keyboard.key(snap_angle),
 					lock_angle: input.keyboard.key(lock_angle),
@@ -1811,8 +1820,8 @@ impl Fsm for PenToolFsmState {
 				state
 			}
 			(PenToolFsmState::DraggingHandle(_), PenToolMessage::SwapHandles) => {
-				if !tool_data.handle_swap {
-					tool_data.handle_swap = true
+				if !tool_data.handle_swapped {
+					tool_data.handle_swapped = true
 				}
 				tool_data.swap_handles(layer, document, shape_editor, input, responses);
 				responses.add(OverlaysMessage::Draw);

From 24eb19e8cedf9de3f28a5a5e0dfddcaff72d4f18 Mon Sep 17 00:00:00 2001
From: Keavon Chambers <keavon@keavon.com>
Date: Mon, 7 Apr 2025 22:32:44 -0700
Subject: [PATCH 19/21] Add terminology diagram

---
 .../messages/tool/tool_messages/pen_tool.rs   | 25 +++++++++++++------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 3ee6bb9652..1b03892218 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -283,21 +283,26 @@ enum HandleMode {
 }
 
 /// The type of handle which is dragged by the cursor (under the cursor).
+///
+/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png)
 #[derive(Clone, Debug, Default, PartialEq, Copy)]
 enum TargetHandle {
 	#[default]
 	None,
-	/// This is the handle being dragged and represents the primary handle
-	/// of the next segment that will be placed after the current handle and next anchor are placed.
-	/// Its position is stored in `tool_data.next_handle_start`.
+	/// This is the handle being dragged and represents the out handle of the next preview segment that will be placed
+	/// after the current preview segment is finalized. Its position is stored in `tool_data.next_handle_start`.
 	///
-	/// Pressing Tab swaps to the opposite handle type. The swapped handle can be either `PreviewInHandle` or,
-	/// in the case of a bent segment, [`ManipulatorPointId::EndHandle`] or [`ManipulatorPointId::PrimaryHandle`].
+	/// Pressing Tab swaps to the opposite handle type. The swapped handle can be either [`ManipulatorPointId::PreviewInHandle`]
+	/// or, in the case of a bent segment, [`ManipulatorPointId::EndHandle`] or [`ManipulatorPointId::PrimaryHandle`].
 	///
 	/// When closing a path, the handle being dragged becomes the end handle of the currently placed anchor.
+	///
+	/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png)
 	FuturePreviewOutHandle,
-	/// The opposite handle that is drawn after placing an anchor and starting to drag
-	/// the "next handle start", continuing until Tab is pressed to swap the handles.
+	/// The opposite handle that is drawn after placing an anchor and starting to drag the "next handle start",
+	/// continuing until Tab is pressed to swap the handles.
+	///
+	/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png)
 	PreviewInHandle,
 	/// This is the primary handle of the segment from whose endpoint a new handle is being drawn.
 	/// When closing the path, the handle being dragged will be the [`TargetHandle::PreviewInHandle`] (see its documentation);
@@ -305,10 +310,14 @@ enum TargetHandle {
 	///
 	/// If a handle is dragged from a different endpoint within the same layer, the opposite handle will be
 	/// `ManipulatorPoint::Primary` if that point is the starting point of its path.
+	///
+	/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png)
 	PriorOutHandle(SegmentId),
 	/// This is the end handle of the segment from whose endpoint a new handle is being drawn (same cases apply
 	/// as mentioned in [`TargetHandle::PriorOutHandle`]). If a handle is dragged from a different endpoint within the same
 	/// layer, the opposite handle will be `ManipulatorPoint::EndHandle` if that point is the end point of its path.
+	///
+	/// ![Terminology](https://files.keavon.com/-/EachNotedLovebird/capture.png)
 	PriorInHandle(SegmentId),
 }
 
@@ -401,7 +410,6 @@ impl PenToolData {
 		match handle_type {
 			TargetHandle::FuturePreviewOutHandle => self.check_end_handle_type(vector_data),
 			TargetHandle::PreviewInHandle => match (self.path_closed, self.prior_segment_endpoint, self.prior_segment) {
-				(false, _, _) => TargetHandle::FuturePreviewOutHandle,
 				(true, Some(point), Some(segment)) => {
 					if vector_data.segment_start_from_id(segment) == Some(point) {
 						TargetHandle::PriorOutHandle(segment)
@@ -409,6 +417,7 @@ impl PenToolData {
 						TargetHandle::PriorInHandle(segment)
 					}
 				}
+				(false, _, _) => TargetHandle::FuturePreviewOutHandle,
 				_ => TargetHandle::None,
 			},
 			_ => {

From 3054a3186e58bb4d7a8ada839848a1d22c8c179f Mon Sep 17 00:00:00 2001
From: Keavon Chambers <keavon@keavon.com>
Date: Mon, 7 Apr 2025 22:59:35 -0700
Subject: [PATCH 20/21] Add Ctrl "Lock Angle" hint

---
 editor/src/messages/tool/tool_messages/pen_tool.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 1b03892218..40b3647cec 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -1976,7 +1976,11 @@ impl Fsm for PenToolFsmState {
 				]),
 				HintGroup(vec![HintInfo::keys([Key::Shift], "15° Increments"), HintInfo::keys([Key::Control], "Lock Angle")]),
 				HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Sharp Point"), HintInfo::mouse(MouseMotion::LmbDrag, "Add Smooth Point")]),
-				HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, ""), HintInfo::mouse(MouseMotion::LmbDrag, "Bend Prev. Point").prepend_slash()]),
+				HintGroup(vec![
+					HintInfo::mouse(MouseMotion::Lmb, ""),
+					HintInfo::mouse(MouseMotion::LmbDrag, "Bend Prev. Point").prepend_slash(),
+					HintInfo::keys([Key::Control], "Lock Angle").prepend_plus(),
+				]),
 			]),
 			PenToolFsmState::DraggingHandle(mode) => {
 				let mut dragging_hint_data = HintData(Vec::new());

From 5ee4239fce009cf4afa6ffac03950eb9be478f29 Mon Sep 17 00:00:00 2001
From: Keavon Chambers <keavon@keavon.com>
Date: Mon, 7 Apr 2025 23:17:42 -0700
Subject: [PATCH 21/21] Rename other hint

---
 editor/src/messages/tool/tool_messages/path_tool.rs | 2 +-
 editor/src/messages/tool/tool_messages/pen_tool.rs  | 2 +-
 2 files changed, 2 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 4aac4f15c3..f724f1d742 100644
--- a/editor/src/messages/tool/tool_messages/path_tool.rs
+++ b/editor/src/messages/tool/tool_messages/path_tool.rs
@@ -1468,7 +1468,7 @@ impl Fsm for PathToolFsmState {
 				let drag_anchor = HintInfo::keys([Key::Space], "Drag Anchor");
 				let toggle_group = match dragging_state.point_select_state {
 					PointSelectState::HandleNoPair | PointSelectState::HandleWithPair => {
-						let mut hints = vec![HintInfo::keys([Key::Tab], "Swap Selected Handles")];
+						let mut hints = vec![HintInfo::keys([Key::Tab], "Swap Dragged Handle")];
 						hints.push(HintInfo::keys(
 							[Key::KeyC],
 							if colinear == ManipulatorAngle::Colinear {
diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs
index 40b3647cec..498bd53fb0 100644
--- a/editor/src/messages/tool/tool_messages/pen_tool.rs
+++ b/editor/src/messages/tool/tool_messages/pen_tool.rs
@@ -1998,7 +1998,7 @@ impl Fsm for PenToolFsmState {
 						vec![HintInfo::keys([Key::KeyC], "Break Colinear Handles")]
 					}
 				};
-				toggle_group.push(HintInfo::keys([Key::Tab], "Swap Selected Handles"));
+				toggle_group.push(HintInfo::keys([Key::Tab], "Swap Dragged Handle"));
 
 				let mut common_hints = vec![HintInfo::keys([Key::Shift], "15° Increments"), HintInfo::keys([Key::Control], "Lock Angle")];
 				let mut hold_group = match mode {