@@ -55,6 +55,7 @@ pub struct PathToolOptions {
5555pub enum PathToolMessage {
5656 // Standard messages
5757 Abort ,
58+ CanvasTransformed ,
5859 SelectionChanged ,
5960 Overlays {
6061 context : OverlayContext ,
@@ -511,6 +512,7 @@ impl ToolTransition for PathTool {
511512 fn event_to_message_map ( & self ) -> EventToMessageMap {
512513 EventToMessageMap {
513514 tool_abort : Some ( PathToolMessage :: Abort . into ( ) ) ,
515+ canvas_transformed : Some ( PathToolMessage :: CanvasTransformed . into ( ) ) ,
514516 selection_changed : Some ( PathToolMessage :: SelectionChanged . into ( ) ) ,
515517 overlay_provider : Some ( |context| PathToolMessage :: Overlays { context } . into ( ) ) ,
516518 ..Default :: default ( )
@@ -561,7 +563,7 @@ struct PathToolData {
561563 snap_manager : SnapManager ,
562564 lasso_polygon : Vec < DVec2 > ,
563565 selection_mode : Option < SelectionMode > ,
564- drag_start_pos : DVec2 ,
566+ drag_start_doc : DVec2 ,
565567 previous_mouse_position : DVec2 ,
566568 toggle_colinear_debounce : bool ,
567569 opposing_handle_lengths : Option < OpposingHandleLengths > ,
@@ -645,14 +647,19 @@ impl PathToolData {
645647 // Convert previous mouse position to viewport space first
646648 let document_to_viewport = metadata. document_to_viewport ;
647649 let previous_mouse = document_to_viewport. transform_point2 ( self . previous_mouse_position ) ;
648- if previous_mouse == self . drag_start_pos {
650+ let drag_start_vp = document_to_viewport. transform_point2 ( self . drag_start_doc ) ;
651+ if previous_mouse == drag_start_vp {
649652 let tolerance = DVec2 :: splat ( SELECTION_TOLERANCE ) ;
650- [ self . drag_start_pos - tolerance, self . drag_start_pos + tolerance]
653+ [ drag_start_vp - tolerance, drag_start_vp + tolerance]
651654 } else {
652- [ self . drag_start_pos , previous_mouse]
655+ [ drag_start_vp , previous_mouse]
653656 }
654657 }
655658
659+ fn drag_start_viewport ( & self , document : & DocumentMessageHandler ) -> DVec2 {
660+ document. metadata ( ) . document_to_viewport . transform_point2 ( self . drag_start_doc )
661+ }
662+
656663 fn update_selection_status ( & mut self , shape_editor : & mut ShapeState , document : & DocumentMessageHandler ) {
657664 let selection_status = get_selection_status ( & document. network_interface , shape_editor) ;
658665
@@ -736,7 +743,7 @@ impl PathToolData {
736743 self . double_click_handled = false ;
737744 self . opposing_handle_lengths = None ;
738745
739- self . drag_start_pos = input. mouse . position ;
746+ self . drag_start_doc = document . metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
740747
741748 if input. time - self . last_click_time > DOUBLE_CLICK_MILLISECONDS {
742749 self . saved_points_before_anchor_convert_smooth_sharp . clear ( ) ;
@@ -784,7 +791,7 @@ impl PathToolData {
784791 }
785792
786793 if let Some ( selected_points) = selection_info {
787- self . drag_start_pos = input. mouse . position ;
794+ self . drag_start_doc = document . metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
788795
789796 // If selected points contain only handles and there was some selection before, then it is stored and becomes restored upon release
790797 let mut dragging_only_handles = true ;
@@ -871,7 +878,7 @@ impl PathToolData {
871878 // TODO: If the segment connected to one of the endpoints is also selected then select that point
872879 }
873880
874- self . drag_start_pos = input. mouse . position ;
881+ self . drag_start_doc = document . metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
875882 let viewport_to_document = document. metadata ( ) . document_to_viewport . inverse ( ) ;
876883 self . previous_mouse_position = viewport_to_document. transform_point2 ( input. mouse . position ) ;
877884
@@ -900,15 +907,15 @@ impl PathToolData {
900907
901908 self . started_drawing_from_inside = true ;
902909
903- self . drag_start_pos = input. mouse . position ;
910+ self . drag_start_doc = document . metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
904911 self . previous_mouse_position = document. metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
905912
906913 let selection_shape = if lasso_select { SelectionShapeType :: Lasso } else { SelectionShapeType :: Box } ;
907914 PathToolFsmState :: Drawing { selection_shape }
908915 }
909916 // Start drawing
910917 else {
911- self . drag_start_pos = input. mouse . position ;
918+ self . drag_start_doc = document . metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
912919 self . previous_mouse_position = document. metadata ( ) . document_to_viewport . inverse ( ) . transform_point2 ( input. mouse . position ) ;
913920
914921 let selection_shape = if lasso_select { SelectionShapeType :: Lasso } else { SelectionShapeType :: Box } ;
@@ -1153,7 +1160,7 @@ impl PathToolData {
11531160 fn start_snap_along_axis ( & mut self , shape_editor : & mut ShapeState , document : & DocumentMessageHandler , input : & InputPreprocessorMessageHandler , responses : & mut VecDeque < Message > ) {
11541161 // Find the negative delta to take the point to the drag start position
11551162 let current_mouse = input. mouse . position ;
1156- let drag_start = self . drag_start_pos ;
1163+ let drag_start = self . drag_start_viewport ( document ) ;
11571164 let opposite_delta = drag_start - current_mouse;
11581165
11591166 shape_editor. move_selected_points_and_segments ( None , document, opposite_delta, false , true , false , None , false , responses) ;
@@ -1174,7 +1181,7 @@ impl PathToolData {
11741181 fn stop_snap_along_axis ( & mut self , shape_editor : & mut ShapeState , document : & DocumentMessageHandler , input : & InputPreprocessorMessageHandler , responses : & mut VecDeque < Message > ) {
11751182 // Calculate the negative delta of the selection and move it back to the drag start
11761183 let current_mouse = input. mouse . position ;
1177- let drag_start = self . drag_start_pos ;
1184+ let drag_start = self . drag_start_viewport ( document ) ;
11781185
11791186 let opposite_delta = drag_start - current_mouse;
11801187 let Some ( axis) = self . snapping_axis else { return } ;
@@ -1463,7 +1470,7 @@ impl PathToolData {
14631470 let mut was_alt_dragging = false ;
14641471
14651472 if self . snapping_axis . is_none ( ) {
1466- if self . alt_clicked_on_anchor && !self . alt_dragging_from_anchor && self . drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD {
1473+ if self . alt_clicked_on_anchor && !self . alt_dragging_from_anchor && self . drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD {
14671474 // Checking which direction the dragging begins
14681475 self . alt_dragging_from_anchor = true ;
14691476 let Some ( layer) = document. network_interface . selected_nodes ( ) . selected_layers ( document. metadata ( ) ) . next ( ) else {
@@ -1485,7 +1492,7 @@ impl PathToolData {
14851492 return ;
14861493 } ;
14871494
1488- let delta = input. mouse . position - self . drag_start_pos ;
1495+ let delta = input. mouse . position - self . drag_start_viewport ( document ) ;
14891496 let handle = if delta. dot ( tangent1) >= delta. dot ( tangent2) {
14901497 segment1. to_manipulator_point ( )
14911498 } else {
@@ -1528,7 +1535,7 @@ impl PathToolData {
15281535 // Constantly checking and changing the snapping axis based on current mouse position
15291536 if snap_axis && self . snapping_axis . is_some ( ) {
15301537 let Some ( current_axis) = self . snapping_axis else { return } ;
1531- let total_delta = self . drag_start_pos - input. mouse . position ;
1538+ let total_delta = self . drag_start_viewport ( document ) - input. mouse . position ;
15321539
15331540 if ( total_delta. x . abs ( ) > total_delta. y . abs ( ) && current_axis == Axis :: Y ) || ( total_delta. y . abs ( ) > total_delta. x . abs ( ) && current_axis == Axis :: X ) {
15341541 self . stop_snap_along_axis ( shape_editor, document, input, responses) ;
@@ -1706,7 +1713,7 @@ impl Fsm for PathToolFsmState {
17061713 }
17071714 ( _, PathToolMessage :: Overlays { context : mut overlay_context } ) => {
17081715 // Set this to show ghost line only if drag actually happened
1709- if matches ! ( self , Self :: Dragging ( _) ) && tool_data. drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD {
1716+ if matches ! ( self , Self :: Dragging ( _) ) && tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD {
17101717 for ( outline, layer) in & tool_data. ghost_outline {
17111718 let transform = document. metadata ( ) . transform_to_viewport ( * layer) ;
17121719 overlay_context. outline ( outline. iter ( ) , transform, Some ( COLOR_OVERLAY_GRAY ) ) ;
@@ -1904,7 +1911,8 @@ impl Fsm for PathToolFsmState {
19041911 let ( points_inside, segments_inside) = match selection_shape {
19051912 SelectionShapeType :: Box => {
19061913 let previous_mouse = document. metadata ( ) . document_to_viewport . transform_point2 ( tool_data. previous_mouse_position ) ;
1907- let bbox = Rect :: new ( tool_data. drag_start_pos . x , tool_data. drag_start_pos . y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
1914+ let drag_start_vp = tool_data. drag_start_viewport ( document) ;
1915+ let bbox = Rect :: new ( drag_start_vp. x , drag_start_vp. y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
19081916 shape_editor. get_inside_points_and_segments (
19091917 & document. network_interface ,
19101918 SelectionShape :: Box ( bbox) ,
@@ -1971,7 +1979,7 @@ impl Fsm for PathToolFsmState {
19711979 // Draw the snapping axis lines
19721980 if tool_data. snapping_axis . is_some ( ) {
19731981 let Some ( axis) = tool_data. snapping_axis else { return self } ;
1974- let origin = tool_data. drag_start_pos ;
1982+ let origin = tool_data. drag_start_viewport ( document ) ;
19751983 let viewport_diagonal = viewport. size ( ) . into_dvec2 ( ) . length ( ) ;
19761984
19771985 match axis {
@@ -2099,11 +2107,11 @@ impl Fsm for PathToolFsmState {
20992107 let selected_only_handles = !shape_editor. selected_points ( ) . any ( |point| matches ! ( point, ManipulatorPointId :: Anchor ( _) ) ) ;
21002108 tool_data. stored_selection = None ;
21012109
2102- if !tool_data. saved_selection_before_handle_drag . is_empty ( ) && ( tool_data. drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD ) && ( selected_only_handles) {
2110+ if !tool_data. saved_selection_before_handle_drag . is_empty ( ) && ( tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD ) && ( selected_only_handles) {
21032111 tool_data. handle_drag_toggle = true ;
21042112 }
21052113
2106- if tool_data. drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD {
2114+ if tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD {
21072115 tool_data. molding_segment = true ;
21082116 }
21092117
@@ -2245,15 +2253,15 @@ impl Fsm for PathToolFsmState {
22452253 ( PathToolFsmState :: Drawing { selection_shape : selection_type } , PathToolMessage :: PointerOutsideViewport { .. } ) => {
22462254 // Auto-panning
22472255 if let Some ( offset) = tool_data. auto_panning . shift_viewport ( input, viewport, responses) {
2248- tool_data. drag_start_pos += offset;
2256+ tool_data. drag_start_doc += document . metadata ( ) . document_to_viewport . inverse ( ) . transform_vector2 ( offset) ;
22492257 }
22502258
22512259 PathToolFsmState :: Drawing { selection_shape : selection_type }
22522260 }
22532261 ( PathToolFsmState :: Dragging ( dragging_state) , PathToolMessage :: PointerOutsideViewport { .. } ) => {
22542262 // Auto-panning
22552263 if let Some ( offset) = tool_data. auto_panning . shift_viewport ( input, viewport, responses) {
2256- tool_data. drag_start_pos += offset;
2264+ tool_data. drag_start_doc += document . metadata ( ) . document_to_viewport . inverse ( ) . transform_vector2 ( offset) ;
22572265 }
22582266
22592267 PathToolFsmState :: Dragging ( dragging_state)
@@ -2314,7 +2322,7 @@ impl Fsm for PathToolFsmState {
23142322
23152323 let document_to_viewport = document. metadata ( ) . document_to_viewport ;
23162324 let previous_mouse = document_to_viewport. transform_point2 ( tool_data. previous_mouse_position ) ;
2317- if tool_data. drag_start_pos == previous_mouse {
2325+ if tool_data. drag_start_viewport ( document ) == previous_mouse {
23182326 responses. add ( NodeGraphMessage :: SelectedNodesSet { nodes : vec ! [ ] } ) ;
23192327 } else {
23202328 let selection_mode = match tool_action_data. preferences . get_selection_mode ( ) {
@@ -2324,7 +2332,8 @@ impl Fsm for PathToolFsmState {
23242332
23252333 match selection_shape {
23262334 SelectionShapeType :: Box => {
2327- let bbox = Rect :: new ( tool_data. drag_start_pos . x , tool_data. drag_start_pos . y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
2335+ let drag_start_vp = tool_data. drag_start_viewport ( document) ;
2336+ let bbox = Rect :: new ( drag_start_vp. x , drag_start_vp. y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
23282337
23292338 shape_editor. select_all_in_shape (
23302339 & document. network_interface ,
@@ -2355,7 +2364,7 @@ impl Fsm for PathToolFsmState {
23552364 PathToolFsmState :: Ready
23562365 }
23572366 ( PathToolFsmState :: Dragging { .. } , PathToolMessage :: Escape | PathToolMessage :: RightClick ) => {
2358- if tool_data. handle_drag_toggle && tool_data. drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD {
2367+ if tool_data. handle_drag_toggle && tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD {
23592368 shape_editor. deselect_all_points ( ) ;
23602369 shape_editor. deselect_all_segments ( ) ;
23612370
@@ -2410,7 +2419,7 @@ impl Fsm for PathToolFsmState {
24102419 } ;
24112420 tool_data. started_drawing_from_inside = false ;
24122421
2413- if tool_data. drag_start_pos . distance ( previous_mouse) < 1e-8 {
2422+ if tool_data. drag_start_viewport ( document ) . distance ( previous_mouse) < 1e-8 {
24142423 // Clicked inside or outside the shape then deselect all of the points/segments
24152424 if document. click ( input, viewport) . is_some ( ) && tool_data. stored_selection . is_none ( ) {
24162425 tool_data. stored_selection = Some ( shape_editor. selected_shape_state . clone ( ) ) ;
@@ -2421,7 +2430,8 @@ impl Fsm for PathToolFsmState {
24212430 } else {
24222431 match selection_shape {
24232432 SelectionShapeType :: Box => {
2424- let bbox = Rect :: new ( tool_data. drag_start_pos . x , tool_data. drag_start_pos . y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
2433+ let drag_start_vp = tool_data. drag_start_viewport ( document) ;
2434+ let bbox = Rect :: new ( drag_start_vp. x , drag_start_vp. y , previous_mouse. x , previous_mouse. y ) . abs ( ) ;
24252435
24262436 shape_editor. select_all_in_shape (
24272437 & document. network_interface ,
@@ -2454,7 +2464,7 @@ impl Fsm for PathToolFsmState {
24542464 ( _, PathToolMessage :: DragStop { extend_selection, .. } ) => {
24552465 tool_data. ghost_outline . clear ( ) ;
24562466 let extend_selection = input. keyboard . get ( extend_selection as usize ) ;
2457- let drag_occurred = tool_data. drag_start_pos . distance ( input. mouse . position ) > DRAG_THRESHOLD ;
2467+ let drag_occurred = tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) > DRAG_THRESHOLD ;
24582468 let mut segment_dissolved = false ;
24592469 let mut point_inserted = false ;
24602470
@@ -2585,7 +2595,7 @@ impl Fsm for PathToolFsmState {
25852595 }
25862596 }
25872597 // Deselect all points if the user clicks the filled region of the shape
2588- else if tool_data. drag_start_pos . distance ( input. mouse . position ) <= DRAG_THRESHOLD {
2598+ else if tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) <= DRAG_THRESHOLD {
25892599 shape_editor. deselect_all_points ( ) ;
25902600 shape_editor. deselect_all_segments ( ) ;
25912601 }
@@ -3037,7 +3047,7 @@ impl Fsm for PathToolFsmState {
30373047
30383048 if nearest_point. is_some ( ) {
30393049 // Flip the selected point between smooth and sharp
3040- if !tool_data. double_click_handled && tool_data. drag_start_pos . distance ( input. mouse . position ) <= DRAG_THRESHOLD {
3050+ if !tool_data. double_click_handled && tool_data. drag_start_viewport ( document ) . distance ( input. mouse . position ) <= DRAG_THRESHOLD {
30413051 responses. add ( DocumentMessage :: StartTransaction ) ;
30423052
30433053 shape_editor. select_points_by_layer_and_id ( & tool_data. saved_points_before_anchor_convert_smooth_sharp ) ;
@@ -3119,6 +3129,42 @@ impl Fsm for PathToolFsmState {
31193129
31203130 PathToolFsmState :: Ready
31213131 }
3132+ // PTZ handling: re-emit PointerMove to recompute positions with updated document_to_viewport
3133+ ( PathToolFsmState :: Dragging ( dragging_state) , PathToolMessage :: CanvasTransformed ) => {
3134+ let modifier_keys = PathToolMessage :: PointerMove {
3135+ equidistant : Key :: Alt ,
3136+ toggle_colinear : Key :: KeyC ,
3137+ move_anchor_with_handles : Key :: Space ,
3138+ snap_angle : Key :: Control ,
3139+ lock_angle : Key :: Shift ,
3140+ delete_segment : Key :: Backspace ,
3141+ break_colinear_molding : Key :: Tab ,
3142+ segment_editing_modifier : Key :: Alt ,
3143+ } ;
3144+ responses. add ( modifier_keys) ;
3145+ responses. add ( OverlaysMessage :: Draw ) ;
3146+ PathToolFsmState :: Dragging ( dragging_state)
3147+ }
3148+ ( PathToolFsmState :: Drawing { selection_shape } , PathToolMessage :: CanvasTransformed ) => {
3149+ let modifier_keys = PathToolMessage :: PointerMove {
3150+ equidistant : Key :: Alt ,
3151+ toggle_colinear : Key :: KeyC ,
3152+ move_anchor_with_handles : Key :: Space ,
3153+ snap_angle : Key :: Control ,
3154+ lock_angle : Key :: Shift ,
3155+ delete_segment : Key :: Backspace ,
3156+ break_colinear_molding : Key :: Tab ,
3157+ segment_editing_modifier : Key :: Alt ,
3158+ } ;
3159+ responses. add ( modifier_keys) ;
3160+ responses. add ( OverlaysMessage :: Draw ) ;
3161+ PathToolFsmState :: Drawing { selection_shape }
3162+ }
3163+ ( PathToolFsmState :: SlidingPoint , PathToolMessage :: CanvasTransformed ) => {
3164+ responses. add ( OverlaysMessage :: Draw ) ;
3165+ PathToolFsmState :: SlidingPoint
3166+ }
3167+ ( _, PathToolMessage :: CanvasTransformed ) => self ,
31223168 ( _, PathToolMessage :: Abort ) => {
31233169 responses. add ( OverlaysMessage :: Draw ) ;
31243170 PathToolFsmState :: Ready
0 commit comments