From 495fabf416db500fb9991fce6ae3f5cf40df3aea Mon Sep 17 00:00:00 2001 From: 0SlowPoke0 Date: Mon, 6 Jan 2025 22:19:56 +0530 Subject: [PATCH 1/4] grab_scale_path and backspace for pen --- .../messages/input_mapper/input_mappings.rs | 2 ++ .../messages/tool/tool_messages/pen_tool.rs | 11 ++++++++++ .../transform_layer_message_handler.rs | 20 +++++++++++++++++-- node-graph/gcore/src/vector/vector_data.rs | 7 +++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs index f29c0fb2be..a684eba092 100644 --- a/editor/src/messages/input_mapper/input_mappings.rs +++ b/editor/src/messages/input_mapper/input_mappings.rs @@ -258,6 +258,8 @@ pub fn input_mappings() -> Mapping { entry!(KeyDown(MouseRight); action_dispatch=PenToolMessage::Confirm), entry!(KeyDown(Escape); action_dispatch=PenToolMessage::Confirm), entry!(KeyDown(Enter); action_dispatch=PenToolMessage::Confirm), + entry!(KeyDown(Delete); action_dispatch=PenToolMessage::RemovePreviousHandle), + entry!(KeyDown(Backspace); action_dispatch=PenToolMessage::RemovePreviousHandle), // // FreehandToolMessage entry!(PointerMove; action_dispatch=FreehandToolMessage::PointerMove), diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 356200de3c..72f30c01ae 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -62,6 +62,7 @@ pub enum PenToolMessage { Undo, UpdateOptions(PenOptionsUpdate), RecalculateLatestPointsPosition, + RemovePreviousHandle, } #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] @@ -175,6 +176,7 @@ impl<'a> MessageHandler> for PenTool PointerMove, Confirm, Abort, + RemovePreviousHandle ), } } @@ -685,6 +687,15 @@ impl Fsm for PenToolFsmState { PenToolFsmState::PlacingAnchor } } + (PenToolFsmState::PlacingAnchor, PenToolMessage::RemovePreviousHandle) => { + if let Some(last_point) = tool_data.latest_points.last_mut() { + last_point.handle_start = last_point.pos; + responses.add(OverlaysMessage::Draw); + } else { + log::warn!("No latest point available to modify handle_start."); + } + self + } (PenToolFsmState::DraggingHandle, PenToolMessage::DragStop) => tool_data .finish_placing_handle(SnapData::new(document, input), transform, responses) .unwrap_or(PenToolFsmState::PlacingAnchor), diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 6b2f3ac525..0581aa9da0 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -77,8 +77,24 @@ impl MessageHandler> for TransformLayer let mut point_count: usize = 0; let get_location = |point: &ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); let points = shape_editor.selected_points(); - - *selected.pivot = points.filter_map(get_location).inspect(|_| point_count += 1).sum::() / point_count as f64; + let selected_points: Vec<&ManipulatorPointId> = points.collect(); + + if selected_points.len() == 1 { + if let Some(point) = selected_points.first() { + match point { + ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { + if let Some(anchor_position) = point.get_anchor_position(&vector_data) { + *selected.pivot = viewspace.transform_point2(anchor_position); + } + } + _ => { + *selected.pivot = selected_points.iter().filter_map(|point| get_location(point)).inspect(|_| point_count += 1).sum::() / point_count as f64; + } + } + } + } else { + *selected.pivot = selected_points.iter().filter_map(|point| get_location(point)).inspect(|_| point_count += 1).sum::() / point_count as f64; + } } } else { *selected.pivot = selected.mean_average_of_pivots(); diff --git a/node-graph/gcore/src/vector/vector_data.rs b/node-graph/gcore/src/vector/vector_data.rs index 21e5630b05..1b29fcd297 100644 --- a/node-graph/gcore/src/vector/vector_data.rs +++ b/node-graph/gcore/src/vector/vector_data.rs @@ -306,6 +306,13 @@ impl ManipulatorPointId { } } + pub fn get_anchor_position(&self, vector_data: &VectorData) -> Option { + match self { + ManipulatorPointId::EndHandle(_) | ManipulatorPointId::PrimaryHandle(_) => self.get_anchor(vector_data).and_then(|id| vector_data.point_domain.position_from_id(id)), + _ => self.get_position(vector_data), + } + } + /// Attempt to get a pair of handles. For an anchor this is the first two handles connected. For a handle it is self and the first opposing handle. #[must_use] pub fn get_handle_pair(self, vector_data: &VectorData) -> Option<[HandleId; 2]> { From 139bbddd7a0695d54653c509fc65a6c0237fa044 Mon Sep 17 00:00:00 2001 From: 0SlowPoke0 Date: Thu, 9 Jan 2025 10:06:18 +0530 Subject: [PATCH 2/4] minor improvements and fixes --- .../src/messages/tool/tool_message_handler.rs | 12 ++- .../messages/tool/tool_messages/path_tool.rs | 14 +-- .../transform_layer_message_handler.rs | 95 +++++++++++++++++++ node-graph/gcore/src/vector/vector_data.rs | 7 ++ 4 files changed, 111 insertions(+), 17 deletions(-) diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index ca855b90d7..b9183ab293 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -76,8 +76,8 @@ impl MessageHandler> for ToolMessageHandler { self.tool_is_active = true; // Send the old and new tools a transition to their FSM Abort states - let mut send_abort_to_tool = |tool_type, update_hints_and_cursor: bool| { - if let Some(tool) = tool_data.tools.get_mut(&tool_type) { + let mut send_abort_to_tool = |old_tool: ToolType, new_tool: ToolType, update_hints_and_cursor: bool| { + if let Some(tool) = tool_data.tools.get_mut(&new_tool) { let mut data = ToolActionHandlerData { document, document_id, @@ -101,9 +101,13 @@ impl MessageHandler> for ToolMessageHandler { tool.process_message(ToolMessage::UpdateCursor, responses, &mut data); } } + if matches!(old_tool, ToolType::Path | ToolType::Select) { + responses.add(TransformLayerMessage::CancelTransformOperation); + } }; - send_abort_to_tool(tool_type, true); - send_abort_to_tool(old_tool, false); + + send_abort_to_tool(old_tool, tool_type, true); + send_abort_to_tool(old_tool, old_tool, false); // Unsubscribe old tool from the broadcaster tool_data.tools.get(&tool_type).unwrap().deactivate(responses); diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index ab582d5eaf..e883a87f9a 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -648,19 +648,7 @@ impl Fsm for PathToolFsmState { self } (Self::InsertPoint, PathToolMessage::Escape | PathToolMessage::Delete | PathToolMessage::RightClick) => tool_data.end_insertion(shape_editor, responses, InsertEndKind::Abort), - (Self::InsertPoint, PathToolMessage::GRS { key: propagate }) => { - // MAYBE: use `InputMapperMessage::KeyDown(..)` instead - match propagate { - // TODO: Don't use `Key::G` directly, instead take it as a variable from the input mappings list like in all other places - Key::KeyG => responses.add(TransformLayerMessage::BeginGrab), - // TODO: Don't use `Key::R` directly, instead take it as a variable from the input mappings list like in all other places - Key::KeyR => responses.add(TransformLayerMessage::BeginRotate), - // TODO: Don't use `Key::S` directly, instead take it as a variable from the input mappings list like in all other places - Key::KeyS => responses.add(TransformLayerMessage::BeginScale), - _ => warn!("Unexpected GRS key"), - } - tool_data.end_insertion(shape_editor, responses, InsertEndKind::Abort) - } + (Self::InsertPoint, PathToolMessage::GRS { key: _ }) => PathToolFsmState::InsertPoint, // Mouse down ( _, diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 0581aa9da0..4f16d9c90b 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -43,6 +43,7 @@ type TransformData<'a> = (&'a DocumentMessageHandler, &'a InputPreprocessorMessa impl MessageHandler> for TransformLayerMessageHandler { fn process_message(&mut self, message: TransformLayerMessage, responses: &mut VecDeque, (document, input, tool_data, shape_editor): TransformData) { let using_path_tool = tool_data.active_tool_type == ToolType::Path; + let using_select_tool = tool_data.active_tool_type == ToolType::Select; // TODO: Add support for transforming layer not in the document network let selected_layers = document @@ -120,6 +121,17 @@ impl MessageHandler> for TransformLayer responses.add(NodeGraphMessage::RunDocumentGraph); } TransformLayerMessage::BeginGrab => { + if !(using_path_tool || using_select_tool) { + return; + } + let points = shape_editor.selected_points(); + let selected_points: Vec<&ManipulatorPointId> = points.collect(); + + if using_path_tool && selected_points.is_empty() { + responses.add(TransformLayerMessage::CancelTransformOperation); + return; + } + if let TransformOperation::Grabbing(_) = self.transform_operation { return; } @@ -136,6 +148,56 @@ impl MessageHandler> for TransformLayer selected.original_transforms.clear(); } TransformLayerMessage::BeginRotate => { + if !(using_path_tool || using_select_tool) { + return; + } + let Some(&layer) = selected_layers.first() else { + return; + }; + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return; + }; + let points = shape_editor.selected_points(); + let selected_points: Vec<&ManipulatorPointId> = points.collect(); + + if using_path_tool && selected_points.is_empty() { + responses.add(TransformLayerMessage::CancelTransformOperation); + return; + } + + if selected_points.len() == 1 { + if let Some(point) = selected_points.first() { + match point { + ManipulatorPointId::Anchor(_) => { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + if (handle1.get_handle_length(&vector_data) == 0.0 && handle2.get_handle_length(&vector_data) == 0.0) + || (handle1.get_handle_length(&vector_data) == f64::MAX && handle2.get_handle_length(&vector_data) == f64::MAX) + { + self.transform_operation = TransformOperation::None; + + responses.add(TransformLayerMessage::CancelTransformOperation); + return; + } + } + } + _ => { + let handle_position = point.get_position(&vector_data); + let anchor_position = point.get_anchor_position(&vector_data); + + if let (Some(handle_pos), Some(anchor_pos)) = (handle_position, anchor_position) { + // Calculate the distance between the handle and anchor + let distance = (handle_pos - anchor_pos).length(); + + // If the distance is zero, return early + if distance == 0.0 { + return; + } + } + } + } + } + } + if let TransformOperation::Rotating(_) = self.transform_operation { return; } @@ -152,6 +214,39 @@ impl MessageHandler> for TransformLayer selected.original_transforms.clear(); } TransformLayerMessage::BeginScale => { + if !(using_path_tool || using_select_tool) { + return; + } + let Some(&layer) = selected_layers.first() else { + return; + }; + let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { + return; + }; + + let points = shape_editor.selected_points(); + let selected_points: Vec<&ManipulatorPointId> = points.collect(); + + if using_path_tool && selected_points.is_empty() { + responses.add(TransformLayerMessage::CancelTransformOperation); + return; + } + + if selected_points.len() == 1 { + if let Some(point) = selected_points.first() { + if let ManipulatorPointId::Anchor(_) = point { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + if (handle1.get_handle_length(&vector_data) == 0.0 && handle2.get_handle_length(&vector_data) == 0.0) + || (handle1.get_handle_length(&vector_data) == f64::MAX && handle2.get_handle_length(&vector_data) == f64::MAX) + { + responses.add(TransformLayerMessage::CancelTransformOperation); + return; + } + } + } + } + } + if let TransformOperation::Scaling(_) = self.transform_operation { return; } diff --git a/node-graph/gcore/src/vector/vector_data.rs b/node-graph/gcore/src/vector/vector_data.rs index 1b29fcd297..fc236beace 100644 --- a/node-graph/gcore/src/vector/vector_data.rs +++ b/node-graph/gcore/src/vector/vector_data.rs @@ -403,6 +403,13 @@ impl HandleId { } } + pub fn get_handle_length(self, vector_data: &VectorData) -> f64 { + let anchor_position = self.to_manipulator_point().get_anchor_position(&vector_data).unwrap(); + let handle_position = self.to_manipulator_point().get_position(&vector_data); + let handle_length = handle_position.map(|pos| (pos - anchor_position).length()).unwrap_or(f64::MAX); + handle_length + } + /// Set the handle's position relative to the anchor which is the start anchor for the primary handle and end anchor for the end handle. #[must_use] pub fn set_relative_position(self, relative_position: DVec2) -> VectorModificationType { From 9cb7fa7977d3bc1c1adbcf91dc6fffef2fd21597 Mon Sep 17 00:00:00 2001 From: 0SlowPoke0 Date: Tue, 14 Jan 2025 17:03:40 +0530 Subject: [PATCH 3/4] code-review changes --- .../transform_layer_message_handler.rs | 157 +++++++----------- 1 file changed, 63 insertions(+), 94 deletions(-) diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 4f16d9c90b..17abbc97fd 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -76,25 +76,18 @@ impl MessageHandler> for TransformLayer let viewspace = document.metadata().transform_to_viewport(selected_layers[0]); let mut point_count: usize = 0; - let get_location = |point: &ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); + let get_location = |point: &&ManipulatorPointId| point.get_position(&vector_data).map(|position| viewspace.transform_point2(position)); let points = shape_editor.selected_points(); let selected_points: Vec<&ManipulatorPointId> = points.collect(); if selected_points.len() == 1 { - if let Some(point) = selected_points.first() { - match point { - ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) => { - if let Some(anchor_position) = point.get_anchor_position(&vector_data) { - *selected.pivot = viewspace.transform_point2(anchor_position); - } - } - _ => { - *selected.pivot = selected_points.iter().filter_map(|point| get_location(point)).inspect(|_| point_count += 1).sum::() / point_count as f64; - } - } + let point = &selected_points[0]; + if let ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) = point { + let anchor_position = point.get_anchor_position(&vector_data).unwrap(); + *selected.pivot = viewspace.transform_point2(anchor_position); + } else { + *selected.pivot = selected_points.iter().filter_map(get_location).inspect(|_| point_count += 1).sum::() / point_count as f64; } - } else { - *selected.pivot = selected_points.iter().filter_map(|point| get_location(point)).inspect(|_| point_count += 1).sum::() / point_count as f64; } } } else { @@ -121,23 +114,13 @@ impl MessageHandler> for TransformLayer responses.add(NodeGraphMessage::RunDocumentGraph); } TransformLayerMessage::BeginGrab => { - if !(using_path_tool || using_select_tool) { - return; - } - let points = shape_editor.selected_points(); - let selected_points: Vec<&ManipulatorPointId> = points.collect(); - - if using_path_tool && selected_points.is_empty() { - responses.add(TransformLayerMessage::CancelTransformOperation); - return; - } - - if let TransformOperation::Grabbing(_) = self.transform_operation { - return; - } + if !(using_path_tool || using_select_tool) + || (using_path_tool && shape_editor.selected_points().next().is_none()) + || matches!(self.transform_operation, TransformOperation::Grabbing(_)) + || selected_layers.is_empty() + { + selected.original_transforms.clear(); - // Don't allow grab with no selected layers - if selected_layers.is_empty() { return; } @@ -148,62 +131,46 @@ impl MessageHandler> for TransformLayer selected.original_transforms.clear(); } TransformLayerMessage::BeginRotate => { - if !(using_path_tool || using_select_tool) { + let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect(); + if !(using_path_tool || using_select_tool) + || (using_path_tool && selected_points.is_empty()) + || selected_layers.is_empty() + || matches!(self.transform_operation, TransformOperation::Rotating(_)) + { + selected.original_transforms.clear(); return; } - let Some(&layer) = selected_layers.first() else { - return; - }; - let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { - return; - }; - let points = shape_editor.selected_points(); - let selected_points: Vec<&ManipulatorPointId> = points.collect(); - if using_path_tool && selected_points.is_empty() { - responses.add(TransformLayerMessage::CancelTransformOperation); - return; - } + if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { + if selected_points.len() == 1 { + let point = &selected_points[0]; - if selected_points.len() == 1 { - if let Some(point) = selected_points.first() { match point { ManipulatorPointId::Anchor(_) => { if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { - if (handle1.get_handle_length(&vector_data) == 0.0 && handle2.get_handle_length(&vector_data) == 0.0) + if (handle1.get_handle_length(&vector_data) == 0. && handle2.get_handle_length(&vector_data) == 0.) || (handle1.get_handle_length(&vector_data) == f64::MAX && handle2.get_handle_length(&vector_data) == f64::MAX) { - self.transform_operation = TransformOperation::None; - - responses.add(TransformLayerMessage::CancelTransformOperation); return; } } } _ => { - let handle_position = point.get_position(&vector_data); - let anchor_position = point.get_anchor_position(&vector_data); + // TODO: Need to fix handle snap to anchor issue. SEE (https://discord.com/channels/731730685944922173/1217752903209713715). - if let (Some(handle_pos), Some(anchor_pos)) = (handle_position, anchor_position) { - // Calculate the distance between the handle and anchor - let distance = (handle_pos - anchor_pos).length(); + let handle_length = point.as_handle().and_then(|handle| Some(handle.get_handle_length(&vector_data))); - // If the distance is zero, return early - if distance == 0.0 { + if let Some(length) = handle_length { + if length == 0. { + selected.original_transforms.clear(); return; } } } } } - } - - if let TransformOperation::Rotating(_) = self.transform_operation { - return; - } - - // Don't allow rotate with no selected layers - if selected_layers.is_empty() { + } else { + selected.original_transforms.clear(); return; } @@ -214,45 +181,47 @@ impl MessageHandler> for TransformLayer selected.original_transforms.clear(); } TransformLayerMessage::BeginScale => { - if !(using_path_tool || using_select_tool) { + let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect(); + + if (using_path_tool && selected_points.is_empty()) + || !(using_path_tool || using_select_tool) + || matches!(self.transform_operation, TransformOperation::Scaling(_)) + || selected_layers.is_empty() + { + selected.original_transforms.clear(); return; } - let Some(&layer) = selected_layers.first() else { - return; - }; - let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else { - return; - }; - let points = shape_editor.selected_points(); - let selected_points: Vec<&ManipulatorPointId> = points.collect(); + if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { + if selected_points.len() == 1 { + let point = &selected_points[0]; - if using_path_tool && selected_points.is_empty() { - responses.add(TransformLayerMessage::CancelTransformOperation); - return; - } + match point { + ManipulatorPointId::Anchor(_) => { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + let handle1_length = handle1.get_handle_length(&vector_data); + let handle2_length = handle2.get_handle_length(&vector_data); - if selected_points.len() == 1 { - if let Some(point) = selected_points.first() { - if let ManipulatorPointId::Anchor(_) = point { - if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { - if (handle1.get_handle_length(&vector_data) == 0.0 && handle2.get_handle_length(&vector_data) == 0.0) - || (handle1.get_handle_length(&vector_data) == f64::MAX && handle2.get_handle_length(&vector_data) == f64::MAX) - { - responses.add(TransformLayerMessage::CancelTransformOperation); - return; + if (handle1_length == 0. && handle2_length == 0.) || (handle1_length == f64::MAX && handle2_length == f64::MAX) { + selected.original_transforms.clear(); + return; + } + } + } + _ => { + let handle_length = point.as_handle().and_then(|handle| Some(handle.get_handle_length(&vector_data))); + + if let Some(length) = handle_length { + if length == 0. { + selected.original_transforms.clear(); + return; + } } } } } - } - - if let TransformOperation::Scaling(_) = self.transform_operation { - return; - } - - // Don't allow scale with no selected layers - if selected_layers.is_empty() { + } else { + selected.original_transforms.clear(); return; } From d0c80e2dda9c304687c45f9205d4f3c514552abe Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 15 Jan 2025 00:25:17 -0800 Subject: [PATCH 4/4] Avoid more nesting, and other code cleanup --- .../src/messages/tool/tool_message_handler.rs | 1 + .../messages/tool/tool_messages/pen_tool.rs | 2 +- .../transform_layer_message_handler.rs | 110 ++++++++---------- node-graph/gcore/src/vector/vector_data.rs | 10 +- 4 files changed, 56 insertions(+), 67 deletions(-) diff --git a/editor/src/messages/tool/tool_message_handler.rs b/editor/src/messages/tool/tool_message_handler.rs index b9183ab293..239f0acc09 100644 --- a/editor/src/messages/tool/tool_message_handler.rs +++ b/editor/src/messages/tool/tool_message_handler.rs @@ -101,6 +101,7 @@ impl MessageHandler> for ToolMessageHandler { tool.process_message(ToolMessage::UpdateCursor, responses, &mut data); } } + if matches!(old_tool, ToolType::Path | ToolType::Select) { responses.add(TransformLayerMessage::CancelTransformOperation); } diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 72f30c01ae..1d2169ca30 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -176,7 +176,7 @@ impl<'a> MessageHandler> for PenTool PointerMove, Confirm, Abort, - RemovePreviousHandle + RemovePreviousHandle, ), } } diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 17abbc97fd..477796c89c 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -80,8 +80,7 @@ impl MessageHandler> for TransformLayer let points = shape_editor.selected_points(); let selected_points: Vec<&ManipulatorPointId> = points.collect(); - if selected_points.len() == 1 { - let point = &selected_points[0]; + if let [point] = selected_points.as_slice() { if let ManipulatorPointId::PrimaryHandle(_) | ManipulatorPointId::EndHandle(_) = point { let anchor_position = point.get_anchor_position(&vector_data).unwrap(); *selected.pivot = viewspace.transform_point2(anchor_position); @@ -114,10 +113,10 @@ impl MessageHandler> for TransformLayer responses.add(NodeGraphMessage::RunDocumentGraph); } TransformLayerMessage::BeginGrab => { - if !(using_path_tool || using_select_tool) + if (!using_path_tool && !using_select_tool) || (using_path_tool && shape_editor.selected_points().next().is_none()) - || matches!(self.transform_operation, TransformOperation::Grabbing(_)) || selected_layers.is_empty() + || matches!(self.transform_operation, TransformOperation::Grabbing(_)) { selected.original_transforms.clear(); @@ -132,7 +131,8 @@ impl MessageHandler> for TransformLayer } TransformLayerMessage::BeginRotate => { let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect(); - if !(using_path_tool || using_select_tool) + + if (!using_path_tool && !using_select_tool) || (using_path_tool && selected_points.is_empty()) || selected_layers.is_empty() || matches!(self.transform_operation, TransformOperation::Rotating(_)) @@ -141,37 +141,31 @@ impl MessageHandler> for TransformLayer return; } - if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { - if selected_points.len() == 1 { - let point = &selected_points[0]; - - match point { - ManipulatorPointId::Anchor(_) => { - if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { - if (handle1.get_handle_length(&vector_data) == 0. && handle2.get_handle_length(&vector_data) == 0.) - || (handle1.get_handle_length(&vector_data) == f64::MAX && handle2.get_handle_length(&vector_data) == f64::MAX) - { - return; - } - } - } - _ => { - // TODO: Need to fix handle snap to anchor issue. SEE (https://discord.com/channels/731730685944922173/1217752903209713715). + let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) else { + selected.original_transforms.clear(); + return; + }; - let handle_length = point.as_handle().and_then(|handle| Some(handle.get_handle_length(&vector_data))); + if let [point] = selected_points.as_slice() { + if matches!(point, ManipulatorPointId::Anchor(_)) { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + let handle1_length = handle1.length(&vector_data); + let handle2_length = handle2.length(&vector_data); - if let Some(length) = handle_length { - if length == 0. { - selected.original_transforms.clear(); - return; - } - } + if (handle1_length == 0. && handle2_length == 0.) || (handle1_length == f64::MAX && handle2_length == f64::MAX) { + return; } } + } else { + // TODO: Fix handle snap to anchor issue, see + + let handle_length = point.as_handle().map(|handle| handle.length(&vector_data)); + + if handle_length == Some(0.) { + selected.original_transforms.clear(); + return; + } } - } else { - selected.original_transforms.clear(); - return; } begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse); @@ -184,45 +178,38 @@ impl MessageHandler> for TransformLayer let selected_points: Vec<&ManipulatorPointId> = shape_editor.selected_points().collect(); if (using_path_tool && selected_points.is_empty()) - || !(using_path_tool || using_select_tool) - || matches!(self.transform_operation, TransformOperation::Scaling(_)) + || (!using_path_tool && !using_select_tool) || selected_layers.is_empty() + || matches!(self.transform_operation, TransformOperation::Scaling(_)) { selected.original_transforms.clear(); return; } - if let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) { - if selected_points.len() == 1 { - let point = &selected_points[0]; - - match point { - ManipulatorPointId::Anchor(_) => { - if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { - let handle1_length = handle1.get_handle_length(&vector_data); - let handle2_length = handle2.get_handle_length(&vector_data); - - if (handle1_length == 0. && handle2_length == 0.) || (handle1_length == f64::MAX && handle2_length == f64::MAX) { - selected.original_transforms.clear(); - return; - } - } - } - _ => { - let handle_length = point.as_handle().and_then(|handle| Some(handle.get_handle_length(&vector_data))); - - if let Some(length) = handle_length { - if length == 0. { - selected.original_transforms.clear(); - return; - } - } + let Some(vector_data) = selected_layers.first().and_then(|&layer| document.network_interface.compute_modified_vector(layer)) else { + selected.original_transforms.clear(); + return; + }; + + if let [point] = selected_points.as_slice() { + if matches!(point, ManipulatorPointId::Anchor(_)) { + if let Some([handle1, handle2]) = point.get_handle_pair(&vector_data) { + let handle1_length = handle1.length(&vector_data); + let handle2_length = handle2.length(&vector_data); + + if (handle1_length == 0. && handle2_length == 0.) || (handle1_length == f64::MAX && handle2_length == f64::MAX) { + selected.original_transforms.clear(); + return; } } + } else { + let handle_length = point.as_handle().map(|handle| handle.length(&vector_data)); + + if handle_length == Some(0.) { + selected.original_transforms.clear(); + return; + } } - } else { - selected.original_transforms.clear(); - return; } begin_operation(self.transform_operation, &mut self.typing, &mut self.mouse_position, &mut self.start_mouse); @@ -295,6 +282,7 @@ impl MessageHandler> for TransformLayer } }; } + self.mouse_position = input.mouse.position; } TransformLayerMessage::SelectionChanged => { diff --git a/node-graph/gcore/src/vector/vector_data.rs b/node-graph/gcore/src/vector/vector_data.rs index fc236beace..93cadbbb52 100644 --- a/node-graph/gcore/src/vector/vector_data.rs +++ b/node-graph/gcore/src/vector/vector_data.rs @@ -403,11 +403,11 @@ impl HandleId { } } - pub fn get_handle_length(self, vector_data: &VectorData) -> f64 { - let anchor_position = self.to_manipulator_point().get_anchor_position(&vector_data).unwrap(); - let handle_position = self.to_manipulator_point().get_position(&vector_data); - let handle_length = handle_position.map(|pos| (pos - anchor_position).length()).unwrap_or(f64::MAX); - handle_length + /// Calculate the magnitude of the handle from the anchor. + pub fn length(self, vector_data: &VectorData) -> f64 { + let anchor_position = self.to_manipulator_point().get_anchor_position(vector_data).unwrap(); + let handle_position = self.to_manipulator_point().get_position(vector_data); + handle_position.map(|pos| (pos - anchor_position).length()).unwrap_or(f64::MAX) } /// Set the handle's position relative to the anchor which is the start anchor for the primary handle and end anchor for the end handle.