Skip to content

Commit 06484ef

Browse files
adamgerhantKeavon
andauthored
Show red connectors on a type-erroring node and accurate connector colors upstream of it (#3110)
* Refactor TypeSource * Add complete valid types * Add invalid type * Improve valid/complete types and disconnecting * Code review * Return types on error --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 7d739c4 commit 06484ef

File tree

19 files changed

+543
-448
lines changed

19 files changed

+543
-448
lines changed

editor/src/messages/portfolio/document/document_message_handler.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType
1717
use crate::messages::portfolio::document::properties_panel::properties_panel_message_handler::PropertiesPanelMessageContext;
1818
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
1919
use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, DocumentMode, FlipAxis, PTZ};
20-
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate, OutputConnector};
20+
use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeTemplate};
2121
use crate::messages::portfolio::document::utility_types::nodes::RawBuffer;
2222
use crate::messages::portfolio::utility_types::PanelType;
2323
use crate::messages::portfolio::utility_types::PersistentData;
@@ -2819,16 +2819,11 @@ impl DocumentMessageHandler {
28192819
.tooltip("Add an operation to the end of this layer's chain of nodes")
28202820
.disabled(!has_selection || has_multiple_selection)
28212821
.popover_layout({
2822-
// Showing only compatible types
2822+
// Showing only compatible types for the layer based on the output type of the node upstream from its horizontal input
28232823
let compatible_type = selected_layer.and_then(|layer| {
2824-
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &self.network_interface);
2825-
let node_type = graph_layer.horizontal_layer_flow().nth(1);
2826-
if let Some(node_id) = node_type {
2827-
let (output_type, _) = self.network_interface.output_type(&OutputConnector::node(node_id, 0), &self.selection_network_path);
2828-
Some(format!("type:{}", output_type.nested_type()))
2829-
} else {
2830-
None
2831-
}
2824+
self.network_interface
2825+
.upstream_output_connector(&InputConnector::node(layer.to_node(), 1), &[])
2826+
.and_then(|upstream_output| self.network_interface.output_type(&upstream_output, &[]).add_node_string())
28322827
});
28332828

28342829
let mut node_chooser = NodeCatalog::new();

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers;
77
use crate::messages::prelude::*;
88
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
99
use glam::{DAffine2, DVec2, IVec2};
10+
use graph_craft::document::value::TaggedValue;
1011
use graph_craft::document::{NodeId, NodeInput};
1112
use graphene_std::Color;
1213
use graphene_std::renderer::Quad;
1314
use graphene_std::renderer::convert_usvg_path::convert_usvg_path;
15+
use graphene_std::table::Table;
1416
use graphene_std::text::{Font, TypesettingConfig};
1517
use graphene_std::vector::style::{Fill, Gradient, GradientStops, GradientType, PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
1618

@@ -140,10 +142,18 @@ impl MessageHandler<GraphOperationMessage, GraphOperationMessageContext<'_>> for
140142
skip_rerender: true,
141143
});
142144
}
145+
146+
// Set the bottom input of the artboard back to artboard
147+
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
148+
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
143149
} else {
144150
// We have some non layers (e.g. just a rectangle node). We disconnect the bottom input and connect it to the left input.
145151
network_interface.disconnect_input(&InputConnector::node(artboard_layer.to_node(), 0), &[]);
146152
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 1), primary_input, &[]);
153+
154+
// Set the bottom input of the artboard back to artboard
155+
let bottom_input = NodeInput::value(TaggedValue::Artboard(Table::new()), true);
156+
network_interface.set_input(&InputConnector::node(artboard_layer.to_node(), 0), bottom_input, &[]);
147157
}
148158
}
149159
responses.add_front(NodeGraphMessage::SelectedNodesSet { nodes: vec![id] });

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,8 @@ impl<'a> ModifyInputsContext<'a> {
303303
// If inserting a 'Path' node, insert a 'Flatten Path' node if the type is `Graphic`.
304304
// TODO: Allow the 'Path' node to operate on table data by utilizing the reference (index or ID?) for each row.
305305
if node_definition.identifier == "Path" {
306-
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]).0.nested_type().clone();
307-
if layer_input_type == concrete!(Table<Graphic>) {
306+
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]);
307+
if layer_input_type.compiled_nested_type() == Some(&concrete!(Table<Graphic>)) {
308308
let Some(flatten_path_definition) = resolve_document_node_type("Flatten Path") else {
309309
log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id");
310310
return None;

editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,37 @@ use graphene_std::registry::*;
66
use graphene_std::*;
77
use std::collections::HashSet;
88

9+
/// Traverses a document node template and metadata in parallel to link the protonodes to their reference
10+
fn traverse_node(node: &DocumentNode, node_metadata: &mut DocumentNodePersistentMetadata) {
11+
match &node.implementation {
12+
DocumentNodeImplementation::Network(node_network) => {
13+
for (nested_node_id, nested_node) in node_network.nodes.iter() {
14+
let nested_metadata = node_metadata
15+
.network_metadata
16+
.as_mut()
17+
.expect("Network node must have network metadata")
18+
.persistent_metadata
19+
.node_metadata
20+
.get_mut(nested_node_id)
21+
.expect("Network metadata must have corresponding node id");
22+
traverse_node(nested_node, &mut nested_metadata.persistent_metadata);
23+
}
24+
}
25+
DocumentNodeImplementation::ProtoNode(proto_node_identifier) => {
26+
if let Some(metadata) = NODE_METADATA.lock().unwrap().get(proto_node_identifier) {
27+
node_metadata.reference = Some(metadata.display_name.to_string());
28+
}
29+
}
30+
DocumentNodeImplementation::Extract => {}
31+
}
32+
}
33+
934
pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec<DocumentNodeDefinition> {
35+
// Link the protonodes with custom networks to their reference
36+
for node in custom.iter_mut() {
37+
traverse_node(&node.node_template.document_node, &mut node.node_template.persistent_node_metadata);
38+
}
39+
1040
// Remove struct generics
1141
for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() {
1242
let NodeTemplate {

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,19 @@ use crate::messages::portfolio::document::node_graph::utility_types::{ContextMen
1010
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
1111
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
1212
use crate::messages::portfolio::document::utility_types::network_interface::{
13-
self, FlowType, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing, TypeSource,
13+
self, FlowType, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing,
1414
};
1515
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
1616
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
1717
use crate::messages::prelude::*;
1818
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
19-
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode};
19+
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
2020
use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed;
2121
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
2222
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
2323
use crate::messages::viewport::Position;
2424
use glam::{DAffine2, DVec2, IVec2};
2525
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
26-
use graph_craft::proto::GraphErrors;
2726
use graphene_std::math::math_ext::QuadExt;
2827
use graphene_std::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath;
2928
use graphene_std::*;
@@ -51,7 +50,6 @@ pub struct NodeGraphMessageContext<'a> {
5150
pub struct NodeGraphMessageHandler {
5251
// TODO: Remove network and move to NodeNetworkInterface
5352
pub network: Vec<NodeId>,
54-
pub node_graph_errors: GraphErrors,
5553
has_selection: bool,
5654
widgets: [LayoutGroup; 2],
5755
/// Used to add a transaction for the first node move when dragging.
@@ -875,13 +873,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
875873
self.disconnecting = Some(*clicked_input);
876874

877875
let output_connector = if *clicked_input == InputConnector::Export(0) {
878-
network_interface.root_node(selection_network_path).map(|root_node| root_node.to_connector())
876+
network_interface.root_node(breadcrumb_network_path).map(|root_node| root_node.to_connector())
879877
} else {
880-
network_interface.upstream_output_connector(clicked_input, selection_network_path)
878+
network_interface.upstream_output_connector(clicked_input, breadcrumb_network_path)
881879
};
882880
let Some(output_connector) = output_connector else { return };
883-
self.wire_in_progress_from_connector = network_interface.output_position(&output_connector, selection_network_path);
884-
self.wire_in_progress_type = FrontendGraphDataType::from_type(&network_interface.input_type(clicked_input, breadcrumb_network_path).0);
881+
self.wire_in_progress_from_connector = network_interface.output_position(&output_connector, breadcrumb_network_path);
882+
883+
self.wire_in_progress_type = network_interface.output_type(&output_connector, breadcrumb_network_path).displayed_type();
885884
return;
886885
}
887886

@@ -891,8 +890,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
891890
self.initial_disconnecting = false;
892891

893892
self.wire_in_progress_from_connector = network_interface.output_position(&clicked_output, selection_network_path);
894-
let (output_type, source) = &network_interface.output_type(&clicked_output, breadcrumb_network_path);
895-
self.wire_in_progress_type = FrontendGraphDataType::displayed_type(output_type, source);
893+
let output_type = network_interface.output_type(&clicked_output, breadcrumb_network_path);
894+
self.wire_in_progress_type = output_type.displayed_type();
896895

897896
self.update_node_graph_hints(responses);
898897
return;
@@ -1211,21 +1210,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
12111210
}
12121211

12131212
// Get the output types from the network interface
1214-
let (output_type, type_source) = network_interface.output_type(&output_connector, selection_network_path);
12151213
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
12161214
warn!("No network_metadata");
12171215
return;
12181216
};
12191217

1220-
let compatible_type = match type_source {
1221-
TypeSource::RandomProtonodeImplementation | TypeSource::Error(_) => None,
1222-
_ => Some(format!("type:{}", output_type.nested_type())),
1223-
};
1224-
12251218
let appear_right_of_mouse = if ipp.mouse.position.x > viewport.size().y() - 173. { -173. } else { 0. };
12261219
let appear_above_mouse = if ipp.mouse.position.y > viewport.size().y() - 34. { -34. } else { 0. };
12271220
let node_graph_shift = DVec2::new(appear_right_of_mouse, appear_above_mouse) / network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.matrix2.x_axis.x;
12281221

1222+
let compatible_type = network_interface.output_type(&output_connector, selection_network_path).add_node_string();
1223+
12291224
self.context_menu = Some(ContextMenuInformation {
12301225
context_menu_coordinates: ((point.x + node_graph_shift.x) as i32, (point.y + node_graph_shift.y) as i32),
12311226
context_menu_data: ContextMenuData::CreateNode { compatible_type },
@@ -1632,7 +1627,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
16321627
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 {
16331628
nodes.push(*node_id);
16341629
}
1635-
for error in &self.node_graph_errors {
1630+
for error in &network_interface.resolved_types.node_graph_errors {
16361631
if error.node_path.contains(node_id) {
16371632
nodes.push(*node_id);
16381633
}
@@ -1996,13 +1991,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
19961991
responses.add(NodeGraphMessage::SendGraph);
19971992
}
19981993
NodeGraphMessage::UpdateTypes { resolved_types, node_graph_errors } => {
1999-
for (path, node_type) in resolved_types.add {
2000-
network_interface.resolved_types.types.insert(path.to_vec(), node_type);
2001-
}
2002-
for path in resolved_types.remove {
2003-
network_interface.resolved_types.types.remove(&path.to_vec());
2004-
}
2005-
self.node_graph_errors = node_graph_errors;
1994+
network_interface.resolved_types.update(resolved_types, node_graph_errors);
20061995
}
20071996
NodeGraphMessage::UpdateActionButtons => {
20081997
if selection_network_path == breadcrumb_network_path {
@@ -2115,16 +2104,7 @@ impl NodeGraphMessageHandler {
21152104
.popover_layout({
21162105
// Showing only compatible types
21172106
let compatible_type = match (selection_includes_layers, has_multiple_selection, selected_layer) {
2118-
(true, false, Some(layer)) => {
2119-
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface);
2120-
let node_type = graph_layer.horizontal_layer_flow().nth(1);
2121-
if let Some(node_id) = node_type {
2122-
let (output_type, _) = network_interface.output_type(&OutputConnector::node(node_id, 0), &[]);
2123-
Some(format!("type:{}", output_type.nested_type()))
2124-
} else {
2125-
None
2126-
}
2127-
}
2107+
(true, false, Some(layer)) => network_interface.output_type(&OutputConnector::node(layer.to_node(), 1), &[]).add_node_string(),
21282108
_ => None,
21292109
};
21302110

@@ -2437,17 +2417,10 @@ impl NodeGraphMessageHandler {
24372417
.icon(Some("Node".to_string()))
24382418
.tooltip("Add an operation to the end of this layer's chain of nodes")
24392419
.popover_layout({
2440-
let layer_identifier = LayerNodeIdentifier::new(layer, context.network_interface);
2441-
let compatible_type = {
2442-
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer_identifier, context.network_interface);
2443-
let node_type = graph_layer.horizontal_layer_flow().nth(1);
2444-
if let Some(node_id) = node_type {
2445-
let (output_type, _) = context.network_interface.output_type(&OutputConnector::node(node_id, 0), &[]);
2446-
Some(format!("type:{}", output_type.nested_type()))
2447-
} else {
2448-
None
2449-
}
2450-
};
2420+
let compatible_type = context
2421+
.network_interface
2422+
.upstream_output_connector(&InputConnector::node(layer, 1), &[])
2423+
.and_then(|upstream_output| context.network_interface.output_type(&upstream_output, &[]).add_node_string());
24512424

24522425
let mut node_chooser = NodeCatalog::new();
24532426
node_chooser.intial_search = compatible_type.unwrap_or("".to_string());
@@ -2579,13 +2552,14 @@ impl NodeGraphMessageHandler {
25792552

25802553
let locked = network_interface.is_locked(&node_id, breadcrumb_network_path);
25812554

2582-
let errors = self
2555+
let errors = network_interface
2556+
.resolved_types
25832557
.node_graph_errors
25842558
.iter()
25852559
.find(|error| error.node_path == node_id_path)
25862560
.map(|error| format!("{:?}", error.error.clone()))
25872561
.or_else(|| {
2588-
if self.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
2562+
if network_interface.resolved_types.node_graph_errors.iter().any(|error| error.node_path.starts_with(&node_id_path)) {
25892563
Some("Node graph type error within this node".to_string())
25902564
} else {
25912565
None
@@ -2768,7 +2742,6 @@ impl Default for NodeGraphMessageHandler {
27682742
fn default() -> Self {
27692743
Self {
27702744
network: Vec::new(),
2771-
node_graph_errors: Vec::new(),
27722745
has_selection: false,
27732746
widgets: [LayoutGroup::Row { widgets: Vec::new() }, LayoutGroup::Row { widgets: Vec::new() }],
27742747
drag_start: None,
@@ -2800,7 +2773,6 @@ impl Default for NodeGraphMessageHandler {
28002773
impl PartialEq for NodeGraphMessageHandler {
28012774
fn eq(&self, other: &Self) -> bool {
28022775
self.network == other.network
2803-
&& self.node_graph_errors == other.node_graph_errors
28042776
&& self.has_selection == other.has_selection
28052777
&& self.widgets == other.widgets
28062778
&& self.drag_start == other.drag_start

0 commit comments

Comments
 (0)