@@ -67,6 +67,7 @@ pub enum PathToolMessage {
67
67
extend_selection : Key ,
68
68
lasso_select : Key ,
69
69
handle_drag_from_anchor : Key ,
70
+ drag_restore_handle : Key ,
70
71
} ,
71
72
NudgeSelectedPoints {
72
73
delta_x : f64 ,
@@ -362,7 +363,6 @@ struct PathToolData {
362
363
saved_points_before_handle_drag : Vec < ManipulatorPointId > ,
363
364
handle_drag_toggle : bool ,
364
365
dragging_state : DraggingState ,
365
- current_selected_handle_id : Option < ManipulatorPointId > ,
366
366
angle : f64 ,
367
367
opposite_handle_position : Option < DVec2 > ,
368
368
last_clicked_point_was_selected : bool ,
@@ -438,6 +438,7 @@ impl PathToolData {
438
438
extend_selection : bool ,
439
439
lasso_select : bool ,
440
440
handle_drag_from_anchor : bool ,
441
+ drag_zero_handle : bool ,
441
442
) -> PathToolFsmState {
442
443
self . double_click_handled = false ;
443
444
self . opposing_handle_lengths = None ;
@@ -500,6 +501,24 @@ impl PathToolData {
500
501
}
501
502
}
502
503
504
+ if let Some ( ( Some ( point) , Some ( vector_data) ) ) = shape_editor
505
+ . find_nearest_point_indices ( & document. network_interface , input. mouse . position , SELECTION_THRESHOLD )
506
+ . and_then ( |( layer, point) | Some ( ( point. as_anchor ( ) , document. network_interface . compute_modified_vector ( layer) ) ) )
507
+ {
508
+ let handles = vector_data
509
+ . all_connected ( point)
510
+ . filter ( |handle| handle. length ( & vector_data) < 1e-6 )
511
+ . map ( |handle| handle. to_manipulator_point ( ) )
512
+ . collect :: < Vec < _ > > ( ) ;
513
+ let endpoint = vector_data. extendable_points ( false ) . any ( |anchor| point == anchor) ;
514
+
515
+ if drag_zero_handle && ( handles. len ( ) == 1 && !endpoint) {
516
+ shape_editor. deselect_all_points ( ) ;
517
+ shape_editor. select_points_by_manipulator_id ( & handles) ;
518
+ shape_editor. convert_selected_manipulators_to_colinear_handles ( responses, document) ;
519
+ }
520
+ }
521
+
503
522
self . start_dragging_point ( selected_points, input, document, shape_editor) ;
504
523
responses. add ( OverlaysMessage :: Draw ) ;
505
524
}
@@ -689,6 +708,7 @@ impl PathToolData {
689
708
handle_id : ManipulatorPointId ,
690
709
lock_angle : bool ,
691
710
snap_angle : bool ,
711
+ tangent_to_neighboring_tangents : bool ,
692
712
) -> f64 {
693
713
let current_angle = -handle_vector. angle_to ( DVec2 :: X ) ;
694
714
@@ -699,17 +719,22 @@ impl PathToolData {
699
719
. and_then ( |( layer, _) | document. network_interface . compute_modified_vector ( * layer) )
700
720
{
701
721
if relative_vector. length ( ) < 25. && lock_angle && !self . angle_locked {
702
- if let Some ( angle) = calculate_lock_angle ( self , shape_editor, responses, document, & vector_data, handle_id) {
722
+ if let Some ( angle) = calculate_lock_angle ( self , shape_editor, responses, document, & vector_data, handle_id, tangent_to_neighboring_tangents ) {
703
723
self . angle = angle;
724
+ self . angle_locked = true ;
704
725
return angle;
705
726
}
706
727
}
707
728
}
708
729
709
- // When the angle is locked we use the old angle
710
-
711
- if self . current_selected_handle_id == Some ( handle_id) && lock_angle {
730
+ if lock_angle && !self . angle_locked {
712
731
self . angle_locked = true ;
732
+ self . angle = -relative_vector. angle_to ( DVec2 :: X ) ;
733
+ return -relative_vector. angle_to ( DVec2 :: X ) ;
734
+ }
735
+
736
+ // When the angle is locked we use the old angle
737
+ if self . angle_locked {
713
738
return self . angle ;
714
739
}
715
740
@@ -720,8 +745,6 @@ impl PathToolData {
720
745
handle_angle = ( handle_angle / snap_resolution) . round ( ) * snap_resolution;
721
746
}
722
747
723
- // Cache the angle and handle id for lock angle
724
- self . current_selected_handle_id = Some ( handle_id) ;
725
748
self . angle = handle_angle;
726
749
727
750
handle_angle
@@ -747,6 +770,7 @@ impl PathToolData {
747
770
origin : anchor_position,
748
771
direction : handle_direction. normalize_or_zero ( ) ,
749
772
} ;
773
+
750
774
self . snap_manager . constrained_snap ( & snap_data, & snap_point, snap_constraint, Default :: default ( ) )
751
775
}
752
776
false => self . snap_manager . free_snap ( & snap_data, & snap_point, Default :: default ( ) ) ,
@@ -850,7 +874,17 @@ impl PathToolData {
850
874
let snapped_delta = if let Some ( ( handle_pos, anchor_pos, handle_id) ) = self . try_get_selected_handle_and_anchor ( shape_editor, document) {
851
875
let cursor_pos = handle_pos + raw_delta;
852
876
853
- let handle_angle = self . calculate_handle_angle ( shape_editor, document, responses, handle_pos - anchor_pos, cursor_pos - anchor_pos, handle_id, lock_angle, snap_angle) ;
877
+ let handle_angle = self . calculate_handle_angle (
878
+ shape_editor,
879
+ document,
880
+ responses,
881
+ handle_pos - anchor_pos,
882
+ cursor_pos - anchor_pos,
883
+ handle_id,
884
+ lock_angle,
885
+ snap_angle,
886
+ equidistant,
887
+ ) ;
854
888
855
889
let constrained_direction = DVec2 :: new ( handle_angle. cos ( ) , handle_angle. sin ( ) ) ;
856
890
let projected_length = ( cursor_pos - anchor_pos) . dot ( constrained_direction) ;
@@ -1109,17 +1143,18 @@ impl Fsm for PathToolFsmState {
1109
1143
extend_selection,
1110
1144
lasso_select,
1111
1145
handle_drag_from_anchor,
1112
- ..
1146
+ drag_restore_handle ,
1113
1147
} ,
1114
1148
) => {
1115
1149
let extend_selection = input. keyboard . get ( extend_selection as usize ) ;
1116
1150
let lasso_select = input. keyboard . get ( lasso_select as usize ) ;
1117
1151
let handle_drag_from_anchor = input. keyboard . get ( handle_drag_from_anchor as usize ) ;
1152
+ let drag_zero_handle = input. keyboard . get ( drag_restore_handle as usize ) ;
1118
1153
1119
1154
tool_data. selection_mode = None ;
1120
1155
tool_data. lasso_polygon . clear ( ) ;
1121
1156
1122
- tool_data. mouse_down ( shape_editor, document, input, responses, extend_selection, lasso_select, handle_drag_from_anchor)
1157
+ tool_data. mouse_down ( shape_editor, document, input, responses, extend_selection, lasso_select, handle_drag_from_anchor, drag_zero_handle )
1123
1158
}
1124
1159
(
1125
1160
PathToolFsmState :: Drawing { selection_shape } ,
@@ -1375,6 +1410,7 @@ impl Fsm for PathToolFsmState {
1375
1410
tool_data. saved_points_before_handle_drag . clear ( ) ;
1376
1411
tool_data. handle_drag_toggle = false ;
1377
1412
}
1413
+ tool_data. angle_locked = false ;
1378
1414
responses. add ( DocumentMessage :: AbortTransaction ) ;
1379
1415
tool_data. snap_manager . cleanup ( responses) ;
1380
1416
PathToolFsmState :: Ready
@@ -1443,6 +1479,7 @@ impl Fsm for PathToolFsmState {
1443
1479
1444
1480
tool_data. alt_dragging_from_anchor = false ;
1445
1481
tool_data. alt_clicked_on_anchor = false ;
1482
+ tool_data. angle_locked = false ;
1446
1483
1447
1484
if tool_data. select_anchor_toggled {
1448
1485
shape_editor. deselect_all_points ( ) ;
@@ -1775,6 +1812,7 @@ fn calculate_lock_angle(
1775
1812
document : & DocumentMessageHandler ,
1776
1813
vector_data : & VectorData ,
1777
1814
handle_id : ManipulatorPointId ,
1815
+ tangent_to_neighboring_tangents : bool ,
1778
1816
) -> Option < f64 > {
1779
1817
let anchor = handle_id. get_anchor ( vector_data) ?;
1780
1818
let anchor_position = vector_data. point_domain . position_from_id ( anchor) ;
@@ -1808,7 +1846,14 @@ fn calculate_lock_angle(
1808
1846
let angle_2 = calculate_segment_angle ( anchor, segment, vector_data, false ) ;
1809
1847
1810
1848
match ( angle_1, angle_2) {
1811
- ( Some ( angle_1) , Some ( angle_2) ) => Some ( ( angle_1 + angle_2) / 2.0 ) ,
1849
+ ( Some ( angle_1) , Some ( angle_2) ) => {
1850
+ let angle = Some ( ( angle_1 + angle_2) / 2. ) ;
1851
+ if tangent_to_neighboring_tangents {
1852
+ angle. map ( |angle| angle + std:: f64:: consts:: FRAC_PI_2 )
1853
+ } else {
1854
+ angle
1855
+ }
1856
+ }
1812
1857
( Some ( angle_1) , None ) => Some ( angle_1) ,
1813
1858
( None , Some ( angle_2) ) => Some ( angle_2) ,
1814
1859
( None , None ) => None ,
0 commit comments