Add lock angle modifier to the Pen tool (#1049)
* adds lock angle to pen tool The current [Shift] Break Handle behavior should become Alt instead of Shift The current [Ctrl] Snap 15° behavior should become Shift instead of Ctrl Implement the extend-in-this-direction feature called [Ctrl] Lock Angle that exists in the Line tool, but doesn't yet exist in the Pen tool * avoid clone by passing exlusive ref to tool data field directly * Rearrange hints --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
92cb553961
commit
069a2351f2
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue