Fix wires on document change and errors on hidden nodes (#2897)

* Fix wires on document change and errors on hidden nodes

* Code cleanup
This commit is contained in:
Adam Gerhant
2025-07-19 01:48:42 -07:00
committed by GitHub
parent 7ef9e5a3e8
commit e4ec67d852
9 changed files with 68 additions and 74 deletions
@@ -182,8 +182,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
device_pixel_ratio, device_pixel_ratio,
} = context; } = context;
let selected_nodes_bounding_box_viewport = self.network_interface.selected_nodes_bounding_box_viewport(&self.breadcrumb_network_path);
let selected_visible_layers_bounding_box_viewport = self.selected_visible_layers_bounding_box_viewport();
match message { match message {
// Sub-messages // Sub-messages
DocumentMessage::Navigation(message) => { DocumentMessage::Navigation(message) => {
@@ -191,11 +189,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
network_interface: &mut self.network_interface, network_interface: &mut self.network_interface,
breadcrumb_network_path: &self.breadcrumb_network_path, breadcrumb_network_path: &self.breadcrumb_network_path,
ipp, ipp,
selection_bounds: if self.graph_view_overlay_open {
selected_nodes_bounding_box_viewport
} else {
selected_visible_layers_bounding_box_viewport
},
document_ptz: &mut self.document_ptz, document_ptz: &mut self.document_ptz,
graph_view_overlay_open: self.graph_view_overlay_open, graph_view_overlay_open: self.graph_view_overlay_open,
preferences, preferences,
@@ -259,7 +252,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
AlignAxis::X => DVec2::X, AlignAxis::X => DVec2::X,
AlignAxis::Y => DVec2::Y, AlignAxis::Y => DVec2::Y,
}; };
let Some(combined_box) = self.selected_visible_layers_bounding_box_viewport() else { let Some(combined_box) = self.network_interface.selected_layers_artwork_bounding_box_viewport() else {
return; return;
}; };
@@ -486,7 +479,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
FlipAxis::X => DVec2::new(-1., 1.), FlipAxis::X => DVec2::new(-1., 1.),
FlipAxis::Y => DVec2::new(1., -1.), FlipAxis::Y => DVec2::new(1., -1.),
}; };
if let Some([min, max]) = self.selected_visible_and_unlock_layers_bounding_box_viewport() { if let Some([min, max]) = self.network_interface.selected_unlocked_layers_bounding_box_viewport() {
let center = (max + min) / 2.; let center = (max + min) / 2.;
let bbox_trans = DAffine2::from_translation(-center); let bbox_trans = DAffine2::from_translation(-center);
let mut added_transaction = false; let mut added_transaction = false;
@@ -506,7 +499,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
} }
DocumentMessage::RotateSelectedLayers { degrees } => { DocumentMessage::RotateSelectedLayers { degrees } => {
// Get the bounding box of selected layers in viewport space // Get the bounding box of selected layers in viewport space
if let Some([min, max]) = self.selected_visible_and_unlock_layers_bounding_box_viewport() { if let Some([min, max]) = self.network_interface.selected_unlocked_layers_bounding_box_viewport() {
// Calculate the center of the bounding box to use as rotation pivot // Calculate the center of the bounding box to use as rotation pivot
let center = (max + min) / 2.; let center = (max + min) / 2.;
// Transform that moves pivot point to origin // Transform that moves pivot point to origin
@@ -1063,13 +1056,13 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
self.selected_layers_reorder(relative_index_offset, responses); self.selected_layers_reorder(relative_index_offset, responses);
} }
DocumentMessage::ClipLayer { id } => { DocumentMessage::ClipLayer { id } => {
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); let layer = LayerNodeIdentifier::new(id, &self.network_interface);
responses.add(DocumentMessage::AddTransaction); responses.add(DocumentMessage::AddTransaction);
responses.add(GraphOperationMessage::ClipModeToggle { layer }); responses.add(GraphOperationMessage::ClipModeToggle { layer });
} }
DocumentMessage::SelectLayer { id, ctrl, shift } => { DocumentMessage::SelectLayer { id, ctrl, shift } => {
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); let layer = LayerNodeIdentifier::new(id, &self.network_interface);
let mut nodes = vec![]; let mut nodes = vec![];
@@ -1266,7 +1259,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
responses.add(OverlaysMessage::Draw); responses.add(OverlaysMessage::Draw);
} }
DocumentMessage::ToggleLayerExpansion { id, recursive } => { DocumentMessage::ToggleLayerExpansion { id, recursive } => {
let layer = LayerNodeIdentifier::new(id, &self.network_interface, &[]); let layer = LayerNodeIdentifier::new(id, &self.network_interface);
let metadata = self.metadata(); let metadata = self.metadata();
let is_collapsed = self.collapsed.0.contains(&layer); let is_collapsed = self.collapsed.0.contains(&layer);
@@ -1323,7 +1316,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
self.network_interface.document_network().nodes.contains_key(node_id)) self.network_interface.document_network().nodes.contains_key(node_id))
.filter_map(|(node_id, click_targets)| { .filter_map(|(node_id, click_targets)| {
self.network_interface.is_layer(&node_id, &[]).then(|| { self.network_interface.is_layer(&node_id, &[]).then(|| {
let layer = LayerNodeIdentifier::new(node_id, &self.network_interface, &[]); let layer = LayerNodeIdentifier::new(node_id, &self.network_interface);
(layer, click_targets) (layer, click_targets)
}) })
}) })
@@ -1708,31 +1701,6 @@ impl DocumentMessageHandler {
.last() .last()
} }
/// 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.network_interface
.selected_nodes()
.selected_visible_layers(&self.network_interface)
.filter_map(|layer| self.metadata().bounding_box_viewport(layer))
.reduce(graphene_std::renderer::Quad::combine_bounds)
}
pub fn selected_visible_and_unlock_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(&self.network_interface)
.filter_map(|layer| self.metadata().bounding_box_viewport(layer))
.reduce(graphene_std::renderer::Quad::combine_bounds)
}
pub fn selected_visible_and_unlock_layers_bounding_box_document(&self) -> Option<[DVec2; 2]> {
self.network_interface
.selected_nodes()
.selected_visible_and_unlocked_layers(&self.network_interface)
.map(|layer| self.metadata().nonzero_bounding_box(layer))
.reduce(graphene_std::renderer::Quad::combine_bounds)
}
pub fn document_network(&self) -> &NodeNetwork { pub fn document_network(&self) -> &NodeNetwork {
self.network_interface.document_network() self.network_interface.document_network()
} }
@@ -119,7 +119,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone(); let primary_input = artboard.inputs.first().expect("Artboard should have a primary input").clone();
if let NodeInput::Node { node_id, .. } = &primary_input { if let NodeInput::Node { node_id, .. } = &primary_input {
if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) { if network_interface.is_layer(node_id, &[]) && !network_interface.is_artboard(node_id, &[]) {
network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface, &[]), artboard_layer, 0, &[]); network_interface.move_layer_to_stack(LayerNodeIdentifier::new(*node_id, network_interface), artboard_layer, 0, &[]);
} else { } else {
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]); network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]); network_interface.set_input(&InputConnector::node(id, 0), primary_input, &[]);
@@ -124,7 +124,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier { pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier {
let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template(); let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template();
self.network_interface.insert_node(new_id, new_merge_node, &[]); self.network_interface.insert_node(new_id, new_merge_node, &[]);
LayerNodeIdentifier::new(new_id, self.network_interface, &[]) LayerNodeIdentifier::new(new_id, self.network_interface)
} }
/// Creates an artboard as the primary export for the document network /// Creates an artboard as the primary export for the document network
@@ -138,7 +138,7 @@ impl<'a> ModifyInputsContext<'a> {
Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)), Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)),
]); ]);
self.network_interface.insert_node(new_id, artboard_node_template, &[]); self.network_interface.insert_node(new_id, artboard_node_template, &[]);
LayerNodeIdentifier::new(new_id, self.network_interface, &[]) LayerNodeIdentifier::new(new_id, self.network_interface)
} }
pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) { pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) {
@@ -236,7 +236,7 @@ impl<'a> ModifyInputsContext<'a> {
self.layer_node.or_else(|| { self.layer_node.or_else(|| {
let export_node = self.network_interface.document_network().exports.first().and_then(|export| export.as_node())?; let export_node = self.network_interface.document_network().exports.first().and_then(|export| export.as_node())?;
if self.network_interface.is_layer(&export_node, &[]) { if self.network_interface.is_layer(&export_node, &[]) {
Some(LayerNodeIdentifier::new(export_node, self.network_interface, &[])) Some(LayerNodeIdentifier::new(export_node, self.network_interface))
} else { } else {
None None
} }
@@ -18,7 +18,6 @@ pub struct NavigationMessageContext<'a> {
pub network_interface: &'a mut NodeNetworkInterface, pub network_interface: &'a mut NodeNetworkInterface,
pub breadcrumb_network_path: &'a [NodeId], pub breadcrumb_network_path: &'a [NodeId],
pub ipp: &'a InputPreprocessorMessageHandler, pub ipp: &'a InputPreprocessorMessageHandler,
pub selection_bounds: Option<[DVec2; 2]>,
pub document_ptz: &'a mut PTZ, pub document_ptz: &'a mut PTZ,
pub graph_view_overlay_open: bool, pub graph_view_overlay_open: bool,
pub preferences: &'a PreferencesMessageHandler, pub preferences: &'a PreferencesMessageHandler,
@@ -39,7 +38,6 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
network_interface, network_interface,
breadcrumb_network_path, breadcrumb_network_path,
ipp, ipp,
selection_bounds,
document_ptz, document_ptz,
graph_view_overlay_open, graph_view_overlay_open,
preferences, preferences,
@@ -386,9 +384,16 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
responses.add(DocumentMessage::PTZUpdate); responses.add(DocumentMessage::PTZUpdate);
responses.add(NodeGraphMessage::SetGridAlignedEdges); responses.add(NodeGraphMessage::SetGridAlignedEdges);
} }
// Fully zooms in on the selected
NavigationMessage::FitViewportToSelection => { NavigationMessage::FitViewportToSelection => {
let selection_bounds = if graph_view_overlay_open {
network_interface.selected_nodes_bounding_box_viewport(breadcrumb_network_path)
} else {
network_interface.selected_layers_artwork_bounding_box_viewport()
};
if let Some(bounds) = selection_bounds { if let Some(bounds) = selection_bounds {
let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { let Some(ptz) = get_ptz(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else {
log::error!("Could not get node graph PTZ in FitViewportToSelection"); log::error!("Could not get node graph PTZ in FitViewportToSelection");
return; return;
}; };
@@ -1387,6 +1387,11 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
if node_bbox[1].x >= document_bbox[0].x && node_bbox[0].x <= document_bbox[1].x && node_bbox[1].y >= document_bbox[0].y && node_bbox[0].y <= document_bbox[1].y { if node_bbox[1].x >= document_bbox[0].x && node_bbox[0].x <= document_bbox[1].x && node_bbox[1].y >= document_bbox[0].y && node_bbox[0].y <= document_bbox[1].y {
nodes.push(*node_id); nodes.push(*node_id);
} }
for error in &self.node_graph_errors {
if error.node_path.contains(node_id) {
nodes.push(*node_id);
}
}
} }
responses.add(FrontendMessage::UpdateVisibleNodes { nodes }); responses.add(FrontendMessage::UpdateVisibleNodes { nodes });
@@ -2399,19 +2404,19 @@ impl NodeGraphMessageHandler {
let mut ancestors_of_selected = HashSet::new(); let mut ancestors_of_selected = HashSet::new();
let mut descendants_of_selected = HashSet::new(); let mut descendants_of_selected = HashSet::new();
for selected_layer in &selected_layers { for selected_layer in &selected_layers {
for ancestor in LayerNodeIdentifier::new(*selected_layer, network_interface, &[]).ancestors(network_interface.document_metadata()) { for ancestor in LayerNodeIdentifier::new(*selected_layer, network_interface).ancestors(network_interface.document_metadata()) {
if ancestor != LayerNodeIdentifier::ROOT_PARENT && ancestor.to_node() != *selected_layer { if ancestor != LayerNodeIdentifier::ROOT_PARENT && ancestor.to_node() != *selected_layer {
ancestors_of_selected.insert(ancestor.to_node()); ancestors_of_selected.insert(ancestor.to_node());
} }
} }
for descendant in LayerNodeIdentifier::new(*selected_layer, network_interface, &[]).descendants(network_interface.document_metadata()) { for descendant in LayerNodeIdentifier::new(*selected_layer, network_interface).descendants(network_interface.document_metadata()) {
descendants_of_selected.insert(descendant.to_node()); descendants_of_selected.insert(descendant.to_node());
} }
} }
for (&node_id, node_metadata) in &network_interface.document_network_metadata().persistent_metadata.node_metadata { for (&node_id, node_metadata) in &network_interface.document_network_metadata().persistent_metadata.node_metadata {
if node_metadata.persistent_metadata.is_layer() { if node_metadata.persistent_metadata.is_layer() {
let layer = LayerNodeIdentifier::new(node_id, network_interface, &[]); let layer = LayerNodeIdentifier::new(node_id, network_interface);
let children_allowed = let children_allowed =
// The layer has other layers as children along the secondary input's horizontal flow // The layer has other layers as children along the secondary input's horizontal flow
@@ -250,12 +250,8 @@ impl LayerNodeIdentifier {
/// Construct a [`LayerNodeIdentifier`], debug asserting that it is a layer node. This should only be used in the document network since the structure is not loaded in nested networks. /// Construct a [`LayerNodeIdentifier`], debug asserting that it is a layer node. This should only be used in the document network since the structure is not loaded in nested networks.
#[track_caller] #[track_caller]
pub fn new(node_id: NodeId, network_interface: &NodeNetworkInterface, network_path: &[NodeId]) -> Self { pub fn new(node_id: NodeId, network_interface: &NodeNetworkInterface) -> Self {
debug_assert!( debug_assert!(network_interface.is_layer(&node_id, &[]), "Layer identifier constructed from non-layer node {node_id}",);
network_interface.is_layer(&node_id, network_path),
"Layer identifier constructed from non-layer node {node_id}: {:#?}",
network_interface.nested_network(network_path).unwrap().nodes.get(&node_id)
);
Self::new_unchecked(node_id) Self::new_unchecked(node_id)
} }
@@ -203,12 +203,12 @@ impl NodeNetworkInterface {
} }
/// Returns the first downstream layer(inclusive) from a node. If the node is a layer, it will return itself. /// Returns the first downstream layer(inclusive) from a node. If the node is a layer, it will return itself.
pub fn downstream_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<LayerNodeIdentifier> { pub fn downstream_layer_for_chain_node(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<NodeId> {
let mut id = *node_id; let mut id = *node_id;
while !self.is_layer(&id, network_path) { while !self.is_layer(&id, network_path) {
id = self.outward_wires(network_path)?.get(&OutputConnector::node(id, 0))?.first()?.node_id()?; id = self.outward_wires(network_path)?.get(&OutputConnector::node(id, 0))?.first()?.node_id()?;
} }
Some(LayerNodeIdentifier::new(id, self, network_path)) Some(id)
} }
/// Returns all downstream layers (inclusive) from a node. If the node is a layer, it will return itself. /// Returns all downstream layers (inclusive) from a node. If the node is a layer, it will return itself.
@@ -388,8 +388,8 @@ impl NodeNetworkInterface {
} }
// If a chain node does not have a selected downstream layer, then set the position to absolute // If a chain node does not have a selected downstream layer, then set the position to absolute
let downstream_layer = self.downstream_layer(node_id, network_path); let downstream_layer = self.downstream_layer_for_chain_node(node_id, network_path);
if downstream_layer.is_none_or(|downstream_layer| new_ids.keys().all(|key| *key != downstream_layer.to_node())) { if downstream_layer.is_none_or(|downstream_layer| new_ids.keys().all(|key| *key != downstream_layer)) {
let Some(position) = self.position(node_id, network_path) else { let Some(position) = self.position(node_id, network_path) else {
log::error!("Could not get position in create_node_template"); log::error!("Could not get position in create_node_template");
return None; return None;
@@ -1244,7 +1244,7 @@ impl NodeNetworkInterface {
.as_ref() .as_ref()
.is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[])) .is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[]))
{ {
Some(LayerNodeIdentifier::new(*node_id, self, &[])) Some(LayerNodeIdentifier::new(*node_id, self))
} else { } else {
None None
} }
@@ -3025,7 +3025,7 @@ impl NodeNetworkInterface {
// Helper functions for mutable getters // Helper functions for mutable getters
impl NodeNetworkInterface { impl NodeNetworkInterface {
pub fn upstream_chain_nodes(&mut self, network_path: &[NodeId]) -> Vec<NodeId> { pub fn upstream_chain_nodes(&self, network_path: &[NodeId]) -> Vec<NodeId> {
let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else {
log::error!("Could not get selected nodes in upstream_chain_nodes"); log::error!("Could not get selected nodes in upstream_chain_nodes");
return Vec::new(); return Vec::new();
@@ -3156,7 +3156,7 @@ impl NodeNetworkInterface {
self.document_metadata.document_to_viewport = transform; self.document_metadata.document_to_viewport = transform;
} }
pub fn is_eligible_to_be_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool { pub fn is_eligible_to_be_layer(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
let Some(node) = self.document_node(node_id, network_path) else { let Some(node) = self.document_node(node_id, network_path) else {
log::error!("Could not get node {node_id} in is_eligible_to_be_layer"); log::error!("Could not get node {node_id} in is_eligible_to_be_layer");
return false; return false;
@@ -3362,6 +3362,24 @@ impl NodeNetworkInterface {
.map(|[a, b]| [node_graph_to_viewport.transform_point2(a), node_graph_to_viewport.transform_point2(b)]) .map(|[a, b]| [node_graph_to_viewport.transform_point2(a), node_graph_to_viewport.transform_point2(b)])
} }
pub fn selected_layers_artwork_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_nodes()
.0
.iter()
.filter(|node| self.is_layer(&node, &[]))
.filter_map(|layer| self.document_metadata.bounding_box_viewport(LayerNodeIdentifier::new(*layer, self)))
.reduce(Quad::combine_bounds)
}
pub fn selected_unlocked_layers_bounding_box_viewport(&self) -> Option<[DVec2; 2]> {
self.selected_nodes()
.0
.iter()
.filter(|node| self.is_layer(&node, &[]) && !self.is_layer(&node, &[]))
.filter_map(|layer| self.document_metadata.bounding_box_viewport(LayerNodeIdentifier::new(*layer, self)))
.reduce(Quad::combine_bounds)
}
/// Get the combined bounding box of the click targets of the selected nodes in the node graph in layer space /// Get the combined bounding box of the click targets of the selected nodes in the node graph in layer space
pub fn selected_nodes_bounding_box(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> { pub fn selected_nodes_bounding_box(&mut self, network_path: &[NodeId]) -> Option<[DVec2; 2]> {
let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else { let Some(selected_nodes) = self.selected_nodes_in_nested_network(network_path) else {
@@ -3451,7 +3469,7 @@ impl NodeNetworkInterface {
let Some(first_root_layer) = self let Some(first_root_layer) = self
.upstream_flow_back_from_nodes(vec![root_node.node_id], &[], FlowType::PrimaryFlow) .upstream_flow_back_from_nodes(vec![root_node.node_id], &[], FlowType::PrimaryFlow)
.find_map(|node_id| if self.is_layer(&node_id, &[]) { Some(LayerNodeIdentifier::new(node_id, self, &[])) } else { None }) .find_map(|node_id| if self.is_layer(&node_id, &[]) { Some(LayerNodeIdentifier::new(node_id, self)) } else { None })
else { else {
return; return;
}; };
@@ -3467,7 +3485,7 @@ impl NodeNetworkInterface {
if horizontal_root_node_id == first_root_layer.to_node() { if horizontal_root_node_id == first_root_layer.to_node() {
for current_node_id in horizontal_flow_iter { for current_node_id in horizontal_flow_iter {
if self.is_layer(&current_node_id, &[]) { if self.is_layer(&current_node_id, &[]) {
let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); let current_layer_node = LayerNodeIdentifier::new(current_node_id, self);
if !self.document_metadata.structure.contains_key(&current_layer_node) { if !self.document_metadata.structure.contains_key(&current_layer_node) {
if current_node_id == first_root_layer.to_node() { if current_node_id == first_root_layer.to_node() {
awaiting_primary_flow.push((current_node_id, LayerNodeIdentifier::ROOT_PARENT)); awaiting_primary_flow.push((current_node_id, LayerNodeIdentifier::ROOT_PARENT));
@@ -3484,7 +3502,7 @@ impl NodeNetworkInterface {
// Skip the horizontal_root_node_id node // Skip the horizontal_root_node_id node
for current_node_id in horizontal_flow_iter.skip(1) { for current_node_id in horizontal_flow_iter.skip(1) {
if self.is_layer(&current_node_id, &[]) { if self.is_layer(&current_node_id, &[]) {
let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); let current_layer_node = LayerNodeIdentifier::new(current_node_id, self);
if !self.document_metadata.structure.contains_key(&current_layer_node) { if !self.document_metadata.structure.contains_key(&current_layer_node) {
awaiting_primary_flow.push((current_node_id, parent_layer_node)); awaiting_primary_flow.push((current_node_id, parent_layer_node));
children.push((parent_layer_node, current_layer_node)); children.push((parent_layer_node, current_layer_node));
@@ -3505,7 +3523,7 @@ impl NodeNetworkInterface {
for current_node_id in primary_flow_iter.skip(1) { for current_node_id in primary_flow_iter.skip(1) {
if self.is_layer(&current_node_id, &[]) { if self.is_layer(&current_node_id, &[]) {
// Create a new layer for the top of each stack, and add it as a child to the previous parent // Create a new layer for the top of each stack, and add it as a child to the previous parent
let current_layer_node = LayerNodeIdentifier::new(current_node_id, self, &[]); let current_layer_node = LayerNodeIdentifier::new(current_node_id, self);
if !self.document_metadata.structure.contains_key(&current_layer_node) { if !self.document_metadata.structure.contains_key(&current_layer_node) {
children.push(current_layer_node); children.push(current_layer_node);
@@ -3568,7 +3586,7 @@ impl NodeNetworkInterface {
} }
stack.extend(self_network_metadata.persistent_metadata.node_metadata.keys().map(|node_id| { stack.extend(self_network_metadata.persistent_metadata.node_metadata.keys().map(|node_id| {
let mut current_path = path.clone(); let mut current_path: Vec<NodeId> = path.clone();
current_path.push(*node_id); current_path.push(*node_id);
current_path current_path
})); }));
@@ -5087,8 +5105,8 @@ impl NodeNetworkInterface {
} }
self.unload_upstream_node_click_targets(vec![*node_id], network_path); self.unload_upstream_node_click_targets(vec![*node_id], network_path);
// Reload click target of the layer which encapsulate the chain // Reload click target of the layer which encapsulate the chain
if let Some(downstream_layer) = self.downstream_layer(node_id, network_path) { if let Some(downstream_layer) = self.downstream_layer_for_chain_node(node_id, network_path) {
self.unload_node_click_targets(&downstream_layer.to_node(), network_path); self.unload_node_click_targets(&downstream_layer, network_path);
} }
self.unload_all_nodes_bounding_box(network_path); self.unload_all_nodes_bounding_box(network_path);
} }
@@ -5205,7 +5223,7 @@ impl NodeNetworkInterface {
/// node_id is the first chain node, not the layer /// node_id is the first chain node, not the layer
fn set_upstream_chain_to_absolute(&mut self, node_id: &NodeId, network_path: &[NodeId]) { fn set_upstream_chain_to_absolute(&mut self, node_id: &NodeId, network_path: &[NodeId]) {
let Some(downstream_layer) = self.downstream_layer(node_id, network_path) else { let Some(downstream_layer) = self.downstream_layer_for_chain_node(node_id, network_path) else {
log::error!("Could not get downstream layer in set_upstream_chain_to_absolute"); log::error!("Could not get downstream layer in set_upstream_chain_to_absolute");
return; return;
}; };
@@ -5218,7 +5236,7 @@ impl NodeNetworkInterface {
if self.is_chain(upstream_id, network_path) { if self.is_chain(upstream_id, network_path) {
self.set_absolute_position(upstream_id, previous_position, network_path); self.set_absolute_position(upstream_id, previous_position, network_path);
// Reload click target of the layer which used to encapsulate the chain // Reload click target of the layer which used to encapsulate the chain
self.unload_node_click_targets(&downstream_layer.to_node(), network_path); self.unload_node_click_targets(&downstream_layer, network_path);
} }
// If there is an upstream layer then stop breaking the chain // If there is an upstream layer then stop breaking the chain
else { else {
@@ -5297,8 +5315,8 @@ impl NodeNetworkInterface {
// Deselect chain nodes upstream from a selected layer // Deselect chain nodes upstream from a selected layer
if self.is_chain(selected_node, network_path) if self.is_chain(selected_node, network_path)
&& self && self
.downstream_layer(selected_node, network_path) .downstream_layer_for_chain_node(selected_node, network_path)
.is_some_and(|downstream_layer| node_ids.contains(&downstream_layer.to_node())) .is_some_and(|downstream_layer| node_ids.contains(&downstream_layer))
{ {
node_ids.remove(selected_node); node_ids.remove(selected_node);
} }
@@ -789,6 +789,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open }); responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
if node_graph_open { if node_graph_open {
responses.add(NodeGraphMessage::UpdateGraphBarRight); responses.add(NodeGraphMessage::UpdateGraphBarRight);
responses.add(NodeGraphMessage::UnloadWires);
responses.add(NodeGraphMessage::SendWires)
} else { } else {
responses.add(PortfolioMessage::UpdateDocumentWidgets); responses.add(PortfolioMessage::UpdateDocumentWidgets);
} }
@@ -1323,7 +1323,7 @@ mod test_transform_layer {
let document = editor.active_document_mut(); let document = editor.active_document_mut();
let group_children = document.network_interface.downstream_layers(&group_layer.to_node(), &[]); let group_children = document.network_interface.downstream_layers(&group_layer.to_node(), &[]);
if !group_children.is_empty() { if !group_children.is_empty() {
Some(LayerNodeIdentifier::new(group_children[0], &document.network_interface, &[])) Some(LayerNodeIdentifier::new(group_children[0], &document.network_interface))
} else { } else {
None None
} }