Skip to content

Commit a721b8c

Browse files
committed
Prefer lasso select within object for path tool
1 parent 4bfe55f commit a721b8c

1 file changed

Lines changed: 126 additions & 106 deletions

File tree

editor/src/messages/tool/tool_messages/path_tool.rs

Lines changed: 126 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,13 @@ pub struct SlidingPointInfo {
363363
connected_segments: [SlidingSegmentData; 2],
364364
}
365365

366+
enum MouseDownIntent<'a> {
367+
UpdatePoint { already_selected: bool, selection_info: Option<SelectedPointsInfo> },
368+
MoldSegment { segment: &'a ClosestSegment },
369+
SelectLayer { layer: LayerNodeIdentifier },
370+
Draw,
371+
}
372+
366373
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
367374
enum PathToolFsmState {
368375
#[default]
@@ -502,135 +509,148 @@ impl PathToolData {
502509

503510
let old_selection = shape_editor.selected_points().cloned().collect::<Vec<_>>();
504511

505-
// Check if the point is already selected; if not, select the first point within the threshold (in pixels)
506-
// Don't select the points which are not shown currently in PathOverlayMode
507-
if let Some((already_selected, mut selection_info)) = shape_editor.get_point_selection_state(
508-
&document.network_interface,
509-
input.mouse.position,
510-
SELECTION_THRESHOLD,
511-
path_overlay_mode,
512-
self.frontier_handles_info.clone(),
513-
) {
514-
responses.add(DocumentMessage::StartTransaction);
515-
516-
self.last_clicked_point_was_selected = already_selected;
517-
518-
// If the point is already selected and shift (`extend_selection`) is used, keep the selection unchanged.
519-
// Otherwise, select the first point within the threshold.
520-
if !(already_selected && extend_selection) {
521-
if let Some(updated_selection_info) = shape_editor.change_point_selection(
522-
&document.network_interface,
523-
input.mouse.position,
524-
SELECTION_THRESHOLD,
525-
extend_selection,
526-
path_overlay_mode,
527-
self.frontier_handles_info.clone(),
528-
) {
529-
selection_info = updated_selection_info;
530-
}
512+
let mouse_down_intent = {
513+
// Check if the point is already selected; if not, select the first point within the threshold (in pixels)
514+
if let Some((already_selected, selection_info)) = shape_editor.get_point_selection_state(
515+
&document.network_interface,
516+
input.mouse.position,
517+
SELECTION_THRESHOLD,
518+
path_overlay_mode,
519+
self.frontier_handles_info.clone(),
520+
) {
521+
MouseDownIntent::UpdatePoint { already_selected, selection_info }
522+
} else if lasso_select {
523+
MouseDownIntent::Draw
524+
} else if let Some(closed_segment) = &self.segment {
525+
MouseDownIntent::MoldSegment { segment: closed_segment }
526+
} else if let Some(layer) = document.click(input) {
527+
MouseDownIntent::SelectLayer { layer }
528+
} else {
529+
MouseDownIntent::Draw
531530
}
531+
};
532532

533-
if let Some(selected_points) = selection_info {
534-
self.drag_start_pos = input.mouse.position;
533+
match mouse_down_intent {
534+
MouseDownIntent::UpdatePoint { already_selected, mut selection_info } => {
535+
responses.add(DocumentMessage::StartTransaction);
535536

536-
// If selected points contain only handles and there was some selection before, then it is stored and becomes restored upon release
537-
let mut dragging_only_handles = true;
538-
for point in &selected_points.points {
539-
if matches!(point.point_id, ManipulatorPointId::Anchor(_)) {
540-
dragging_only_handles = false;
541-
break;
537+
self.last_clicked_point_was_selected = already_selected;
538+
539+
// If the point is already selected and shift (`extend_selection`) is used, keep the selection unchanged.
540+
// Otherwise, select the first point within the threshold.
541+
if !(already_selected && extend_selection) {
542+
if let Some(updated_selection_info) = shape_editor.change_point_selection(
543+
&document.network_interface,
544+
input.mouse.position,
545+
SELECTION_THRESHOLD,
546+
extend_selection,
547+
path_overlay_mode,
548+
self.frontier_handles_info.clone(),
549+
) {
550+
selection_info = updated_selection_info;
542551
}
543552
}
544-
if dragging_only_handles && !self.handle_drag_toggle && !old_selection.is_empty() {
545-
self.saved_points_before_handle_drag = old_selection;
546-
}
547553

548-
if handle_drag_from_anchor {
549-
if let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) {
550-
// Check that selected point is an anchor
551-
if let (Some(point_id), Some(vector_data)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) {
552-
let handles = vector_data.all_connected(point_id).collect::<Vec<_>>();
553-
self.alt_clicked_on_anchor = true;
554-
for handle in &handles {
555-
let modification_type = handle.set_relative_position(DVec2::ZERO);
556-
responses.add(GraphOperationMessage::Vector { layer, modification_type });
557-
for &handles in &vector_data.colinear_manipulators {
558-
if handles.contains(handle) {
559-
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
560-
responses.add(GraphOperationMessage::Vector { layer, modification_type });
554+
if let Some(selected_points) = selection_info {
555+
self.drag_start_pos = input.mouse.position;
556+
557+
// If selected points contain only handles and there was some selection before, then it is stored and becomes restored upon release
558+
let mut dragging_only_handles = true;
559+
for point in &selected_points.points {
560+
if matches!(point.point_id, ManipulatorPointId::Anchor(_)) {
561+
dragging_only_handles = false;
562+
break;
563+
}
564+
}
565+
if dragging_only_handles && !self.handle_drag_toggle && !old_selection.is_empty() {
566+
self.saved_points_before_handle_drag = old_selection;
567+
}
568+
569+
if handle_drag_from_anchor {
570+
if let Some((layer, point)) = shape_editor.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD) {
571+
// Check that selected point is an anchor
572+
if let (Some(point_id), Some(vector_data)) = (point.as_anchor(), document.network_interface.compute_modified_vector(layer)) {
573+
let handles = vector_data.all_connected(point_id).collect::<Vec<_>>();
574+
self.alt_clicked_on_anchor = true;
575+
for handle in &handles {
576+
let modification_type = handle.set_relative_position(DVec2::ZERO);
577+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
578+
for &handles in &vector_data.colinear_manipulators {
579+
if handles.contains(handle) {
580+
let modification_type = VectorModificationType::SetG1Continuous { handles, enabled: false };
581+
responses.add(GraphOperationMessage::Vector { layer, modification_type });
582+
}
561583
}
562584
}
585+
586+
let manipulator_point_id = handles[0].to_manipulator_point();
587+
shape_editor.deselect_all_points();
588+
shape_editor.select_points_by_manipulator_id(&vec![manipulator_point_id]);
589+
responses.add(PathToolMessage::SelectedPointUpdated);
563590
}
591+
}
592+
}
593+
594+
if let Some((Some(point), Some(vector_data))) = shape_editor
595+
.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD)
596+
.map(|(layer, point)| (point.as_anchor(), document.network_interface.compute_modified_vector(layer)))
597+
{
598+
let handles = vector_data
599+
.all_connected(point)
600+
.filter(|handle| handle.length(&vector_data) < 1e-6)
601+
.map(|handle| handle.to_manipulator_point())
602+
.collect::<Vec<_>>();
603+
let endpoint = vector_data.extendable_points(false).any(|anchor| point == anchor);
564604

565-
let manipulator_point_id = handles[0].to_manipulator_point();
605+
if drag_zero_handle && (handles.len() == 1 && !endpoint) {
566606
shape_editor.deselect_all_points();
567-
shape_editor.select_points_by_manipulator_id(&vec![manipulator_point_id]);
568-
responses.add(PathToolMessage::SelectedPointUpdated);
607+
shape_editor.select_points_by_manipulator_id(&handles);
608+
shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document);
569609
}
570610
}
571-
}
572611

573-
if let Some((Some(point), Some(vector_data))) = shape_editor
574-
.find_nearest_point_indices(&document.network_interface, input.mouse.position, SELECTION_THRESHOLD)
575-
.map(|(layer, point)| (point.as_anchor(), document.network_interface.compute_modified_vector(layer)))
576-
{
577-
let handles = vector_data
578-
.all_connected(point)
579-
.filter(|handle| handle.length(&vector_data) < 1e-6)
580-
.map(|handle| handle.to_manipulator_point())
581-
.collect::<Vec<_>>();
582-
let endpoint = vector_data.extendable_points(false).any(|anchor| point == anchor);
583-
584-
if drag_zero_handle && (handles.len() == 1 && !endpoint) {
585-
shape_editor.deselect_all_points();
586-
shape_editor.select_points_by_manipulator_id(&handles);
587-
shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document);
588-
}
612+
self.start_dragging_point(selected_points, input, document, shape_editor);
613+
responses.add(OverlaysMessage::Draw);
589614
}
590-
591-
self.start_dragging_point(selected_points, input, document, shape_editor);
592-
responses.add(OverlaysMessage::Draw);
615+
PathToolFsmState::Dragging(self.dragging_state)
593616
}
594-
PathToolFsmState::Dragging(self.dragging_state)
595-
}
596-
// We didn't find a point nearby, so we will see if there is a segment to insert a point on
597-
else if let Some(closed_segment) = &mut self.segment {
598-
responses.add(DocumentMessage::StartTransaction);
617+
MouseDownIntent::MoldSegment { segment: closed_segment } => {
618+
responses.add(DocumentMessage::StartTransaction);
599619

600-
// Calculating and storing handle positions
601-
let handle1 = ManipulatorPointId::PrimaryHandle(closed_segment.segment());
602-
let handle2 = ManipulatorPointId::EndHandle(closed_segment.segment());
620+
// Calculating and storing handle positions
621+
let handle1 = ManipulatorPointId::PrimaryHandle(closed_segment.segment());
622+
let handle2 = ManipulatorPointId::EndHandle(closed_segment.segment());
603623

604-
if let Some(vector_data) = document.network_interface.compute_modified_vector(closed_segment.layer()) {
605-
if let (Some(pos1), Some(pos2)) = (handle1.get_position(&vector_data), handle2.get_position(&vector_data)) {
606-
self.molding_info = Some((pos1, pos2))
624+
if let Some(vector_data) = document.network_interface.compute_modified_vector(closed_segment.layer()) {
625+
if let (Some(pos1), Some(pos2)) = (handle1.get_position(&vector_data), handle2.get_position(&vector_data)) {
626+
self.molding_info = Some((pos1, pos2))
627+
}
607628
}
629+
PathToolFsmState::MoldingSegment
608630
}
631+
// We didn't find a segment, so consider selecting the nearest shape instead
632+
MouseDownIntent::SelectLayer { layer } => {
633+
shape_editor.deselect_all_points();
634+
if extend_selection {
635+
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
636+
} else {
637+
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
638+
}
639+
self.drag_start_pos = input.mouse.position;
640+
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
609641

610-
PathToolFsmState::MoldingSegment
611-
}
612-
// We didn't find a segment, so consider selecting the nearest shape instead
613-
else if let Some(layer) = document.click(input) {
614-
shape_editor.deselect_all_points();
615-
if extend_selection {
616-
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![layer.to_node()] });
617-
} else {
618-
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
619-
}
620-
self.drag_start_pos = input.mouse.position;
621-
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
622-
623-
responses.add(DocumentMessage::StartTransaction);
642+
responses.add(DocumentMessage::StartTransaction);
624643

625-
PathToolFsmState::Dragging(self.dragging_state)
626-
}
627-
// Start drawing
628-
else {
629-
self.drag_start_pos = input.mouse.position;
630-
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
644+
PathToolFsmState::Dragging(self.dragging_state)
645+
}
646+
// Start drawing
647+
MouseDownIntent::Draw => {
648+
self.drag_start_pos = input.mouse.position;
649+
self.previous_mouse_position = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);
631650

632-
let selection_shape = if lasso_select { SelectionShapeType::Lasso } else { SelectionShapeType::Box };
633-
PathToolFsmState::Drawing { selection_shape }
651+
let selection_shape = if lasso_select { SelectionShapeType::Lasso } else { SelectionShapeType::Box };
652+
PathToolFsmState::Drawing { selection_shape }
653+
}
634654
}
635655
}
636656

0 commit comments

Comments
 (0)