Fix changed events for widget nodes

Need an internal delay to ensure graph has finished processing
This commit is contained in:
space-nuko
2023-05-08 02:52:04 -05:00
parent 2d8b121fb3
commit e6172b0648
5 changed files with 61 additions and 32 deletions

View File

@@ -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 { BuiltInSlotType, LiteGraph, NodeMode, type ITextWidget, type IToggleWidget, type SerializedLGraphNode, type SlotLayout } from "@litegraph-ts/core";
import { get } from "svelte/store"; import { get } from "svelte/store";
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode"; import ComfyGraphNode, { type ComfyGraphNodeProperties } from "./ComfyGraphNode";
import type { GalleryOutput } from "./ComfyWidgetNodes"; import type { ComfyWidgetNode, GalleryOutput } from "./ComfyWidgetNodes";
export class ComfyQueueEvents extends ComfyGraphNode { export class ComfyQueueEvents extends ComfyGraphNode {
static slotLayout: SlotLayout = { static slotLayout: SlotLayout = {
@@ -272,7 +272,6 @@ export class ComfySetNodeModeAction extends ComfyGraphNode {
constructor(title?: string) { constructor(title?: string) {
super(title) super(title)
this.displayWidget = this.addWidget("text", "Tags", this.properties.targetTags, "targetTags") 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) { 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) { override onAction(action: any, param: any) {
let enabled = this.properties.enabled let enabled = this.getInputData(0)
if (typeof param === "object" && "enabled" in param) if (typeof param === "object" && "enabled" in param)
enabled = param["enabled"] enabled = param["enabled"]
@@ -305,7 +299,10 @@ export class ComfySetNodeModeAction extends ComfyGraphNode {
} else { } else {
newMode = NodeMode.NEVER; newMode = NodeMode.NEVER;
} }
console.warn("CHANGEMODE", newMode == NodeMode.ALWAYS ? "ALWAYS" : "NEVER", tags, node)
node.changeMode(newMode); 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); const hasTag = tags.some(t => container.attrs.tags.indexOf(t) != -1);
if (hasTag) { if (hasTag) {
container.attrs.hidden = !enabled; container.attrs.hidden = !enabled;
console.warn("Cont", container.attrs.tags, tags, hasTag, container.attrs, enabled)
} }
container.attrsChanged.set(get(container.attrsChanged) + 1) container.attrsChanged.set(get(container.attrsChanged) + 1)
} }

View File

@@ -52,6 +52,16 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
copyFromInputLink: boolean = true; 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; abstract defaultValue: T;
/** Names of properties to add as inputs */ /** Names of properties to add as inputs */
@@ -109,11 +119,6 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
override changeMode(modeTo: NodeMode): boolean { override changeMode(modeTo: NodeMode): boolean {
const result = super.changeMode(modeTo); const result = super.changeMode(modeTo);
this.notifyPropsChanged(); 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; return result;
} }
@@ -124,13 +129,23 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
if (this.outputIndex !== null && this.outputs.length >= this.outputIndex) { if (this.outputIndex !== null && this.outputs.length >= this.outputIndex) {
this.setOutputData(this.outputIndex, get(this.value)) this.setOutputData(this.outputIndex, get(this.value))
} }
if (this.changedIndex !== null && this.outputs.length >= this.changedIndex) { if (this.changedIndex !== null && this.outputs.length >= this.changedIndex) {
const changedOutput = this.outputs[this.changedIndex] if (!this.delayChangedEvent)
if (changedOutput.type === BuiltInSlotType.EVENT) this.triggerChangeEvent(get(this.value))
this.triggerSlot(this.changedIndex, 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) { setValue(value: any) {
this.value.set(value) this.value.set(value)
} }
@@ -160,6 +175,18 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
const data = this.shownOutputProperties[propName] const data = this.shownOutputProperties[propName]
this.setOutputData(data.index, this.properties[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( onConnectOutput(
@@ -199,8 +226,13 @@ export abstract class ComfyWidgetNode<T = any> extends ComfyGraphNode {
} }
notifyPropsChanged() { notifyPropsChanged() {
const layoutEntry = layoutState.findLayoutEntryForNode(this.id)
if (layoutEntry && layoutEntry.parent) {
layoutEntry.parent.attrsChanged.set(get(layoutEntry.parent.attrsChanged) + 1)
}
console.debug("propsChanged", this) console.debug("propsChanged", this)
this.propsChanged.set(get(this.propsChanged) + 1) this.propsChanged.set(get(this.propsChanged) + 1)
} }
override onConnectionsChange( override onConnectionsChange(
@@ -700,11 +732,9 @@ export class ComfyRadioNode extends ComfyWidgetNode<string> {
this.index = index; this.index = index;
this.indexWidget.value = index; this.indexWidget.value = index;
this.setOutputData(1, this.index)
const changed = value != get(this.value);
super.setValue(value) super.setValue(value)
if (changed)
this.triggerSlot(2, { value: value, index: index })
} }
} }

View File

@@ -32,8 +32,7 @@
} }
function onSelect(e: CustomEvent<SelectData>) { function onSelect(e: CustomEvent<SelectData>) {
$nodeValue = e.detail.value node.setValue(e.detail.value)
node.setValue($nodeValue)
node.index = e.detail.index as number node.index = e.detail.index as number
navigator.vibrate(20) navigator.vibrate(20)
} }
@@ -50,6 +49,7 @@
choices={node.properties.choices} choices={node.properties.choices}
disabled={isDisabled(widget)} disabled={isDisabled(widget)}
label={widget.attrs.title} label={widget.attrs.title}
show_label={widget.attrs.title && widget.attrs.title !== ""}
value={$nodeValue} value={$nodeValue}
on:select={onSelect} on:select={onSelect}
/> />

View File

@@ -173,14 +173,17 @@ body {
background: var(--ae-panel-bg-color) !important; background: var(--ae-panel-bg-color) !important;
} }
.container { // Add blocks for components not located in a physical container
.z-index0, .z-index1, .z-index2 { // TODO make it work with accordions/tabs
> .block > .v-pane > .animation-wrapper > .widget:not(.edit) { // .container {
padding: var(--ae-inside-padding-size) !important; // .z-index0, .z-index1, .z-index2 {
border: 1px solid var(--ae-panel-border-color) !important; // > .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) { .widget:has(> .gradio-button) {
height: 100%; height: 100%;