mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 18:08:12 +08:00
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:
committed by
Keavon Chambers
co-authored by
Keavon Chambers
parent
92cb553961
commit
069a2351f2
@@ -171,7 +171,7 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(DoubleClick; action_dispatch=PathToolMessage::InsertPoint),
|
entry!(DoubleClick; action_dispatch=PathToolMessage::InsertPoint),
|
||||||
//
|
//
|
||||||
// PenToolMessage
|
// 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!(KeyDown(Lmb); action_dispatch=PenToolMessage::DragStart),
|
||||||
entry!(KeyUp(Lmb); action_dispatch=PenToolMessage::DragStop),
|
entry!(KeyUp(Lmb); action_dispatch=PenToolMessage::DragStop),
|
||||||
entry!(KeyDown(Rmb); action_dispatch=PenToolMessage::Confirm),
|
entry!(KeyDown(Rmb); action_dispatch=PenToolMessage::Confirm),
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ pub enum PenToolMessage {
|
|||||||
PointerMove {
|
PointerMove {
|
||||||
snap_angle: Key,
|
snap_angle: Key,
|
||||||
break_handle: Key,
|
break_handle: Key,
|
||||||
|
lock_angle: Key,
|
||||||
},
|
},
|
||||||
Undo,
|
Undo,
|
||||||
UpdateOptions(PenOptionsUpdate),
|
UpdateOptions(PenOptionsUpdate),
|
||||||
@@ -148,6 +149,7 @@ struct PenToolData {
|
|||||||
should_mirror: bool,
|
should_mirror: bool,
|
||||||
// Indicates that curve extension is occurring from the first point, rather than (more commonly) the last point
|
// Indicates that curve extension is occurring from the first point, rather than (more commonly) the last point
|
||||||
from_start: bool,
|
from_start: bool,
|
||||||
|
angle: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fsm for PenToolFsmState {
|
impl Fsm for PenToolFsmState {
|
||||||
@@ -399,7 +401,7 @@ impl Fsm for PenToolFsmState {
|
|||||||
tool_data.should_mirror = true;
|
tool_data.should_mirror = true;
|
||||||
process().unwrap_or(PenToolFsmState::PlacingAnchor)
|
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 = || {
|
let mut process = || {
|
||||||
// Get subpath
|
// Get subpath
|
||||||
let layer_path = tool_data.path.as_ref()?;
|
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 mouse = tool_data.snap_manager.snap_position(responses, document, input.mouse.position);
|
||||||
let pos = transform.inverse().transform_point2(mouse);
|
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)
|
// Update points on current segment (to show preview of new handle)
|
||||||
let msg = Operation::MoveManipulatorPoint {
|
let msg = Operation::MoveManipulatorPoint {
|
||||||
@@ -460,10 +465,11 @@ impl Fsm for PenToolFsmState {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(PenToolFsmState::PlacingAnchor, PenToolMessage::PointerMove { snap_angle, .. }) => {
|
(PenToolFsmState::PlacingAnchor, PenToolMessage::PointerMove { snap_angle, lock_angle, .. }) => {
|
||||||
let mut process = || {
|
let mut process = || {
|
||||||
// Get subpath
|
// 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())?;
|
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
|
// 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) {
|
if mouse.distance_squared(transform.transform_point2(relative.position)) < crate::consts::SNAP_POINT_TOLERANCE.powi(2) {
|
||||||
pos = relative.position;
|
pos = relative.position;
|
||||||
} else {
|
} 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 {
|
let hint_data = match self {
|
||||||
PenToolFsmState::Ready => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Draw Path")])]),
|
PenToolFsmState::Ready => HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Draw Path")])]),
|
||||||
PenToolFsmState::DraggingHandle | PenToolFsmState::PlacingAnchor => HintData(vec![
|
PenToolFsmState::DraggingHandle | PenToolFsmState::PlacingAnchor => HintData(vec![
|
||||||
HintGroup(vec![HintInfo::mouse(MouseMotion::LmbDrag, "Add Handle")]),
|
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Anchor"), HintInfo::mouse(MouseMotion::LmbDrag, "Add Handle")]),
|
||||||
HintGroup(vec![HintInfo::mouse(MouseMotion::Lmb, "Add Anchor")]),
|
HintGroup(vec![HintInfo::keys([Key::Shift], "Snap 15°"), HintInfo::keys([Key::Control], "Lock Angle")]),
|
||||||
HintGroup(vec![HintInfo::keys([Key::Control], "Snap 15°")]),
|
HintGroup(vec![HintInfo::keys([Key::Alt], "Break Handle")]), // TODO: Show this only when dragging a handle
|
||||||
HintGroup(vec![HintInfo::keys([Key::Shift], "Break Handle")]),
|
|
||||||
HintGroup(vec![HintInfo::keys([Key::Enter], "End Path")]),
|
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 position if the key is pressed.
|
||||||
/// Snap the angle of the line from relative to pos if the key is pressed.
|
fn compute_snapped_angle(cached_angle: &mut f64, lock_angle: bool, snap_angle: bool, position: DVec2, relative: DVec2) -> DVec2 {
|
||||||
fn compute_snapped_angle(input: &InputPreprocessorMessageHandler, key: Key, pos: DVec2, relative: DVec2) -> DVec2 {
|
let delta = relative - position;
|
||||||
if input.keyboard.get(key as usize) {
|
let mut angle = -delta.angle_between(DVec2::X);
|
||||||
let delta = relative - pos;
|
|
||||||
|
|
||||||
let length = delta.length();
|
if lock_angle {
|
||||||
let mut angle = -delta.angle_between(DVec2::X);
|
angle = *cached_angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if snap_angle {
|
||||||
let snap_resolution = LINE_ROTATE_SNAP_ANGLE.to_radians();
|
let snap_resolution = LINE_ROTATE_SNAP_ANGLE.to_radians();
|
||||||
angle = (angle / snap_resolution).round() * snap_resolution;
|
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());
|
let rotated = DVec2::new(length * angle.cos(), length * angle.sin());
|
||||||
relative - rotated
|
relative - rotated
|
||||||
} else {
|
} else {
|
||||||
pos
|
position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user