diff --git a/editor/src/messages/tool/common_functionality/compass_rose.rs b/editor/src/messages/tool/common_functionality/compass_rose.rs index fe9a052e..8a7a2f6b 100644 --- a/editor/src/messages/tool/common_functionality/compass_rose.rs +++ b/editor/src/messages/tool/common_functionality/compass_rose.rs @@ -101,3 +101,13 @@ impl Axis { matches!(self, Self::X | Self::Y) } } + +impl From for DVec2 { + fn from(value: Axis) -> Self { + match value { + Axis::X => DVec2::X, + Axis::Y => DVec2::Y, + Axis::None => DVec2::ZERO, + } + } +} diff --git a/editor/src/messages/tool/common_functionality/transformation_cage.rs b/editor/src/messages/tool/common_functionality/transformation_cage.rs index 7f049bb7..031cbaa1 100644 --- a/editor/src/messages/tool/common_functionality/transformation_cage.rs +++ b/editor/src/messages/tool/common_functionality/transformation_cage.rs @@ -8,6 +8,7 @@ use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms; use crate::messages::prelude::*; +use crate::messages::tool::common_functionality::compass_rose::Axis; use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration; use glam::{DAffine2, DMat2, DVec2}; use graphene_core::renderer::Quad; @@ -286,25 +287,30 @@ impl SelectedEdges { } /// Aligns the mouse position to the closest axis -pub fn axis_align_drag(axis_align: bool, position: DVec2, start: DVec2) -> DVec2 { +pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVec2) -> 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); let snapped_angle = (angle / snap_resolution).round() * snap_resolution; + let axis_vector = DVec2::from_angle(snapped_angle); if snapped_angle.is_finite() { - start + DVec2::new(snapped_angle.cos(), snapped_angle.sin()) * mouse_position.length() + start + axis_vector * mouse_position.dot(axis_vector).abs() } else { start } + } else if axis.is_constraint() { + let mouse_position = position - start; + let axis_vector: DVec2 = axis.into(); + start + axis_vector * mouse_position.dot(axis_vector) } else { position } } /// Snaps a dragging event from the artboard or select tool -pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 { - let mouse_position = axis_align_drag(axis_align, snap_data.input.mouse.position, start); +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; 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); @@ -324,7 +330,8 @@ pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: Snap let mut point = point.clone(); point.document_point += total_mouse_delta_document; - let snapped = if axis_align { + let constrained_along_axis = snap_to_axis || axis.is_constraint(); + let snapped = if constrained_along_axis { let constraint = SnapConstraint::Line { origin: point.document_point, direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X), diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index 947185a7..44020223 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -3,6 +3,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; +use crate::messages::tool::common_functionality::compass_rose::Axis; use crate::messages::tool::common_functionality::resize::Resize; use crate::messages::tool::common_functionality::snapping; use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint; @@ -283,7 +284,7 @@ impl Fsm for ArtboardToolFsmState { let snap_data = SnapData::ignore(document, input, &ignore); let document_to_viewport = document.metadata().document_to_viewport; let [start, current] = [tool_data.drag_start, tool_data.drag_current].map(|point| document_to_viewport.transform_point2(point)); - let mouse_delta = snap_drag(start, current, axis_align, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); + let mouse_delta = snap_drag(start, current, axis_align, Axis::None, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); let size = bounds.bounds[1] - bounds.bounds[0]; let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_delta); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 9d5de9ee..88c142e8 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -319,6 +319,7 @@ struct SelectToolData { cursor: MouseCursorIcon, pivot: Pivot, compass_rose: CompassRose, + line_center: DVec2, skew_edge: EdgeBool, nested_selection_behavior: NestedSelectionBehavior, selected_layers_count: usize, @@ -660,6 +661,9 @@ impl Fsm for SelectToolFsmState { // Update compass rose tool_data.compass_rose.refresh_position(document); let compass_center = tool_data.compass_rose.compass_rose_position(); + if !matches!(self, Self::Dragging { .. }) { + tool_data.line_center = compass_center; + } overlay_context.compass_rose(compass_center, angle, show_compass_with_ring); let axis_state = if let SelectToolFsmState::Dragging { axis, .. } = self { @@ -691,7 +695,8 @@ impl Fsm for SelectToolFsmState { let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).rgba_hex(); &format!("#{}", color_string) }; - overlay_context.line(compass_center - direction * viewport_diagonal, compass_center + direction * viewport_diagonal, Some(color)); + let line_center = tool_data.line_center; + overlay_context.line(line_center - direction * viewport_diagonal, line_center + direction * viewport_diagonal, Some(color)); } } } @@ -984,7 +989,7 @@ impl Fsm for SelectToolFsmState { tool_data.stop_duplicates(document, responses); } - tool_data.axis_align = input.keyboard.key(modifier_keys.axis_align) && !axis.is_constraint(); + tool_data.axis_align = input.keyboard.key(modifier_keys.axis_align); // Ignore the non duplicated layers if the current layers have not spawned yet. let layers_exist = tool_data.layers_dragging.iter().all(|&layer| document.metadata().click_targets(layer).is_some()); @@ -992,12 +997,13 @@ impl Fsm for SelectToolFsmState { let snap_data = SnapData::ignore(document, input, ignore); let (start, current) = (tool_data.drag_start, tool_data.drag_current); - let mouse_delta = snap_drag(start, current, tool_data.axis_align, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); let e0 = tool_data .bounding_box_manager .as_ref() .map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds)) .map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X)); + + let mouse_delta = snap_drag(start, current, tool_data.axis_align, axis, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates); let mouse_delta = match axis { Axis::X => mouse_delta.project_onto(e0), Axis::Y => mouse_delta.project_onto(e0.perp()),