From c156c0a4ce3f27d77861992ad22566f5af1a9722 Mon Sep 17 00:00:00 2001 From: 0SlowPoke0 <142654792+0SlowPoke0@users.noreply.github.com> Date: Sat, 12 Apr 2025 15:20:35 +0530 Subject: [PATCH] Improve Pen tool segment drawing confirm/cancel behavior (#2555) * implement enter to end path * fixed_abort * added_hints * edge-case * Code review --------- Co-authored-by: Keavon Chambers --- .../utility_types/network_interface.rs | 2 +- .../messages/tool/tool_messages/pen_tool.rs | 77 ++++++++++++++++--- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index aebe55f5..8d240973 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -1169,7 +1169,7 @@ impl NodeNetworkInterface { if is_layer && *reference == Some("Merge".to_string()) { "Untitled Layer".to_string() } else { - reference.clone().unwrap_or("Untitled node".to_string()) + reference.clone().unwrap_or("Untitled Node".to_string()) } } else { self.display_name(node_id, network_path) diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 498bd53f..c3fdce8d 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -356,6 +356,7 @@ struct PenToolData { path_closed: bool, handle_mode: HandleMode, + prior_segment_layer: Option, prior_segment_endpoint: Option, prior_segment: Option, handle_type: TargetHandle, @@ -380,6 +381,13 @@ impl PenToolData { self.latest_points.push(point); } + fn cleanup(&mut self, responses: &mut VecDeque) { + self.handle_end = None; + self.latest_points.clear(); + self.point_index = 0; + self.snap_manager.cleanup(responses); + } + /// 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.prior_segment_endpoint, self.prior_segment, self.path_closed) { @@ -1253,9 +1261,13 @@ impl PenToolData { let viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document); let tolerance = crate::consts::SNAP_POINT_TOLERANCE; + self.prior_segment = None; + self.prior_segment_endpoint = None; + self.prior_segment_layer = None; if let Some((layer, point, _position)) = closest_point(document, viewport, tolerance, document.metadata().all_layers(), |_| false, preferences) { self.prior_segment_endpoint = Some(point); + self.prior_segment_layer = Some(layer); let vector_data = document.network_interface.compute_modified_vector(layer).unwrap(); let segment = vector_data.all_connected(point).collect::>().first().map(|s| s.segment); self.prior_segment = segment; @@ -1902,16 +1914,62 @@ impl Fsm for PenToolFsmState { state } - (PenToolFsmState::DraggingHandle(..) | PenToolFsmState::PlacingAnchor, PenToolMessage::Confirm) => { + (PenToolFsmState::DraggingHandle(..), PenToolMessage::Confirm) => { + // Confirm to end path + if let Some((vector_data, layer)) = layer.and_then(|layer| document.network_interface.compute_modified_vector(layer)).zip(layer) { + let single_point_in_layer = vector_data.point_domain.ids().len() == 1; + tool_data.finish_placing_handle(SnapData::new(document, input), transform, preferences, responses); + let latest_points = tool_data.latest_points.len() == 1; + + if latest_points && single_point_in_layer { + responses.add(NodeGraphMessage::DeleteNodes { + node_ids: vec![layer.to_node()], + delete_children: true, + }); + responses.add(NodeGraphMessage::RunDocumentGraph); + } else if (latest_points && tool_data.prior_segment_endpoint.is_none()) + || (tool_data.prior_segment_endpoint.is_some() && tool_data.prior_segment_layer != Some(layer) && latest_points) + { + let vector_modification = VectorModificationType::RemovePoint { + id: tool_data.latest_point().unwrap().id, + }; + responses.add(GraphOperationMessage::Vector { + layer, + modification_type: vector_modification, + }); + responses.add(PenToolMessage::Abort); + } else { + responses.add(DocumentMessage::EndTransaction); + } + } + + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + responses.add(OverlaysMessage::Draw); + + PenToolFsmState::Ready + } + (PenToolFsmState::PlacingAnchor, PenToolMessage::Confirm) => { responses.add(DocumentMessage::EndTransaction); - tool_data.handle_end = None; - tool_data.latest_points.clear(); - tool_data.point_index = 0; - tool_data.snap_manager.cleanup(responses); + tool_data.cleanup(responses); tool_data.cleanup_target_selections(shape_editor, layer, document, responses); PenToolFsmState::Ready } + (PenToolFsmState::DraggingHandle(..), PenToolMessage::Abort) => { + if tool_data.handle_end.is_none() { + responses.add(DocumentMessage::AbortTransaction); + tool_data.cleanup(responses); + tool_data.cleanup_target_selections(shape_editor, layer, document, responses); + + PenToolFsmState::Ready + } else { + tool_data + .place_anchor(SnapData::new(document, input), transform, input.mouse.position, preferences, responses) + .unwrap_or(PenToolFsmState::Ready) + } + } (_, PenToolMessage::Abort) => { let should_delete_layer = if layer.is_some() { let vector_data = document.network_interface.compute_modified_vector(layer.unwrap()).unwrap(); @@ -1921,10 +1979,7 @@ impl Fsm for PenToolFsmState { }; responses.add(DocumentMessage::AbortTransaction); - tool_data.handle_end = None; - tool_data.latest_points.clear(); - tool_data.point_index = 0; - tool_data.snap_manager.cleanup(responses); + tool_data.cleanup(responses); tool_data.cleanup_target_selections(shape_editor, layer, document, responses); if should_delete_layer { @@ -1986,8 +2041,8 @@ impl Fsm for PenToolFsmState { let mut dragging_hint_data = HintData(Vec::new()); dragging_hint_data.0.push(HintGroup(vec![ HintInfo::mouse(MouseMotion::Rmb, ""), - HintInfo::keys([Key::Escape], "").prepend_slash(), - HintInfo::keys([Key::Enter], "End Path").prepend_slash(), + HintInfo::keys([Key::Escape], "Cancel Segment").prepend_slash(), + HintInfo::keys([Key::Enter], "End Path"), ])); let mut toggle_group = match mode {