From 27f9e3f00e8d012598bdbc688cb7266b6afbfe56 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 27 Mar 2024 05:17:08 -0700 Subject: [PATCH] Move node visibility flag from NodeNetwork to DocumentNode (#1708) * protonode -> proto node * Move node visibility flag from NodeNetwork to DocumentNode * Add serde default for new field * Logic improvements --- .../messages/input_mapper/default_mapping.rs | 2 +- .../document/document_message_handler.rs | 13 +-- .../document/node_graph/node_graph_message.rs | 8 +- .../node_graph/node_graph_message_handler.rs | 92 ++++++++++--------- .../document/node_graph/utility_types.rs | 2 +- .../document/utility_types/clipboards.rs | 4 +- .../utility_types/document_metadata.rs | 43 ++++++--- .../portfolio/document/utility_types/nodes.rs | 16 ++-- .../portfolio/portfolio_message_handler.rs | 10 +- .../tool/common_functionality/pivot.rs | 6 +- .../tool/common_functionality/snapping.rs | 2 +- .../tool/tool_messages/gradient_tool.rs | 6 +- .../tool/tool_messages/select_tool.rs | 8 +- .../messages/tool/tool_messages/text_tool.rs | 2 +- editor/src/node_graph_executor.rs | 4 +- frontend/.eslintrc.cjs | 4 +- frontend/src/components/panels/Layers.svelte | 4 +- frontend/src/components/views/Graph.svelte | 8 +- frontend/src/wasm-communication/messages.ts | 4 +- frontend/wasm/src/editor_api.rs | 4 +- node-graph/README.md | 4 +- node-graph/compilation-client/src/main.rs | 1 - node-graph/graph-craft/src/document.rs | 36 ++++---- node-graph/graph-craft/src/proto.rs | 4 +- .../src/dynamic_executor.rs | 10 +- website/.eslintrc.js | 2 +- website/other/bezier-rs-demos/.eslintrc.cjs | 2 +- 27 files changed, 161 insertions(+), 140 deletions(-) diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index ff353efb..4920f8d7 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -57,7 +57,7 @@ pub fn default_mapping() -> Mapping { entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut), entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy), entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes), - entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=NodeGraphMessage::ToggleSelectedHidden), + entry!(KeyDown(KeyH); modifiers=[Accel], action_dispatch=NodeGraphMessage::ToggleSelectedVisibility), // // TransformLayerMessage entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation), diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index b6a29247..de705a3f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -822,7 +822,7 @@ impl DocumentMessageHandler { self.metadata .root() .descendants(&self.metadata) - .filter(|&layer| self.selected_nodes.layer_visible(layer, self.network(), self.metadata())) + .filter(|&layer| self.selected_nodes.layer_visible(layer, self.metadata())) .filter(|&layer| !is_artboard(layer, network)) .filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets))) .filter(move |(layer, target)| target.iter().any(move |target| target.intersect_rectangle(document_quad, self.metadata.transform_to_document(*layer)))) @@ -835,7 +835,7 @@ impl DocumentMessageHandler { self.metadata .root() .descendants(&self.metadata) - .filter(|&layer| self.selected_nodes.layer_visible(layer, self.network(), self.metadata())) + .filter(|&layer| self.selected_nodes.layer_visible(layer, self.metadata())) .filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets))) .filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer)))) .map(|(layer, _)| layer) @@ -849,7 +849,7 @@ impl DocumentMessageHandler { /// Get the combined bounding box of the click targets of the selected visible layers in viewport space pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> { self.selected_nodes - .selected_visible_layers(self.network(), self.metadata()) + .selected_visible_layers(self.metadata()) .filter_map(|layer| self.metadata.bounding_box_viewport(layer)) .reduce(graphene_core::renderer::Quad::combine_bounds) } @@ -887,13 +887,6 @@ impl DocumentMessageHandler { Ok(document) } - /// Returns the bounding boxes for all visible layers. - pub fn bounding_boxes(&self) -> impl Iterator + '_ { - // TODO: Remove this function entirely? - // self.visible_layers().filter_map(|path| self.document_legacy.viewport_bounding_box(path, font_cache).ok()?) - std::iter::empty() - } - /// Called recursively by the entry function [`serialize_root`]. fn serialize_structure(&self, folder: LayerNodeIdentifier, structure_section: &mut Vec, data_section: &mut Vec, path: &mut Vec) { let mut space = 0; diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs index b22d1535..7769be00 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -89,13 +89,13 @@ pub enum NodeGraphMessage { ShiftNode { node_id: NodeId, }, - ToggleSelectedHidden, - ToggleHidden { + ToggleSelectedVisibility, + ToggleVisibility { node_id: NodeId, }, - SetHidden { + SetVisibility { node_id: NodeId, - hidden: bool, + visible: bool, }, SetName { node_id: NodeId, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index a0a83334..a1f7173c 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -59,8 +59,8 @@ impl<'a> MessageHandler> for NodeGrap load_network_structure(document_network, document_metadata, selected_nodes, collapsed); } NodeGraphMessage::SelectedNodesUpdated => { - self.update_selection_action_buttons(document_network, selected_nodes, responses); - self.update_selected(document_network, selected_nodes, responses); + self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses); + self.update_selected(document_network, document_metadata, selected_nodes, responses); if selected_nodes.selected_layers(document_metadata).count() <= 1 { responses.add(DocumentMessage::SetRangeSelectionLayer { new_layer: selected_nodes.selected_layers(document_metadata).next(), @@ -195,7 +195,7 @@ impl<'a> MessageHandler> for NodeGrap if let Some(network) = document_network.nested_network(&self.network) { self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses); } - self.update_selected(document_network, selected_nodes, responses); + self.update_selected(document_network, document_metadata, selected_nodes, responses); } NodeGraphMessage::DuplicateSelectedNodes => { if let Some(network) = document_network.nested_network(&self.network) { @@ -221,7 +221,7 @@ impl<'a> MessageHandler> for NodeGrap responses.add(NodeGraphMessage::InsertNode { node_id, document_node }); } - self.update_selected(document_network, selected_nodes, responses); + self.update_selected(document_network, document_metadata, selected_nodes, responses); } } NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => { @@ -234,7 +234,7 @@ impl<'a> MessageHandler> for NodeGrap if let Some(network) = document_network.nested_network(&self.network) { self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses); } - self.update_selected(document_network, selected_nodes, responses); + self.update_selected(document_network, document_metadata, selected_nodes, responses); } NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => { let Some(network) = document_network.nested_network(&self.network) else { @@ -447,36 +447,46 @@ impl<'a> MessageHandler> for NodeGrap self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses); } - NodeGraphMessage::ToggleSelectedHidden => { - if let Some(network) = document_network.nested_network(&self.network) { - responses.add(DocumentMessage::StartTransaction); + NodeGraphMessage::ToggleSelectedVisibility => { + responses.add(DocumentMessage::StartTransaction); - let new_hidden = !selected_nodes.selected_nodes().any(|id| network.disabled.contains(id)); - for &node_id in selected_nodes.selected_nodes() { - responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden }); - } + // If any of the selected nodes are hidden, show them all. Otherwise, hide them all. + let visible = selected_nodes.selected_nodes().all(|&node_id| document_metadata.node_is_visible(node_id)); + let visible = !visible; + + for &node_id in selected_nodes.selected_nodes() { + responses.add(NodeGraphMessage::SetVisibility { node_id, visible }); } } - NodeGraphMessage::ToggleHidden { node_id } => { - if let Some(network) = document_network.nested_network(&self.network) { - let new_hidden = !network.disabled.contains(&node_id); - responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden }); - } + NodeGraphMessage::ToggleVisibility { node_id } => { + let visible = document_metadata.node_is_visible(node_id); + let visible = !visible; + + responses.add(NodeGraphMessage::SetVisibility { node_id, visible }); } - NodeGraphMessage::SetHidden { node_id, hidden } => { - if let Some(network) = document_network.nested_network_mut(&self.network) { - if !hidden { - network.disabled.retain(|&id| node_id != id); - } else if !network.imports.contains(&node_id) && !network.original_outputs().iter().any(|output| output.node_id == node_id) { - network.disabled.push(node_id); - } + NodeGraphMessage::SetVisibility { node_id, visible } => { + (|| { + let Some(network) = document_network.nested_network_mut(&self.network) else { return }; + + let input_or_output = network.imports.contains(&node_id) || network.original_outputs().iter().any(|output| output.node_id == node_id); + let visibility = if visible { + true + } else if !input_or_output { + false + } else { + return; + }; + + // Set what we determined shall be the visibility of the node + let Some(node) = network.nodes.get_mut(&node_id) else { return }; + node.visible = visibility; // Only generate node graph if one of the selected nodes is connected to the output if network.connected_to_output(node_id) { responses.add(NodeGraphMessage::RunDocumentGraph); } - } - self.update_selection_action_buttons(document_network, selected_nodes, responses); + })(); + self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses); } NodeGraphMessage::SetName { node_id, name } => { responses.add(DocumentMessage::StartTransaction); @@ -508,7 +518,7 @@ impl<'a> MessageHandler> for NodeGrap } } - self.update_selection_action_buttons(document_network, selected_nodes, responses); + self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses); responses.add(NodeGraphMessage::RunDocumentGraph); } @@ -522,7 +532,7 @@ impl<'a> MessageHandler> for NodeGrap let node_types = document_node_types::collect_node_types(); responses.add(FrontendMessage::UpdateNodeTypes { node_types }); } - self.update_selected(document_network, selected_nodes, responses); + self.update_selected(document_network, document_metadata, selected_nodes, responses); } NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => { self.resolved_types = resolved_types; @@ -540,7 +550,7 @@ impl<'a> MessageHandler> for NodeGrap impl NodeGraphMessageHandler { pub fn actions_with_node_graph_open(&self, graph_open: bool) -> ActionList { if self.has_selection && graph_open { - actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes, ToggleSelectedHidden) + actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes, ToggleSelectedVisibility) } else { actions!(NodeGraphMessageDiscriminant;) } @@ -554,8 +564,8 @@ impl NodeGraphMessageHandler { }); } - /// Updates the buttons for disable and preview - fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { + /// Updates the buttons for visibility and preview + fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { if let Some(network) = document_network.nested_network(&self.network) { let mut widgets = Vec::new(); @@ -565,18 +575,18 @@ impl NodeGraphMessageHandler { // If there is at least one other selected node then show the hide or show button if selection.next().is_some() { // Check if any of the selected nodes are disabled - let is_hidden = selected_nodes.selected_nodes().any(|id| network.disabled.contains(id)); + let all_visible = selected_nodes.selected_nodes().all(|&id| document_metadata.node_is_visible(id)); // Check if multiple nodes are selected let multiple_nodes = selection.next().is_some(); - // Generate the enable or disable button accordingly - let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") }; + // Generate the visible/hidden button accordingly + let (hide_show_label, hide_show_icon) = if all_visible { ("Make Hidden", "EyeVisible") } else { ("Make Visible", "EyeHidden") }; let hide_button = TextButton::new(hide_show_label) .icon(Some(hide_show_icon.to_string())) - .tooltip(if is_hidden { "Show selected nodes/layers" } else { "Hide selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" }) - .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedHidden)) - .on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into()) + .tooltip(if all_visible { "Hide selected nodes/layers" } else { "Show selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" }) + .tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility)) + .on_update(move |_| NodeGraphMessage::ToggleSelectedVisibility.into()) .widget_holder(); widgets.push(hide_button); @@ -745,7 +755,7 @@ impl NodeGraphMessageHandler { exposed_outputs, position: node.metadata.position.into(), previewed: network.outputs_contain(node_id), - disabled: network.disabled.contains(&node_id), + visible: node.visible, errors: errors.map(|e| format!("{e:?}")), }); } @@ -774,7 +784,7 @@ impl NodeGraphMessageHandler { parent_id: layer.parent(metadata).map(|parent| parent.to_node()), name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(), tooltip: if cfg!(debug_assertions) { format!("Layer ID: {node_id}") } else { "".into() }, - disabled: network.disabled.contains(&node_id), + visible: node.visible, }; responses.add(FrontendMessage::UpdateDocumentLayerDetails { data }); } @@ -795,8 +805,8 @@ impl NodeGraphMessageHandler { } /// Updates the frontend's selection state in line with the backend - fn update_selected(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { - self.update_selection_action_buttons(document_network, selected_nodes, responses); + fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, selected_nodes: &SelectedNodes, responses: &mut VecDeque) { + self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses); responses.add(FrontendMessage::UpdateNodeGraphSelection { selected: selected_nodes.selected_nodes_ref().clone(), }); diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index d528b377..6bf6ff53 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -84,7 +84,7 @@ pub struct FrontendNode { #[serde(rename = "exposedOutputs")] pub exposed_outputs: Vec, pub position: (i32, i32), - pub disabled: bool, + pub visible: bool, pub previewed: bool, pub errors: Option, } diff --git a/editor/src/messages/portfolio/document/utility_types/clipboards.rs b/editor/src/messages/portfolio/document/utility_types/clipboards.rs index 549fd482..a9db4211 100644 --- a/editor/src/messages/portfolio/document/utility_types/clipboards.rs +++ b/editor/src/messages/portfolio/document/utility_types/clipboards.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; pub enum Clipboard { Internal, - _InternalClipboardCount, // Keep this as the last entry in internal clipboards since it is used for counting the number of enum variants + _InternalClipboardCount, // Keep this as the last entry of **internal** clipboards since it is used for counting the number of enum variants Device, } @@ -19,7 +19,7 @@ pub const INTERNAL_CLIPBOARD_COUNT: u8 = Clipboard::_InternalClipboardCount as u pub struct CopyBufferEntry { pub nodes: HashMap, pub selected: bool, - pub disabled: bool, + pub visible: bool, pub collapsed: bool, pub alias: String, } 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 d148de1e..94467529 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -14,12 +14,15 @@ use std::num::NonZeroU64; // DocumentMetadata // ================ +// TODO: To avoid storing a stateful snapshot of some other system's state (which is easily to accidentally get out of sync), +// TODO: it might be better to have a system that can query the state of the node network on demand. #[derive(Debug, Clone)] pub struct DocumentMetadata { upstream_transforms: HashMap, structure: HashMap, artboards: HashSet, folders: HashSet, + hidden: HashSet, click_targets: HashMap>, /// Transform from document space to viewport space. pub document_to_viewport: DAffine2, @@ -29,10 +32,11 @@ impl Default for DocumentMetadata { fn default() -> Self { Self { upstream_transforms: HashMap::new(), - click_targets: HashMap::new(), structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]), artboards: HashSet::new(), folders: HashSet::new(), + hidden: HashSet::new(), + click_targets: HashMap::new(), document_to_viewport: DAffine2::IDENTITY, } } @@ -118,6 +122,10 @@ impl DocumentMetadata { self.artboards.contains(&layer) } + pub fn node_is_visible(&self, layer: NodeId) -> bool { + !self.hidden.contains(&layer) + } + /// Folders sorted from most nested to least nested pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator) -> Vec { let mut folders: Vec<_> = layers.filter(|layer| self.folders.contains(layer)).collect(); @@ -138,8 +146,9 @@ impl DocumentMetadata { } self.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]); - self.folders = HashSet::new(); self.artboards = HashSet::new(); + self.folders = HashSet::new(); + self.hidden = HashSet::new(); let id = graph.exports[0].node_id; let Some(output_node) = graph.nodes.get(&id) else { @@ -150,22 +159,26 @@ impl DocumentMetadata { }; let parent = LayerNodeIdentifier::ROOT; let mut stack = vec![(layer_node, node_id, parent)]; - while let Some((node, id, parent)) = stack.pop() { - let mut current = Some((node, id)); - while let Some(&(current_node, current_id)) = current.as_ref() { - let current_identifier = LayerNodeIdentifier::new_unchecked(current_id); - if !self.structure.contains_key(¤t_identifier) { - parent.push_child(self, current_identifier); + while let Some((node, node_id, parent)) = stack.pop() { + let mut current = Some((node, node_id)); + while let Some(&(current_node, current_node_id)) = current.as_ref() { + let current_layer_id = LayerNodeIdentifier::new_unchecked(current_node_id); + if !self.structure.contains_key(¤t_layer_id) { + parent.push_child(self, current_layer_id); if let Some((child_node, child_id)) = first_child_layer(graph, current_node) { - stack.push((child_node, child_id, current_identifier)); + stack.push((child_node, child_id, current_layer_id)); } - if is_artboard(current_identifier, graph) { - self.artboards.insert(current_identifier); + if is_artboard(current_layer_id, graph) { + self.artboards.insert(current_layer_id); } - if is_folder(current_identifier, graph) { - self.folders.insert(current_identifier); + if is_folder(current_layer_id, graph) { + self.folders.insert(current_layer_id); + } + + if !current_node.visible { + self.hidden.insert(current_node_id); } } @@ -532,9 +545,9 @@ impl<'a> Iterator for AxisIter<'a> { } } -// ============== +// =============== // DescendantsIter -// ============== +// =============== #[derive(Clone)] pub struct DescendantsIter<'a> { diff --git a/editor/src/messages/portfolio/document/utility_types/nodes.rs b/editor/src/messages/portfolio/document/utility_types/nodes.rs index ffeb5cd5..f3e788b8 100644 --- a/editor/src/messages/portfolio/document/utility_types/nodes.rs +++ b/editor/src/messages/portfolio/document/utility_types/nodes.rs @@ -1,9 +1,9 @@ -use graph_craft::document::{NodeId, NodeNetwork}; +use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; + +use graph_craft::document::NodeId; use serde::ser::SerializeStruct; -use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)] pub struct RawBuffer(Vec); @@ -46,7 +46,7 @@ pub struct LayerPanelEntry { #[serde(rename = "layerClassification")] pub layer_classification: LayerClassification, pub expanded: bool, - pub disabled: bool, + pub visible: bool, #[serde(rename = "parentId")] pub parent_id: Option, pub depth: usize, @@ -56,12 +56,12 @@ pub struct LayerPanelEntry { pub struct SelectedNodes(pub Vec); impl SelectedNodes { - pub fn layer_visible(&self, layer: LayerNodeIdentifier, network: &NodeNetwork, metadata: &DocumentMetadata) -> bool { - !layer.ancestors(metadata).any(|layer| network.disabled.contains(&layer.to_node())) + pub fn layer_visible(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool { + layer.ancestors(metadata).all(|layer| metadata.node_is_visible(layer.to_node())) } - pub fn selected_visible_layers<'a>(&'a self, network: &'a NodeNetwork, metadata: &'a DocumentMetadata) -> impl Iterator + '_ { - self.selected_layers(metadata).filter(move |&layer| self.layer_visible(layer, network, metadata)) + pub fn selected_visible_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator + '_ { + self.selected_layers(metadata).filter(move |&layer| self.layer_visible(layer, metadata)) } pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator + '_ { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 8e8737a6..d6042afd 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -202,7 +202,7 @@ impl MessageHandler> for PortfolioMes ) .collect(), selected: active_document.selected_nodes.selected_layers_contains(layer, active_document.metadata()), - disabled: !active_document.selected_nodes.layer_visible(layer, active_document.network(), active_document.metadata()), + visible: active_document.selected_nodes.layer_visible(layer, active_document.metadata()), collapsed: false, alias: previous_alias, }); @@ -388,8 +388,8 @@ impl MessageHandler> for PortfolioMes if entry.selected { responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] }); } - if entry.disabled { - responses.add(NodeGraphMessage::SetHidden { node_id: id, hidden: entry.disabled }); + if !entry.visible { + responses.add(NodeGraphMessage::SetVisibility { node_id: id, visible: false }); } } }; @@ -419,8 +419,8 @@ impl MessageHandler> for PortfolioMes if entry.selected { responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] }); } - if entry.disabled { - responses.add(NodeGraphMessage::SetHidden { node_id: id, hidden: entry.disabled }); + if !entry.visible { + responses.add(NodeGraphMessage::SetVisibility { node_id: id, visible: false }); } } diff --git a/editor/src/messages/tool/common_functionality/pivot.rs b/editor/src/messages/tool/common_functionality/pivot.rs index 614bf9b4..c762ca50 100644 --- a/editor/src/messages/tool/common_functionality/pivot.rs +++ b/editor/src/messages/tool/common_functionality/pivot.rs @@ -45,7 +45,7 @@ impl Pivot { /// Recomputes the pivot position and transform. fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) { - let mut layers = document.selected_nodes.selected_visible_layers(document.network(), document.metadata()); + let mut layers = document.selected_nodes.selected_visible_layers(document.metadata()); let Some(first) = layers.next() else { // If no layers are selected then we revert things back to default self.normalized_pivot = DVec2::splat(0.5); @@ -66,7 +66,7 @@ impl Pivot { // If more than one layer is selected we use the AABB with the mean of the pivots let xy_summation = document .selected_nodes - .selected_visible_layers(document.network(), document.metadata()) + .selected_visible_layers(document.metadata()) .map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.metadata)) .reduce(|a, b| a + b) .unwrap_or_default(); @@ -101,7 +101,7 @@ impl Pivot { /// Sets the viewport position of the pivot for all selected layers. pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque) { - for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) { + for layer in document.selected_nodes.selected_visible_layers(document.metadata()) { let transform = Self::get_layer_pivot_transform(layer, document); let pivot = transform.inverse().transform_point2(position); // Only update the pivot when computed position is finite. Infinite can happen when scale is 0. diff --git a/editor/src/messages/tool/common_functionality/snapping.rs b/editor/src/messages/tool/common_functionality/snapping.rs index 7eb95cdf..57f5c50e 100644 --- a/editor/src/messages/tool/common_functionality/snapping.rs +++ b/editor/src/messages/tool/common_functionality/snapping.rs @@ -255,7 +255,7 @@ impl SnapManager { if candidates.len() > 10 { return; } - if !document.selected_nodes.layer_visible(layer, &document.network, &document.metadata) { + if !document.selected_nodes.layer_visible(layer, &document.metadata) { return; } if snap_data.ignore.contains(&layer) { diff --git a/editor/src/messages/tool/tool_messages/gradient_tool.rs b/editor/src/messages/tool/tool_messages/gradient_tool.rs index dd1487b7..0b7d8bc8 100644 --- a/editor/src/messages/tool/tool_messages/gradient_tool.rs +++ b/editor/src/messages/tool/tool_messages/gradient_tool.rs @@ -247,7 +247,7 @@ impl Fsm for GradientToolFsmState { (_, GradientToolMessage::Overlays(mut overlay_context)) => { let selected = tool_data.selected_gradient.as_ref(); - for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) { + for layer in document.selected_nodes.selected_visible_layers(document.metadata()) { let Some(gradient) = get_gradient(layer, &document.network) else { continue }; let transform = gradient_space_transform(layer, document); let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging); @@ -318,7 +318,7 @@ impl Fsm for GradientToolFsmState { self } (_, GradientToolMessage::InsertStop) => { - for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) { + for layer in document.selected_nodes.selected_visible_layers(document.metadata()) { let Some(mut gradient) = get_gradient(layer, &document.network) else { continue }; let transform = gradient_space_transform(layer, document); @@ -357,7 +357,7 @@ impl Fsm for GradientToolFsmState { let tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2); let mut dragging = false; - for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) { + for layer in document.selected_nodes.selected_visible_layers(document.metadata()) { let Some(gradient) = get_gradient(layer, &document.network) else { continue }; let transform = gradient_space_transform(layer, document); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 728a9205..5894dd04 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -391,7 +391,7 @@ impl Fsm for SelectToolFsmState { tool_data.selected_layers_count = selected_layers_count; // Outline selected layers - for layer in document.selected_nodes.selected_visible_layers(document.network(), document.metadata()) { + for layer in document.selected_nodes.selected_visible_layers(document.metadata()) { overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer)); } @@ -405,13 +405,13 @@ impl Fsm for SelectToolFsmState { // Update bounds let transform = document .selected_nodes - .selected_visible_layers(document.network(), document.metadata()) + .selected_visible_layers(document.metadata()) .next() .map(|layer| document.metadata().transform_to_viewport(layer)); let transform = transform.unwrap_or(DAffine2::IDENTITY); let bounds = document .selected_nodes - .selected_visible_layers(document.network(), document.metadata()) + .selected_visible_layers(document.metadata()) .filter_map(|layer| { document .metadata() @@ -472,7 +472,7 @@ impl Fsm for SelectToolFsmState { .map(|bounding_box| bounding_box.check_rotate(input.mouse.position)) .unwrap_or_default(); - let mut selected: Vec<_> = document.selected_nodes.selected_visible_layers(document.network(), document.metadata()).collect(); + let mut selected: Vec<_> = document.selected_nodes.selected_visible_layers(document.metadata()).collect(); let intersection = document.click(input.mouse.position, &document.network); // If the user is dragging the bounding box bounds, go into ResizingBounds mode. diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 1ec71f7e..6f1c0c1c 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -215,7 +215,7 @@ impl TextToolData { /// Set the editing state of the currently modifying layer fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque) { if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network) { - responses.add(NodeGraphMessage::SetHidden { node_id, hidden: editable }); + responses.add(NodeGraphMessage::SetVisibility { node_id, visible: !editable }); } if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) { diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index d6a9cf52..7f5ada86 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -190,7 +190,7 @@ impl NodeRuntime { image_frame: None, }; - // Required to ensure that the appropriate protonodes are reinserted when the Editor API changes. + // Required to ensure that the appropriate proto nodes are reinserted when the Editor API changes. let mut graph_input_hash = DefaultHasher::new(); editor_api.font_cache.hash(&mut graph_input_hash); let font_hash_code = graph_input_hash.finish(); @@ -218,7 +218,7 @@ impl NodeRuntime { Err(e) => return Err(e), }; - assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?"); + assert_ne!(proto_network.nodes.len(), 0, "No proto nodes exist?"); if let Err(e) = self.executor.update(proto_network).await { self.node_graph_errors = e; } else { diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index b8b9123a..32485f10 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -50,7 +50,7 @@ module.exports = { camelcase: ["error", { properties: "always" }], "linebreak-style": ["error", "unix"], "eol-last": ["error", "always"], - "max-len": ["error", { code: 200, tabWidth: 4 }], + "max-len": ["error", { code: 200, tabWidth: 4, ignorePattern: `d="([\\s\\S]*?)"` }], "prefer-destructuring": "off", "no-console": "warn", "no-debugger": "warn", @@ -81,6 +81,8 @@ module.exports = { // Import plugin config (for intelligently validating module import statements) "import/no-unresolved": "error", + // `no-duplicates` disabled due to . Reenable if that issue gets fixed. + "import/no-duplicates": "off", "import/prefer-default-export": "off", "import/no-relative-packages": "error", "import/order": [ diff --git a/frontend/src/components/panels/Layers.svelte b/frontend/src/components/panels/Layers.svelte index df5bc5a7..f1ca23cc 100644 --- a/frontend/src/components/panels/Layers.svelte +++ b/frontend/src/components/panels/Layers.svelte @@ -417,8 +417,8 @@ class={"visibility"} action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())} size={24} - icon={listing.entry.disabled ? "EyeHidden" : "EyeVisible"} - tooltip={listing.entry.disabled ? "Disabled" : "Enabled"} + icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"} + tooltip={listing.entry.visible ? "Visible" : "Hidden"} /> {/each} diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 74bbb35d..bec98709 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -795,7 +795,7 @@ class="layer" class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)} class:previewed={node.previewed} - class:disabled={node.disabled} + class:disabled={!node.visible} style:--offset-left={(node.position?.x || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundX || 0 : 0)} style:--offset-top={(node.position?.y || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundY || 0 : 0)} style:--clip-path-id={`url(#${clipPathId})`} @@ -891,8 +891,8 @@ class={"visibility"} action={(e) => (toggleLayerVisibility(node.id), e?.stopPropagation())} size={24} - icon={node.disabled ? "EyeHidden" : "EyeVisible"} - tooltip={node.disabled ? "Disabled" : "Enabled"} + icon={node.visible ? "EyeVisible" : "EyeHidden"} + tooltip={node.visible ? "Visible" : "Hidden"} /> @@ -913,7 +913,7 @@ class="node" class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)} class:previewed={node.previewed} - class:disabled={node.disabled} + class:disabled={!node.visible} style:--offset-left={(node.position?.x || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundX || 0 : 0)} style:--offset-top={(node.position?.y || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundY || 0 : 0)} style:--clip-path-id={`url(#${clipPathId})`} diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 3df903e1..704be65f 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -124,7 +124,7 @@ export class FrontendNode { readonly previewed!: boolean; - readonly disabled!: boolean; + readonly visible!: boolean; readonly errors!: string | undefined; } @@ -613,7 +613,7 @@ export class LayerPanelEntry { expanded!: boolean; - disabled!: boolean; + visible!: boolean; parentId!: bigint | undefined; diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 99631d04..f79344c6 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -757,8 +757,8 @@ impl JsEditorHandle { /// Toggle visibility of a layer from the layer list #[wasm_bindgen(js_name = toggleLayerVisibility)] pub fn toggle_layer_visibility(&self, id: u64) { - let id = NodeId(id); - let message = NodeGraphMessage::ToggleHidden { node_id: id }; + let node_id = NodeId(id); + let message = NodeGraphMessage::ToggleVisibility { node_id }; self.dispatch(message); } diff --git a/node-graph/README.md b/node-graph/README.md index a19a96e4..629d4ba3 100644 --- a/node-graph/README.md +++ b/node-graph/README.md @@ -60,7 +60,7 @@ pub fn multiply_opacity(document_node: &DocumentNode, node_id: NodeId, _context: } ``` -## Graphene (protonode executor) +## Graphene (proto node executor) The graphene crate (found in `gcore/`) and the graphene standard library (found in `gstd/`) is where actual implementation for nodes are located. @@ -100,7 +100,7 @@ fn test_opacity_node() { The `graphene_core::value::CopiedNode` is a node that, when evaluated, copies `10_f32` and returns it. -## Creating a new protonode +## Creating a new proto node Instead of manually implementing the `Node` trait with complex generics, one can use the `node_fn` macro, which can be applied to a function like `opacity_node` with an attribute of the name of the node: diff --git a/node-graph/compilation-client/src/main.rs b/node-graph/compilation-client/src/main.rs index 72f1593f..a07a8089 100644 --- a/node-graph/compilation-client/src/main.rs +++ b/node-graph/compilation-client/src/main.rs @@ -39,7 +39,6 @@ fn add_network() -> NodeNetwork { NodeNetwork { imports: vec![], exports: vec![NodeOutput::new(NodeId(0), 0)], - disabled: vec![], previous_outputs: None, nodes: [DocumentNode { name: "Blend Image".into(), diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index dddfc086..09c3a98b 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -152,18 +152,24 @@ pub struct DocumentNode { /// Now, the call from `F` directly reaches the `CacheNode` and the `CacheNode` can decide whether to call `G.eval(input_from_f)` /// in the event of a cache miss or just return the cached data in the event of a cache hit. pub manual_composition: Option, + // TODO: Remove once this references its definition instead (see above TODO). + /// Indicates to the UI if a primary output should be drawn for this node. + /// True for most nodes, but the Split Channels node is an example of a node that has multiple secondary outputs but no primary output. #[serde(default = "return_true")] pub has_primary_output: bool, // A nested document network or a proto-node identifier. pub implementation: DocumentNodeImplementation, + /// Represents the eye icon for hiding/showing the node in the graph UI. When hidden, a node gets replaced with an identity node during the graph flattening step. + #[serde(default = "return_true")] + pub visible: bool, /// Metadata about the node including its position in the graph UI. pub metadata: DocumentNodeMetadata, - /// When two different protonodes hash to the same value (e.g. two value nodes each containing `2_u32` or two multiply nodes that have the same node IDs as input), the duplicates are removed. + /// When two different proto nodes hash to the same value (e.g. two value nodes each containing `2_u32` or two multiply nodes that have the same node IDs as input), the duplicates are removed. /// See [`crate::proto::ProtoNetwork::generate_stable_node_ids`] for details. /// However sometimes this is not desirable, for example in the case of a [`graphene_core::memo::MonitorNode`] that needs to be accessed outside of the graph. #[serde(default)] pub skip_deduplication: bool, - /// Used as a hash of the graph input where applicable. This ensures that protonodes that depend on the graph's input are always regenerated. + /// Used as a hash of the graph input where applicable. This ensures that proto nodes that depend on the graph's input are always regenerated. #[serde(default)] pub world_state_hash: u64, /// The path to this node and its inputs and outputs as of when [`NodeNetwork::generate_node_paths`] was called. @@ -185,7 +191,7 @@ pub struct Source { pub struct OriginalLocation { /// The original location to the document node - e.g. [grandparent_id, parent_id, node_id]. pub path: Option>, - /// Each document input source maps to one protonode input (however one protonode input may come from several sources) + /// Each document input source maps to one proto node input (however one proto node input may come from several sources) pub inputs_source: HashMap, /// A list of document sources for the node's output pub outputs_source: HashMap, @@ -203,6 +209,7 @@ impl Default for DocumentNode { manual_composition: Default::default(), has_primary_output: true, implementation: Default::default(), + visible: true, metadata: Default::default(), skip_deduplication: Default::default(), world_state_hash: Default::default(), @@ -272,7 +279,7 @@ impl DocumentNode { (ProtoNodeInput::None, ConstructionArgs::Value(tagged_value)) } NodeInput::Node { node_id, output_index, lambda } => { - assert_eq!(output_index, 0, "Outputs should be flattened before converting to protonode. {:#?}", self.name); + assert_eq!(output_index, 0, "Outputs should be flattened before converting to proto node. {:#?}", self.name); let node = if lambda { ProtoNodeInput::NodeLambda(node_id) } else { ProtoNodeInput::Node(node_id) }; (node, ConstructionArgs::Nodes(vec![])) } @@ -445,9 +452,9 @@ pub enum DocumentNodeImplementation { /// /// A nested [`NodeNetwork`] that is flattened by the [`NodeNetwork::flatten`] function. Network(NodeNetwork), - /// This describes a (document) node implemented as a protonode. + /// This describes a (document) node implemented as a proto node. /// - /// A protonode identifier which can be found in `node_registry.rs`. + /// A proto node identifier which can be found in `node_registry.rs`. ProtoNode(ProtoNodeIdentifier), /// The Extract variant is a tag which tells the compilation process to do something special. It invokes language-level functionality built for use by the ExtractNode to enable metaprogramming. /// When the ExtractNode is compiled, it gets replaced by a value node containing a representation of the source code for the function/lambda of the document node that's fed into the ExtractNode @@ -523,9 +530,6 @@ pub struct NodeNetwork { pub exports: Vec, /// The list of all nodes in this network. pub nodes: HashMap, - /// Nodes that the user has disabled/hidden with the visibility eye icon. - /// These nodes get replaced with Identity nodes during the graph flattening step. - pub disabled: Vec, /// In the case when another node is previewed (chosen by the user as a temporary output), this stores what it previously was so it can be restored later. pub previous_outputs: Option>, } @@ -540,7 +544,6 @@ impl std::hash::Hash for NodeNetwork { id.hash(state); node.hash(state); } - self.disabled.hash(state); self.previous_outputs.hash(state); } } @@ -567,7 +570,6 @@ impl NodeNetwork { imports: node.inputs.iter().filter(|input| matches!(input, NodeInput::Network(_))).map(|_| NodeId(0)).collect(), exports: vec![NodeOutput::new(NodeId(0), 0)], nodes: [(NodeId(0), node)].into_iter().collect(), - disabled: vec![], previous_outputs: None, } } @@ -815,7 +817,6 @@ impl NodeNetwork { pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) { self.imports.iter_mut().for_each(|id| *id = f(*id)); self.exports.iter_mut().for_each(|output| output.node_id = f(output.node_id)); - self.disabled.iter_mut().for_each(|id| *id = f(*id)); self.previous_outputs .iter_mut() .for_each(|nodes| nodes.iter_mut().for_each(|output| output.node_id = f(output.node_id))); @@ -843,7 +844,7 @@ impl NodeNetwork { outwards_links } - /// Populate the [`DocumentNode::path`], which stores the location of the document node to allow for matching the resulting protonodes to the document node for the purposes of typing and finding monitor nodes. + /// Populate the [`DocumentNode::path`], which stores the location of the document node to allow for matching the resulting proto nodes to the document node for the purposes of typing and finding monitor nodes. pub fn generate_node_paths(&mut self, prefix: &[NodeId]) { for (node_id, node) in &mut self.nodes { let mut new_path = prefix.to_vec(); @@ -930,8 +931,11 @@ impl NodeNetwork { return; }; - if node.implementation != DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()) && self.disabled.contains(&id) { - node.implementation = DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()); + // If the node is hidden, replace it with an identity node + let identity_node = DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()); + if !node.visible && node.implementation != identity_node { + node.implementation = identity_node; + if node.is_layer() { // Connect layer node to the graphic group below node.inputs.drain(..1); @@ -939,6 +943,7 @@ impl NodeNetwork { node.inputs.drain(1..); } self.nodes.insert(id, node); + return; } @@ -983,7 +988,6 @@ impl NodeNetwork { let new_nodes = inner_network.nodes.keys().cloned().collect::>(); // Copy nodes from the inner network into the parent network self.nodes.extend(inner_network.nodes); - self.disabled.extend(inner_network.disabled); let mut network_offsets = HashMap::new(); assert_eq!( diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index 8983cab9..89553f31 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -200,7 +200,7 @@ impl ConstructionArgs { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Hash, Eq)] -/// A protonode is an intermediate step between the `DocumentNode` and the boxed struct that actually runs the node (found in the [`BorrowTree`]). It has one primary input and several secondary inputs in [`ConstructionArgs`]. +/// A proto node is an intermediate step between the `DocumentNode` and the boxed struct that actually runs the node (found in the [`BorrowTree`]). It has one primary input and several secondary inputs in [`ConstructionArgs`]. pub struct ProtoNode { pub construction_args: ConstructionArgs, pub input: ProtoNodeInput, @@ -718,7 +718,7 @@ impl TypingContext { ConstructionArgs::Inline(ref inline) => vec![inline.ty.clone()], }; - // Get the node input type from the protonode declaration + // Get the node input type from the proto node declaration let input = match node.input { ProtoNodeInput::None => concrete!(()), ProtoNodeInput::ManualComposition(ref ty) => ty.clone(), diff --git a/node-graph/interpreted-executor/src/dynamic_executor.rs b/node-graph/interpreted-executor/src/dynamic_executor.rs index f9410cfd..b34baa80 100644 --- a/node-graph/interpreted-executor/src/dynamic_executor.rs +++ b/node-graph/interpreted-executor/src/dynamic_executor.rs @@ -17,7 +17,7 @@ pub struct DynamicExecutor { output: NodeId, /// Stores all of the dynamic node structs. tree: BorrowTree, - /// Stores the types of the protonodes. + /// Stores the types of the proto nodes. typing_context: TypingContext, // This allows us to keep the nodes around for one more frame which is used for introspection orphaned_nodes: Vec, @@ -111,11 +111,11 @@ impl<'a, I: StaticType + 'a> Executor for &'a DynamicExecutor { pub struct BorrowTree { /// A hashmap of node IDs and dynamically typed nodes. nodes: HashMap, - /// A hashmap from the document path to the protonode ID. + /// A hashmap from the document path to the proto node ID. source_map: HashMap, NodeId>, - /// Each document input source maps to one protonode input (however one protonode input may come from several sources) + /// Each document input source maps to one proto node input (however one proto node input may come from several sources) inputs_source_map: HashMap, - /// A mapping of document input sources to the (single) protonode output + /// A mapping of document input sources to the (single) proto node output outputs_source_map: HashMap, } @@ -193,7 +193,7 @@ impl BorrowTree { .extend((0..params).flat_map(|i| proto_node.original_location.inputs(i).map(move |source| (source, (id, i))))); self.outputs_source_map.extend(proto_node.original_location.outputs(0).map(|source| (source, id))); for x in proto_node.original_location.outputs_source.values() { - assert_eq!(*x, 0, "protonodes should refer to output index 0"); + assert_eq!(*x, 0, "Proto nodes should refer to output index 0"); } match &proto_node.construction_args { diff --git a/website/.eslintrc.js b/website/.eslintrc.js index e4f6d915..5cbe47b7 100644 --- a/website/.eslintrc.js +++ b/website/.eslintrc.js @@ -38,7 +38,7 @@ module.exports = { camelcase: ["error", { properties: "always" }], "linebreak-style": ["error", "unix"], "eol-last": ["error", "always"], - "max-len": ["error", { code: 200, tabWidth: 4 }], + "max-len": ["error", { code: 200, tabWidth: 4, ignorePattern: `d="([\\s\\S]*?)"` }], "prefer-destructuring": "off", "no-console": "warn", "no-debugger": "warn", diff --git a/website/other/bezier-rs-demos/.eslintrc.cjs b/website/other/bezier-rs-demos/.eslintrc.cjs index 50241be8..a079a104 100644 --- a/website/other/bezier-rs-demos/.eslintrc.cjs +++ b/website/other/bezier-rs-demos/.eslintrc.cjs @@ -35,7 +35,7 @@ module.exports = { camelcase: ["error", { properties: "always" }], "linebreak-style": ["error", "unix"], "eol-last": ["error", "always"], - "max-len": ["error", { code: 200, tabWidth: 4 }], + "max-len": ["error", { code: 200, tabWidth: 4, ignorePattern: `d="([\\s\\S]*?)"` }], "prefer-destructuring": "off", "no-console": "warn", "no-debugger": "warn",