mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 10:18:11 +08:00
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 <keavon@keavon.com> Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Keavon Chambers
Dennis Kobert
parent
964cf6df15
commit
b7f2163998
@@ -1062,6 +1062,13 @@ impl Document {
|
|||||||
}
|
}
|
||||||
Some(vec![LayerChanged { path: layer_path.clone() }])
|
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 } => {
|
Operation::DeselectAllManipulatorPoints { layer_path } => {
|
||||||
let layer = self.layer_mut(&layer_path)?;
|
let layer = self.layer_mut(&layer_path)?;
|
||||||
if let Some(shape) = layer.as_subpath_mut() {
|
if let Some(shape) = layer.as_subpath_mut() {
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ pub enum Operation {
|
|||||||
DeselectAllManipulatorPoints {
|
DeselectAllManipulatorPoints {
|
||||||
layer_path: Vec<LayerId>,
|
layer_path: Vec<LayerId>,
|
||||||
},
|
},
|
||||||
|
SelectAllAnchors {
|
||||||
|
layer_path: Vec<LayerId>,
|
||||||
|
},
|
||||||
DuplicateLayer {
|
DuplicateLayer {
|
||||||
path: Vec<LayerId>,
|
path: Vec<LayerId>,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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!(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(Delete); action_dispatch=PathToolMessage::Delete),
|
||||||
entry!(KeyDown(Backspace); 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),
|
entry!(DoubleClick; action_dispatch=PathToolMessage::InsertPoint),
|
||||||
//
|
//
|
||||||
// PenToolMessage
|
// PenToolMessage
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ impl ShapeEditor {
|
|||||||
manipulator_group_id,
|
manipulator_group_id,
|
||||||
manipulator_type: ManipulatorType::from_index(manipulator_point_index),
|
manipulator_type: ManipulatorType::from_index(manipulator_point_index),
|
||||||
};
|
};
|
||||||
|
|
||||||
points.push(point_info);
|
points.push(point_info);
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
Operation::SelectManipulatorPoints {
|
Operation::SelectManipulatorPoints {
|
||||||
@@ -187,6 +188,11 @@ impl ShapeEditor {
|
|||||||
self.iter(document).flat_map(|shape| shape.manipulator_groups().iter())
|
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<Message>, itersections: Vec<u64>) {
|
||||||
|
responses.push_back(Operation::SelectAllAnchors { layer_path: itersections }.into());
|
||||||
|
}
|
||||||
|
|
||||||
/// Provide the currently selected points by reference.
|
/// Provide the currently selected points by reference.
|
||||||
pub fn selected_points<'a>(&'a self, document: &'a Document) -> impl Iterator<Item = &'a ManipulatorPoint> {
|
pub fn selected_points<'a>(&'a self, document: &'a Document) -> impl Iterator<Item = &'a ManipulatorPoint> {
|
||||||
self.selected_manipulator_groups(document).flat_map(|manipulator_group| manipulator_group.selected_points())
|
self.selected_manipulator_groups(document).flat_map(|manipulator_group| manipulator_group.selected_points())
|
||||||
|
|||||||
@@ -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::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
|
||||||
use crate::messages::layout::utility_types::layout_widget::PropertyHolder;
|
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::overlay_renderer::OverlayRenderer;
|
||||||
use crate::messages::tool::common_functionality::shape_editor::{ManipulatorPointInfo, ShapeEditor};
|
use crate::messages::tool::common_functionality::shape_editor::{ManipulatorPointInfo, ShapeEditor};
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
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::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||||
|
|
||||||
@@ -38,7 +39,9 @@ pub enum PathToolMessage {
|
|||||||
DragStart {
|
DragStart {
|
||||||
add_to_selection: Key,
|
add_to_selection: Key,
|
||||||
},
|
},
|
||||||
DragStop,
|
DragStop {
|
||||||
|
shift_mirror_distance: Key,
|
||||||
|
},
|
||||||
InsertPoint,
|
InsertPoint,
|
||||||
PointerMove {
|
PointerMove {
|
||||||
alt_mirror_angle: Key,
|
alt_mirror_angle: Key,
|
||||||
@@ -109,6 +112,7 @@ struct PathToolData {
|
|||||||
snap_manager: SnapManager,
|
snap_manager: SnapManager,
|
||||||
|
|
||||||
drag_start_pos: DVec2,
|
drag_start_pos: DVec2,
|
||||||
|
previous_mouse_position: DVec2,
|
||||||
alt_debounce: bool,
|
alt_debounce: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,12 +158,12 @@ impl Fsm for PathToolFsmState {
|
|||||||
}
|
}
|
||||||
// Mouse down
|
// Mouse down
|
||||||
(_, PathToolMessage::DragStart { add_to_selection }) => {
|
(_, 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)
|
// Select the first point within the threshold (in pixels)
|
||||||
if let Some(mut selected_points) = tool_data
|
if let Some(mut selected_points) = tool_data
|
||||||
.shape_editor
|
.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());
|
responses.push_back(DocumentMessage::StartTransaction.into());
|
||||||
|
|
||||||
@@ -186,8 +190,8 @@ impl Fsm for PathToolFsmState {
|
|||||||
|
|
||||||
let include_handles = tool_data.shape_editor.selected_layers_ref();
|
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.snap_manager.add_all_document_handles(document, input, &include_handles, &[], &selected_points.points);
|
||||||
|
tool_data.drag_start_pos = input.mouse.position;
|
||||||
tool_data.drag_start_pos = input.mouse.position - selected_points.offset;
|
tool_data.previous_mouse_position = input.mouse.position - selected_points.offset;
|
||||||
PathToolFsmState::Dragging
|
PathToolFsmState::Dragging
|
||||||
}
|
}
|
||||||
// We didn't find a point nearby, so consider selecting the nearest shape instead
|
// We didn't find a point nearby, so consider selecting the nearest shape instead
|
||||||
@@ -198,19 +202,26 @@ impl Fsm for PathToolFsmState {
|
|||||||
.document_legacy
|
.document_legacy
|
||||||
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), render_data);
|
.intersects_quad_root(Quad::from_box([input.mouse.position - selection_size, input.mouse.position + selection_size]), render_data);
|
||||||
if !intersection.is_empty() {
|
if !intersection.is_empty() {
|
||||||
if toggle_add_to_selection {
|
if shift_pressed {
|
||||||
responses.push_back(DocumentMessage::AddSelectedLayers { additional_layers: intersection }.into());
|
responses.push_back(DocumentMessage::AddSelectedLayers { additional_layers: intersection }.into());
|
||||||
} else {
|
} else {
|
||||||
|
// Selects the topmost layer when selecting intersecting shapes
|
||||||
|
let top_most_intersection = intersection[intersection.len() - 1].clone();
|
||||||
responses.push_back(
|
responses.push_back(
|
||||||
DocumentMessage::SetSelectedLayers {
|
DocumentMessage::SetSelectedLayers {
|
||||||
replacement_selected_layers: intersection,
|
replacement_selected_layers: vec![top_most_intersection.clone()],
|
||||||
}
|
}
|
||||||
.into(),
|
.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 {
|
} else {
|
||||||
// Clear the previous selection if we didn't find anything
|
// 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());
|
responses.push_back(DocumentMessage::DeselectAllLayers.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,12 +251,29 @@ impl Fsm for PathToolFsmState {
|
|||||||
|
|
||||||
// Move the selected points by the mouse position
|
// Move the selected points by the mouse position
|
||||||
let snapped_position = tool_data.snap_manager.snap_position(responses, document, input.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
|
||||||
tool_data.drag_start_pos = snapped_position;
|
.shape_editor
|
||||||
|
.move_selected_points(snapped_position - tool_data.previous_mouse_position, shift_pressed, responses);
|
||||||
|
tool_data.previous_mouse_position = snapped_position;
|
||||||
PathToolFsmState::Dragging
|
PathToolFsmState::Dragging
|
||||||
}
|
}
|
||||||
// Mouse up
|
// 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);
|
tool_data.snap_manager.cleanup(responses);
|
||||||
PathToolFsmState::Ready
|
PathToolFsmState::Ready
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user