diff --git a/src/lib/graphSync.ts b/src/lib/graphSync.ts index e13161f..de355d5 100644 --- a/src/lib/graphSync.ts +++ b/src/lib/graphSync.ts @@ -1,5 +1,5 @@ import type { LGraph } from "@litegraph-ts/core"; -import widgetState, { type WidgetStateStore, type WidgetUIStateStore } from "./stores/widgetState"; +import widgetState, { type WidgetStateStore, type WidgetUIState, type WidgetUIStateStore } from "./stores/widgetState"; import type ComfyApp from "./components/ComfyApp"; import type { Unsubscriber } from "svelte/store"; @@ -9,12 +9,18 @@ type WidgetSubStore = { } /* - * Responsible for watching and synchronizing state changes from the frontend to the litegraph instance. - * The other way around is unnecessary since the nodes in ComfyBox can't be interacted with. + * Responsible for watching for and synchronizing state changes from the + * frontend to the litegraph instance. + * + * The other way around is unnecessary since the nodes in ComfyBox can't be + * interacted with. If that were true the implementation would be way more + * complex since litegraph doesn't (currently) expose a global + * event-emitter-like thing for when nodes/widgets are changed. * * Assumptions: - * - Widgets can't be added to a node after they're created + * - Widgets can't be added to a node after they're created (messes up the indices in WidgetSubStore[]) * - Widgets can't be interacted with from the graph, only from the frontend + * - Only one workflow/graph can ever be loaded into the program */ export default class GraphSync { graph: LGraph; @@ -26,18 +32,19 @@ export default class GraphSync { constructor(app: ComfyApp) { this.graph = app.lGraph; - this._unsubscribe = widgetState.subscribe(this.onWidgetStateChanged.bind(this)); + this._unsubscribe = widgetState.subscribe(this.onAllWidgetStateChanged.bind(this)); this._finalizer = new FinalizationRegistry((id: number) => { console.log(`${this} has been garbage collected`); this._unsubscribe(); }); } - private onWidgetStateChanged(state: WidgetStateStore) { + /* + * Fired when the entire widget graph changes. + */ + private onAllWidgetStateChanged(state: WidgetStateStore) { // TODO assumes only a single graph's widget state. - console.warn("ONWIDGETSTATECHANGE") - for (let nodeId in state) { if (!this.stores[nodeId]) { this.addStores(state, nodeId); @@ -59,10 +66,8 @@ export default class GraphSync { this.stores[nodeId] = [] for (const wuis of state[nodeId]) { - const unsub = wuis.value.subscribe((v) => { - console.log("CHANGE", v) - }) - this.stores[nodeId].push({ store: wuis.value, unsubscribe: unsub }); + const unsub = wuis.value.subscribe((v) => this.onWidgetStateChanged(wuis, v)) + this.stores[nodeId].push({ store: wuis.vlue, unsubscribe: unsub }); } console.log("NEWSTORES", this.stores[nodeId]) @@ -75,4 +80,12 @@ export default class GraphSync { } delete this.stores[nodeId] } + + /* + * Fired when a single widget's value changes. + */ + private onWidgetStateChanged(wuis: WidgetUIState, value: any) { + wuis.widget.value = value; + this.graph.setDirtyCanvas(true, true); + } } diff --git a/src/lib/stores/widgetState.ts b/src/lib/stores/widgetState.ts index 8cfe616..027646f 100644 --- a/src/lib/stores/widgetState.ts +++ b/src/lib/stores/widgetState.ts @@ -10,9 +10,19 @@ import { subStore } from "immer-loves-svelte" export type WidgetUIStateStore = Writable export type WidgetUIState = { + /** position in the node's list of widgets */ + index: number, + /** parent node containing the widget */ node: LGraphNode, + /** actual widget instance */ widget: IWidget, + /** widget value as a store, to react to changes */ value: WidgetUIStateStore, + /** + * true if this widget was added purely from the frontend. what this means: + * - this widget's state will not be saved to the workflow + * - the widget was added on startup by some subclass of ComfyGraphNode + */ isVirtual: boolean } diff --git a/src/lib/widgets/ComboWidget.svelte b/src/lib/widgets/ComboWidget.svelte index 21e70b6..b00b47c 100644 --- a/src/lib/widgets/ComboWidget.svelte +++ b/src/lib/widgets/ComboWidget.svelte @@ -9,18 +9,23 @@ let option: any; $: if(item) { - option = get(item.value); - itemValue = item.value + if (!itemValue) + itemValue = item.value; + if (!option) + option = get(item.value); }; + + $: if (option && itemValue) { + $itemValue = option.value + }
- {#if item} + {#if item && $itemValue}