diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 14a9ea5107..f004921ef8 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -89,7 +89,7 @@ pub struct FrontendGraphOutput { // Metadata that is common to nodes and layers #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendNodeMetadata { - #[serde(rename = "node_id")] + #[serde(rename = "nodeId")] pub node_id: NodeId, // TODO: Remove and replace with popup manager system #[serde(rename = "canBeLayer")] diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs b/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs index aae024f91c..60a3357725 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs @@ -72,8 +72,8 @@ impl NodeNetworkInterface { locked: self.is_locked(&node_id, network_path), chain_width: self.chain_width(&node_id, network_path), layer_has_left_border_gap: self.layer_has_left_border_gap(&node_id, network_path), - primary_input_connected_to_layer: self.primary_output_connected_to_layer(&node_id, network_path), - primary_output_connected_to_layer: self.primary_input_connected_to_layer(&node_id, network_path), + primary_input_connected_to_layer: self.primary_input_connected_to_layer(&node_id, network_path), + primary_output_connected_to_layer: self.primary_output_connected_to_layer(&node_id, network_path), }); FrontendNodeOrLayer { node: None, layer } } diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 0c48a672a2..4e45e8e9f9 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -130,20 +130,24 @@ editor.handle.createNode(nodeType, $nodeGraph.contextMenuInformation.contextMenuCoordinates.x, $nodeGraph.contextMenuInformation.contextMenuCoordinates.y); } - function nodeBorderMask(nodeWidth: number, primaryInputExists: boolean, exposedSecondaryInputs: number, primaryOutputExists: boolean, exposedSecondaryOutputs: number): string { - const nodeHeight = Math.max(1 + exposedSecondaryInputs, 1 + exposedSecondaryOutputs) * 24; + function nodeBorderMask(nodeInputs: (FrontendGraphInput | undefined)[], nodeOutputs: (FrontendGraphOutput | undefined)[]): string { + const nodeWidth = 120; + const secondaryInputs = nodeInputs.slice(1).filter((x): x is FrontendGraphInput => x !== undefined); + const secondaryOutputs = nodeOutputs.slice(1); + + const nodeHeight = Math.max(1 + secondaryInputs.length, 1 + secondaryOutputs.length) * 24; const boxes: { x: number; y: number; width: number; height: number }[] = []; // Primary input - if (primaryInputExists) boxes.push({ x: -8, y: 4, width: 16, height: 16 }); + if (nodeInputs[0]) boxes.push({ x: -8, y: 4, width: 16, height: 16 }); // Secondary inputs - for (let i = 0; i < exposedSecondaryInputs; i++) boxes.push({ x: -8, y: 4 + (i + 1) * 24, width: 16, height: 16 }); + for (let i = 0; i < secondaryInputs.length; i++) boxes.push({ x: -8, y: 4 + (i + 1) * 24, width: 16, height: 16 }); // Primary output - if (primaryOutputExists) boxes.push({ x: nodeWidth - 8, y: 4, width: 16, height: 16 }); + if (nodeOutputs[0]) boxes.push({ x: nodeWidth - 8, y: 4, width: 16, height: 16 }); // Exposed outputs - for (let i = 0; i < exposedSecondaryOutputs; i++) boxes.push({ x: nodeWidth - 8, y: 4 + (i + 1) * 24, width: 16, height: 16 }); + for (let i = 0; i < secondaryOutputs.length; i++) boxes.push({ x: nodeWidth - 8, y: 4 + (i + 1) * 24, width: 16, height: 16 }); return borderMask(boxes, nodeWidth, nodeHeight); } @@ -203,11 +207,17 @@ return `Connected to:\n${input.connectedToString}`; } - function zipWithUndefined(arr1: FrontendGraphInput[], arr2: FrontendGraphOutput[]) { - const maxLength = Math.max(arr1.length, arr2.length); - const result = []; + function collectExposedInputsOutputs( + inputs: (FrontendGraphInput | undefined)[], + outputs: (FrontendGraphOutput | undefined)[], + ): [FrontendGraphInput | undefined, FrontendGraphOutput | undefined][] { + const secondaryInputs = inputs.slice(1).filter((x): x is FrontendGraphInput => x !== undefined); + const secondaryOutputs = outputs.slice(1); + const maxLength = Math.max(secondaryInputs.length, secondaryOutputs.length); + const result: [FrontendGraphInput | undefined, FrontendGraphOutput | undefined][] = []; + for (let i = 0; i < maxLength; i++) { - result.push([arr1[i], arr2[i]]); + result.push([secondaryInputs[i] || undefined, secondaryOutputs[i] || undefined]); } return result; } @@ -485,124 +495,118 @@ {/if} - -
- - {#each Array.from($nodeGraph.nodesToRender).filter(([nodeId, node]) => node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) as [nodeId, layer]} - {@const clipPathId = String(Math.random()).substring(2)} - {@const layerAreaWidth = $nodeGraph.layerWidths.get(layer.id) || 8} - {@const layerChainWidth = layer.chainWidth !== 0 ? layer.chainWidth + 0.5 : 0} - {@const description = (layer.reference && $nodeGraph.nodeDescriptions.get(layer.reference)) || undefined} -
- {#if layer.errors} - {layer.errors} - {layer.errors} - {/if} -
- {#if $nodeGraph.thumbnails.has(nodeId)} - {@html $nodeGraph.thumbnails.get(nodeId)} +
+ {#each Array.from($nodeGraph.nodesToRender) as [nodeId, nodeToRender]} + {#if nodeToRender.nodeOrLayer.layer !== undefined} + {@const nodeMetadata = nodeToRender.metadata} + {@const layer = nodeToRender.nodeOrLayer.layer} + {@const clipPathId = String(Math.random()).substring(2)} + {@const layerAreaWidth = $nodeGraph.layerWidths.get(nodeToRender.metadata.nodeId) || 8} + {@const layerChainWidth = layer.chainWidth !== 0 ? layer.chainWidth + 0.5 : 0} + {@const description = (nodeMetadata.reference && $nodeGraph.nodeDescriptions.get(nodeMetadata.reference)) || undefined} +
+ {#if nodeMetadata.errors} + {layer.errors} + {layer.errors} {/if} - - {#if layer.primaryOutput} +
+ {#if $nodeGraph.thumbnails.has(nodeId)} + {@html $nodeGraph.thumbnails.get(nodeId)} + {/if} + - {outputTooltip(layer.primaryOutput)} - {#if layer.primaryOutput.connectedTo.length > 0} - - {#if layer.primaryOutputConnectedToLayer} - - {/if} - {:else} - + {outputTooltip(layer.output)} + 0 ? "var(--data-color)" : "var(--data-color-dim)"} /> + + {#if layer.output.connectedTo.length > 0 && layer.primaryOutputConnectedToLayer} + {/if} - {/if} - - - {#if layer.primaryInput} - {inputTooltip(layer.primaryInput)} - {/if} - {#if layer.primaryInput?.connectedTo !== "nothing"} - - {#if layer.primaryInputConnectedToLayer} - - {/if} - {:else} - - {/if} - -
- - {#if layer.exposedInputs.length > 0} -
+ - {inputTooltip(layer.exposedInputs[0])} - {#if layer.exposedInputs[0].connectedTo !== undefined} - + {#if layer.bottomInput} + {inputTooltip(layer.bottomInput)} + {/if} + {#if layer.bottomInput?.connectedToNode !== undefined} + + {#if layer.primaryInputConnectedToLayer} + + {/if} {:else} - + {/if}
- {/if} -
- - {layer.displayName} + + {#if layer.sideInput} +
+ + {inputTooltip(layer.sideInput)} + + +
+ {/if} +
+ + {nodeMetadata.displayName} +
+
+ { + /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ + }} + tooltip={nodeMetadata.visible ? "Visible" : "Hidden"} + /> + + + + + + + + +
-
- { - /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ - }} - tooltip={layer.visible ? "Visible" : "Hidden"} - /> - - - - - - - - - -
+ {/if} {/each} -
@@ -630,129 +634,96 @@ {/if}
- - - {#each Array.from($nodeGraph.nodesToRender).filter(([nodeId, node]) => !node.isLayer && $nodeGraph.visibleNodes.has(nodeId)) as [nodeId, node]} - {@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)} - {@const clipPathId = String(Math.random()).substring(2)} - {@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined} -
- {#if node.errors} - {node.errors} - {node.errors} - {/if} - -
- - - {node.displayName} -
- - {#if exposedInputsOutputs.length > 0} -
- {#each exposedInputsOutputs as [input, output]} -
- - {input !== undefined ? input.name : output.name} - -
+ {#each Array.from($nodeGraph.nodesToRender) as [nodeId, nodeToRender]} + {#if nodeToRender.nodeOrLayer.node !== undefined && $nodeGraph.visibleNodes.has(nodeId)} + {@const nodeMetadata = nodeToRender.metadata} + {@const node = nodeToRender.nodeOrLayer.node} + {@const exposedInputsOutputs = collectExposedInputsOutputs(node.inputs, node.outputs)} + {@const clipPathId = String(Math.random()).substring(2)} + {@const description = (nodeMetadata.reference && $nodeGraph.nodeDescriptions.get(nodeMetadata.reference)) || undefined} +
+ {#if nodeMetadata.errors} + {node.errors} + {node.errors} + {/if} + +
+ + + {nodeMetadata.displayName} +
+ + {#if exposedInputsOutputs.length > 0} +
+ {#each exposedInputsOutputs as [input, output]} +
+ + {input?.name ?? output?.name ?? ""} + +
+ {/each} +
+ {/if} + +
+ {#each node.inputs as input} + {#if input !== undefined} + + {inputTooltip(input)} + + + {/if} {/each}
- {/if} - -
- {#if node.primaryInput?.dataType} - - {inputTooltip(node.primaryInput)} - {#if node.primaryInput.connectedTo !== undefined} - - {:else} - + +
+ {#each node.outputs as output} + {#if output !== undefined} + + {outputTooltip(output)} + + {/if} - - {/if} - {#each node.exposedInputs as secondary, index} - {#if index < node.exposedInputs.length} - - {inputTooltip(secondary)} - {#if secondary.connectedTo !== undefined} - - {:else} - - {/if} - - {/if} - {/each} + {/each} +
+ + + + + + +
- -
- {#if node.primaryOutput} - - {outputTooltip(node.primaryOutput)} - {#if node.primaryOutput.connectedTo !== undefined} - - {:else} - - {/if} - - {/if} - {#each node.exposedOutputs as secondary} - - {outputTooltip(secondary)} - {#if secondary.connectedTo !== undefined} - - {:else} - - {/if} - - {/each} -
- - - - - - - -
+ {/if} {/each}
@@ -1095,6 +1066,8 @@ // Keeps the connectors above the wires z-index: 1; + margin-top: -24px; + &.input { left: -3px; }