diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 330fe16abc..d9adf1288c 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1406,17 +1406,11 @@ impl MessageHandler> for DocumentMes self.network_interface.update_first_element_source_id(first_element_source_id); } DocumentMessage::UpdateClickTargets { click_targets } => { - // TODO: Allow non layer nodes to have click targets let layer_click_targets = click_targets .into_iter() - .filter(|(node_id, _)| - // Ensure that the layer is in the document network to prevent logging an error - self.network_interface.document_network().nodes.contains_key(node_id)) - .filter_map(|(node_id, click_targets)| { - self.network_interface.is_layer(&node_id, &[]).then(|| { - let layer = LayerNodeIdentifier::new(node_id, &self.network_interface); - (layer, click_targets) - }) + .map(|(node_id, click_targets)| { + let layer = LayerNodeIdentifier::new_unchecked(node_id); + (layer, click_targets) }) .collect(); self.network_interface.update_click_targets(layer_click_targets); diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 4188eff338..57d9f3f3a3 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -71,24 +71,16 @@ impl DocumentMetadata { } pub fn transform_to_viewport(&self, layer: LayerNodeIdentifier) -> DAffine2 { - // We're not allowed to convert the root parent to a node id - if layer == LayerNodeIdentifier::ROOT_PARENT { - return self.document_to_viewport; - } - - let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); - let local_transform = self.local_transforms.get(&layer.to_node()).copied().unwrap_or_default(); + let node_id = if layer == LayerNodeIdentifier::ROOT_PARENT { NodeId(0) } else { layer.to_node() }; + let footprint = self.upstream_footprints.get(&node_id).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); + let local_transform = self.local_transforms.get(&node_id).copied().unwrap_or_default(); footprint * local_transform } pub fn transform_to_viewport_if_feeds(&self, layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> DAffine2 { - // We're not allowed to convert the root parent to a node id - if layer == LayerNodeIdentifier::ROOT_PARENT { - return self.document_to_viewport; - } - - let footprint = self.upstream_footprints.get(&layer.to_node()).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); + let node_id = if layer == LayerNodeIdentifier::ROOT_PARENT { NodeId(0) } else { layer.to_node() }; + let footprint = self.upstream_footprints.get(&node_id).map(|footprint| footprint.transform).unwrap_or(self.document_to_viewport); let mut use_local = true; let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface); @@ -266,10 +258,7 @@ impl LayerNodeIdentifier { /// Access the node id of this layer pub fn to_node(self) -> NodeId { - let id = NodeId(u64::from(self.0) - 1); - debug_assert!(id != NodeId(0), "LayerNodeIdentifier::ROOT_PARENT cannot be converted to NodeId"); - - id + NodeId(u64::from(self.0) - 1) } /// Access the parent layer if possible diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 23ab3c64f2..5ecb50b254 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -1184,7 +1184,8 @@ impl NodeNetworkInterface { /// Calculates the document bounds in document space pub fn document_bounds_document_space(&self, include_artboards: bool) -> Option<[DVec2; 2]> { - self.document_metadata + let all_layers_bounds = self + .document_metadata .all_layers() .filter(|layer| include_artboards || !self.is_artboard(&layer.to_node(), &[])) .filter_map(|layer| { @@ -1206,7 +1207,16 @@ impl NodeNetworkInterface { } self.document_metadata.bounding_box_document(layer) }) - .reduce(Quad::combine_bounds) + .reduce(Quad::combine_bounds); + + let root_artwork_bounds = self.document_metadata().bounding_box_document(LayerNodeIdentifier::ROOT_PARENT); + + match (all_layers_bounds, root_artwork_bounds) { + (Some(a), Some(b)) => Some(Quad::combine_bounds(a, b)), + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (None, None) => None, + } } /// Calculates the selected layer bounds in document space diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 2b78e595a6..9c90367db5 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -238,12 +238,22 @@ impl NodeGraphExecutor { }; // Calculate the bounding box of the region to be exported - let bounds = match export_config.bounds { + let mut bounds = match export_config.bounds { ExportBounds::AllArtwork => document.network_interface.document_bounds_document_space(!export_config.transparent_background), ExportBounds::Selection => document.network_interface.selected_bounds_document_space(!export_config.transparent_background, &[]), ExportBounds::Artboard(id) => document.metadata().bounding_box_document(id), } .ok_or_else(|| "No bounding box".to_string())?; + + // Add a small amount of padding to the bounding box if we are exporting everything or a selection. + // This provides a better framing and ensures we don't clip the outer half of strokes at the edge. + if matches!(export_config.bounds, ExportBounds::AllArtwork | ExportBounds::Selection) { + let size = (bounds[1] - bounds[0]).max(DVec2::splat(1.)); + let padding = size * 0.05; + bounds[0] -= padding; + bounds[1] += padding; + } + let resolution = (bounds[1] - bounds[0]).round().as_uvec2(); let transform = DAffine2::from_translation(bounds[0]).inverse(); diff --git a/node-graph/libraries/rendering/src/renderer.rs b/node-graph/libraries/rendering/src/renderer.rs index fcea51c45c..dfc4f8403a 100644 --- a/node-graph/libraries/rendering/src/renderer.rs +++ b/node-graph/libraries/rendering/src/renderer.rs @@ -307,8 +307,12 @@ impl Render for Graphic { fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option) { if let Some(element_id) = element_id { match self { - Graphic::Graphic(_) => { + Graphic::Graphic(table) => { metadata.upstream_footprints.insert(element_id, footprint); + if let Some(row) = table.iter().next() { + metadata.first_element_source_id.insert(element_id, *row.source_node_id); + metadata.local_transforms.insert(element_id, *row.transform); + } } Graphic::Vector(table) => { metadata.upstream_footprints.insert(element_id, footprint); @@ -505,9 +509,9 @@ impl Render for Table { } } - fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option) { + fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option) { for row in self.iter() { - row.element.collect_metadata(metadata, footprint, *row.source_node_id); + row.element.collect_metadata(metadata, footprint, row.source_node_id.or(element_id)); } } diff --git a/node-graph/nodes/gstd/src/render_node.rs b/node-graph/nodes/gstd/src/render_node.rs index 01972d040c..0814b1a979 100644 --- a/node-graph/nodes/gstd/src/render_node.rs +++ b/node-graph/nodes/gstd/src/render_node.rs @@ -57,7 +57,7 @@ async fn render_intermediate<'a: 'n, T: 'static + Render + WasmNotSend + Send + let footprint = Footprint::default(); let mut metadata = RenderMetadata::default(); - data.collect_metadata(&mut metadata, footprint, None); + data.collect_metadata(&mut metadata, footprint, Some(graph_craft::document::NodeId(0))); let contains_artboard = data.contains_artboard(); match &render_params.render_output_type {