1+ use crate :: consts:: CREATE_CURVE_THRESHOLD ;
12use crate :: document:: DocumentMessageHandler ;
23use crate :: frontend:: utility_types:: MouseCursorIcon ;
34use crate :: input:: keyboard:: { Key , MouseMotion } ;
@@ -7,6 +8,7 @@ use crate::message_prelude::*;
78use crate :: misc:: { HintData , HintGroup , HintInfo , KeysGroup } ;
89use crate :: viewport_tools:: snapping:: SnapHandler ;
910use crate :: viewport_tools:: tool:: { DocumentToolData , Fsm , ToolActionHandlerData } ;
11+ use crate :: viewport_tools:: vector_editor:: constants:: ControlPointType ;
1012use crate :: viewport_tools:: vector_editor:: shape_editor:: ShapeEditor ;
1113use crate :: viewport_tools:: vector_editor:: vector_shape:: VectorShape ;
1214
@@ -133,6 +135,7 @@ struct PenToolData {
133135 bez_path : Vec < PathEl > ,
134136 snap_handler : SnapHandler ,
135137 shape_editor : ShapeEditor ,
138+ drag_start_position : DVec2 ,
136139}
137140
138141impl Fsm for PenToolFsmState {
@@ -173,7 +176,7 @@ impl Fsm for PenToolFsmState {
173176 let start_position = transform. inverse ( ) . transform_point2 ( snapped_position) ;
174177 data. weight = tool_options. line_weight ;
175178
176- // Create the initial shape with a bez_path (only contains a moveto initially)
179+ // Create the initial shape with a ` bez_path` (only contains a moveto initially)
177180 if let Some ( layer_path) = & data. path {
178181 data. bez_path = start_bez_path ( start_position) ;
179182 responses. push_back (
@@ -193,36 +196,49 @@ impl Fsm for PenToolFsmState {
193196 Drawing
194197 }
195198 ( Drawing , DragStart ) => {
199+ data. drag_start_position = input. mouse . position ;
196200 add_to_curve ( data, input, transform, document, responses) ;
197201 Drawing
198202 }
199203 ( Drawing , DragStop ) => {
200204 // Deselect everything (this means we are no longer dragging the handle)
201205 data. shape_editor . deselect_all ( responses) ;
202206
207+ // If the drag does not exceed the threshold, then replace the curve with a line
208+ if data. drag_start_position . distance ( input. mouse . position ) < CREATE_CURVE_THRESHOLD {
209+ // Modify the second to last element (as we have an unplaced element tracing to the cursor as the last element)
210+ let replace_index = data. bez_path . len ( ) - 2 ;
211+ let line_from_curve = convert_curve_to_line ( data. bez_path [ replace_index] ) ;
212+ replace_path_element ( data, transform, replace_index, line_from_curve, responses) ;
213+ }
214+
203215 // Reselect the last point
204216 if let Some ( last_anchor) = data. shape_editor . select_last_anchor ( ) {
205- last_anchor. select_point ( 0 , true , responses) ;
217+ last_anchor. select_point ( ControlPointType :: Anchor as usize , true , responses) ;
206218 }
207219
220+ // Move the newly selected points to the cursor
221+ let snapped_position = data. snap_handler . snap_position ( responses, input. viewport_bounds . size ( ) , document, input. mouse . position ) ;
222+ data. shape_editor . move_selected_points ( snapped_position, false , responses) ;
223+
208224 Drawing
209225 }
210226 ( Drawing , PointerMove ) => {
227+ // Move selected points
211228 let snapped_position = data. snap_handler . snap_position ( responses, input. viewport_bounds . size ( ) , document, input. mouse . position ) ;
212- //data.shape_editor.update_shapes(document, responses);
213229 data. shape_editor . move_selected_points ( snapped_position, false , responses) ;
214230
215231 Drawing
216232 }
217233 ( Drawing , Confirm ) | ( Drawing , Abort ) => {
218- // Add a curve to the path
219- if let Some ( layer_path) = & data. path {
220- remove_curve_from_end ( & mut data. bez_path ) ;
221- responses. push_back ( apply_bez_path ( layer_path. clone ( ) , data. bez_path . clone ( ) , transform) ) ;
222- }
223-
224234 // Cleanup, we are either canceling or finished drawing
225235 if data. bez_path . len ( ) >= 2 {
236+ // Remove the last segment
237+ remove_from_curve ( data) ;
238+ if let Some ( layer_path) = & data. path {
239+ responses. push_back ( apply_bez_path ( layer_path. clone ( ) , data. bez_path . clone ( ) , transform) ) ;
240+ }
241+
226242 responses. push_back ( DocumentMessage :: DeselectAllLayers . into ( ) ) ;
227243 responses. push_back ( DocumentMessage :: CommitTransaction . into ( ) ) ;
228244 } else {
@@ -281,65 +297,86 @@ impl Fsm for PenToolFsmState {
281297 }
282298}
283299
284- // Add to the curve and select the second anchor of the last point and the newly added anchor point
300+ /// Add to the curve and select the second anchor of the last point and the newly added anchor point
285301fn add_to_curve ( data : & mut PenToolData , input : & InputPreprocessorMessageHandler , transform : DAffine2 , document : & DocumentMessageHandler , responses : & mut VecDeque < Message > ) {
286- // We need to make sure we have the most up-to-date bez_path
287- // Would like to remove this hack eventually
288- if !data. shape_editor . shapes_to_modify . is_empty ( ) {
289- // Hacky way of saving the curve changes
290- data. bez_path = data. shape_editor . shapes_to_modify [ 0 ] . bez_path . elements ( ) . to_vec ( ) ;
291- }
302+ // Refresh data's representation of the path
303+ update_path_representation ( data) ;
292304
293305 // Setup our position params
294306 let snapped_position = data. snap_handler . snap_position ( responses, input. viewport_bounds . size ( ) , document, input. mouse . position ) ;
295307 let position = transform. inverse ( ) . transform_point2 ( snapped_position) ;
296308
297309 // Add a curve to the path
298310 if let Some ( layer_path) = & data. path {
299- add_curve_to_end ( position, & mut data. bez_path ) ;
311+ // Push curve onto path
312+ let point = Point { x : position. x , y : position. y } ;
313+ data. bez_path . push ( PathEl :: CurveTo ( point, point, point) ) ;
314+
300315 responses. push_back ( apply_bez_path ( layer_path. clone ( ) , data. bez_path . clone ( ) , transform) ) ;
301316
302317 // Clear previous overlays
303318 data. shape_editor . remove_overlays ( responses) ;
304319
305- // Create a new shape from the updated bez_path
320+ // Create a new ` shape` from the updated ` bez_path`
306321 let bez_path = data. bez_path . clone ( ) . into_iter ( ) . collect ( ) ;
307322 data. curve_shape = VectorShape :: new ( layer_path. to_vec ( ) , transform, & bez_path, false , responses) ;
308323 data. shape_editor . set_shapes_to_modify ( vec ! [ data. curve_shape. clone( ) ] ) ;
309324
310- // Select the second to last segment 's handle
325+ // Select the second to last `PathEl` 's handle
311326 data. shape_editor . set_shape_selected ( 0 ) ;
312327 let handle_element = data. shape_editor . select_nth_anchor ( 0 , -2 ) ;
313- handle_element. select_point ( 2 , true , responses) ;
328+ handle_element. select_point ( ControlPointType :: Handle2 as usize , true , responses) ;
314329
315- // Select the last segment 's anchor point
330+ // Select the last `PathEl` 's anchor point
316331 if let Some ( last_anchor) = data. shape_editor . select_last_anchor ( ) {
317- last_anchor. select_point ( 0 , true , responses) ;
332+ last_anchor. select_point ( ControlPointType :: Anchor as usize , true , responses) ;
318333 }
319334 data. shape_editor . set_selected_mirror_options ( true , true ) ;
320335 }
321336}
322337
323- // Create the initial moveto for the bez_path
338+ /// Replace a `PathEl` with another inside of `bez_path` by index
339+ fn replace_path_element ( data : & mut PenToolData , transform : DAffine2 , replace_index : usize , replacement : PathEl , responses : & mut VecDeque < Message > ) {
340+ data. bez_path [ replace_index] = replacement;
341+ if let Some ( layer_path) = & data. path {
342+ responses. push_back ( apply_bez_path ( layer_path. clone ( ) , data. bez_path . clone ( ) , transform) ) ;
343+ }
344+ }
345+
346+ /// Remove a curve from the end of the `bez_path`
347+ fn remove_from_curve ( data : & mut PenToolData ) {
348+ // Refresh data's representation of the path
349+ update_path_representation ( data) ;
350+ data. bez_path . pop ( ) ;
351+ }
352+
353+ /// Create the initial moveto for the `bez_path`
324354fn start_bez_path ( start_position : DVec2 ) -> Vec < PathEl > {
325355 vec ! [ PathEl :: MoveTo ( Point {
326356 x: start_position. x,
327357 y: start_position. y,
328358 } ) ]
329359}
330360
331- // Add a curve to the bez_path
332- fn add_curve_to_end ( point : DVec2 , bez_path : & mut Vec < PathEl > ) {
333- let point = Point { x : point. x , y : point. y } ;
334- bez_path. push ( PathEl :: CurveTo ( point, point, point) ) ;
361+ /// Convert curve `PathEl` into a line `PathEl`
362+ fn convert_curve_to_line ( curve : PathEl ) -> PathEl {
363+ match curve {
364+ PathEl :: CurveTo ( _, _, p) => PathEl :: LineTo ( p) ,
365+ _ => PathEl :: MoveTo ( Point :: ZERO ) ,
366+ }
335367}
336368
337- // Add a curve to the bez_path
338- fn remove_curve_from_end ( bez_path : & mut Vec < PathEl > ) {
339- bez_path. pop ( ) ;
369+ /// Update data's version of `bez_path` to match `ShapeEditor`'s version
370+ fn update_path_representation ( data : & mut PenToolData ) {
371+ // TODO Update ShapeEditor to provide similar functionality
372+ // We need to make sure we have the most up-to-date bez_path
373+ if !data. shape_editor . shapes_to_modify . is_empty ( ) {
374+ // Hacky way of saving the curve changes
375+ data. bez_path = data. shape_editor . shapes_to_modify [ 0 ] . bez_path . elements ( ) . to_vec ( ) ;
376+ }
340377}
341378
342- // Apply the bez_path to the shape in the viewport
379+ /// Apply the ` bez_path` to the ` shape` in the viewport
343380fn apply_bez_path ( layer_path : Vec < LayerId > , bez_path : Vec < PathEl > , transform : DAffine2 ) -> Message {
344381 Operation :: SetShapePathInViewport {
345382 path : layer_path,
0 commit comments