11use super :: select_tool:: extend_lasso;
22use super :: tool_prelude:: * ;
33use crate :: consts:: {
4- COLOR_OVERLAY_BLUE , COLOR_OVERLAY_GREEN , COLOR_OVERLAY_RED , DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD , DRAG_THRESHOLD , HANDLE_ROTATE_SNAP_ANGLE , SEGMENT_INSERTION_DISTANCE ,
5- SEGMENT_OVERLAY_SIZE , SELECTION_THRESHOLD , SELECTION_TOLERANCE ,
4+ COLOR_OVERLAY_BLUE , COLOR_OVERLAY_GREEN , COLOR_OVERLAY_RED , DOUBLE_CLICK_MILLISECONDS , DRAG_DIRECTION_MODE_DETERMINATION_THRESHOLD , DRAG_THRESHOLD , HANDLE_ROTATE_SNAP_ANGLE ,
5+ SEGMENT_INSERTION_DISTANCE , SEGMENT_OVERLAY_SIZE , SELECTION_THRESHOLD , SELECTION_TOLERANCE ,
66} ;
77use crate :: messages:: portfolio:: document:: overlays:: utility_functions:: { path_overlays, selected_segments} ;
88use crate :: messages:: portfolio:: document:: overlays:: utility_types:: { DrawHandles , OverlayContext } ;
@@ -12,7 +12,7 @@ use crate::messages::portfolio::document::utility_types::transformation::Axis;
1212use crate :: messages:: preferences:: SelectionMode ;
1313use crate :: messages:: tool:: common_functionality:: auto_panning:: AutoPanning ;
1414use crate :: messages:: tool:: common_functionality:: shape_editor:: {
15- ClosestSegment , ManipulatorAngle , OpposingHandleLengths , SelectedPointsInfo , SelectionChange , SelectionShape , SelectionShapeType , ShapeState ,
15+ ClosestSegment , ManipulatorAngle , OpposingHandleLengths , SelectedLayerState , SelectedPointsInfo , SelectionChange , SelectionShape , SelectionShapeType , ShapeState ,
1616} ;
1717use crate :: messages:: tool:: common_functionality:: snapping:: { SnapCache , SnapCandidatePoint , SnapConstraint , SnapData , SnapManager } ;
1818use crate :: messages:: tool:: common_functionality:: utility_functions:: { calculate_segment_angle, find_two_param_best_approximate} ;
@@ -58,7 +58,10 @@ pub enum PathToolMessage {
5858 } ,
5959 Escape ,
6060 ClosePath ,
61- FlipSmoothSharp ,
61+ DoubleClick {
62+ extend_selection : Key ,
63+ shrink_selection : Key ,
64+ } ,
6265 GRS {
6366 // Should be `Key::KeyG` (Grab), `Key::KeyR` (Rotate), or `Key::KeyS` (Scale)
6467 key : Key ,
@@ -319,7 +322,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathToo
319322 fn actions ( & self ) -> ActionList {
320323 match self . fsm_state {
321324 PathToolFsmState :: Ready => actions ! ( PathToolMessageDiscriminant ;
322- FlipSmoothSharp ,
325+ DoubleClick ,
323326 MouseDown ,
324327 Delete ,
325328 NudgeSelectedPoints ,
@@ -334,7 +337,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathToo
334337 PathToolFsmState :: Dragging ( _) => actions ! ( PathToolMessageDiscriminant ;
335338 Escape ,
336339 RightClick ,
337- FlipSmoothSharp ,
340+ DoubleClick ,
338341 DragStop ,
339342 PointerMove ,
340343 Delete ,
@@ -343,7 +346,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PathToo
343346 SwapSelectedHandles ,
344347 ) ,
345348 PathToolFsmState :: Drawing { .. } => actions ! ( PathToolMessageDiscriminant ;
346- FlipSmoothSharp ,
349+ DoubleClick ,
347350 DragStop ,
348351 PointerMove ,
349352 Delete ,
@@ -462,6 +465,8 @@ struct PathToolData {
462465 adjacent_anchor_offset : Option < DVec2 > ,
463466 sliding_point_info : Option < SlidingPointInfo > ,
464467 started_drawing_from_inside : bool ,
468+ first_selected_with_single_click : bool ,
469+ stored_selection : Option < HashMap < LayerNodeIdentifier , SelectedLayerState > > ,
465470}
466471
467472impl PathToolData {
@@ -544,8 +549,9 @@ impl PathToolData {
544549
545550 self . drag_start_pos = input. mouse . position ;
546551
547- if ! self . saved_points_before_anchor_convert_smooth_sharp . is_empty ( ) && ( input. time - self . last_click_time > 500 ) {
552+ if input. time - self . last_click_time > DOUBLE_CLICK_MILLISECONDS {
548553 self . saved_points_before_anchor_convert_smooth_sharp . clear ( ) ;
554+ self . stored_selection = None ;
549555 }
550556
551557 self . last_click_time = input. time ;
@@ -685,20 +691,18 @@ impl PathToolData {
685691 PathToolFsmState :: MoldingSegment
686692 }
687693 }
688- // We didn't find a segment, so consider selecting the nearest shape instead and start drawing
694+ // If no other layers are selected and this is a single-click, then also select the layer (exception)
689695 else if let Some ( layer) = document. click ( input) {
690- shape_editor. deselect_all_points ( ) ;
691- shape_editor. deselect_all_segments ( ) ;
692- if extend_selection {
693- responses. add ( NodeGraphMessage :: SelectedNodesAdd { nodes : vec ! [ layer. to_node( ) ] } ) ;
694- } else {
696+ if shape_editor. selected_shape_state . is_empty ( ) {
697+ self . first_selected_with_single_click = true ;
695698 responses. add ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ layer. to_node( ) ] } ) ;
696699 }
697- self . drag_start_pos = input. mouse . position ;
698- self . previous_mouse_position = document. metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
699700
700701 self . started_drawing_from_inside = true ;
701702
703+ self . drag_start_pos = input. mouse . position ;
704+ self . previous_mouse_position = document. metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
705+
702706 let selection_shape = if lasso_select { SelectionShapeType :: Lasso } else { SelectionShapeType :: Box } ;
703707 PathToolFsmState :: Drawing { selection_shape }
704708 }
@@ -1557,7 +1561,9 @@ impl Fsm for PathToolFsmState {
15571561 } ,
15581562 ) => {
15591563 tool_data. previous_mouse_position = document. metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
1564+
15601565 tool_data. started_drawing_from_inside = false ;
1566+ tool_data. stored_selection = None ;
15611567
15621568 if selection_shape == SelectionShapeType :: Lasso {
15631569 extend_lasso ( & mut tool_data. lasso_polygon , input. mouse . position ) ;
@@ -1604,6 +1610,7 @@ impl Fsm for PathToolFsmState {
16041610 break_colinear_molding,
16051611 } ,
16061612 ) => {
1613+ tool_data. stored_selection = None ;
16071614 let mut selected_only_handles = true ;
16081615
16091616 let selected_points = shape_editor. selected_points ( ) ;
@@ -1727,6 +1734,7 @@ impl Fsm for PathToolFsmState {
17271734 if tool_data. adjacent_anchor_offset . is_some ( ) {
17281735 tool_data. adjacent_anchor_offset = None ;
17291736 }
1737+ tool_data. stored_selection = None ;
17301738
17311739 responses. add ( OverlaysMessage :: Draw ) ;
17321740
@@ -1895,12 +1903,16 @@ impl Fsm for PathToolFsmState {
18951903 SelectionMode :: Directional => tool_data. calculate_selection_mode_from_direction ( document. metadata ( ) ) ,
18961904 selection_mode => selection_mode,
18971905 } ;
1906+ tool_data. started_drawing_from_inside = false ;
18981907
18991908 if tool_data. drag_start_pos . distance ( previous_mouse) < 1e-8 {
1900- // If click happens inside of a shape then don't set selected nodes to empty
1901- if document. click ( input) . is_none ( ) {
1902- responses . add ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ ] } ) ;
1909+ // Clicked inside or outside the shape then deselect all of the points/segments
1910+ if document. click ( input) . is_some ( ) && tool_data . stored_selection . is_none ( ) {
1911+ tool_data . stored_selection = Some ( shape_editor . selected_shape_state . clone ( ) ) ;
19031912 }
1913+
1914+ shape_editor. deselect_all_points ( ) ;
1915+ shape_editor. deselect_all_segments ( ) ;
19041916 } else {
19051917 match selection_shape {
19061918 SelectionShapeType :: Box => {
@@ -2072,8 +2084,8 @@ impl Fsm for PathToolFsmState {
20722084 shape_editor. delete_point_and_break_path ( document, responses) ;
20732085 PathToolFsmState :: Ready
20742086 }
2075- ( _, PathToolMessage :: FlipSmoothSharp ) => {
2076- // Double-clicked on a point
2087+ ( _, PathToolMessage :: DoubleClick { extend_selection , shrink_selection } ) => {
2088+ // Double-clicked on a point (flip smooth/sharp behavior)
20772089 let nearest_point = shape_editor. find_nearest_point_indices ( & document. network_interface , input. mouse . position , SELECTION_THRESHOLD ) ;
20782090 if nearest_point. is_some ( ) {
20792091 // Flip the selected point between smooth and sharp
@@ -2090,13 +2102,70 @@ impl Fsm for PathToolFsmState {
20902102
20912103 return PathToolFsmState :: Ready ;
20922104 }
2093-
20942105 // Double-clicked on a filled region
2095- if let Some ( layer) = document. click ( input) {
2096- // Select all points in the layer
2097- shape_editor. select_connected_anchors ( document, layer, input. mouse . position ) ;
2106+ else if let Some ( layer) = document. click ( input) {
2107+ let extend_selection = input. keyboard . get ( extend_selection as usize ) ;
2108+ let shrink_selection = input. keyboard . get ( shrink_selection as usize ) ;
2109+
2110+ if shape_editor. is_selected_layer ( layer) {
2111+ if extend_selection && !tool_data. first_selected_with_single_click {
2112+ responses. add ( NodeGraphMessage :: SelectedNodesRemove { nodes : vec ! [ layer. to_node( ) ] } ) ;
2113+
2114+ if let Some ( selection) = & tool_data. stored_selection {
2115+ let mut selection = selection. clone ( ) ;
2116+ selection. remove ( & layer) ;
2117+ shape_editor. selected_shape_state = selection;
2118+ tool_data. stored_selection = None ;
2119+ }
2120+ } else if shrink_selection && !tool_data. first_selected_with_single_click {
2121+ // Only deselect all the points of the double clicked layer
2122+ if let Some ( selection) = & tool_data. stored_selection {
2123+ let selection = selection. clone ( ) ;
2124+ shape_editor. selected_shape_state = selection;
2125+ tool_data. stored_selection = None ;
2126+ }
2127+
2128+ let state = shape_editor. selected_shape_state . get_mut ( & layer) . expect ( "No state for selected layer" ) ;
2129+ state. deselect_all_points_in_layer ( ) ;
2130+ state. deselect_all_segments_in_layer ( ) ;
2131+ } else if !tool_data. first_selected_with_single_click {
2132+ // Select according to the selected editing mode
2133+ let point_editing_mode = tool_options. path_editing_mode . point_editing_mode ;
2134+ let segment_editing_mode = tool_options. path_editing_mode . segment_editing_mode ;
2135+ shape_editor. select_connected ( document, layer, input. mouse . position , point_editing_mode, segment_editing_mode) ;
2136+
2137+ // Select all the other layers back again
2138+ if let Some ( selection) = & tool_data. stored_selection {
2139+ let mut selection = selection. clone ( ) ;
2140+ selection. remove ( & layer) ;
2141+
2142+ for ( layer, state) in selection {
2143+ shape_editor. selected_shape_state . insert ( layer, state) ;
2144+ }
2145+ tool_data. stored_selection = None ;
2146+ }
2147+ }
2148+
2149+ // If it was the very first click without there being an existing selection,
2150+ // then the single-click behavior and double-click behavior should not collide
2151+ tool_data. first_selected_with_single_click = false ;
2152+ } else if extend_selection {
2153+ responses. add ( NodeGraphMessage :: SelectedNodesAdd { nodes : vec ! [ layer. to_node( ) ] } ) ;
2154+
2155+ if let Some ( selection) = & tool_data. stored_selection {
2156+ shape_editor. selected_shape_state = selection. clone ( ) ;
2157+ tool_data. stored_selection = None ;
2158+ }
2159+ } else {
2160+ responses. add ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ layer. to_node( ) ] } ) ;
2161+ }
2162+
20982163 responses. add ( OverlaysMessage :: Draw ) ;
20992164 }
2165+ // Double clicked on the background
2166+ else {
2167+ responses. add ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ ] } ) ;
2168+ }
21002169
21012170 PathToolFsmState :: Ready
21022171 }
0 commit comments