From e6172b06481e224372b021e60a388efe96deffcf Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Mon, 8 May 2023 02:52:04 -0500 Subject: [PATCH] Fix changed events for widget nodes Need an internal delay to ensure graph has finished processing --- litegraph | 2 +- src/lib/nodes/ComfyActionNodes.ts | 16 ++++----- src/lib/nodes/ComfyWidgetNodes.ts | 52 +++++++++++++++++++++++------- src/lib/widgets/RadioWidget.svelte | 4 +-- src/scss/ux.scss | 19 ++++++----- 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/litegraph b/litegraph index a6d94ec..b7ebbf5 160000 --- a/litegraph +++ b/litegraph @@ -1 +1 @@ -Subproject commit a6d94ecb4dcb771f8c9870c29f7cb53f153f93cf +Subproject commit b7ebbf57d3b08a1a859809f8f95e1c37e841406a diff --git a/src/lib/nodes/ComfyActionNodes.ts b/src/lib/nodes/ComfyActionNodes.ts index 55e1e7b..383b3b0 100644 --- a/src/lib/nodes/ComfyActionNodes.ts +++ b/src/lib/nodes/ComfyActionNodes.ts @@ -5,7 +5,7 @@ import queueState from "$lib/stores/queueState"; import { BuiltInSlotType, LiteGraph, NodeMode, type ITextWidget, type IToggleWidget, type SerializedLGraphNode, type SlotLayout } from "@litegraph-ts/core"; import { get } from "svelte/store"; import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"; -import type { GalleryOutput } from "./ComfyWidgetNodes"; +import type { ComfyWidgetNode, GalleryOutput } from "./ComfyWidgetNodes"; export class ComfyQueueEvents extends ComfyGraphNode { static slotLayout: SlotLayout = { @@ -272,7 +272,6 @@ export class ComfySetNodeModeAction extends ComfyGraphNode { constructor(title?: string) { super(title) this.displayWidget = this.addWidget("text", "Tags", this.properties.targetTags, "targetTags") - this.enableWidget = this.addWidget("toggle", "Enable", this.properties.enable, "enable") } override onPropertyChanged(property: any, value: any) { @@ -281,14 +280,9 @@ export class ComfySetNodeModeAction extends ComfyGraphNode { } } - override onExecute() { - const enabled = this.getInputData(0) - if (typeof enabled === "boolean") - this.setProperty("enabled", enabled) - } - override onAction(action: any, param: any) { - let enabled = this.properties.enabled + let enabled = this.getInputData(0) + if (typeof param === "object" && "enabled" in param) enabled = param["enabled"] @@ -305,7 +299,10 @@ export class ComfySetNodeModeAction extends ComfyGraphNode { } else { newMode = NodeMode.NEVER; } + console.warn("CHANGEMODE", newMode == NodeMode.ALWAYS ? "ALWAYS" : "NEVER", tags, node) node.changeMode(newMode); + if ("notifyPropsChanged" in node) + (node as ComfyWidgetNode).notifyPropsChanged(); } } } @@ -316,7 +313,6 @@ export class ComfySetNodeModeAction extends ComfyGraphNode { const hasTag = tags.some(t => container.attrs.tags.indexOf(t) != -1); if (hasTag) { container.attrs.hidden = !enabled; - console.warn("Cont", container.attrs.tags, tags, hasTag, container.attrs, enabled) } container.attrsChanged.set(get(container.attrsChanged) + 1) } diff --git a/src/lib/nodes/ComfyWidgetNodes.ts b/src/lib/nodes/ComfyWidgetNodes.ts index 1dd90e2..7513566 100644 --- a/src/lib/nodes/ComfyWidgetNodes.ts +++ b/src/lib/nodes/ComfyWidgetNodes.ts @@ -52,6 +52,16 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { copyFromInputLink: boolean = true; + /** + * If true wait until next frame update to trigger the changed event. + * Reason is, if the event is triggered immediately then other stuff that wants to run + * their own onExecute on the output value won't have completed yet. + */ + delayChangedEvent: boolean = true; + + private _aboutToChange: number = 0; + private _aboutToChangeValue: any = null; + abstract defaultValue: T; /** Names of properties to add as inputs */ @@ -109,11 +119,6 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { override changeMode(modeTo: NodeMode): boolean { const result = super.changeMode(modeTo); this.notifyPropsChanged(); - // Also need to notify the parent container since it's what controls the - // hidden state of the widget - // const layoutEntry = layoutState.findLayoutEntryForNode(this.id) - // if (layoutEntry && layoutEntry.parent) - // layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1) return result; } @@ -124,13 +129,23 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { if (this.outputIndex !== null && this.outputs.length >= this.outputIndex) { this.setOutputData(this.outputIndex, get(this.value)) } + if (this.changedIndex !== null && this.outputs.length >= this.changedIndex) { - const changedOutput = this.outputs[this.changedIndex] - if (changedOutput.type === BuiltInSlotType.EVENT) - this.triggerSlot(this.changedIndex, get(this.value)) + if (!this.delayChangedEvent) + this.triggerChangeEvent(get(this.value)) + else { + this._aboutToChange = 2; // wait 1.5-2 frames, in case we're already in the middle of one + this._aboutToChangeValue = get(this.value); + } } } + private triggerChangeEvent(value: any) { + const changedOutput = this.outputs[this.changedIndex] + if (changedOutput.type === BuiltInSlotType.EVENT) + this.triggerSlot(this.changedIndex, value) + } + setValue(value: any) { this.value.set(value) } @@ -160,6 +175,18 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { const data = this.shownOutputProperties[propName] this.setOutputData(data.index, this.properties[propName]) } + + // Fire a pending change event after one full step of the graph has + // finished processing + if (this._aboutToChange > 0) { + this._aboutToChange -= 1 + if (this._aboutToChange <= 0) { + const value = this._aboutToChangeValue; + this._aboutToChange = 0; + this._aboutToChangeValue = null; + this.triggerChangeEvent(value); + } + } } onConnectOutput( @@ -199,8 +226,13 @@ export abstract class ComfyWidgetNode extends ComfyGraphNode { } notifyPropsChanged() { + const layoutEntry = layoutState.findLayoutEntryForNode(this.id) + if (layoutEntry && layoutEntry.parent) { + layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1) + } console.debug("propsChanged", this) this.propsChanged.set(get(this.propsChanged) + 1) + } override onConnectionsChange( @@ -700,11 +732,9 @@ export class ComfyRadioNode extends ComfyWidgetNode { this.index = index; this.indexWidget.value = index; + this.setOutputData(1, this.index) - const changed = value != get(this.value); super.setValue(value) - if (changed) - this.triggerSlot(2, { value: value, index: index }) } } diff --git a/src/lib/widgets/RadioWidget.svelte b/src/lib/widgets/RadioWidget.svelte index f33f5f7..c22eef9 100644 --- a/src/lib/widgets/RadioWidget.svelte +++ b/src/lib/widgets/RadioWidget.svelte @@ -32,8 +32,7 @@ } function onSelect(e: CustomEvent) { - $nodeValue = e.detail.value - node.setValue($nodeValue) + node.setValue(e.detail.value) node.index = e.detail.index as number navigator.vibrate(20) } @@ -50,6 +49,7 @@ choices={node.properties.choices} disabled={isDisabled(widget)} label={widget.attrs.title} + show_label={widget.attrs.title && widget.attrs.title !== ""} value={$nodeValue} on:select={onSelect} /> diff --git a/src/scss/ux.scss b/src/scss/ux.scss index 9f9f534..b0a696f 100644 --- a/src/scss/ux.scss +++ b/src/scss/ux.scss @@ -173,14 +173,17 @@ body { background: var(--ae-panel-bg-color) !important; } -.container { - .z-index0, .z-index1, .z-index2 { - > .block > .v-pane > .animation-wrapper > .widget:not(.edit) { - padding: var(--ae-inside-padding-size) !important; - border: 1px solid var(--ae-panel-border-color) !important; - } - } -} +// Add blocks for components not located in a physical container +// TODO make it work with accordions/tabs +// .container { +// .z-index0, .z-index1, .z-index2 { +// > .block > .v-pane > .animation-wrapper > .widget:not(.edit) { +// padding: var(--ae-inside-padding-size) !important; +// border: 1px solid var(--ae-panel-border-color) !important; +// } +// } +// } + .widget:has(> .gradio-button) { height: 100%;