mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 19:38:12 +08:00
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
This commit is contained in:
@@ -57,7 +57,7 @@ pub fn default_mapping() -> Mapping {
|
|||||||
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut),
|
entry!(KeyDown(KeyX); modifiers=[Accel], action_dispatch=NodeGraphMessage::Cut),
|
||||||
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy),
|
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=NodeGraphMessage::Copy),
|
||||||
entry!(KeyDown(KeyD); modifiers=[Accel], action_dispatch=NodeGraphMessage::DuplicateSelectedNodes),
|
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
|
// TransformLayerMessage
|
||||||
entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation),
|
entry!(KeyDown(Enter); action_dispatch=TransformLayerMessage::ApplyTransformOperation),
|
||||||
|
|||||||
@@ -822,7 +822,7 @@ impl DocumentMessageHandler {
|
|||||||
self.metadata
|
self.metadata
|
||||||
.root()
|
.root()
|
||||||
.descendants(&self.metadata)
|
.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(|&layer| !is_artboard(layer, network))
|
||||||
.filter_map(|layer| self.metadata.click_target(layer).map(|targets| (layer, targets)))
|
.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))))
|
.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
|
self.metadata
|
||||||
.root()
|
.root()
|
||||||
.descendants(&self.metadata)
|
.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_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))))
|
.filter(move |(layer, target)| target.iter().any(|target: &ClickTarget| target.intersect_point(point, self.metadata.transform_to_document(*layer))))
|
||||||
.map(|(layer, _)| 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
|
/// 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]> {
|
pub fn selected_visible_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
|
||||||
self.selected_nodes
|
self.selected_nodes
|
||||||
.selected_visible_layers(self.network(), self.metadata())
|
.selected_visible_layers(self.metadata())
|
||||||
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
|
.filter_map(|layer| self.metadata.bounding_box_viewport(layer))
|
||||||
.reduce(graphene_core::renderer::Quad::combine_bounds)
|
.reduce(graphene_core::renderer::Quad::combine_bounds)
|
||||||
}
|
}
|
||||||
@@ -887,13 +887,6 @@ impl DocumentMessageHandler {
|
|||||||
Ok(document)
|
Ok(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the bounding boxes for all visible layers.
|
|
||||||
pub fn bounding_boxes(&self) -> impl Iterator<Item = [DVec2; 2]> + '_ {
|
|
||||||
// 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`].
|
/// Called recursively by the entry function [`serialize_root`].
|
||||||
fn serialize_structure(&self, folder: LayerNodeIdentifier, structure_section: &mut Vec<u64>, data_section: &mut Vec<u64>, path: &mut Vec<LayerNodeIdentifier>) {
|
fn serialize_structure(&self, folder: LayerNodeIdentifier, structure_section: &mut Vec<u64>, data_section: &mut Vec<u64>, path: &mut Vec<LayerNodeIdentifier>) {
|
||||||
let mut space = 0;
|
let mut space = 0;
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ pub enum NodeGraphMessage {
|
|||||||
ShiftNode {
|
ShiftNode {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
},
|
},
|
||||||
ToggleSelectedHidden,
|
ToggleSelectedVisibility,
|
||||||
ToggleHidden {
|
ToggleVisibility {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
},
|
},
|
||||||
SetHidden {
|
SetVisibility {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
hidden: bool,
|
visible: bool,
|
||||||
},
|
},
|
||||||
SetName {
|
SetName {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
|
load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SelectedNodesUpdated => {
|
NodeGraphMessage::SelectedNodesUpdated => {
|
||||||
self.update_selection_action_buttons(document_network, selected_nodes, responses);
|
self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses);
|
||||||
self.update_selected(document_network, selected_nodes, responses);
|
self.update_selected(document_network, document_metadata, selected_nodes, responses);
|
||||||
if selected_nodes.selected_layers(document_metadata).count() <= 1 {
|
if selected_nodes.selected_layers(document_metadata).count() <= 1 {
|
||||||
responses.add(DocumentMessage::SetRangeSelectionLayer {
|
responses.add(DocumentMessage::SetRangeSelectionLayer {
|
||||||
new_layer: selected_nodes.selected_layers(document_metadata).next(),
|
new_layer: selected_nodes.selected_layers(document_metadata).next(),
|
||||||
@@ -195,7 +195,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
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.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 => {
|
NodeGraphMessage::DuplicateSelectedNodes => {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
@@ -221,7 +221,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
responses.add(NodeGraphMessage::InsertNode { node_id, document_node });
|
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 } => {
|
NodeGraphMessage::ExitNestedNetwork { depth_of_nesting } => {
|
||||||
@@ -234,7 +234,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
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.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 } => {
|
NodeGraphMessage::ExposeInput { node_id, input_index, new_exposed } => {
|
||||||
let Some(network) = document_network.nested_network(&self.network) else {
|
let Some(network) = document_network.nested_network(&self.network) else {
|
||||||
@@ -447,36 +447,46 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
|
|
||||||
self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
|
self.send_graph(network, graph_view_overlay_open, document_metadata, selected_nodes, collapsed, responses);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ToggleSelectedHidden => {
|
NodeGraphMessage::ToggleSelectedVisibility => {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
|
||||||
|
|
||||||
let new_hidden = !selected_nodes.selected_nodes().any(|id| network.disabled.contains(id));
|
// If any of the selected nodes are hidden, show them all. Otherwise, hide them all.
|
||||||
for &node_id in selected_nodes.selected_nodes() {
|
let visible = selected_nodes.selected_nodes().all(|&node_id| document_metadata.node_is_visible(node_id));
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
let visible = !visible;
|
||||||
}
|
|
||||||
|
for &node_id in selected_nodes.selected_nodes() {
|
||||||
|
responses.add(NodeGraphMessage::SetVisibility { node_id, visible });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ToggleHidden { node_id } => {
|
NodeGraphMessage::ToggleVisibility { node_id } => {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
let visible = document_metadata.node_is_visible(node_id);
|
||||||
let new_hidden = !network.disabled.contains(&node_id);
|
let visible = !visible;
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id, hidden: new_hidden });
|
|
||||||
}
|
responses.add(NodeGraphMessage::SetVisibility { node_id, visible });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetHidden { node_id, hidden } => {
|
NodeGraphMessage::SetVisibility { node_id, visible } => {
|
||||||
if let Some(network) = document_network.nested_network_mut(&self.network) {
|
(|| {
|
||||||
if !hidden {
|
let Some(network) = document_network.nested_network_mut(&self.network) else { return };
|
||||||
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) {
|
let input_or_output = network.imports.contains(&node_id) || network.original_outputs().iter().any(|output| output.node_id == node_id);
|
||||||
network.disabled.push(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
|
// Only generate node graph if one of the selected nodes is connected to the output
|
||||||
if network.connected_to_output(node_id) {
|
if network.connected_to_output(node_id) {
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
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 } => {
|
NodeGraphMessage::SetName { node_id, name } => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
@@ -508,7 +518,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> 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);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
}
|
}
|
||||||
@@ -522,7 +532,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
let node_types = document_node_types::collect_node_types();
|
let node_types = document_node_types::collect_node_types();
|
||||||
responses.add(FrontendMessage::UpdateNodeTypes { 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 } => {
|
NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => {
|
||||||
self.resolved_types = resolved_types;
|
self.resolved_types = resolved_types;
|
||||||
@@ -540,7 +550,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||||||
impl NodeGraphMessageHandler {
|
impl NodeGraphMessageHandler {
|
||||||
pub fn actions_with_node_graph_open(&self, graph_open: bool) -> ActionList {
|
pub fn actions_with_node_graph_open(&self, graph_open: bool) -> ActionList {
|
||||||
if self.has_selection && graph_open {
|
if self.has_selection && graph_open {
|
||||||
actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes, ToggleSelectedHidden)
|
actions!(NodeGraphMessageDiscriminant; DeleteSelectedNodes, Cut, Copy, DuplicateSelectedNodes, ToggleSelectedVisibility)
|
||||||
} else {
|
} else {
|
||||||
actions!(NodeGraphMessageDiscriminant;)
|
actions!(NodeGraphMessageDiscriminant;)
|
||||||
}
|
}
|
||||||
@@ -554,8 +564,8 @@ impl NodeGraphMessageHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the buttons for disable and preview
|
/// Updates the buttons for visibility and preview
|
||||||
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
|
fn update_selection_action_buttons(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
|
||||||
if let Some(network) = document_network.nested_network(&self.network) {
|
if let Some(network) = document_network.nested_network(&self.network) {
|
||||||
let mut widgets = Vec::new();
|
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 there is at least one other selected node then show the hide or show button
|
||||||
if selection.next().is_some() {
|
if selection.next().is_some() {
|
||||||
// Check if any of the selected nodes are disabled
|
// 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
|
// Check if multiple nodes are selected
|
||||||
let multiple_nodes = selection.next().is_some();
|
let multiple_nodes = selection.next().is_some();
|
||||||
|
|
||||||
// Generate the enable or disable button accordingly
|
// Generate the visible/hidden button accordingly
|
||||||
let (hide_show_label, hide_show_icon) = if is_hidden { ("Make Visible", "EyeHidden") } else { ("Make Hidden", "EyeVisible") };
|
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)
|
let hide_button = TextButton::new(hide_show_label)
|
||||||
.icon(Some(hide_show_icon.to_string()))
|
.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(if all_visible { "Hide selected nodes/layers" } else { "Show selected nodes/layers" }.to_string() + if multiple_nodes { "s" } else { "" })
|
||||||
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedHidden))
|
.tooltip_shortcut(action_keys!(NodeGraphMessageDiscriminant::ToggleSelectedVisibility))
|
||||||
.on_update(move |_| NodeGraphMessage::ToggleSelectedHidden.into())
|
.on_update(move |_| NodeGraphMessage::ToggleSelectedVisibility.into())
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
widgets.push(hide_button);
|
widgets.push(hide_button);
|
||||||
|
|
||||||
@@ -745,7 +755,7 @@ impl NodeGraphMessageHandler {
|
|||||||
exposed_outputs,
|
exposed_outputs,
|
||||||
position: node.metadata.position.into(),
|
position: node.metadata.position.into(),
|
||||||
previewed: network.outputs_contain(node_id),
|
previewed: network.outputs_contain(node_id),
|
||||||
disabled: network.disabled.contains(&node_id),
|
visible: node.visible,
|
||||||
errors: errors.map(|e| format!("{e:?}")),
|
errors: errors.map(|e| format!("{e:?}")),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -774,7 +784,7 @@ impl NodeGraphMessageHandler {
|
|||||||
parent_id: layer.parent(metadata).map(|parent| parent.to_node()),
|
parent_id: layer.parent(metadata).map(|parent| parent.to_node()),
|
||||||
name: network.nodes.get(&node_id).map(|node| node.alias.clone()).unwrap_or_default(),
|
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() },
|
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 });
|
responses.add(FrontendMessage::UpdateDocumentLayerDetails { data });
|
||||||
}
|
}
|
||||||
@@ -795,8 +805,8 @@ impl NodeGraphMessageHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the frontend's selection state in line with the backend
|
/// 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<Message>) {
|
fn update_selected(&mut self, document_network: &NodeNetwork, document_metadata: &DocumentMetadata, selected_nodes: &SelectedNodes, responses: &mut VecDeque<Message>) {
|
||||||
self.update_selection_action_buttons(document_network, selected_nodes, responses);
|
self.update_selection_action_buttons(document_network, document_metadata, selected_nodes, responses);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphSelection {
|
responses.add(FrontendMessage::UpdateNodeGraphSelection {
|
||||||
selected: selected_nodes.selected_nodes_ref().clone(),
|
selected: selected_nodes.selected_nodes_ref().clone(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ pub struct FrontendNode {
|
|||||||
#[serde(rename = "exposedOutputs")]
|
#[serde(rename = "exposedOutputs")]
|
||||||
pub exposed_outputs: Vec<FrontendGraphOutput>,
|
pub exposed_outputs: Vec<FrontendGraphOutput>,
|
||||||
pub position: (i32, i32),
|
pub position: (i32, i32),
|
||||||
pub disabled: bool,
|
pub visible: bool,
|
||||||
pub previewed: bool,
|
pub previewed: bool,
|
||||||
pub errors: Option<String>,
|
pub errors: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::collections::HashMap;
|
|||||||
pub enum Clipboard {
|
pub enum Clipboard {
|
||||||
Internal,
|
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,
|
Device,
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ pub const INTERNAL_CLIPBOARD_COUNT: u8 = Clipboard::_InternalClipboardCount as u
|
|||||||
pub struct CopyBufferEntry {
|
pub struct CopyBufferEntry {
|
||||||
pub nodes: HashMap<NodeId, DocumentNode>,
|
pub nodes: HashMap<NodeId, DocumentNode>,
|
||||||
pub selected: bool,
|
pub selected: bool,
|
||||||
pub disabled: bool,
|
pub visible: bool,
|
||||||
pub collapsed: bool,
|
pub collapsed: bool,
|
||||||
pub alias: String,
|
pub alias: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,15 @@ use std::num::NonZeroU64;
|
|||||||
// DocumentMetadata
|
// 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DocumentMetadata {
|
pub struct DocumentMetadata {
|
||||||
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
upstream_transforms: HashMap<NodeId, (Footprint, DAffine2)>,
|
||||||
structure: HashMap<LayerNodeIdentifier, NodeRelations>,
|
structure: HashMap<LayerNodeIdentifier, NodeRelations>,
|
||||||
artboards: HashSet<LayerNodeIdentifier>,
|
artboards: HashSet<LayerNodeIdentifier>,
|
||||||
folders: HashSet<LayerNodeIdentifier>,
|
folders: HashSet<LayerNodeIdentifier>,
|
||||||
|
hidden: HashSet<NodeId>,
|
||||||
click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
|
click_targets: HashMap<LayerNodeIdentifier, Vec<ClickTarget>>,
|
||||||
/// Transform from document space to viewport space.
|
/// Transform from document space to viewport space.
|
||||||
pub document_to_viewport: DAffine2,
|
pub document_to_viewport: DAffine2,
|
||||||
@@ -29,10 +32,11 @@ impl Default for DocumentMetadata {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
upstream_transforms: HashMap::new(),
|
upstream_transforms: HashMap::new(),
|
||||||
click_targets: HashMap::new(),
|
|
||||||
structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]),
|
structure: HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]),
|
||||||
artboards: HashSet::new(),
|
artboards: HashSet::new(),
|
||||||
folders: HashSet::new(),
|
folders: HashSet::new(),
|
||||||
|
hidden: HashSet::new(),
|
||||||
|
click_targets: HashMap::new(),
|
||||||
document_to_viewport: DAffine2::IDENTITY,
|
document_to_viewport: DAffine2::IDENTITY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,6 +122,10 @@ impl DocumentMetadata {
|
|||||||
self.artboards.contains(&layer)
|
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
|
/// Folders sorted from most nested to least nested
|
||||||
pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> {
|
pub fn folders_sorted_by_most_nested(&self, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Vec<LayerNodeIdentifier> {
|
||||||
let mut folders: Vec<_> = layers.filter(|layer| self.folders.contains(layer)).collect();
|
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.structure = HashMap::from_iter([(LayerNodeIdentifier::ROOT, NodeRelations::default())]);
|
||||||
self.folders = HashSet::new();
|
|
||||||
self.artboards = HashSet::new();
|
self.artboards = HashSet::new();
|
||||||
|
self.folders = HashSet::new();
|
||||||
|
self.hidden = HashSet::new();
|
||||||
|
|
||||||
let id = graph.exports[0].node_id;
|
let id = graph.exports[0].node_id;
|
||||||
let Some(output_node) = graph.nodes.get(&id) else {
|
let Some(output_node) = graph.nodes.get(&id) else {
|
||||||
@@ -150,22 +159,26 @@ impl DocumentMetadata {
|
|||||||
};
|
};
|
||||||
let parent = LayerNodeIdentifier::ROOT;
|
let parent = LayerNodeIdentifier::ROOT;
|
||||||
let mut stack = vec![(layer_node, node_id, parent)];
|
let mut stack = vec![(layer_node, node_id, parent)];
|
||||||
while let Some((node, id, parent)) = stack.pop() {
|
while let Some((node, node_id, parent)) = stack.pop() {
|
||||||
let mut current = Some((node, id));
|
let mut current = Some((node, node_id));
|
||||||
while let Some(&(current_node, current_id)) = current.as_ref() {
|
while let Some(&(current_node, current_node_id)) = current.as_ref() {
|
||||||
let current_identifier = LayerNodeIdentifier::new_unchecked(current_id);
|
let current_layer_id = LayerNodeIdentifier::new_unchecked(current_node_id);
|
||||||
if !self.structure.contains_key(¤t_identifier) {
|
if !self.structure.contains_key(¤t_layer_id) {
|
||||||
parent.push_child(self, current_identifier);
|
parent.push_child(self, current_layer_id);
|
||||||
|
|
||||||
if let Some((child_node, child_id)) = first_child_layer(graph, current_node) {
|
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) {
|
if is_artboard(current_layer_id, graph) {
|
||||||
self.artboards.insert(current_identifier);
|
self.artboards.insert(current_layer_id);
|
||||||
}
|
}
|
||||||
if is_folder(current_identifier, graph) {
|
if is_folder(current_layer_id, graph) {
|
||||||
self.folders.insert(current_identifier);
|
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
|
// DescendantsIter
|
||||||
// ==============
|
// ===============
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DescendantsIter<'a> {
|
pub struct DescendantsIter<'a> {
|
||||||
|
|||||||
@@ -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 serde::ser::SerializeStruct;
|
||||||
|
|
||||||
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, specta::Type)]
|
||||||
pub struct RawBuffer(Vec<u8>);
|
pub struct RawBuffer(Vec<u8>);
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ pub struct LayerPanelEntry {
|
|||||||
#[serde(rename = "layerClassification")]
|
#[serde(rename = "layerClassification")]
|
||||||
pub layer_classification: LayerClassification,
|
pub layer_classification: LayerClassification,
|
||||||
pub expanded: bool,
|
pub expanded: bool,
|
||||||
pub disabled: bool,
|
pub visible: bool,
|
||||||
#[serde(rename = "parentId")]
|
#[serde(rename = "parentId")]
|
||||||
pub parent_id: Option<NodeId>,
|
pub parent_id: Option<NodeId>,
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
@@ -56,12 +56,12 @@ pub struct LayerPanelEntry {
|
|||||||
pub struct SelectedNodes(pub Vec<NodeId>);
|
pub struct SelectedNodes(pub Vec<NodeId>);
|
||||||
|
|
||||||
impl SelectedNodes {
|
impl SelectedNodes {
|
||||||
pub fn layer_visible(&self, layer: LayerNodeIdentifier, network: &NodeNetwork, metadata: &DocumentMetadata) -> bool {
|
pub fn layer_visible(&self, layer: LayerNodeIdentifier, metadata: &DocumentMetadata) -> bool {
|
||||||
!layer.ancestors(metadata).any(|layer| network.disabled.contains(&layer.to_node()))
|
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<Item = LayerNodeIdentifier> + '_ {
|
pub fn selected_visible_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||||
self.selected_layers(metadata).filter(move |&layer| self.layer_visible(layer, network, metadata))
|
self.selected_layers(metadata).filter(move |&layer| self.layer_visible(layer, metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
pub fn selected_layers<'a>(&'a self, metadata: &'a DocumentMetadata) -> impl Iterator<Item = LayerNodeIdentifier> + '_ {
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||||||
)
|
)
|
||||||
.collect(),
|
.collect(),
|
||||||
selected: active_document.selected_nodes.selected_layers_contains(layer, active_document.metadata()),
|
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,
|
collapsed: false,
|
||||||
alias: previous_alias,
|
alias: previous_alias,
|
||||||
});
|
});
|
||||||
@@ -388,8 +388,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||||||
if entry.selected {
|
if entry.selected {
|
||||||
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
||||||
}
|
}
|
||||||
if entry.disabled {
|
if !entry.visible {
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id: id, hidden: entry.disabled });
|
responses.add(NodeGraphMessage::SetVisibility { node_id: id, visible: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -419,8 +419,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
|
|||||||
if entry.selected {
|
if entry.selected {
|
||||||
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
responses.add(NodeGraphMessage::SelectedNodesAdd { nodes: vec![id] });
|
||||||
}
|
}
|
||||||
if entry.disabled {
|
if !entry.visible {
|
||||||
responses.add(NodeGraphMessage::SetHidden { node_id: id, hidden: entry.disabled });
|
responses.add(NodeGraphMessage::SetVisibility { node_id: id, visible: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ impl Pivot {
|
|||||||
|
|
||||||
/// Recomputes the pivot position and transform.
|
/// Recomputes the pivot position and transform.
|
||||||
fn recalculate_pivot(&mut self, document: &DocumentMessageHandler) {
|
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 {
|
let Some(first) = layers.next() else {
|
||||||
// If no layers are selected then we revert things back to default
|
// If no layers are selected then we revert things back to default
|
||||||
self.normalized_pivot = DVec2::splat(0.5);
|
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
|
// If more than one layer is selected we use the AABB with the mean of the pivots
|
||||||
let xy_summation = document
|
let xy_summation = document
|
||||||
.selected_nodes
|
.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))
|
.map(|layer| graph_modification_utils::get_viewport_pivot(layer, &document.network, &document.metadata))
|
||||||
.reduce(|a, b| a + b)
|
.reduce(|a, b| a + b)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@@ -101,7 +101,7 @@ impl Pivot {
|
|||||||
|
|
||||||
/// Sets the viewport position of the pivot for all selected layers.
|
/// Sets the viewport position of the pivot for all selected layers.
|
||||||
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
pub fn set_viewport_position(&self, position: DVec2, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||||
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 transform = Self::get_layer_pivot_transform(layer, document);
|
||||||
let pivot = transform.inverse().transform_point2(position);
|
let pivot = transform.inverse().transform_point2(position);
|
||||||
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
// Only update the pivot when computed position is finite. Infinite can happen when scale is 0.
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ impl SnapManager {
|
|||||||
if candidates.len() > 10 {
|
if candidates.len() > 10 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !document.selected_nodes.layer_visible(layer, &document.network, &document.metadata) {
|
if !document.selected_nodes.layer_visible(layer, &document.metadata) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if snap_data.ignore.contains(&layer) {
|
if snap_data.ignore.contains(&layer) {
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
(_, GradientToolMessage::Overlays(mut overlay_context)) => {
|
||||||
let selected = tool_data.selected_gradient.as_ref();
|
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 Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
let transform = gradient_space_transform(layer, document);
|
||||||
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
|
let dragging = selected.filter(|selected| selected.layer == layer).map(|selected| selected.dragging);
|
||||||
@@ -318,7 +318,7 @@ impl Fsm for GradientToolFsmState {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
(_, GradientToolMessage::InsertStop) => {
|
(_, 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 Some(mut gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
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 tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
|
||||||
|
|
||||||
let mut dragging = false;
|
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 Some(gradient) = get_gradient(layer, &document.network) else { continue };
|
||||||
let transform = gradient_space_transform(layer, document);
|
let transform = gradient_space_transform(layer, document);
|
||||||
|
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
tool_data.selected_layers_count = selected_layers_count;
|
tool_data.selected_layers_count = selected_layers_count;
|
||||||
|
|
||||||
// Outline selected layers
|
// 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));
|
overlay_context.outline(document.metadata().layer_outline(layer), document.metadata().transform_to_viewport(layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,13 +405,13 @@ impl Fsm for SelectToolFsmState {
|
|||||||
// Update bounds
|
// Update bounds
|
||||||
let transform = document
|
let transform = document
|
||||||
.selected_nodes
|
.selected_nodes
|
||||||
.selected_visible_layers(document.network(), document.metadata())
|
.selected_visible_layers(document.metadata())
|
||||||
.next()
|
.next()
|
||||||
.map(|layer| document.metadata().transform_to_viewport(layer));
|
.map(|layer| document.metadata().transform_to_viewport(layer));
|
||||||
let transform = transform.unwrap_or(DAffine2::IDENTITY);
|
let transform = transform.unwrap_or(DAffine2::IDENTITY);
|
||||||
let bounds = document
|
let bounds = document
|
||||||
.selected_nodes
|
.selected_nodes
|
||||||
.selected_visible_layers(document.network(), document.metadata())
|
.selected_visible_layers(document.metadata())
|
||||||
.filter_map(|layer| {
|
.filter_map(|layer| {
|
||||||
document
|
document
|
||||||
.metadata()
|
.metadata()
|
||||||
@@ -472,7 +472,7 @@ impl Fsm for SelectToolFsmState {
|
|||||||
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
|
.map(|bounding_box| bounding_box.check_rotate(input.mouse.position))
|
||||||
.unwrap_or_default();
|
.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);
|
let intersection = document.click(input.mouse.position, &document.network);
|
||||||
|
|
||||||
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
|
// If the user is dragging the bounding box bounds, go into ResizingBounds mode.
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ impl TextToolData {
|
|||||||
/// Set the editing state of the currently modifying layer
|
/// Set the editing state of the currently modifying layer
|
||||||
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
fn set_editing(&self, editable: bool, font_cache: &FontCache, document: &DocumentMessageHandler, responses: &mut VecDeque<Message>) {
|
||||||
if let Some(node_id) = graph_modification_utils::get_fill_id(self.layer, &document.network) {
|
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) {
|
if let Some(editing_text) = self.editing_text.as_ref().filter(|_| editable) {
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ impl NodeRuntime {
|
|||||||
image_frame: None,
|
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();
|
let mut graph_input_hash = DefaultHasher::new();
|
||||||
editor_api.font_cache.hash(&mut graph_input_hash);
|
editor_api.font_cache.hash(&mut graph_input_hash);
|
||||||
let font_hash_code = graph_input_hash.finish();
|
let font_hash_code = graph_input_hash.finish();
|
||||||
@@ -218,7 +218,7 @@ impl NodeRuntime {
|
|||||||
Err(e) => return Err(e),
|
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 {
|
if let Err(e) = self.executor.update(proto_network).await {
|
||||||
self.node_graph_errors = e;
|
self.node_graph_errors = e;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ module.exports = {
|
|||||||
camelcase: ["error", { properties: "always" }],
|
camelcase: ["error", { properties: "always" }],
|
||||||
"linebreak-style": ["error", "unix"],
|
"linebreak-style": ["error", "unix"],
|
||||||
"eol-last": ["error", "always"],
|
"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",
|
"prefer-destructuring": "off",
|
||||||
"no-console": "warn",
|
"no-console": "warn",
|
||||||
"no-debugger": "warn",
|
"no-debugger": "warn",
|
||||||
@@ -81,6 +81,8 @@ module.exports = {
|
|||||||
|
|
||||||
// Import plugin config (for intelligently validating module import statements)
|
// Import plugin config (for intelligently validating module import statements)
|
||||||
"import/no-unresolved": "error",
|
"import/no-unresolved": "error",
|
||||||
|
// `no-duplicates` disabled due to <https://github.com/import-js/eslint-plugin-import/issues/1479#issuecomment-1789527447>. Reenable if that issue gets fixed.
|
||||||
|
"import/no-duplicates": "off",
|
||||||
"import/prefer-default-export": "off",
|
"import/prefer-default-export": "off",
|
||||||
"import/no-relative-packages": "error",
|
"import/no-relative-packages": "error",
|
||||||
"import/order": [
|
"import/order": [
|
||||||
|
|||||||
@@ -417,8 +417,8 @@
|
|||||||
class={"visibility"}
|
class={"visibility"}
|
||||||
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
action={(e) => (toggleLayerVisibility(listing.entry.id), e?.stopPropagation())}
|
||||||
size={24}
|
size={24}
|
||||||
icon={listing.entry.disabled ? "EyeHidden" : "EyeVisible"}
|
icon={listing.entry.visible ? "EyeVisible" : "EyeHidden"}
|
||||||
tooltip={listing.entry.disabled ? "Disabled" : "Enabled"}
|
tooltip={listing.entry.visible ? "Visible" : "Hidden"}
|
||||||
/>
|
/>
|
||||||
</LayoutRow>
|
</LayoutRow>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -795,7 +795,7 @@
|
|||||||
class="layer"
|
class="layer"
|
||||||
class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)}
|
class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)}
|
||||||
class:previewed={node.previewed}
|
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-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:--offset-top={(node.position?.y || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundY || 0 : 0)}
|
||||||
style:--clip-path-id={`url(#${clipPathId})`}
|
style:--clip-path-id={`url(#${clipPathId})`}
|
||||||
@@ -891,8 +891,8 @@
|
|||||||
class={"visibility"}
|
class={"visibility"}
|
||||||
action={(e) => (toggleLayerVisibility(node.id), e?.stopPropagation())}
|
action={(e) => (toggleLayerVisibility(node.id), e?.stopPropagation())}
|
||||||
size={24}
|
size={24}
|
||||||
icon={node.disabled ? "EyeHidden" : "EyeVisible"}
|
icon={node.visible ? "EyeVisible" : "EyeHidden"}
|
||||||
tooltip={node.disabled ? "Disabled" : "Enabled"}
|
tooltip={node.visible ? "Visible" : "Hidden"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<svg class="border-mask" width="0" height="0">
|
<svg class="border-mask" width="0" height="0">
|
||||||
@@ -913,7 +913,7 @@
|
|||||||
class="node"
|
class="node"
|
||||||
class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)}
|
class:selected={showSelected($nodeGraph.selected, boxSelection, node.id, nodeIndex)}
|
||||||
class:previewed={node.previewed}
|
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-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:--offset-top={(node.position?.y || 0) + ($nodeGraph.selected.includes(node.id) ? draggingNodes?.roundY || 0 : 0)}
|
||||||
style:--clip-path-id={`url(#${clipPathId})`}
|
style:--clip-path-id={`url(#${clipPathId})`}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export class FrontendNode {
|
|||||||
|
|
||||||
readonly previewed!: boolean;
|
readonly previewed!: boolean;
|
||||||
|
|
||||||
readonly disabled!: boolean;
|
readonly visible!: boolean;
|
||||||
|
|
||||||
readonly errors!: string | undefined;
|
readonly errors!: string | undefined;
|
||||||
}
|
}
|
||||||
@@ -613,7 +613,7 @@ export class LayerPanelEntry {
|
|||||||
|
|
||||||
expanded!: boolean;
|
expanded!: boolean;
|
||||||
|
|
||||||
disabled!: boolean;
|
visible!: boolean;
|
||||||
|
|
||||||
parentId!: bigint | undefined;
|
parentId!: bigint | undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -757,8 +757,8 @@ impl JsEditorHandle {
|
|||||||
/// Toggle visibility of a layer from the layer list
|
/// Toggle visibility of a layer from the layer list
|
||||||
#[wasm_bindgen(js_name = toggleLayerVisibility)]
|
#[wasm_bindgen(js_name = toggleLayerVisibility)]
|
||||||
pub fn toggle_layer_visibility(&self, id: u64) {
|
pub fn toggle_layer_visibility(&self, id: u64) {
|
||||||
let id = NodeId(id);
|
let node_id = NodeId(id);
|
||||||
let message = NodeGraphMessage::ToggleHidden { node_id: id };
|
let message = NodeGraphMessage::ToggleVisibility { node_id };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
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.
|
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:
|
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:
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ fn add_network() -> NodeNetwork {
|
|||||||
NodeNetwork {
|
NodeNetwork {
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
||||||
disabled: vec![],
|
|
||||||
previous_outputs: None,
|
previous_outputs: None,
|
||||||
nodes: [DocumentNode {
|
nodes: [DocumentNode {
|
||||||
name: "Blend Image".into(),
|
name: "Blend Image".into(),
|
||||||
|
|||||||
@@ -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)`
|
/// 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.
|
/// in the event of a cache miss or just return the cached data in the event of a cache hit.
|
||||||
pub manual_composition: Option<Type>,
|
pub manual_composition: Option<Type>,
|
||||||
|
// 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")]
|
#[serde(default = "return_true")]
|
||||||
pub has_primary_output: bool,
|
pub has_primary_output: bool,
|
||||||
// A nested document network or a proto-node identifier.
|
// A nested document network or a proto-node identifier.
|
||||||
pub implementation: DocumentNodeImplementation,
|
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.
|
/// Metadata about the node including its position in the graph UI.
|
||||||
pub metadata: DocumentNodeMetadata,
|
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.
|
/// 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.
|
/// 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)]
|
#[serde(default)]
|
||||||
pub skip_deduplication: bool,
|
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)]
|
#[serde(default)]
|
||||||
pub world_state_hash: u64,
|
pub world_state_hash: u64,
|
||||||
/// The path to this node and its inputs and outputs as of when [`NodeNetwork::generate_node_paths`] was called.
|
/// 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 {
|
pub struct OriginalLocation {
|
||||||
/// The original location to the document node - e.g. [grandparent_id, parent_id, node_id].
|
/// The original location to the document node - e.g. [grandparent_id, parent_id, node_id].
|
||||||
pub path: Option<Vec<NodeId>>,
|
pub path: Option<Vec<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)
|
||||||
pub inputs_source: HashMap<Source, usize>,
|
pub inputs_source: HashMap<Source, usize>,
|
||||||
/// A list of document sources for the node's output
|
/// A list of document sources for the node's output
|
||||||
pub outputs_source: HashMap<Source, usize>,
|
pub outputs_source: HashMap<Source, usize>,
|
||||||
@@ -203,6 +209,7 @@ impl Default for DocumentNode {
|
|||||||
manual_composition: Default::default(),
|
manual_composition: Default::default(),
|
||||||
has_primary_output: true,
|
has_primary_output: true,
|
||||||
implementation: Default::default(),
|
implementation: Default::default(),
|
||||||
|
visible: true,
|
||||||
metadata: Default::default(),
|
metadata: Default::default(),
|
||||||
skip_deduplication: Default::default(),
|
skip_deduplication: Default::default(),
|
||||||
world_state_hash: Default::default(),
|
world_state_hash: Default::default(),
|
||||||
@@ -272,7 +279,7 @@ impl DocumentNode {
|
|||||||
(ProtoNodeInput::None, ConstructionArgs::Value(tagged_value))
|
(ProtoNodeInput::None, ConstructionArgs::Value(tagged_value))
|
||||||
}
|
}
|
||||||
NodeInput::Node { node_id, output_index, lambda } => {
|
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) };
|
let node = if lambda { ProtoNodeInput::NodeLambda(node_id) } else { ProtoNodeInput::Node(node_id) };
|
||||||
(node, ConstructionArgs::Nodes(vec![]))
|
(node, ConstructionArgs::Nodes(vec![]))
|
||||||
}
|
}
|
||||||
@@ -445,9 +452,9 @@ pub enum DocumentNodeImplementation {
|
|||||||
///
|
///
|
||||||
/// A nested [`NodeNetwork`] that is flattened by the [`NodeNetwork::flatten`] function.
|
/// A nested [`NodeNetwork`] that is flattened by the [`NodeNetwork::flatten`] function.
|
||||||
Network(NodeNetwork),
|
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),
|
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.
|
/// 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
|
/// 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<NodeOutput>,
|
pub exports: Vec<NodeOutput>,
|
||||||
/// The list of all nodes in this network.
|
/// The list of all nodes in this network.
|
||||||
pub nodes: HashMap<NodeId, DocumentNode>,
|
pub nodes: HashMap<NodeId, DocumentNode>,
|
||||||
/// 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<NodeId>,
|
|
||||||
/// 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.
|
/// 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<Vec<NodeOutput>>,
|
pub previous_outputs: Option<Vec<NodeOutput>>,
|
||||||
}
|
}
|
||||||
@@ -540,7 +544,6 @@ impl std::hash::Hash for NodeNetwork {
|
|||||||
id.hash(state);
|
id.hash(state);
|
||||||
node.hash(state);
|
node.hash(state);
|
||||||
}
|
}
|
||||||
self.disabled.hash(state);
|
|
||||||
self.previous_outputs.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(),
|
imports: node.inputs.iter().filter(|input| matches!(input, NodeInput::Network(_))).map(|_| NodeId(0)).collect(),
|
||||||
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
exports: vec![NodeOutput::new(NodeId(0), 0)],
|
||||||
nodes: [(NodeId(0), node)].into_iter().collect(),
|
nodes: [(NodeId(0), node)].into_iter().collect(),
|
||||||
disabled: vec![],
|
|
||||||
previous_outputs: None,
|
previous_outputs: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,7 +817,6 @@ impl NodeNetwork {
|
|||||||
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) {
|
pub fn map_ids(&mut self, f: impl Fn(NodeId) -> NodeId + Copy) {
|
||||||
self.imports.iter_mut().for_each(|id| *id = f(*id));
|
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.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
|
self.previous_outputs
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|nodes| nodes.iter_mut().for_each(|output| output.node_id = f(output.node_id)));
|
.for_each(|nodes| nodes.iter_mut().for_each(|output| output.node_id = f(output.node_id)));
|
||||||
@@ -843,7 +844,7 @@ impl NodeNetwork {
|
|||||||
outwards_links
|
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]) {
|
pub fn generate_node_paths(&mut self, prefix: &[NodeId]) {
|
||||||
for (node_id, node) in &mut self.nodes {
|
for (node_id, node) in &mut self.nodes {
|
||||||
let mut new_path = prefix.to_vec();
|
let mut new_path = prefix.to_vec();
|
||||||
@@ -930,8 +931,11 @@ impl NodeNetwork {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if node.implementation != DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()) && self.disabled.contains(&id) {
|
// If the node is hidden, replace it with an identity node
|
||||||
node.implementation = DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into());
|
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() {
|
if node.is_layer() {
|
||||||
// Connect layer node to the graphic group below
|
// Connect layer node to the graphic group below
|
||||||
node.inputs.drain(..1);
|
node.inputs.drain(..1);
|
||||||
@@ -939,6 +943,7 @@ impl NodeNetwork {
|
|||||||
node.inputs.drain(1..);
|
node.inputs.drain(1..);
|
||||||
}
|
}
|
||||||
self.nodes.insert(id, node);
|
self.nodes.insert(id, node);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,7 +988,6 @@ impl NodeNetwork {
|
|||||||
let new_nodes = inner_network.nodes.keys().cloned().collect::<Vec<_>>();
|
let new_nodes = inner_network.nodes.keys().cloned().collect::<Vec<_>>();
|
||||||
// Copy nodes from the inner network into the parent network
|
// Copy nodes from the inner network into the parent network
|
||||||
self.nodes.extend(inner_network.nodes);
|
self.nodes.extend(inner_network.nodes);
|
||||||
self.disabled.extend(inner_network.disabled);
|
|
||||||
|
|
||||||
let mut network_offsets = HashMap::new();
|
let mut network_offsets = HashMap::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ impl ConstructionArgs {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Hash, Eq)]
|
#[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 struct ProtoNode {
|
||||||
pub construction_args: ConstructionArgs,
|
pub construction_args: ConstructionArgs,
|
||||||
pub input: ProtoNodeInput,
|
pub input: ProtoNodeInput,
|
||||||
@@ -718,7 +718,7 @@ impl TypingContext {
|
|||||||
ConstructionArgs::Inline(ref inline) => vec![inline.ty.clone()],
|
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 {
|
let input = match node.input {
|
||||||
ProtoNodeInput::None => concrete!(()),
|
ProtoNodeInput::None => concrete!(()),
|
||||||
ProtoNodeInput::ManualComposition(ref ty) => ty.clone(),
|
ProtoNodeInput::ManualComposition(ref ty) => ty.clone(),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub struct DynamicExecutor {
|
|||||||
output: NodeId,
|
output: NodeId,
|
||||||
/// Stores all of the dynamic node structs.
|
/// Stores all of the dynamic node structs.
|
||||||
tree: BorrowTree,
|
tree: BorrowTree,
|
||||||
/// Stores the types of the protonodes.
|
/// Stores the types of the proto nodes.
|
||||||
typing_context: TypingContext,
|
typing_context: TypingContext,
|
||||||
// This allows us to keep the nodes around for one more frame which is used for introspection
|
// This allows us to keep the nodes around for one more frame which is used for introspection
|
||||||
orphaned_nodes: Vec<NodeId>,
|
orphaned_nodes: Vec<NodeId>,
|
||||||
@@ -111,11 +111,11 @@ impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
|||||||
pub struct BorrowTree {
|
pub struct BorrowTree {
|
||||||
/// A hashmap of node IDs and dynamically typed nodes.
|
/// A hashmap of node IDs and dynamically typed nodes.
|
||||||
nodes: HashMap<NodeId, SharedNodeContainer>,
|
nodes: HashMap<NodeId, SharedNodeContainer>,
|
||||||
/// A hashmap from the document path to the protonode ID.
|
/// A hashmap from the document path to the proto node ID.
|
||||||
source_map: HashMap<Vec<NodeId>, NodeId>,
|
source_map: HashMap<Vec<NodeId>, 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<Source, (NodeId, usize)>,
|
inputs_source_map: HashMap<Source, (NodeId, usize)>,
|
||||||
/// 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<Source, NodeId>,
|
outputs_source_map: HashMap<Source, NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ impl BorrowTree {
|
|||||||
.extend((0..params).flat_map(|i| proto_node.original_location.inputs(i).map(move |source| (source, (id, i)))));
|
.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)));
|
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() {
|
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 {
|
match &proto_node.construction_args {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ module.exports = {
|
|||||||
camelcase: ["error", { properties: "always" }],
|
camelcase: ["error", { properties: "always" }],
|
||||||
"linebreak-style": ["error", "unix"],
|
"linebreak-style": ["error", "unix"],
|
||||||
"eol-last": ["error", "always"],
|
"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",
|
"prefer-destructuring": "off",
|
||||||
"no-console": "warn",
|
"no-console": "warn",
|
||||||
"no-debugger": "warn",
|
"no-debugger": "warn",
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ module.exports = {
|
|||||||
camelcase: ["error", { properties: "always" }],
|
camelcase: ["error", { properties: "always" }],
|
||||||
"linebreak-style": ["error", "unix"],
|
"linebreak-style": ["error", "unix"],
|
||||||
"eol-last": ["error", "always"],
|
"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",
|
"prefer-destructuring": "off",
|
||||||
"no-console": "warn",
|
"no-console": "warn",
|
||||||
"no-debugger": "warn",
|
"no-debugger": "warn",
|
||||||
|
|||||||
Reference in New Issue
Block a user