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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 79 additions & 34 deletions editor/src/messages/tool/tool_messages/artboard_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::messages::tool::common_functionality::resize::Resize;
use crate::messages::tool::common_functionality::snapping;
use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
use crate::messages::tool::common_functionality::snapping::SnapData;
use crate::messages::tool::common_functionality::snapping::SnapManager;
use crate::messages::tool::common_functionality::transformation_cage::*;
use graph_craft::document::NodeId;
use graphene_std::Artboard;
Expand Down Expand Up @@ -108,7 +107,6 @@ impl Default for ArtboardToolFsmState {
struct ArtboardToolData {
bounding_box_manager: Option<BoundingBoxManager>,
selected_artboard: Option<LayerNodeIdentifier>,
snap_manager: SnapManager,
cursor: MouseCursorIcon,
drag_start: DVec2,
drag_current: DVec2,
Expand Down Expand Up @@ -188,7 +186,7 @@ impl ArtboardToolData {
let center = from_center.then_some(bounds.center_of_transformation);
let ignore = self.selected_artboard.map_or(Vec::new(), |layer| vec![layer]);
let snap = Some(SizeSnapData {
manager: &mut self.snap_manager,
manager: &mut self.draw.snap_manager,
points: &mut self.snap_candidates,
snap_data: SnapData::ignore(document, input, &ignore),
});
Expand Down Expand Up @@ -275,7 +273,7 @@ impl Fsm for ArtboardToolFsmState {
}
}

tool_data.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);
tool_data.draw.snap_manager.draw_overlays(SnapData::new(document, input), &mut overlay_context);

self
}
Expand Down Expand Up @@ -322,7 +320,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, Axis::None, 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.draw.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);
Expand Down Expand Up @@ -354,6 +352,8 @@ impl Fsm for ArtboardToolFsmState {
ArtboardToolFsmState::Dragging
}
(ArtboardToolFsmState::Drawing, ArtboardToolMessage::PointerMove { constrain_axis_or_aspect, center }) => {
// The draw.calculate_points_ignore_layer uses this value to avoid snapping to itself.
tool_data.draw.layer = tool_data.selected_artboard;
let [start, end] = tool_data.draw.calculate_points_ignore_layer(document, input, center, constrain_axis_or_aspect, true);
let viewport_to_document = document.metadata().document_to_viewport.inverse();
let [start, end] = [start, end].map(|point| viewport_to_document.transform_point2(point));
Expand Down Expand Up @@ -400,11 +400,11 @@ impl Fsm for ArtboardToolFsmState {
.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);
tool_data.draw.snap_manager.preview_draw(&SnapData::new(document, input), input.mouse.position);
responses.add(OverlaysMessage::Draw);
cursor = MouseCursorIcon::Crosshair;
} else {
tool_data.snap_manager.cleanup(responses);
tool_data.draw.cleanup(responses);
}

if tool_data.cursor != cursor {
Expand Down Expand Up @@ -445,7 +445,7 @@ impl Fsm for ArtboardToolFsmState {
(ArtboardToolFsmState::Drawing | ArtboardToolFsmState::ResizingBounds | ArtboardToolFsmState::Dragging, ArtboardToolMessage::PointerUp) => {
responses.add(DocumentMessage::EndTransaction);

tool_data.snap_manager.cleanup(responses);
tool_data.draw.cleanup(responses);

if let Some(bounds) = &mut tool_data.bounding_box_manager {
bounds.original_transforms.clear();
Expand Down Expand Up @@ -553,7 +553,7 @@ impl Fsm for ArtboardToolFsmState {
(ArtboardToolFsmState::Dragging | ArtboardToolFsmState::Drawing | ArtboardToolFsmState::ResizingBounds, ArtboardToolMessage::Abort) => {
responses.add(DocumentMessage::AbortTransaction);

tool_data.snap_manager.cleanup(responses);
tool_data.draw.cleanup(responses);
responses.add(OverlaysMessage::Draw);

ArtboardToolFsmState::Ready { hovered }
Expand Down Expand Up @@ -611,29 +611,61 @@ mod test_artboard {
.collect()
}

#[derive(Debug, PartialEq)]
struct ArtboardLayoutDocument {
position: IVec2,
dimensions: IVec2,
}
impl ArtboardLayoutDocument {
pub fn new(position: impl Into<IVec2>, dimensions: impl Into<IVec2>) -> Self {
Self {
position: position.into(),
dimensions: dimensions.into(),
}
}
}

/// Check if all of the artboards exist in any ordering
async fn has_artboards(editor: &mut EditorTestUtils, mut expected: Vec<ArtboardLayoutDocument>) {
let artboards = get_artboards(editor)
.await
.iter()
.map(|row| ArtboardLayoutDocument::new(row.element.location, row.element.dimensions))
.collect::<Vec<_>>();
assert_eq!(artboards.len(), expected.len(), "incorrect len: actual {:?}, expected {:?}", artboards, expected);

for artboard in artboards {
let Some(index) = expected.iter().position(|expected| *expected == artboard) else {
panic!("found {:?} that did not match any expected artboards\nexpected {:?}", artboard, expected);
};
expected.remove(index);
}
}

#[tokio::test]
async fn artboard_draw_simple() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Artboard, 10.1, 10.8, 19.9, 0.2, ModifierKeys::empty()).await;
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((10, 0), (10, 11))]).await;
}

let artboards = get_artboards(&mut editor).await;

assert_eq!(artboards.len(), 1);
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(10, 0));
assert_eq!(artboards.get(0).unwrap().element.dimensions, IVec2::new(10, 11));
#[tokio::test]
async fn artboard_snapping() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.set_viewport_size(DVec2::splat(-1000.), DVec2::splat(1000.)).await; // Necessary for doing snapping since snaps outside of the viewport are discarded
editor.drag_tool(ToolType::Artboard, 10., 10., 20., 20., ModifierKeys::empty()).await;
editor.drag_tool(ToolType::Artboard, 11., 50., 19., 60., ModifierKeys::empty()).await;
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((10, 10), (10, 10)), ArtboardLayoutDocument::new((10, 50), (10, 10))]).await;
}

#[tokio::test]
async fn artboard_draw_square() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Artboard, 10., 10., -10., 11., ModifierKeys::SHIFT).await;

let artboards = get_artboards(&mut editor).await;
assert_eq!(artboards.len(), 1);
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(-10, 10));
assert_eq!(artboards.get(0).unwrap().element.dimensions, IVec2::new(20, 20));
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((-10, 10), (20, 20))]).await;
}

#[tokio::test]
Expand All @@ -648,12 +680,9 @@ mod test_artboard {
.await;
// Viewport coordinates
editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT).await;

let artboards = get_artboards(&mut editor).await;
assert_eq!(artboards.len(), 1);
assert_eq!(artboards.get(0).unwrap().element.location, IVec2::new(0, 0));
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 10.);
assert_eq!(artboards.get(0).unwrap().element.dimensions, desired_size.round().as_ivec2());

has_artboards(&mut editor, vec![ArtboardLayoutDocument::new(IVec2::new(0, 0), desired_size.round().as_ivec2())]).await;
}

#[tokio::test]
Expand All @@ -669,12 +698,9 @@ mod test_artboard {
.await;
// Viewport coordinates
editor.drag_tool(ToolType::Artboard, 0., 0., 0., 10., ModifierKeys::SHIFT | ModifierKeys::ALT).await;

let artboards = get_artboards(&mut editor).await;
assert_eq!(artboards.len(), 1);
assert_eq!(artboards.get(0).unwrap().element.location, DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2());
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.);
assert_eq!(artboards.get(0).unwrap().element.dimensions, desired_size.round().as_ivec2());
let desired_location = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * -10.).as_ivec2();
let desired_size = DVec2::splat(f64::consts::FRAC_1_SQRT_2 * 20.).as_ivec2();
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new(desired_location, desired_size)]).await;
}

#[tokio::test]
Expand All @@ -685,8 +711,7 @@ mod test_artboard {
editor.drag_tool(ToolType::Artboard, 10.1, 10.8, 19.9, 0.2, ModifierKeys::default()).await;
editor.press(Key::Delete, ModifierKeys::default()).await;

let artboards = get_artboards(&mut editor).await;
assert_eq!(artboards.len(), 0);
has_artboards(&mut editor, vec![]).await;
}

#[tokio::test]
Expand All @@ -696,7 +721,27 @@ mod test_artboard {
editor.new_document().await;

editor.drag_tool_cancel_rmb(ToolType::Artboard).await;
let artboards = get_artboards(&mut editor).await;
assert_eq!(artboards.len(), 0);
has_artboards(&mut editor, vec![]).await;
}

#[tokio::test]
async fn artboard_move() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.drag_tool(ToolType::Artboard, 10., 10., 20., 22., ModifierKeys::empty()).await; // Artboard to drag
editor.drag_tool(ToolType::Artboard, 15., 15., 65., 65., ModifierKeys::empty()).await; // Drag from the middle by (50,50)

has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60, 60), (10, 12))]).await;
}
#[tokio::test]
async fn artboard_move_snapping() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
editor.set_viewport_size(DVec2::splat(-1000.), DVec2::splat(1000.)).await; // Necessary for doing snapping since snaps outside of the viewport are discarded
editor.drag_tool(ToolType::Artboard, 10., 10., 20., 22., ModifierKeys::empty()).await; // Artboard to drag
editor.drag_tool(ToolType::Artboard, 70., 0., 80., 100., ModifierKeys::empty()).await; // Artboard to snap to
editor.drag_tool(ToolType::Artboard, 15., 15., 15. + 49., 15., ModifierKeys::empty()).await; // Drag the artboard so it should snap to the edge

has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60, 10), (10, 12)), ArtboardLayoutDocument::new((70, 0), (10, 100))]).await;
}
}
10 changes: 9 additions & 1 deletion editor/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::application::Editor;
use crate::application::set_uuid_seed;
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
use crate::messages::input_mapper::utility_types::input_mouse::ViewportBounds;
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
use crate::messages::portfolio::utility_types::Platform;
use crate::messages::prelude::*;
Expand Down Expand Up @@ -32,7 +33,6 @@ impl EditorTestUtils {
let _ = GLOBAL_PLATFORM.set(Platform::Windows).is_ok();

editor.handle_message(PortfolioMessage::Init);

Self { editor, runtime }
}

Expand Down Expand Up @@ -293,6 +293,14 @@ impl EditorTestUtils {
)
.await;
}

/// Necessary for doing snapping since snaps outside of the viewport are discarded
pub async fn set_viewport_size(&mut self, top_left: DVec2, bottom_right: DVec2) {
self.handle_message(InputPreprocessorMessage::BoundsOfViewports {
bounds_of_viewports: vec![ViewportBounds { top_left, bottom_right }],
})
.await;
}
}

pub trait FrontendMessageTestUtils {
Expand Down
Loading