Skip to content

Commit 9e2bda3

Browse files
0SlowPoke0Keavon
andauthored
Add G/R/S to the Pen tool to control the outgoing segment handle (#2211)
* more_refactoring_solve_conflict * overlays-target-fix * Code review * select-broken-fix --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 96c5760 commit 9e2bda3

File tree

6 files changed

+236
-50
lines changed

6 files changed

+236
-50
lines changed

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ pub fn input_mappings() -> Mapping {
260260
entry!(KeyDown(Enter); action_dispatch=PenToolMessage::Confirm),
261261
entry!(KeyDown(Delete); action_dispatch=PenToolMessage::RemovePreviousHandle),
262262
entry!(KeyDown(Backspace); action_dispatch=PenToolMessage::RemovePreviousHandle),
263+
entry!(KeyDown(KeyG); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }),
264+
entry!(KeyDown(KeyR); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }),
265+
entry!(KeyDown(KeyS); action_dispatch=PenToolMessage::GRS { grab: KeyG, rotate: KeyR, scale: KeyS }),
263266
//
264267
// FreehandToolMessage
265268
entry!(PointerMove; action_dispatch=FreehandToolMessage::PointerMove),

editor/src/messages/portfolio/document/utility_types/transformation.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ pub struct Selected<'a> {
384384
pub pivot: &'a mut DVec2,
385385
pub shape_editor: Option<&'a ShapeState>,
386386
pub tool_type: &'a ToolType,
387+
// Only for the Pen tool
388+
pub pen_handle: Option<&'a mut DVec2>,
387389
}
388390

389391
impl<'a> Selected<'a> {
@@ -396,6 +398,7 @@ impl<'a> Selected<'a> {
396398
network_interface: &'a NodeNetworkInterface,
397399
shape_editor: Option<&'a ShapeState>,
398400
tool_type: &'a ToolType,
401+
pen_handle: Option<&'a mut DVec2>,
399402
) -> Self {
400403
// If user is using the Select tool then use the original layer transforms
401404
if (*tool_type == ToolType::Select) && (*original_transforms == OriginalTransforms::Path(HashMap::new())) {
@@ -412,6 +415,7 @@ impl<'a> Selected<'a> {
412415
pivot,
413416
shape_editor,
414417
tool_type,
418+
pen_handle,
415419
}
416420
}
417421

@@ -502,6 +506,13 @@ impl<'a> Selected<'a> {
502506
}
503507
}
504508

509+
pub fn apply_transform_pen(&mut self, transformation: DAffine2) {
510+
if let Some(pen_handle) = &self.pen_handle {
511+
let final_position = transformation.transform_point2(**pen_handle);
512+
self.responses.add(PenToolMessage::FinalPosition { final_position });
513+
}
514+
}
515+
505516
pub fn apply_transformation(&mut self, transformation: DAffine2) {
506517
if !self.selected.is_empty() {
507518
// TODO: Cache the result of `shallowest_unique_layers` to avoid this heavy computation every frame of movement, see https://github.com/GraphiteEditor/Graphite/pull/481
@@ -523,7 +534,10 @@ impl<'a> Selected<'a> {
523534
pub fn update_transforms(&mut self, delta: DAffine2) {
524535
let pivot = DAffine2::from_translation(*self.pivot);
525536
let transformation = pivot * delta * pivot.inverse();
526-
self.apply_transformation(transformation);
537+
match self.tool_type {
538+
ToolType::Pen => self.apply_transform_pen(transformation),
539+
_ => self.apply_transformation(transformation),
540+
}
527541
}
528542

529543
pub fn revert_operation(&mut self) {

editor/src/messages/tool/tool_messages/pen_tool.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub enum PenToolMessage {
6363
UpdateOptions(PenOptionsUpdate),
6464
RecalculateLatestPointsPosition,
6565
RemovePreviousHandle,
66+
GRS { grab: Key, rotate: Key, scale: Key },
67+
FinalPosition { final_position: DVec2 },
6668
}
6769

6870
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
@@ -71,6 +73,7 @@ enum PenToolFsmState {
7173
Ready,
7274
DraggingHandle,
7375
PlacingAnchor,
76+
GRSHandle,
7477
}
7578

7679
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, specta::Type)]
@@ -162,13 +165,14 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
162165

163166
fn actions(&self) -> ActionList {
164167
match self.fsm_state {
165-
PenToolFsmState::Ready => actions!(PenToolMessageDiscriminant;
168+
PenToolFsmState::Ready | PenToolFsmState::GRSHandle => actions!(PenToolMessageDiscriminant;
166169
Undo,
167170
DragStart,
168171
DragStop,
169172
Confirm,
170173
Abort,
171174
PointerMove,
175+
FinalPosition
172176
),
173177
PenToolFsmState::DraggingHandle | PenToolFsmState::PlacingAnchor => actions!(PenToolMessageDiscriminant;
174178
DragStart,
@@ -177,6 +181,7 @@ impl<'a> MessageHandler<ToolMessage, &mut ToolActionHandlerData<'a>> for PenTool
177181
Confirm,
178182
Abort,
179183
RemovePreviousHandle,
184+
GRS,
180185
),
181186
}
182187
}
@@ -223,6 +228,8 @@ struct PenToolData {
223228
modifiers: ModifierState,
224229

225230
buffering_merged_vector: bool,
231+
232+
before_grs_pos: DVec2,
226233
}
227234
impl PenToolData {
228235
fn latest_point(&self) -> Option<&LastPoint> {
@@ -563,6 +570,72 @@ impl Fsm for PenToolFsmState {
563570

564571
let ToolMessage::Pen(event) = event else { return self };
565572
match (self, event) {
573+
(PenToolFsmState::PlacingAnchor | PenToolFsmState::GRSHandle, PenToolMessage::GRS { grab, rotate, scale }) => {
574+
let Some(latest) = tool_data.latest_point_mut() else { return PenToolFsmState::PlacingAnchor };
575+
let Some(layer) = layer else { return PenToolFsmState::PlacingAnchor };
576+
577+
if latest.handle_start != latest.pos {
578+
let viewport = document.metadata().transform_to_viewport(layer);
579+
let last_point = viewport.transform_point2(latest.pos);
580+
let handle = viewport.transform_point2(latest.handle_start);
581+
582+
if input.keyboard.key(grab) {
583+
responses.add(TransformLayerMessage::BeginGrabPen { last_point, handle });
584+
} else if input.keyboard.key(rotate) {
585+
responses.add(TransformLayerMessage::BeginRotatePen { last_point, handle });
586+
} else if input.keyboard.key(scale) {
587+
responses.add(TransformLayerMessage::BeginScalePen { last_point, handle });
588+
}
589+
590+
tool_data.before_grs_pos = latest.handle_start;
591+
}
592+
593+
PenToolFsmState::GRSHandle
594+
}
595+
(PenToolFsmState::GRSHandle, PenToolMessage::FinalPosition { final_position: final_pos }) => {
596+
let Some(layer) = layer else { return PenToolFsmState::GRSHandle };
597+
598+
if let Some(latest_pt) = tool_data.latest_point_mut() {
599+
let layer_space_to_viewport = document.metadata().transform_to_viewport(layer);
600+
let final_pos = layer_space_to_viewport.inverse().transform_point2(final_pos);
601+
latest_pt.handle_start = final_pos;
602+
}
603+
604+
responses.add(OverlaysMessage::Draw);
605+
606+
PenToolFsmState::GRSHandle
607+
}
608+
(PenToolFsmState::GRSHandle, PenToolMessage::Confirm) => {
609+
tool_data.next_point = input.mouse.position;
610+
tool_data.next_handle_start = input.mouse.position;
611+
612+
responses.add(OverlaysMessage::Draw);
613+
responses.add(PenToolMessage::PointerMove {
614+
snap_angle: Key::Control,
615+
break_handle: Key::Alt,
616+
lock_angle: Key::Shift,
617+
});
618+
619+
PenToolFsmState::PlacingAnchor
620+
}
621+
(PenToolFsmState::GRSHandle, PenToolMessage::Abort) => {
622+
tool_data.next_point = input.mouse.position;
623+
tool_data.next_handle_start = input.mouse.position;
624+
625+
let previous = tool_data.before_grs_pos;
626+
if let Some(latest) = tool_data.latest_point_mut() {
627+
latest.handle_start = previous;
628+
}
629+
630+
responses.add(OverlaysMessage::Draw);
631+
responses.add(PenToolMessage::PointerMove {
632+
snap_angle: Key::Control,
633+
break_handle: Key::Alt,
634+
lock_angle: Key::Shift,
635+
});
636+
637+
PenToolFsmState::PlacingAnchor
638+
}
566639
(_, PenToolMessage::SelectionChanged) => {
567640
responses.add(OverlaysMessage::Draw);
568641
self
@@ -814,7 +887,7 @@ impl Fsm for PenToolFsmState {
814887

815888
fn update_hints(&self, responses: &mut VecDeque<Message>) {
816889
let hint_data = match self {
817-
PenToolFsmState::Ready => HintData(vec![HintGroup(vec![
890+
PenToolFsmState::Ready | PenToolFsmState::GRSHandle => HintData(vec![HintGroup(vec![
818891
HintInfo::mouse(MouseMotion::Lmb, "Draw Path"),
819892
// TODO: Only show this if a single layer is selected and it's of a valid type (e.g. a vector path but not raster or artboard)
820893
HintInfo::keys([Key::Shift], "Append to Selected Layer").prepend_plus(),

editor/src/messages/tool/tool_messages/select_tool.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,7 @@ impl Fsm for SelectToolFsmState {
632632
&document.network_interface,
633633
None,
634634
&ToolType::Select,
635+
None
635636
);
636637
bounds.center_of_transformation = selected.mean_average_of_pivots();
637638
}
@@ -660,6 +661,7 @@ impl Fsm for SelectToolFsmState {
660661
&document.network_interface,
661662
None,
662663
&ToolType::Select,
664+
None
663665
);
664666

665667
bounds.center_of_transformation = selected.mean_average_of_pivots();
@@ -785,7 +787,16 @@ impl Fsm for SelectToolFsmState {
785787
}
786788
});
787789
let selected = &tool_data.layers_dragging;
788-
let mut selected = Selected::new(&mut bounds.original_transforms, &mut pivot, selected, responses, &document.network_interface, None, &ToolType::Select);
790+
let mut selected = Selected::new(
791+
&mut bounds.original_transforms,
792+
&mut pivot,
793+
selected,
794+
responses,
795+
&document.network_interface,
796+
None,
797+
&ToolType::Select,
798+
None,
799+
);
789800

790801
selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse());
791802

@@ -833,6 +844,7 @@ impl Fsm for SelectToolFsmState {
833844
&document.network_interface,
834845
None,
835846
&ToolType::Select,
847+
None,
836848
);
837849

838850
selected.update_transforms(delta);

editor/src/messages/tool/transform_layer/transform_layer_message.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use crate::messages::input_mapper::utility_types::input_keyboard::Key;
22
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
33
use crate::messages::prelude::*;
44

5+
use glam::DVec2;
6+
57
#[impl_message(Message, ToolMessage, TransformLayer)]
68
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
79
pub enum TransformLayerMessage {
@@ -10,6 +12,9 @@ pub enum TransformLayerMessage {
1012
BeginGrab,
1113
BeginRotate,
1214
BeginScale,
15+
BeginGrabPen { last_point: DVec2, handle: DVec2 },
16+
BeginRotatePen { last_point: DVec2, handle: DVec2 },
17+
BeginScalePen { last_point: DVec2, handle: DVec2 },
1318
CancelTransformOperation,
1419
ConstrainX,
1520
ConstrainY,

0 commit comments

Comments
 (0)