Skip to content

Commit 4e65887

Browse files
authored
Fix the Artboard tool drawing the first artboard on an infinite canvas with layers present (#3356)
Improve creating the first artboard
1 parent 7f10a42 commit 4e65887

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
108108
GraphOperationMessage::NewArtboard { id, artboard } => {
109109
let mut modify_inputs = ModifyInputsContext::new(network_interface, responses);
110110

111+
let artboard_location = artboard.location;
111112
let artboard_layer = modify_inputs.create_artboard(id, artboard);
112113
network_interface.move_layer_to_stack(artboard_layer, LayerNodeIdentifier::ROOT_PARENT, 0, &[]);
113114

@@ -116,13 +117,33 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
116117
log::error!("Artboard not created");
117118
return;
118119
};
120+
let document_metadata = network_interface.document_metadata();
121+
119122
let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone();
120123
if let NodeInput::Node { node_id, .. } = &primary_input {
121-
if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) {
122-
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface), artboard_layer, 0, &[]);
124+
if network_interface.is_artboard(node_id, &[]) {
125+
// Nothing to do here: we have a stack full of artboards!
126+
} else if network_interface.is_layer(node_id, &[]) {
127+
// We have a stack of non-layer artboards.
128+
for (insert_index, layer) in LayerNodeIdentifier::ROOT_PARENT.children(document_metadata).filter(|&layer| layer != artboard_layer).enumerate() {
129+
// Parent the layer to our new artboard (retaining ordering)
130+
responses.add(NodeGraphMessage::MoveLayerToStack {
131+
layer,
132+
parent: artboard_layer,
133+
insert_index,
134+
});
135+
// Apply a translation to prevent the content from shifting
136+
responses.add(GraphOperationMessage::TransformChange {
137+
layer,
138+
transform: DAffine2::from_translation(-artboard_location.as_dvec2()),
139+
transform_in: TransformIn::Local,
140+
skip_rerender: true,
141+
});
142+
}
123143
} else {
144+
// We have some non layers (e.g. just a rectangle node). We disconnect the bottom input and connect it to the left input.
124145
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
125-
network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]);
146+
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 1), primary_input, &[]);
126147
}
127148
}
128149
responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,4 +762,30 @@ mod test_artboard {
762762

763763
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((60, 10), (10, 12)), ArtboardLayoutDocument::new((70, 0), (10, 100))]).await;
764764
}
765+
766+
#[tokio::test]
767+
async fn first_artboard() {
768+
let mut editor = EditorTestUtils::create();
769+
770+
editor.new_document().await;
771+
// Put rectangles in before making the artboard
772+
editor.drag_tool(ToolType::Rectangle, 10., 10., 20., 16., ModifierKeys::empty()).await;
773+
editor.drag_tool(ToolType::Rectangle, 15., 15., 25., 25., ModifierKeys::empty()).await;
774+
775+
// Put the artboard in
776+
editor.drag_tool(ToolType::Artboard, 5., 5., 30., 10., ModifierKeys::empty()).await;
777+
has_artboards(&mut editor, vec![ArtboardLayoutDocument::new((5, 5), (25, 5))]).await;
778+
let document = editor.active_document();
779+
780+
// artboard
781+
// ├── rectangle1
782+
// └── rectangle2
783+
let artboard = document.metadata().all_layers().next().unwrap();
784+
let rectangle2 = artboard.first_child(document.metadata()).unwrap();
785+
let rectangle1 = rectangle2.next_sibling(document.metadata()).unwrap();
786+
787+
// The document bounding boxes should remain the same (content shouldn't shift)
788+
assert_eq!(document.metadata().bounding_box_document(rectangle1).unwrap(), [DVec2::new(10., 10.), DVec2::new(20., 16.)]);
789+
assert_eq!(document.metadata().bounding_box_document(rectangle2).unwrap(), [DVec2::new(15., 15.), DVec2::new(25., 25.)]);
790+
}
765791
}

editor/src/node_graph_executor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,8 @@ mod test {
542542
} else if let Some(x) = dynamic.downcast_ref::<IORecord<Context, Input::Result>>() {
543543
Some(x.output.clone())
544544
} else {
545-
panic!("cannot downcast type for introspection");
545+
warn!("cannot downcast type for introspection");
546+
None
546547
}
547548
}
548549

@@ -557,7 +558,7 @@ mod test {
557558
.iter()
558559
.filter_map(|inputs| inputs.get(Input::INDEX))
559560
.filter_map(|input_monitor_node| runtime.executor.introspect(input_monitor_node).ok())
560-
.filter_map(Instrumented::downcast::<Input>)
561+
.filter_map(Instrumented::downcast::<Input>) // Some might not resolve (e.g. generics that don't work properly)
561562
}
562563

563564
pub fn grab_protonode_input<Input: NodeInputDecleration>(&self, path: &Vec<NodeId>, runtime: &NodeRuntime) -> Option<Input::Result>

0 commit comments

Comments
 (0)