diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index 0464d2c8..0c81b33a 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -171,7 +171,7 @@ pub fn default_mapping() -> Mapping { entry!(DoubleClick; action_dispatch=PathToolMessage::InsertPoint), // // PenToolMessage - entry!(PointerMove; refresh_keys=[Shift, Control], action_dispatch=PenToolMessage::PointerMove { snap_angle: Control, break_handle: Shift }), + entry!(PointerMove; refresh_keys=[Shift, Control], action_dispatch=PenToolMessage::PointerMove { snap_angle: Shift, break_handle: Alt, lock_angle: Control}), entry!(KeyDown(Lmb); action_dispatch=PenToolMessage::DragStart), entry!(KeyUp(Lmb); action_dispatch=PenToolMessage::DragStop), entry!(KeyDown(Rmb); action_dispatch=PenToolMessage::Confirm), diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 0cc6b9e2..f1822614 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -54,6 +54,7 @@ pub enum PenToolMessage { PointerMove { snap_angle: Key, break_handle: Key, + lock_angle: Key, }, Undo, UpdateOptions(PenOptionsUpdate), @@ -148,6 +149,7 @@ struct PenToolData { should_mirror: bool, // Indicates that curve extension is occurring from the first point, rather than (more commonly) the last point from_start: bool, + angle: f64, } impl Fsm for PenToolFsmState { @@ -399,7 +401,7 @@ impl Fsm for PenToolFsmState { tool_data.should_mirror = true; process().unwrap_or(PenToolFsmState::PlacingAnchor) } - (PenToolFsmState::DraggingHandle, PenToolMessage::PointerMove { snap_angle, break_handle }) => { + (PenToolFsmState::DraggingHandle, PenToolMessage::PointerMove { snap_angle, break_handle, lock_angle }) => { let mut process = || { // Get subpath let layer_path = tool_data.path.as_ref()?; @@ -418,7 +420,10 @@ impl Fsm for PenToolFsmState { let mouse = tool_data.snap_manager.snap_position(responses, document, input.mouse.position); let pos = transform.inverse().transform_point2(mouse); - let pos = compute_snapped_angle(input, snap_angle, pos, last_anchor.position); + + let snap_angle = input.keyboard.get(snap_angle as usize); + let lock_angle = input.keyboard.get(lock_angle as usize); + let pos = compute_snapped_angle(&mut tool_data.angle, lock_angle, snap_angle, pos, last_anchor.position); // Update points on current segment (to show preview of new handle) let msg = Operation::MoveManipulatorPoint { @@ -460,10 +465,11 @@ impl Fsm for PenToolFsmState { self } } - (PenToolFsmState::PlacingAnchor, PenToolMessage::PointerMove { snap_angle, .. }) => { + (PenToolFsmState::PlacingAnchor, PenToolMessage::PointerMove { snap_angle, lock_angle, .. }) => { let mut process = || { // Get subpath - let layer_path = tool_data.path.as_ref()?; + let data = tool_data.clone(); + let layer_path = data.path.as_ref()?; let subpath = document.document_legacy.layer(layer_path).ok().and_then(|layer| layer.as_subpath())?; // Get the last manipulator group and the one previous to that @@ -491,7 +497,9 @@ impl Fsm for PenToolFsmState { if mouse.distance_squared(transform.transform_point2(relative.position)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2) { pos = relative.position; } else { - pos = compute_snapped_angle(input, snap_angle, pos, relative.position); + let snap_angle = input.keyboard.get(snap_angle as usize); + let lock_angle = input.keyboard.get(lock_angle as usize); + pos = compute_snapped_angle(&mut tool_data.angle, lock_angle, snap_angle, pos, relative.position); } } @@ -592,10 +600,9 @@ impl Fsm for PenToolFsmState { let hint_data = match self { PenToolFsmState::Ready => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Draw Path")])]), PenToolFsmState::DraggingHandle | PenToolFsmState::PlacingAnchor => HintData(vec![ - HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Add Handle")]), - HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Anchor")]), - HintGroup(vec![HintInfo::keys([Key::Control], "Snap 15°")]), - HintGroup(vec![HintInfo::keys([Key::Shift], "Break Handle")]), + HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Anchor"), HintInfo::mouse(MouseMotion::LmbDrag, "Add Handle")]), + HintGroup(vec![HintInfo::keys([Key::Shift], "Snap 15°"), HintInfo::keys([Key::Control], "Lock Angle")]), + HintGroup(vec![HintInfo::keys([Key::Alt], "Break Handle")]), // TODO: Show this only when dragging a handle HintGroup(vec![HintInfo::keys([Key::Enter], "End Path")]), ]), }; @@ -608,22 +615,28 @@ impl Fsm for PenToolFsmState { } } -// TODO: Expand `pos` name below to the full word (position?) -/// Snap the angle of the line from relative to pos if the key is pressed. -fn compute_snapped_angle(input: &InputPreprocessorMessageHandler, key: Key, pos: DVec2, relative: DVec2) -> DVec2 { - if input.keyboard.get(key as usize) { - let delta = relative - pos; +/// Snap the angle of the line from relative to position if the key is pressed. +fn compute_snapped_angle(cached_angle: &mut f64, lock_angle: bool, snap_angle: bool, position: DVec2, relative: DVec2) -> DVec2 { + let delta = relative - position; + let mut angle = -delta.angle_between(DVec2::X); - let length = delta.length(); - let mut angle = -delta.angle_between(DVec2::X); + if lock_angle { + angle = *cached_angle; + } + if snap_angle { let snap_resolution = LINE_ROTATE_SNAP_ANGLE.to_radians(); angle = (angle / snap_resolution).round() * snap_resolution; + } + *cached_angle = angle; + + if snap_angle || lock_angle { + let length = delta.length(); let rotated = DVec2::new(length * angle.cos(), length * angle.sin()); relative - rotated } else { - pos + position } }