1
+ use crate :: consts:: CREATE_CURVE_THRESHOLD ;
1
2
use crate :: document:: DocumentMessageHandler ;
2
3
use crate :: frontend:: utility_types:: MouseCursorIcon ;
3
4
use crate :: input:: keyboard:: { Key , MouseMotion } ;
@@ -7,6 +8,7 @@ use crate::message_prelude::*;
7
8
use crate :: misc:: { HintData , HintGroup , HintInfo , KeysGroup } ;
8
9
use crate :: viewport_tools:: snapping:: SnapHandler ;
9
10
use crate :: viewport_tools:: tool:: { DocumentToolData , Fsm , ToolActionHandlerData } ;
11
+ use crate :: viewport_tools:: vector_editor:: constants:: ControlPointType ;
10
12
use crate :: viewport_tools:: vector_editor:: shape_editor:: ShapeEditor ;
11
13
use crate :: viewport_tools:: vector_editor:: vector_shape:: VectorShape ;
12
14
@@ -133,6 +135,7 @@ struct PenToolData {
133
135
bez_path : Vec < PathEl > ,
134
136
snap_handler : SnapHandler ,
135
137
shape_editor : ShapeEditor ,
138
+ drag_start_position : DVec2 ,
136
139
}
137
140
138
141
impl Fsm for PenToolFsmState {
@@ -173,7 +176,7 @@ impl Fsm for PenToolFsmState {
173
176
let start_position = transform. inverse ( ) . transform_point2 ( snapped_position) ;
174
177
data. weight = tool_options. line_weight ;
175
178
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)
177
180
if let Some ( layer_path) = & data. path {
178
181
data. bez_path = start_bez_path ( start_position) ;
179
182
responses. push_back (
@@ -193,36 +196,49 @@ impl Fsm for PenToolFsmState {
193
196
Drawing
194
197
}
195
198
( Drawing , DragStart ) => {
199
+ data. drag_start_position = input. mouse . position ;
196
200
add_to_curve ( data, input, transform, document, responses) ;
197
201
Drawing
198
202
}
199
203
( Drawing , DragStop ) => {
200
204
// Deselect everything (this means we are no longer dragging the handle)
201
205
data. shape_editor . deselect_all ( responses) ;
202
206
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
+
203
215
// Reselect the last point
204
216
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) ;
206
218
}
207
219
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
+
208
224
Drawing
209
225
}
210
226
( Drawing , PointerMove ) => {
227
+ // Move selected points
211
228
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);
213
229
data. shape_editor . move_selected_points ( snapped_position, false , responses) ;
214
230
215
231
Drawing
216
232
}
217
233
( 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
-
224
234
// Cleanup, we are either canceling or finished drawing
225
235
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
+
226
242
responses. push_back ( DocumentMessage :: DeselectAllLayers . into ( ) ) ;
227
243
responses. push_back ( DocumentMessage :: CommitTransaction . into ( ) ) ;
228
244
} else {
@@ -281,65 +297,86 @@ impl Fsm for PenToolFsmState {
281
297
}
282
298
}
283
299
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
285
301
fn 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) ;
292
304
293
305
// Setup our position params
294
306
let snapped_position = data. snap_handler . snap_position ( responses, input. viewport_bounds . size ( ) , document, input. mouse . position ) ;
295
307
let position = transform. inverse ( ) . transform_point2 ( snapped_position) ;
296
308
297
309
// Add a curve to the path
298
310
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
+
300
315
responses. push_back ( apply_bez_path ( layer_path. clone ( ) , data. bez_path . clone ( ) , transform) ) ;
301
316
302
317
// Clear previous overlays
303
318
data. shape_editor . remove_overlays ( responses) ;
304
319
305
- // Create a new shape from the updated bez_path
320
+ // Create a new ` shape` from the updated ` bez_path`
306
321
let bez_path = data. bez_path . clone ( ) . into_iter ( ) . collect ( ) ;
307
322
data. curve_shape = VectorShape :: new ( layer_path. to_vec ( ) , transform, & bez_path, false , responses) ;
308
323
data. shape_editor . set_shapes_to_modify ( vec ! [ data. curve_shape. clone( ) ] ) ;
309
324
310
- // Select the second to last segment 's handle
325
+ // Select the second to last `PathEl` 's handle
311
326
data. shape_editor . set_shape_selected ( 0 ) ;
312
327
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) ;
314
329
315
- // Select the last segment 's anchor point
330
+ // Select the last `PathEl` 's anchor point
316
331
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) ;
318
333
}
319
334
data. shape_editor . set_selected_mirror_options ( true , true ) ;
320
335
}
321
336
}
322
337
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`
324
354
fn start_bez_path ( start_position : DVec2 ) -> Vec < PathEl > {
325
355
vec ! [ PathEl :: MoveTo ( Point {
326
356
x: start_position. x,
327
357
y: start_position. y,
328
358
} ) ]
329
359
}
330
360
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
+ }
335
367
}
336
368
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
+ }
340
377
}
341
378
342
- // Apply the bez_path to the shape in the viewport
379
+ /// Apply the ` bez_path` to the ` shape` in the viewport
343
380
fn apply_bez_path ( layer_path : Vec < LayerId > , bez_path : Vec < PathEl > , transform : DAffine2 ) -> Message {
344
381
Operation :: SetShapePathInViewport {
345
382
path : layer_path,
0 commit comments