Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -303,15 +303,19 @@ impl SelectedEdges {
}
}

/// Aligns the mouse position to the closest axis
pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVec2) -> DVec2 {
/// Aligns the mouse position to the closest axis, accounting for canvas rotation.
/// `canvas_rotation` is the angle in radians by which the canvas is tilted.
pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVec2, canvas_rotation: f64) -> DVec2 {
if axis_align {
let mouse_position = position - start;
let snap_resolution = SELECTION_DRAG_ANGLE.to_radians();
let angle = -mouse_position.angle_to(DVec2::X);
// Subtract canvas rotation to work in canvas-local space
let angle = -mouse_position.angle_to(DVec2::X) - canvas_rotation;
let snapped_angle = (angle / snap_resolution).round() * snap_resolution;
let axis_vector = DVec2::from_angle(snapped_angle);
if snapped_angle.is_finite() {
// Add canvas rotation back to get the final screen-space angle
let final_angle = snapped_angle + canvas_rotation;
let axis_vector = DVec2::from_angle(final_angle);
if final_angle.is_finite() {
start + axis_vector * mouse_position.dot(axis_vector).abs()
} else {
start
Expand All @@ -327,8 +331,10 @@ pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVe

/// Snaps a dragging event from the artboard or select tool
pub fn snap_drag(start: DVec2, current: DVec2, snap_to_axis: bool, axis: Axis, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 {
let mouse_position = axis_align_drag(snap_to_axis, axis, snap_data.input.mouse.position, start);
let document = snap_data.document;
// Extract canvas rotation from the document_to_viewport transform
let canvas_rotation = document.metadata().document_to_viewport.matrix2.y_axis.to_angle() - std::f64::consts::FRAC_PI_2;
let mouse_position = axis_align_drag(snap_to_axis, axis, snap_data.input.mouse.position, start, canvas_rotation);
let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start);
let mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - current);
let mut offset = mouse_delta_document;
Expand Down
19 changes: 14 additions & 5 deletions editor/src/messages/tool/tool_messages/select_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ struct SelectToolData {
snap_candidates: Vec<SnapCandidatePoint>,
auto_panning: AutoPanning,
drag_start_center: ViewportPosition,
/// Drag start position in document coordinates, used for axis-aligned snapping that follows canvas pan/tilt
drag_start_document: DVec2,
}

impl SelectToolData {
Expand Down Expand Up @@ -911,12 +913,16 @@ impl Fsm for SelectToolFsmState {
}

if axis_state.is_none_or(|(axis, _)| !axis.is_constraint()) && tool_data.axis_align {
let mouse_position = mouse_position - tool_data.drag_start;
// Convert document-space origin to current viewport (follows pan/tilt)
let viewport_origin = document.metadata().document_to_viewport.transform_point2(tool_data.drag_start_document);
let mouse_position = mouse_position - viewport_origin;
let snap_resolution = SELECTION_DRAG_ANGLE.to_radians();
let angle = -mouse_position.angle_to(DVec2::X);
let snapped_angle = (angle / snap_resolution).round() * snap_resolution;
// Account for canvas rotation
let canvas_rotation = document.metadata().document_to_viewport.matrix2.y_axis.to_angle() - std::f64::consts::FRAC_PI_2;
let angle = -mouse_position.angle_to(DVec2::X) - canvas_rotation;
let snapped_angle = (angle / snap_resolution).round() * snap_resolution + canvas_rotation;

let origin = tool_data.drag_start_center;
let origin = viewport_origin;
let viewport_diagonal = viewport.size().into_dvec2().length();

let edge = DVec2::from_angle(snapped_angle).normalize_or(DVec2::X);
Expand Down Expand Up @@ -1037,6 +1043,7 @@ impl Fsm for SelectToolFsmState {
let (resize, rotate, skew) = transforming_transform_cage(document, &mut tool_data.bounding_box_manager, input, responses, &mut tool_data.layers_dragging, Some(position));

tool_data.drag_start_center = position;
tool_data.drag_start_document = document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position);

// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
// If the user is dragging the rotate trigger, go into RotatingBounds mode.
Expand Down Expand Up @@ -1179,7 +1186,9 @@ impl Fsm for SelectToolFsmState {
let ignore = tool_data.non_duplicated_layers.as_ref().filter(|_| !layers_exist).unwrap_or(&tool_data.layers_dragging);

let snap_data = SnapData::ignore(document, input, viewport, ignore);
let (start, current) = (tool_data.drag_start, tool_data.drag_current);
// Convert document-space origin to current viewport (follows pan/tilt)
let start = document.metadata().document_to_viewport.transform_point2(tool_data.drag_start_document);
let current = tool_data.drag_current;
let e0 = tool_data
.bounding_box_manager
.as_ref()
Expand Down
Loading