mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 13:38:13 +08:00
Add draggable skew triangles to the transform cage (#2300)
* Add triangle handles to transform cage for skew transform Fixes #2299 * Add skew triangles * Fix conflicts which github didn't show * cargo fmt * Fix needed * remove unreachable * use the trap and rect logic * fix quad checks * cursor fix; no triangles if already dragging and not skewing * cargo fmt * Resolve Clippy lints * Add min length for triangle visibility * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
bc6e76208d
commit
1510ad820c
@@ -393,7 +393,10 @@ impl Fsm for ArtboardToolFsmState {
|
||||
}
|
||||
|
||||
(ArtboardToolFsmState::Ready { .. }, ArtboardToolMessage::PointerMove { .. }) => {
|
||||
let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false));
|
||||
let mut cursor = tool_data
|
||||
.bounding_box_manager
|
||||
.as_ref()
|
||||
.map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, false, false, None));
|
||||
|
||||
if cursor == MouseCursorIcon::Default && !hovered {
|
||||
tool_data.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
|
||||
|
||||
@@ -280,7 +280,7 @@ enum SelectToolFsmState {
|
||||
Drawing { selection_shape: SelectionShapeType },
|
||||
Dragging { axis: Axis, using_compass: bool },
|
||||
ResizingBounds,
|
||||
SkewingBounds,
|
||||
SkewingBounds { skew: Key },
|
||||
RotatingBounds,
|
||||
DraggingPivot,
|
||||
}
|
||||
@@ -309,6 +309,7 @@ struct SelectToolData {
|
||||
cursor: MouseCursorIcon,
|
||||
pivot: Pivot,
|
||||
compass_rose: CompassRose,
|
||||
skew_edge: EdgeBool,
|
||||
nested_selection_behavior: NestedSelectionBehavior,
|
||||
selected_layers_count: usize,
|
||||
selected_layers_changed: bool,
|
||||
@@ -577,8 +578,23 @@ impl Fsm for SelectToolFsmState {
|
||||
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
|
||||
.unwrap_or_default();
|
||||
|
||||
let is_resizing_or_rotating = matches!(self, SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. } | SelectToolFsmState::RotatingBounds);
|
||||
|
||||
if let Some(bounds) = tool_data.bounding_box_manager.as_mut() {
|
||||
let edges = bounds.check_selected_edges(input.mouse.position);
|
||||
let is_skewing = matches!(self, SelectToolFsmState::SkewingBounds { .. });
|
||||
let is_near_square = edges.is_some_and(|hover_edge| bounds.over_extended_edge_midpoint(input.mouse.position, hover_edge));
|
||||
if is_skewing || (dragging_bounds && is_near_square && !is_resizing_or_rotating) {
|
||||
bounds.render_skew_gizmos(&mut overlay_context, tool_data.skew_edge);
|
||||
}
|
||||
if !is_skewing && dragging_bounds {
|
||||
if let Some(edges) = edges {
|
||||
tool_data.skew_edge = bounds.get_closest_edge(edges, input.mouse.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let might_resize_or_rotate = dragging_bounds || rotating_bounds;
|
||||
let is_resizing_or_rotating = matches!(self, SelectToolFsmState::ResizingBounds { .. } | SelectToolFsmState::SkewingBounds | SelectToolFsmState::RotatingBounds);
|
||||
let can_get_into_other_states = might_resize_or_rotate && !matches!(self, SelectToolFsmState::Dragging { .. });
|
||||
|
||||
let show_compass = !(can_get_into_other_states || is_resizing_or_rotating);
|
||||
@@ -842,14 +858,19 @@ impl Fsm for SelectToolFsmState {
|
||||
None
|
||||
);
|
||||
bounds.center_of_transformation = selected.mean_average_of_pivots();
|
||||
|
||||
// Check if we're hovering over a skew triangle
|
||||
let edges = bounds.check_selected_edges(input.mouse.position);
|
||||
if let Some(edges) = edges {
|
||||
let closest_edge = bounds.get_closest_edge(edges, input.mouse.position);
|
||||
if bounds.check_skew_handle(input.mouse.position, closest_edge) {
|
||||
tool_data.get_snap_candidates(document, input);
|
||||
return SelectToolFsmState::SkewingBounds { skew };
|
||||
}
|
||||
}
|
||||
}
|
||||
tool_data.get_snap_candidates(document, input);
|
||||
|
||||
if input.keyboard.key(skew) {
|
||||
SelectToolFsmState::SkewingBounds
|
||||
} else {
|
||||
SelectToolFsmState::ResizingBounds
|
||||
}
|
||||
SelectToolFsmState::ResizingBounds
|
||||
}
|
||||
// Dragging the selected layers around to transform them
|
||||
else if can_grab_compass_rose || intersection.is_some_and(|intersection| selected.iter().any(|selected_layer| intersection.starts_with(*selected_layer, document.metadata()))) {
|
||||
@@ -1034,10 +1055,11 @@ impl Fsm for SelectToolFsmState {
|
||||
}
|
||||
SelectToolFsmState::ResizingBounds
|
||||
}
|
||||
(SelectToolFsmState::SkewingBounds, SelectToolMessage::PointerMove(_)) => {
|
||||
(SelectToolFsmState::SkewingBounds { skew }, SelectToolMessage::PointerMove(_)) => {
|
||||
if let Some(ref mut bounds) = &mut tool_data.bounding_box_manager {
|
||||
if let Some(movement) = &mut bounds.selected_edges {
|
||||
let transformation = movement.skew_transform(input.mouse.position, bounds.original_bound_transform);
|
||||
let free_movement = input.keyboard.key(skew);
|
||||
let transformation = movement.skew_transform(input.mouse.position, bounds.original_bound_transform, free_movement);
|
||||
|
||||
tool_data.layers_dragging.retain(|layer| {
|
||||
if *layer != LayerNodeIdentifier::ROOT_PARENT {
|
||||
@@ -1063,7 +1085,7 @@ impl Fsm for SelectToolFsmState {
|
||||
selected.apply_transformation(bounds.original_bound_transform * transformation * bounds.original_bound_transform.inverse(), None);
|
||||
}
|
||||
}
|
||||
SelectToolFsmState::SkewingBounds
|
||||
SelectToolFsmState::SkewingBounds { skew }
|
||||
}
|
||||
(SelectToolFsmState::RotatingBounds, SelectToolMessage::PointerMove(modifier_keys)) => {
|
||||
if let Some(bounds) = &mut tool_data.bounding_box_manager {
|
||||
@@ -1139,7 +1161,16 @@ impl Fsm for SelectToolFsmState {
|
||||
SelectToolFsmState::Drawing { selection_shape }
|
||||
}
|
||||
(SelectToolFsmState::Ready { .. }, SelectToolMessage::PointerMove(_)) => {
|
||||
let mut cursor = tool_data.bounding_box_manager.as_ref().map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true));
|
||||
let dragging_bounds = tool_data
|
||||
.bounding_box_manager
|
||||
.as_mut()
|
||||
.and_then(|bounding_box| bounding_box.check_selected_edges(input.mouse.position))
|
||||
.is_some();
|
||||
|
||||
let mut cursor = tool_data
|
||||
.bounding_box_manager
|
||||
.as_ref()
|
||||
.map_or(MouseCursorIcon::Default, |bounds| bounds.get_cursor(input, true, dragging_bounds, Some(tool_data.skew_edge)));
|
||||
|
||||
// Dragging the pivot overrules the other operations
|
||||
if tool_data.pivot.is_over(input.mouse.position) {
|
||||
@@ -1166,7 +1197,7 @@ impl Fsm for SelectToolFsmState {
|
||||
|
||||
SelectToolFsmState::Dragging { axis, using_compass }
|
||||
}
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::PointerOutsideViewport(_)) => {
|
||||
// AutoPanning
|
||||
if let Some(shift) = tool_data.auto_panning.shift_viewport(input, responses) {
|
||||
if let Some(ref mut bounds) = &mut tool_data.bounding_box_manager {
|
||||
@@ -1271,7 +1302,7 @@ impl Fsm for SelectToolFsmState {
|
||||
let selection = tool_data.nested_selection_behavior;
|
||||
SelectToolFsmState::Ready { selection }
|
||||
}
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||
(SelectToolFsmState::ResizingBounds | SelectToolFsmState::SkewingBounds { .. }, SelectToolMessage::DragStop { .. } | SelectToolMessage::Enter) => {
|
||||
let response = match input.mouse.position.distance(tool_data.drag_start) < 10. * f64::EPSILON {
|
||||
true => DocumentMessage::AbortTransaction,
|
||||
false => DocumentMessage::EndTransaction,
|
||||
@@ -1523,7 +1554,7 @@ impl Fsm for SelectToolFsmState {
|
||||
]);
|
||||
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||
}
|
||||
SelectToolFsmState::DraggingPivot | SelectToolFsmState::SkewingBounds => {
|
||||
SelectToolFsmState::DraggingPivot | SelectToolFsmState::SkewingBounds { .. } => {
|
||||
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]);
|
||||
responses.add(FrontendMessage::UpdateInputHints { hint_data });
|
||||
}
|
||||
|
||||
@@ -325,17 +325,14 @@ impl Fsm for SplineToolFsmState {
|
||||
let append_to_selected_layer = input.keyboard.key(append_to_selected);
|
||||
|
||||
// Create new path in the selected layer when shift is down
|
||||
match (selected_layer, append_to_selected_layer) {
|
||||
(Some(layer), true) => {
|
||||
tool_data.current_layer = Some(layer);
|
||||
if let (Some(layer), true) = (selected_layer, append_to_selected_layer) {
|
||||
tool_data.current_layer = Some(layer);
|
||||
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
let position = transform.inverse().transform_point2(input.mouse.position);
|
||||
tool_data.next_point = position;
|
||||
let transform = document.metadata().transform_to_viewport(layer);
|
||||
let position = transform.inverse().transform_point2(input.mouse.position);
|
||||
tool_data.next_point = position;
|
||||
|
||||
return SplineToolFsmState::Drawing;
|
||||
}
|
||||
_ => {}
|
||||
return SplineToolFsmState::Drawing;
|
||||
}
|
||||
|
||||
responses.add(DocumentMessage::DeselectAllLayers);
|
||||
|
||||
Reference in New Issue
Block a user