mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 07:58:11 +08:00
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 <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
69069ef723
commit
c156c0a4ce
@@ -1169,7 +1169,7 @@ impl NodeNetworkInterface {
|
|||||||
if is_layer && *reference == Some("Merge".to_string()) {
|
if is_layer && *reference == Some("Merge".to_string()) {
|
||||||
"Untitled Layer".to_string()
|
"Untitled Layer".to_string()
|
||||||
} else {
|
} else {
|
||||||
reference.clone().unwrap_or("Untitled node".to_string())
|
reference.clone().unwrap_or("Untitled Node".to_string())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.display_name(node_id, network_path)
|
self.display_name(node_id, network_path)
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ struct PenToolData {
|
|||||||
path_closed: bool,
|
path_closed: bool,
|
||||||
|
|
||||||
handle_mode: HandleMode,
|
handle_mode: HandleMode,
|
||||||
|
prior_segment_layer: Option<LayerNodeIdentifier>,
|
||||||
prior_segment_endpoint: Option<PointId>,
|
prior_segment_endpoint: Option<PointId>,
|
||||||
prior_segment: Option<SegmentId>,
|
prior_segment: Option<SegmentId>,
|
||||||
handle_type: TargetHandle,
|
handle_type: TargetHandle,
|
||||||
@@ -380,6 +381,13 @@ impl PenToolData {
|
|||||||
self.latest_points.push(point);
|
self.latest_points.push(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanup(&mut self, responses: &mut VecDeque<Message>) {
|
||||||
|
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`
|
/// Check whether target handle is primary, end, or `self.handle_end`
|
||||||
fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
|
fn check_end_handle_type(&self, vector_data: &VectorData) -> TargetHandle {
|
||||||
match (self.handle_end, self.prior_segment_endpoint, self.prior_segment, self.path_closed) {
|
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 viewport = document.metadata().document_to_viewport.transform_point2(snapped.snapped_point_document);
|
||||||
|
|
||||||
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
|
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) {
|
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_endpoint = Some(point);
|
||||||
|
self.prior_segment_layer = Some(layer);
|
||||||
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
|
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);
|
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
|
||||||
self.prior_segment = segment;
|
self.prior_segment = segment;
|
||||||
@@ -1902,16 +1914,62 @@ impl Fsm for PenToolFsmState {
|
|||||||
|
|
||||||
state
|
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);
|
responses.add(DocumentMessage::EndTransaction);
|
||||||
tool_data.handle_end = None;
|
tool_data.cleanup(responses);
|
||||||
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);
|
tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
|
||||||
|
|
||||||
PenToolFsmState::Ready
|
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) => {
|
(_, PenToolMessage::Abort) => {
|
||||||
let should_delete_layer = if layer.is_some() {
|
let should_delete_layer = if layer.is_some() {
|
||||||
let vector_data = document.network_interface.compute_modified_vector(layer.unwrap()).unwrap();
|
let vector_data = document.network_interface.compute_modified_vector(layer.unwrap()).unwrap();
|
||||||
@@ -1921,10 +1979,7 @@ impl Fsm for PenToolFsmState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::AbortTransaction);
|
||||||
tool_data.handle_end = None;
|
tool_data.cleanup(responses);
|
||||||
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);
|
tool_data.cleanup_target_selections(shape_editor, layer, document, responses);
|
||||||
|
|
||||||
if should_delete_layer {
|
if should_delete_layer {
|
||||||
@@ -1986,8 +2041,8 @@ impl Fsm for PenToolFsmState {
|
|||||||
let mut dragging_hint_data = HintData(Vec::new());
|
let mut dragging_hint_data = HintData(Vec::new());
|
||||||
dragging_hint_data.0.push(HintGroup(vec![
|
dragging_hint_data.0.push(HintGroup(vec![
|
||||||
HintInfo::mouse(MouseMotion::Rmb, ""),
|
HintInfo::mouse(MouseMotion::Rmb, ""),
|
||||||
HintInfo::keys([Key::Escape], "").prepend_slash(),
|
HintInfo::keys([Key::Escape], "Cancel Segment").prepend_slash(),
|
||||||
HintInfo::keys([Key::Enter], "End Path").prepend_slash(),
|
HintInfo::keys([Key::Enter], "End Path"),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
let mut toggle_group = match mode {
|
let mut toggle_group = match mode {
|
||||||
|
|||||||
Reference in New Issue
Block a user