From b7f216399865feab3b16863f72dfcfb87976aba1 Mon Sep 17 00:00:00 2001 From: Christopher Mendoza <57922269+ChrisMend19@users.noreply.github.com> Date: Sun, 19 Feb 2023 23:26:02 -0800 Subject: [PATCH] Selecting an individual anchor point deselects each of the other points (#963) * Selecting an individual anchor point deselects each of the other points * git gra * Selecting intersecting shapes,selects top shape * Merge commit * cargo fmt * fixed: can't drag multiple selected shapes. * Merge commit * Merge commit * Code review tweaks * Merge commit * Fixed topmost layer and previous_mouse_position * Fixed issues when clicking on anchors * Works * Function name change --------- Co-authored-by: Keavon Chambers Co-authored-by: Dennis Kobert --- document-legacy/src/document.rs | 7 +++ document-legacy/src/operation.rs | 3 ++ .../messages/input_mapper/default_mapping.rs | 2 +- .../tool/common_functionality/shape_editor.rs | 6 +++ .../messages/tool/tool_messages/path_tool.rs | 52 ++++++++++++++----- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/document-legacy/src/document.rs b/document-legacy/src/document.rs index 7a804199..8dfe543e 100644 --- a/document-legacy/src/document.rs +++ b/document-legacy/src/document.rs @@ -1062,6 +1062,13 @@ impl Document { } Some(vec![LayerChanged { path: layer_path.clone() }]) } + Operation::SelectAllAnchors { layer_path } => { + let layer = self.layer_mut(&layer_path)?; + if let Some(subpath) = layer.as_subpath_mut() { + subpath.select_all_anchors(); + } + Some(vec![LayerChanged { path: layer_path.clone() }]) + } Operation::DeselectAllManipulatorPoints { layer_path } => { let layer = self.layer_mut(&layer_path)?; if let Some(shape) = layer.as_subpath_mut() { diff --git a/document-legacy/src/operation.rs b/document-legacy/src/operation.rs index 01f4b1f0..aae0ed73 100644 --- a/document-legacy/src/operation.rs +++ b/document-legacy/src/operation.rs @@ -125,6 +125,9 @@ pub enum Operation { DeselectAllManipulatorPoints { layer_path: Vec, }, + SelectAllAnchors { + layer_path: Vec, + }, DuplicateLayer { path: Vec, }, diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index 105df0b8..07399a13 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -167,7 +167,7 @@ pub fn default_mapping() -> Mapping { entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=PathToolMessage::PointerMove { alt_mirror_angle: Alt, shift_mirror_distance: Shift }), entry!(KeyDown(Delete); action_dispatch=PathToolMessage::Delete), entry!(KeyDown(Backspace); action_dispatch=PathToolMessage::Delete), - entry!(KeyUp(Lmb); action_dispatch=PathToolMessage::DragStop), + entry!(KeyUp(Lmb); action_dispatch=PathToolMessage::DragStop { shift_mirror_distance: Shift }), entry!(DoubleClick; action_dispatch=PathToolMessage::InsertPoint), // // PenToolMessage diff --git a/editor/src/messages/tool/common_functionality/shape_editor.rs b/editor/src/messages/tool/common_functionality/shape_editor.rs index 795f269d..b32b1fa7 100644 --- a/editor/src/messages/tool/common_functionality/shape_editor.rs +++ b/editor/src/messages/tool/common_functionality/shape_editor.rs @@ -103,6 +103,7 @@ impl ShapeEditor { manipulator_group_id, manipulator_type: ManipulatorType::from_index(manipulator_point_index), }; + points.push(point_info); responses.push_back( Operation::SelectManipulatorPoints { @@ -187,6 +188,11 @@ impl ShapeEditor { self.iter(document).flat_map(|shape| shape.manipulator_groups().iter()) } + // Sets the selected points to all points for the corresponding intersection + pub fn select_all_anchors(&self, responses: &mut VecDeque, itersections: Vec) { + responses.push_back(Operation::SelectAllAnchors { layer_path: itersections }.into()); + } + /// Provide the currently selected points by reference. pub fn selected_points<'a>(&'a self, document: &'a Document) -> impl Iterator { self.selected_manipulator_groups(document).flat_map(|manipulator_group| manipulator_group.selected_points()) diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 1775dd5e..8c818033 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -1,4 +1,4 @@ -use crate::consts::{SELECTION_THRESHOLD, SELECTION_TOLERANCE}; +use crate::consts::{DRAG_THRESHOLD, SELECTION_THRESHOLD, SELECTION_TOLERANCE}; use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion}; use crate::messages::layout::utility_types::layout_widget::PropertyHolder; @@ -6,6 +6,7 @@ use crate::messages::prelude::*; use crate::messages::tool::common_functionality::overlay_renderer::OverlayRenderer; use crate::messages::tool::common_functionality::shape_editor::{ManipulatorPointInfo, ShapeEditor}; use crate::messages::tool::common_functionality::snapping::SnapManager; +use crate::messages::tool::common_functionality::transformation_cage::axis_align_drag; use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; @@ -38,7 +39,9 @@ pub enum PathToolMessage { DragStart { add_to_selection: Key, }, - DragStop, + DragStop { + shift_mirror_distance: Key, + }, InsertPoint, PointerMove { alt_mirror_angle: Key, @@ -109,6 +112,7 @@ struct PathToolData { snap_manager: SnapManager, drag_start_pos: DVec2, + previous_mouse_position: DVec2, alt_debounce: bool, } @@ -154,12 +158,12 @@ impl Fsm for PathToolFsmState { } // Mouse down (_, PathToolMessage::DragStart { add_to_selection }) => { - let toggle_add_to_selection = input.keyboard.get(add_to_selection as usize); + let shift_pressed = input.keyboard.get(add_to_selection as usize); // Select the first point within the threshold (in pixels) if let Some(mut selected_points) = tool_data .shape_editor - .select_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD, toggle_add_to_selection, responses) + .select_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD, shift_pressed, responses) { responses.push_back(DocumentMessage::StartTransaction.into()); @@ -186,8 +190,8 @@ impl Fsm for PathToolFsmState { let include_handles = tool_data.shape_editor.selected_layers_ref(); tool_data.snap_manager.add_all_document_handles(document, input, &include_handles, &[], &selected_points.points); - - tool_data.drag_start_pos = input.mouse.position - selected_points.offset; + tool_data.drag_start_pos = input.mouse.position; + tool_data.previous_mouse_position = input.mouse.position - selected_points.offset; PathToolFsmState::Dragging } // We didn't find a point nearby, so consider selecting the nearest shape instead @@ -198,19 +202,26 @@ impl Fsm for PathToolFsmState { .document_legacy .intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), render_data); if !intersection.is_empty() { - if toggle_add_to_selection { + if shift_pressed { responses.push_back(DocumentMessage::AddSelectedLayers { additional_layers: intersection }.into()); } else { + // Selects the topmost layer when selecting intersecting shapes + let top_most_intersection = intersection[intersection.len() - 1].clone(); responses.push_back( DocumentMessage::SetSelectedLayers { - replacement_selected_layers: intersection, + replacement_selected_layers: vec![top_most_intersection.clone()], } .into(), ); + tool_data.drag_start_pos = input.mouse.position; + tool_data.previous_mouse_position = input.mouse.position; + // Selects all the anchor points when clicking in a filled area of shape. If two shapes intersect we pick the topmost layer. + tool_data.shape_editor.select_all_anchors(responses, top_most_intersection); + return PathToolFsmState::Dragging; } } else { // Clear the previous selection if we didn't find anything - if !input.keyboard.get(toggle_add_to_selection as usize) { + if !input.keyboard.get(shift_pressed as usize) { responses.push_back(DocumentMessage::DeselectAllLayers.into()); } } @@ -240,12 +251,29 @@ impl Fsm for PathToolFsmState { // Move the selected points by the mouse position let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.mouse.position); - tool_data.shape_editor.move_selected_points(snapped_position - tool_data.drag_start_pos, shift_pressed, responses); - tool_data.drag_start_pos = snapped_position; + tool_data + .shape_editor + .move_selected_points(snapped_position - tool_data.previous_mouse_position, shift_pressed, responses); + tool_data.previous_mouse_position = snapped_position; PathToolFsmState::Dragging } // Mouse up - (_, PathToolMessage::DragStop) => { + (_, PathToolMessage::DragStop { shift_mirror_distance }) => { + let selected_points = tool_data.shape_editor.selected_points(&document.document_legacy); + let nearest_point = tool_data.shape_editor.find_nearest_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD); + let shift_pressed = input.keyboard.get(shift_mirror_distance as usize); + + if tool_data.drag_start_pos.distance(input.mouse.position) <= DRAG_THRESHOLD && !shift_pressed { + for point in selected_points { + if nearest_point == Some(point) { + responses.push_back(DocumentMessage::DeselectAllManipulatorPoints.into()); + tool_data + .shape_editor + .select_point(&document.document_legacy, input.mouse.position, SELECTION_THRESHOLD, false, responses); + } + } + } + tool_data.snap_manager.cleanup(responses); PathToolFsmState::Ready }