diff --git a/frontend/src/lib/components/graph/Graph.svelte b/frontend/src/lib/components/graph/Graph.svelte index df3246c..98a2a7b 100644 --- a/frontend/src/lib/components/graph/Graph.svelte +++ b/frontend/src/lib/components/graph/Graph.svelte @@ -522,10 +522,11 @@ event.key === "x") && bodyIsFocused ) { + graph.startUndoGroup(); if ($activeNodeId !== -1) { const node = graph.getNode($activeNodeId); if (node) { - graph.removeNode(node); + graph.removeNode(node, { restoreEdges: event.ctrlKey }); $activeNodeId = -1; } } @@ -533,12 +534,13 @@ for (const nodeId of $selectedNodes) { const node = graph.getNode(nodeId); if (node) { - graph.removeNode(node); + graph.removeNode(node, { restoreEdges: event.ctrlKey }); } } $selectedNodes.clear(); $selectedNodes = $selectedNodes; } + graph.saveUndoGroup(); } } diff --git a/frontend/src/lib/components/graph/GraphView.svelte b/frontend/src/lib/components/graph/GraphView.svelte index 2fdc6ac..5f16f60 100644 --- a/frontend/src/lib/components/graph/GraphView.svelte +++ b/frontend/src/lib/components/graph/GraphView.svelte @@ -79,6 +79,6 @@ height: 0px; transform: scale(calc(var(--cz) * 0.1)); display: var(--node-display, block); - opacity: calc((var(--cz) - 2) / 5); + opacity: calc((var(--cz) - 2.5) / 3.5); } diff --git a/frontend/src/lib/graph-manager.ts b/frontend/src/lib/graph-manager.ts index b9ce070..a2b9d6c 100644 --- a/frontend/src/lib/graph-manager.ts +++ b/frontend/src/lib/graph-manager.ts @@ -18,6 +18,8 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { private _edges: Edge[] = []; edges: Writable = writable([]); + currentUndoGroup: number | null = null; + inputSockets: Writable> = writable(new Set()); history: HistoryManager = new HistoryManager(this); @@ -188,9 +190,31 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { } } - removeNode(node: Node) { - const edges = this._edges.filter((edge) => edge[0].id !== node.id && edge[2].id !== node.id); - this.edges.set(edges); + removeNode(node: Node, { restoreEdges = false } = {}) { + + const edgesToNode = this._edges.filter((edge) => edge[2].id === node.id); + const edgesFromNode = this._edges.filter((edge) => edge[0].id === node.id); + for (const edge of [...edgesToNode, ...edgesFromNode]) { + this.removeEdge(edge, { applyDeletion: false }); + } + + if (restoreEdges) { + const outputSockets = edgesToNode.map(e => [e[0], e[1]] as const); + const inputSockets = edgesFromNode.map(e => [e[2], e[3]] as const); + + for (const [to, toSocket] of inputSockets) { + for (const [from, fromSocket] of outputSockets) { + const outputType = from.tmp?.type?.outputs?.[fromSocket]; + const inputType = to?.tmp?.type?.inputs?.[toSocket]?.type; + if (outputType === inputType) { + this.createEdge(from, fromSocket, to, toSocket, { applyUpdate: false }); + continue; + } + } + } + } + + this.edges.set(this._edges); this.nodes.update((nodes) => { nodes.delete(node.id); @@ -222,7 +246,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { this.save(); } - createEdge(from: Node, fromSocket: number, to: Node, toSocket: string) { + createEdge(from: Node, fromSocket: number, to: Node, toSocket: string, { applyUpdate = true } = {}) { const existingEdges = this.getEdgesToNode(to); @@ -245,12 +269,16 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { const edgeToBeReplaced = this._edges.find(e => e[2].id === to.id && e[3] === toSocket); if (edgeToBeReplaced) { - this.removeEdge(edgeToBeReplaced); + this.removeEdge(edgeToBeReplaced, { applyDeletion: applyUpdate }); } - this.edges.update((edges) => { - return [...edges, [from, fromSocket, to, toSocket]]; - }); + if (applyUpdate) { + this.edges.update((edges) => { + return [...edges, [from, fromSocket, to, toSocket]]; + }); + } else { + this._edges.push([from, fromSocket, to, toSocket]); + } from.tmp = from.tmp || {}; from.tmp.children = from.tmp.children || []; @@ -261,10 +289,22 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { to.tmp.parents.push(from); this.execute(); + if (applyUpdate) { + this.save(); + } + } + + startUndoGroup() { + this.currentUndoGroup = 1; + } + + saveUndoGroup() { + this.currentUndoGroup = null; this.save(); } save() { + if (this.currentUndoGroup) return; this.emit("save", this.serialize()); this.history.save(); } @@ -341,7 +381,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { } - removeEdge(edge: Edge) { + removeEdge(edge: Edge, { applyDeletion = true }: { applyDeletion?: boolean } = {}) { const id0 = edge[0].id; const sid0 = edge[1]; const id2 = edge[2].id; @@ -350,10 +390,6 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { const _edge = this._edges.find((e) => e[0].id === id0 && e[1] === sid0 && e[2].id === id2 && e[3] === sid2); if (!_edge) return; - this.edges.update((edges) => { - return edges.filter(e => e !== _edge); - }); - edge[0].tmp = edge[0].tmp || {}; if (edge[0].tmp.children) { edge[0].tmp.children = edge[0].tmp.children.filter(n => n.id !== id2); @@ -364,8 +400,16 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { edge[2].tmp.parents = edge[2].tmp.parents.filter(n => n.id !== id0); } - this.execute(); - this.save(); + if (applyDeletion) { + this.edges.update((edges) => { + return edges.filter(e => e !== _edge); + }); + this.execute(); + this.save(); + } else { + this._edges = this._edges.filter(e => e !== _edge); + } + } getEdgesToNode(node: Node) { @@ -402,7 +446,6 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> { throw new Error(`Template not found: ${template}`); } - } }