@@ -23,10 +23,15 @@ pub enum RadiusHandleState {
23
23
24
24
#[ derive( Clone , Debug , Default , PartialEq ) ]
25
25
pub struct RadiusHandle {
26
+ /// The layer this handle is currently attached to
26
27
pub layer : Option < LayerNodeIdentifier > ,
28
+ /// Original radius value when drag operation started (for delta calculations)
27
29
initial_radius : f64 ,
30
+ /// Current interaction state (inactive/hover/dragging)
28
31
handle_state : RadiusHandleState ,
32
+ /// Angle at which the handle appears on the circle (in radians)
29
33
angle : f64 ,
34
+ /// Previous mouse position (used for calculating movement deltas)
30
35
previous_mouse_position : DVec2 ,
31
36
}
32
37
@@ -48,13 +53,24 @@ impl RadiusHandle {
48
53
self . handle_state = state;
49
54
}
50
55
56
+ /// Determines if the mouse position is within the interactive area of the radius handle
57
+ /// The interactive area is a "dashed line" region around the circle/arc perimeter
58
+ ///
59
+ /// For shapes with stroke: Creates a band around the radius (stroke_width + spacing)
60
+ /// For shapes without stroke: Uses simple distance-from-center comparison
51
61
pub fn check_if_inside_dash_lines ( angle : f64 , mouse_position : DVec2 , viewport : DAffine2 , radius : f64 , document : & DocumentMessageHandler , layer : LayerNodeIdentifier ) -> bool {
52
62
let center = viewport. transform_point2 ( DVec2 :: ZERO ) ;
63
+
53
64
if let Some ( stroke_width) = get_stroke_width ( layer, & document. network_interface ) {
65
+ // For stroked shapes: Create interaction band based on stroke width
54
66
let layer_mouse = viewport. inverse ( ) . transform_point2 ( mouse_position) ;
55
- let spacing = 3. * stroke_width;
56
- layer_mouse. distance ( DVec2 :: ZERO ) >= ( radius - spacing) && layer_mouse. distance ( DVec2 :: ZERO ) <= ( radius + spacing)
67
+ let spacing = 3.0 * stroke_width; // 3x stroke width for comfortable interaction area
68
+ let mouse_distance = layer_mouse. distance ( DVec2 :: ZERO ) ;
69
+
70
+ // Mouse must be within the stroke band around the radius
71
+ mouse_distance >= ( radius - spacing) && mouse_distance <= ( radius + spacing)
57
72
} else {
73
+ // For non-stroked shapes: Simple radial distance check
58
74
let point_position = viewport. transform_point2 ( calculate_circle_point_position ( angle, radius. abs ( ) ) ) ;
59
75
mouse_position. distance ( center) <= point_position. distance ( center)
60
76
}
@@ -89,45 +105,56 @@ impl RadiusHandle {
89
105
}
90
106
}
91
107
108
+ /// Renders visual overlay indicators for the radius handle
109
+ /// Shows dashed ellipses to indicate the interactive area around the shape
92
110
pub fn overlays ( & self , document : & DocumentMessageHandler , overlay_context : & mut OverlayContext ) {
93
111
match & self . handle_state {
94
- RadiusHandleState :: Inactive => { }
112
+ RadiusHandleState :: Inactive => {
113
+ // No visual feedback when inactive
114
+ }
95
115
96
116
RadiusHandleState :: Dragging | RadiusHandleState :: Hover => {
97
117
let Some ( layer) = self . layer else { return } ;
118
+
119
+ // Extract radius from the shape (circle or arc)
98
120
let Some ( radius) = extract_circle_radius ( layer, document) . or ( extract_arc_parameters ( Some ( layer) , document) . map ( |( r, _, _, _) | r) ) else {
99
121
return ;
100
122
} ;
123
+
101
124
let viewport = document. metadata ( ) . transform_to_viewport ( layer) ;
102
125
let center = viewport. transform_point2 ( DVec2 :: ZERO ) ;
103
126
104
- let start_point = viewport. transform_point2 ( calculate_circle_point_position ( 0. , radius) ) . distance ( center) ;
127
+ // Calculate radii at different angles to handle elliptical transformations
128
+ let start_point = viewport. transform_point2 ( calculate_circle_point_position ( 0.0 , radius) ) . distance ( center) ;
105
129
let end_point = viewport. transform_point2 ( calculate_circle_point_position ( FRAC_PI_2 , radius) ) . distance ( center) ;
106
130
107
131
if let Some ( stroke_width) = get_stroke_width ( layer, & document. network_interface ) {
132
+ // For stroked shapes: Show inner and outer interaction boundaries
108
133
let threshold = 15.0 ;
109
134
let min_radius = start_point. min ( end_point) ;
110
135
111
- let extra_spacing = if min_radius < threshold {
112
- 10.0 * ( min_radius / threshold) // smoothly scales from 0 → 10
113
- } else {
114
- 10.0
115
- } ;
136
+ // Dynamic spacing that scales down for very small radii (prevents visual overlap)
137
+ let extra_spacing = if min_radius < threshold { 10.0 * ( min_radius / threshold) } else { 10.0 } ;
116
138
117
139
let spacing = stroke_width + extra_spacing;
140
+
141
+ // Inner boundary (closer to center)
118
142
let smaller_radius_x = ( start_point - spacing) . abs ( ) ;
119
143
let smaller_radius_y = ( end_point - spacing) . abs ( ) ;
120
144
145
+ // Outer boundary (further from center)
121
146
let larger_radius_x = ( start_point + spacing) . abs ( ) ;
122
147
let larger_radius_y = ( end_point + spacing) . abs ( ) ;
123
148
124
- overlay_context. dashed_ellipse ( center, smaller_radius_x, smaller_radius_y, None , None , None , None , None , None , Some ( 4. ) , Some ( 4. ) , Some ( 0.5 ) ) ;
125
- overlay_context. dashed_ellipse ( center, larger_radius_x, larger_radius_y, None , None , None , None , None , None , Some ( 4. ) , Some ( 4. ) , Some ( 0.5 ) ) ;
149
+ // Render both inner and outer dashed ellipses
150
+ overlay_context. dashed_ellipse ( center, smaller_radius_x, smaller_radius_y, None , None , None , None , None , None , Some ( 4.0 ) , Some ( 4.0 ) , Some ( 0.5 ) ) ;
151
+ overlay_context. dashed_ellipse ( center, larger_radius_x, larger_radius_y, None , None , None , None , None , None , Some ( 4.0 ) , Some ( 4.0 ) , Some ( 0.5 ) ) ;
126
152
127
153
return ;
128
154
}
129
155
130
- overlay_context. dashed_ellipse ( center, start_point, end_point, None , None , None , None , None , None , Some ( 4. ) , Some ( 4. ) , Some ( 0.5 ) ) ;
156
+ // For non-stroked shapes: Show single dashed ellipse at the radius
157
+ overlay_context. dashed_ellipse ( center, start_point, end_point, None , None , None , None , None , None , Some ( 4.0 ) , Some ( 4.0 ) , Some ( 0.5 ) ) ;
131
158
}
132
159
}
133
160
}
0 commit comments