{#if $nodeGraph.contextMenuInformation} {#if $nodeGraph.contextMenuInformation.contextMenuData.type === "CreateNode"} createNode(e.detail)} /> {:else if $nodeGraph.contextMenuInformation.contextMenuData.type === "ModifyNode"} { editor.mergeSelectedNodes(); closeContextMenu(); }} flush={true} /> {@const currentlyIsNode = $nodeGraph.contextMenuInformation.contextMenuData.data.currentlyIsNode} { if ($nodeGraph.contextMenuInformation?.contextMenuData.type === "ModifyNode") { editor.setToNodeOrLayer($nodeGraph.contextMenuInformation.contextMenuData.data.nodeId, currentlyIsNode); } closeContextMenu(); }} disabled={!$nodeGraph.contextMenuInformation.contextMenuData.data.canBeLayer} flush={true} /> {#if $nodeGraph.contextMenuInformation.contextMenuData.data.hasSelectedLayers} {@const allLocked = $nodeGraph.contextMenuInformation.contextMenuData.data.allSelectedLayersLocked} {@const nodeId = $nodeGraph.contextMenuInformation.contextMenuData.data.nodeId} { if ($nodeGraph.selected.includes(nodeId)) { editor.toggleSelectedLocked(); } else { editor.toggleLayerLock(nodeId); } closeContextMenu(); }} flush={true} /> {/if} {/if} {/if} {#if $nodeGraph.error}
{$nodeGraph.error.error} {$nodeGraph.error.error}
{/if} {#if $nodeGraph.clickTargets}
{#each $nodeGraph.clickTargets.nodeClickTargets as pathString} {/each} {#each $nodeGraph.clickTargets.layerClickTargets as pathString} {/each} {#each $nodeGraph.clickTargets.connectorClickTargets as pathString} {/each} {#each $nodeGraph.clickTargets.iconClickTargets as pathString} {/each} {#each $nodeGraph.clickTargets.modifyImportExport as pathString} {/each}
{/if}
{#each $nodeGraphWires.values() as map} {#each map.values() as { pathString, centerPathString, dataType, thick, dashed }} {#if thick} {/if} {/each} {/each}
{#if $nodeGraphImportsExports} {#each $nodeGraphImportsExports.imports as frontendOutput, index} {#if frontendOutput} {#if frontendOutput.connectedTo.length > 0} {:else} {/if}
(hoveringImportIndex = index)} on:pointerleave={() => (hoveringImportIndex = undefined)} class="edit-import-export import" class:separator-bottom={index === 0 && $nodeGraphImportsExports.addImportExport} class:separator-top={index === 1 && $nodeGraphImportsExports.addImportExport} style:--offset-left={($nodeGraphImportsExports.importPosition[0] - 8) / 24} style:--offset-top={($nodeGraphImportsExports.importPosition[1] - 8) / 24 + index} > {#if editingNameImportIndex === index} e.key === "Enter" && setEditingImportName(e)} /> {:else}

setEditingImportNameIndex(index, frontendOutput.name)}> {frontendOutput.name}

{/if} {#if (hoveringImportIndex === index || editingNameImportIndex === index) && $nodeGraphImportsExports.addImportExport} { /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ }} /> {#if index > 0}
{/if} {/if}
{:else}
editor.addPrimaryImport()} />
{/if} {/each} {#each $nodeGraphImportsExports.exports as frontendInput, index} {#if frontendInput} {#if frontendInput.connectedTo !== "Connected to nothing."} {:else} {/if}
(hoveringExportIndex = index)} on:pointerleave={() => (hoveringExportIndex = undefined)} class="edit-import-export export" class:separator-bottom={index === 0 && $nodeGraphImportsExports.addImportExport} class:separator-top={index === 1 && $nodeGraphImportsExports.addImportExport} style:--offset-left={($nodeGraphImportsExports.exportPosition[0] - 8) / 24} style:--offset-top={($nodeGraphImportsExports.exportPosition[1] - 8) / 24 + index} > {#if (hoveringExportIndex === index || editingNameExportIndex === index) && $nodeGraphImportsExports.addImportExport} {#if index > 0}
{/if} { /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ }} /> {/if} {#if editingNameExportIndex === index} e.key === "Enter" && setEditingExportName(e)} /> {:else}

setEditingExportNameIndex(index, frontendInput.name)}> {frontendInput.name}

{/if}
{:else}
editor.addPrimaryExport()} />
{/if} {/each} {#if $nodeGraphImportsExports.addImportExport}
editor.addSecondaryImport()} />
editor.addSecondaryExport()} />
{/if} {#if $nodeGraph.reorderImportIndex !== undefined} {@const position = { x: Number($nodeGraphImportsExports.importPosition[0]), y: Number($nodeGraphImportsExports.importPosition[1]) + Number($nodeGraph.reorderImportIndex) * 24, }}
{/if} {#if $nodeGraph.reorderExportIndex !== undefined} {@const position = { x: Number($nodeGraphImportsExports.exportPosition[0]), y: Number($nodeGraphImportsExports.exportPosition[1]) + Number($nodeGraph.reorderExportIndex) * 24, }}
{/if} {/if}
{#each Array.from($nodeGraph.nodes) .filter(([nodeId, node]) => node.isLayer && $visibleNodes.has(nodeId)) .map(([_, node]) => node) as node (node.id)} {@const clipPathId = String(Math.random()).substring(2)} {@const stackDataInput = node.exposedInputs[0]} {@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8} {@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0} {@const hasLeftInputWire = $nodeGraph.hasLeftInputWire.get(node.id) || false} {@const description = node.reference ? $nodeGraph.nodeDescriptions.get(node.reference) : undefined}
{#if $nodeGraph.thumbnails.has(node.id)} {@html $nodeGraph.thumbnails.get(node.id)} {/if} {#if node.primaryOutput} {#if node.primaryOutput.connectedTo.length > 0} {#if node.primaryOutputConnectedToLayer} {/if} {:else} {/if} {/if} {#if node.primaryInput?.connectedTo !== "Connected to nothing."} {#if node.primaryInputConnectedToLayer} {/if} {:else} {/if}
{#if node.exposedInputs.length > 0}
{#if stackDataInput.connectedTo !== undefined} {:else} {/if}
{/if}
{#if editingNameNodeId === node.id} { // Stop propagation when we handle the key ourselves so the global keyboard forwarder (`shouldRedirectKeyboardEventToBackend`) doesn't also dispatch them. // Its Escape carve-out would otherwise close the graph view, and Enter could trigger unrelated bindings. if (e.key === "Enter") { commitEditingNodeName(e); e.stopPropagation(); } else if (e.key === "Escape") { editingNameNodeId = undefined; e.stopPropagation(); } }} /> {:else} {node.displayName} {/if}
{#if node.locked} { /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ }} tooltipLabel="Unlock" /> {/if} { /* Button is purely visual, clicking is handled in NodeGraphMessage::PointerDown */ }} tooltipLabel={node.visible ? "Hide" : "Show"} />
{/each}
{#each $nodeGraphWires.values() as map} {#each map.values() as { pathString, dataType, thick, dashed, isList }} {#if !thick} {#if isList} {:else} {/if} {/if} {/each} {/each} {#if $nodeGraph.wirePathInProgress} {/if}
{#each Array.from($nodeGraph.nodes) .filter(([nodeId, node]) => !node.isLayer && $visibleNodes.has(nodeId)) .map(([_, node]) => node) as node (node.id)} {@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)} {@const clipPathId = String(Math.random()).substring(2)} {@const description = node.reference ? $nodeGraph.nodeDescriptions.get(node.reference) : undefined}
{node.displayName}
{#if exposedInputsOutputs.length > 0}
{#each exposedInputsOutputs as [input, output]}
{input !== undefined ? input.name : output.name}
{/each}
{/if}
{#if node.primaryInput?.dataType} {#if node.primaryInput.connectedTo !== undefined} {:else} {/if} {/if} {#each node.exposedInputs as secondary, index} {#if index < node.exposedInputs.length} {#if secondary.connectedTo !== undefined} {:else} {/if} {/if} {/each}
{#if node.primaryOutput} {#if node.primaryOutput.connectedTo !== undefined} {:else} {/if} {/if} {#each node.exposedOutputs as secondary} {#if secondary.connectedTo !== undefined} {:else} {/if} {/each}
{/each}
{#if $nodeGraph.box}
{/if}