From 2db6c4d73a40dfebc4e5f64fffbea0ecc25643fc Mon Sep 17 00:00:00 2001 From: rgthree Date: Sat, 4 May 2024 21:31:07 -0400 Subject: [PATCH] When a relay has no inputs connected, use its own mode change as the relay signal. --- README.md | 19 +++++- src_web/comfyui/base_node.ts | 5 +- src_web/comfyui/node_mode_relay.ts | 87 ++++++++++++++++++--------- src_web/comfyui/node_mode_repeater.ts | 5 +- web/comfyui/base_node.js | 5 +- web/comfyui/node_mode_relay.js | 75 ++++++++++++++--------- web/comfyui/node_mode_repeater.js | 4 +- 7 files changed, 132 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 51ac5d6..2f6dffb 100644 --- a/README.md +++ b/README.md @@ -238,10 +238,25 @@ Note, you can right-click on a bunch of the rgthree-comfy nodes and select `🛟 ## Mute / Bypass Relay -> An advanced node that, when working with a **Mute / Bypass Repeater** will relay a mute/bypass/activate signal to the repeater +> An advanced node that, when working with a **Mute / Bypass Repeater**, will relay its input nodes' +> modes (Mute, Bypass, or Active) to a connected repeater (which would then repeat that mode change +> to all of its inputs). >
> â„šī¸ More Information -> - Useful when you want a specific node or set of nodes to be muted when a different set of nodes are also muted. +> +> - When all connected input nodes are muted, the relay will set a connected repeater to mute (by +> default). +> - When all connected input nodes are bypassed, the relay will set a connected repeater to +> bypass (by default). +> - When _any_ connected input nodes are active, the relay will set a connected repeater to +> active (by default). +> - **Note:** If no inputs are connected, the relay will set a connected repeater to its mode +> _when its own mode is changed_. **Note**, if any inputs are connected, then the above bullets +> will occur and the Relay's mode does not matter. +> - **Pro Tip:** You can change which signals get sent on the above in the `Properties`. +> For instance, you could configure an inverse relay which will send a MUTE when any of its +> inputs are active (instead of sending an ACTIVE signal), and send an ACTIVE signal when all +> of its inputs are muted (instead of sending a MUTE signal), etc. >
diff --git a/src_web/comfyui/base_node.ts b/src_web/comfyui/base_node.ts index eeea3d4..2a64941 100644 --- a/src_web/comfyui/base_node.ts +++ b/src_web/comfyui/base_node.ts @@ -138,8 +138,9 @@ export abstract class RgthreeBaseNode extends LGraphNode { // @ts-ignore - Changing the property to an accessor here seems to work, but ts compiler complains. override set mode(mode: NodeMode) { if (this.mode_ != mode) { + const oldMode = this.mode_; this.mode_ = mode; - this.onModeChange(); + this.onModeChange(oldMode, mode); } } override get mode() { @@ -147,7 +148,7 @@ export abstract class RgthreeBaseNode extends LGraphNode { } /** When a mode change, we want all connected nodes to match. */ - onModeChange() { + onModeChange(from: NodeMode, to: NodeMode) { // Override } diff --git a/src_web/comfyui/node_mode_relay.ts b/src_web/comfyui/node_mode_relay.ts index 3c37d84..51810b6 100644 --- a/src_web/comfyui/node_mode_relay.ts +++ b/src_web/comfyui/node_mode_relay.ts @@ -23,6 +23,7 @@ import { wait } from "rgthree/common/shared_utils.js"; import { BaseCollectorNode } from "./base_node_collector.js"; import { NodeTypesString, stripRgthree } from "./constants.js"; import { fitString } from "./utils_canvas.js"; +import { rgthree } from "./rgthree.js"; declare const LiteGraph: typeof TLiteGraph; @@ -33,28 +34,30 @@ const MODE_REPEATS = [MODE_MUTE, MODE_BYPASS]; const MODE_NOTHING = -99; // MADE THIS UP. const MODE_TO_OPTION = new Map([ - [MODE_ALWAYS, 'ACTIVE'], - [MODE_MUTE, 'MUTE'], - [MODE_BYPASS, 'BYPASS'], - [MODE_NOTHING, 'NOTHING'], + [MODE_ALWAYS, "ACTIVE"], + [MODE_MUTE, "MUTE"], + [MODE_BYPASS, "BYPASS"], + [MODE_NOTHING, "NOTHING"], ]); const OPTION_TO_MODE = new Map([ - ['ACTIVE', MODE_ALWAYS], - ['MUTE', MODE_MUTE], - ['BYPASS', MODE_BYPASS], - ['NOTHING', MODE_NOTHING], + ["ACTIVE", MODE_ALWAYS], + ["MUTE", MODE_MUTE], + ["BYPASS", MODE_BYPASS], + ["NOTHING", MODE_NOTHING], ]); const MODE_TO_PROPERTY = new Map([ - [MODE_MUTE, 'on_muted_inputs'], - [MODE_BYPASS, 'on_bypassed_inputs'], - [MODE_ALWAYS, 'on_any_active_inputs'], + [MODE_MUTE, "on_muted_inputs"], + [MODE_BYPASS, "on_bypassed_inputs"], + [MODE_ALWAYS, "on_any_active_inputs"], ]); +const logger = rgthree.newLogSession("[NodeModeRelay]"); + /** - * Like a BaseCollectorNode, this relay node connects to a Repeater and changes it mode (so it can go - * on to mute it's connections). + * Like a BaseCollectorNode, this relay node connects to a Repeater node and _relays_ mode changes + * changes to the repeater (so it can go on to modify its connections). */ class NodeModeRelay extends BaseCollectorNode { override readonly inputsPassThroughFollowing: PassThroughFollowing = PassThroughFollowing.ALL; @@ -80,9 +83,9 @@ class NodeModeRelay extends BaseCollectorNode { constructor(title?: string) { super(title); - this.properties['on_muted_inputs'] = 'MUTE'; - this.properties['on_bypassed_inputs'] = 'BYPASS'; - this.properties['on_any_active_inputs'] = 'ACTIVE'; + this.properties["on_muted_inputs"] = "MUTE"; + this.properties["on_bypassed_inputs"] = "BYPASS"; + this.properties["on_any_active_inputs"] = "ACTIVE"; this.onConstructed(); } @@ -100,6 +103,16 @@ class NodeModeRelay extends BaseCollectorNode { return super.onConstructed(); } + override onModeChange(from: NodeMode, to: NodeMode) { + super.onModeChange(from, to); + // If we aren't connected to anything, then we'll use our mode to relay when it changes. + if (this.inputs.length <= 1 && !this.isInputConnected(0) && this.isAnyOutputConnected()) { + const [n, v] = logger.infoParts(`Mode change without any inputs; relaying our mode.`); + console[n]?.(...v); + this.dispatchModeToRepeater(this.mode); + } + } + override configure(info: SerializedLGraphNode): void { // Patch a small issue (~14h) where multiple OPT_CONNECTIONS may have been created. // https://github.com/rgthree/rgthree-comfy/issues/206 @@ -115,14 +128,15 @@ class NodeModeRelay extends BaseCollectorNode { return; } if ( - this.properties['on_muted_inputs'] !== 'MUTE' || - this.properties['on_bypassed_inputs'] !== 'BYPASS' || - this.properties['on_any_active_inputs'] != 'ACTIVE') { + this.properties["on_muted_inputs"] !== "MUTE" || + this.properties["on_bypassed_inputs"] !== "BYPASS" || + this.properties["on_any_active_inputs"] != "ACTIVE" + ) { let margin = 15; ctx.textAlign = "left"; - let label = `*(MUTE > ${this.properties['on_muted_inputs']}, `; - label += `BYPASS > ${this.properties['on_bypassed_inputs']}, `; - label += `ACTIVE > ${this.properties['on_any_active_inputs']})`; + let label = `*(MUTE > ${this.properties["on_muted_inputs"]}, `; + label += `BYPASS > ${this.properties["on_bypassed_inputs"]}, `; + label += `ACTIVE > ${this.properties["on_any_active_inputs"]})`; ctx.fillStyle = LiteGraph.WIDGET_SECONDARY_TEXT_COLOR; const oldFont = ctx.font; ctx.font = "italic " + (LiteGraph.NODE_SUBTEXT_SIZE - 2) + "px Arial"; @@ -134,9 +148,10 @@ class NodeModeRelay extends BaseCollectorNode { override computeSize(out: Vector2) { let size = super.computeSize(out); if ( - this.properties['on_muted_inputs'] !== 'MUTE' || - this.properties['on_bypassed_inputs'] !== 'BYPASS' || - this.properties['on_any_active_inputs'] != 'ACTIVE') { + this.properties["on_muted_inputs"] !== "MUTE" || + this.properties["on_bypassed_inputs"] !== "BYPASS" || + this.properties["on_any_active_inputs"] != "ACTIVE" + ) { size[1] += 17; } return size; @@ -200,9 +215,19 @@ class NodeModeRelay extends BaseCollectorNode { } } + this.dispatchModeToRepeater(mode); + setTimeout(() => { + this.stabilize(); + }, 500); + } + + /** + * Sends the mode to the repeater, checking to see if we're modifying our mode. + */ + private dispatchModeToRepeater(mode?: NodeMode | -99 | null) { if (mode != null) { - const propertyVal = this.properties?.[MODE_TO_PROPERTY.get(mode)||'']; - const newMode = OPTION_TO_MODE.get(propertyVal) + const propertyVal = this.properties?.[MODE_TO_PROPERTY.get(mode) || ""]; + const newMode = OPTION_TO_MODE.get(propertyVal); mode = (newMode !== null ? newMode : mode) as NodeMode | -99; if (mode !== null && mode !== MODE_NOTHING) { if (this.outputs?.length) { @@ -216,9 +241,6 @@ class NodeModeRelay extends BaseCollectorNode { } } } - setTimeout(() => { - this.stabilize(); - }, 500); } override getHelp() { @@ -241,6 +263,11 @@ class NodeModeRelay extends BaseCollectorNode { When any connected input nodes are active, the relay will set a connected repeater to active (by default).

+
  • + If no inputs are connected, the relay will set a connected repeater to its mode when + its own mode is changed. Note, if any inputs are connected, then the above + will occur and the Relay's mode does not matter. +

  • Note, you can change which signals get sent on the above in the Properties. diff --git a/src_web/comfyui/node_mode_repeater.ts b/src_web/comfyui/node_mode_repeater.ts index 28ddd16..e9d9954 100644 --- a/src_web/comfyui/node_mode_repeater.ts +++ b/src_web/comfyui/node_mode_repeater.ts @@ -20,6 +20,7 @@ import { getConnectedInputNodesAndFilterPassThroughs, getConnectedOutputNodesAndFilterPassThroughs, } from "./utils.js"; +import { NodeMode } from "typings/comfy.js"; declare const LiteGraph: typeof TLiteGraph; @@ -172,8 +173,8 @@ class NodeModeRepeater extends BaseCollectorNode { } /** When a mode change, we want all connected nodes to match except for connected relays. */ - override onModeChange() { - super.onModeChange(); + override onModeChange(from: NodeMode, to: NodeMode) { + super.onModeChange(from, to); const linkedNodes = getConnectedInputNodesAndFilterPassThroughs(this).filter(node => node.type !== NodeTypesString.NODE_MODE_RELAY); if (linkedNodes.length) { for (const node of linkedNodes) { diff --git a/web/comfyui/base_node.js b/web/comfyui/base_node.js index dc14379..87c6e10 100644 --- a/web/comfyui/base_node.js +++ b/web/comfyui/base_node.js @@ -61,14 +61,15 @@ export class RgthreeBaseNode extends LGraphNode { } set mode(mode) { if (this.mode_ != mode) { + const oldMode = this.mode_; this.mode_ = mode; - this.onModeChange(); + this.onModeChange(oldMode, mode); } } get mode() { return this.mode_; } - onModeChange() { + onModeChange(from, to) { } async handleAction(action) { action; diff --git a/web/comfyui/node_mode_relay.js b/web/comfyui/node_mode_relay.js index 5182939..8343e6c 100644 --- a/web/comfyui/node_mode_relay.js +++ b/web/comfyui/node_mode_relay.js @@ -4,36 +4,38 @@ import { wait } from "../../rgthree/common/shared_utils.js"; import { BaseCollectorNode } from "./base_node_collector.js"; import { NodeTypesString, stripRgthree } from "./constants.js"; import { fitString } from "./utils_canvas.js"; +import { rgthree } from "./rgthree.js"; const MODE_ALWAYS = 0; const MODE_MUTE = 2; const MODE_BYPASS = 4; const MODE_REPEATS = [MODE_MUTE, MODE_BYPASS]; const MODE_NOTHING = -99; const MODE_TO_OPTION = new Map([ - [MODE_ALWAYS, 'ACTIVE'], - [MODE_MUTE, 'MUTE'], - [MODE_BYPASS, 'BYPASS'], - [MODE_NOTHING, 'NOTHING'], + [MODE_ALWAYS, "ACTIVE"], + [MODE_MUTE, "MUTE"], + [MODE_BYPASS, "BYPASS"], + [MODE_NOTHING, "NOTHING"], ]); const OPTION_TO_MODE = new Map([ - ['ACTIVE', MODE_ALWAYS], - ['MUTE', MODE_MUTE], - ['BYPASS', MODE_BYPASS], - ['NOTHING', MODE_NOTHING], + ["ACTIVE", MODE_ALWAYS], + ["MUTE", MODE_MUTE], + ["BYPASS", MODE_BYPASS], + ["NOTHING", MODE_NOTHING], ]); const MODE_TO_PROPERTY = new Map([ - [MODE_MUTE, 'on_muted_inputs'], - [MODE_BYPASS, 'on_bypassed_inputs'], - [MODE_ALWAYS, 'on_any_active_inputs'], + [MODE_MUTE, "on_muted_inputs"], + [MODE_BYPASS, "on_bypassed_inputs"], + [MODE_ALWAYS, "on_any_active_inputs"], ]); +const logger = rgthree.newLogSession("[NodeModeRelay]"); class NodeModeRelay extends BaseCollectorNode { constructor(title) { super(title); this.inputsPassThroughFollowing = PassThroughFollowing.ALL; this.comfyClass = NodeTypesString.NODE_MODE_RELAY; - this.properties['on_muted_inputs'] = 'MUTE'; - this.properties['on_bypassed_inputs'] = 'BYPASS'; - this.properties['on_any_active_inputs'] = 'ACTIVE'; + this.properties["on_muted_inputs"] = "MUTE"; + this.properties["on_bypassed_inputs"] = "BYPASS"; + this.properties["on_any_active_inputs"] = "ACTIVE"; this.onConstructed(); } onConstructed() { @@ -47,6 +49,15 @@ class NodeModeRelay extends BaseCollectorNode { }, 500); return super.onConstructed(); } + onModeChange(from, to) { + var _a; + super.onModeChange(from, to); + if (this.inputs.length <= 1 && !this.isInputConnected(0) && this.isAnyOutputConnected()) { + const [n, v] = logger.infoParts(`Mode change without any inputs; relaying our mode.`); + (_a = console[n]) === null || _a === void 0 ? void 0 : _a.call(console, ...v); + this.dispatchModeToRepeater(this.mode); + } + } configure(info) { var _a; if ((_a = info.outputs) === null || _a === void 0 ? void 0 : _a.length) { @@ -59,14 +70,14 @@ class NodeModeRelay extends BaseCollectorNode { if ((_a = this.flags) === null || _a === void 0 ? void 0 : _a.collapsed) { return; } - if (this.properties['on_muted_inputs'] !== 'MUTE' || - this.properties['on_bypassed_inputs'] !== 'BYPASS' || - this.properties['on_any_active_inputs'] != 'ACTIVE') { + if (this.properties["on_muted_inputs"] !== "MUTE" || + this.properties["on_bypassed_inputs"] !== "BYPASS" || + this.properties["on_any_active_inputs"] != "ACTIVE") { let margin = 15; ctx.textAlign = "left"; - let label = `*(MUTE > ${this.properties['on_muted_inputs']}, `; - label += `BYPASS > ${this.properties['on_bypassed_inputs']}, `; - label += `ACTIVE > ${this.properties['on_any_active_inputs']})`; + let label = `*(MUTE > ${this.properties["on_muted_inputs"]}, `; + label += `BYPASS > ${this.properties["on_bypassed_inputs"]}, `; + label += `ACTIVE > ${this.properties["on_any_active_inputs"]})`; ctx.fillStyle = LiteGraph.WIDGET_SECONDARY_TEXT_COLOR; const oldFont = ctx.font; ctx.font = "italic " + (LiteGraph.NODE_SUBTEXT_SIZE - 2) + "px Arial"; @@ -76,9 +87,9 @@ class NodeModeRelay extends BaseCollectorNode { } computeSize(out) { let size = super.computeSize(out); - if (this.properties['on_muted_inputs'] !== 'MUTE' || - this.properties['on_bypassed_inputs'] !== 'BYPASS' || - this.properties['on_any_active_inputs'] != 'ACTIVE') { + if (this.properties["on_muted_inputs"] !== "MUTE" || + this.properties["on_bypassed_inputs"] !== "BYPASS" || + this.properties["on_any_active_inputs"] != "ACTIVE") { size[1] += 17; } return size; @@ -96,7 +107,6 @@ class NodeModeRelay extends BaseCollectorNode { }, 500); } stabilize() { - var _a, _b; if (!this.graph || !this.isAnyOutputConnected() || !this.isInputConnected(0)) { return; } @@ -116,8 +126,15 @@ class NodeModeRelay extends BaseCollectorNode { mode = null; } } + this.dispatchModeToRepeater(mode); + setTimeout(() => { + this.stabilize(); + }, 500); + } + dispatchModeToRepeater(mode) { + var _a, _b; if (mode != null) { - const propertyVal = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[MODE_TO_PROPERTY.get(mode) || '']; + const propertyVal = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[MODE_TO_PROPERTY.get(mode) || ""]; const newMode = OPTION_TO_MODE.get(propertyVal); mode = (newMode !== null ? newMode : mode); if (mode !== null && mode !== MODE_NOTHING) { @@ -132,9 +149,6 @@ class NodeModeRelay extends BaseCollectorNode { } } } - setTimeout(() => { - this.stabilize(); - }, 500); } getHelp() { return ` @@ -156,6 +170,11 @@ class NodeModeRelay extends BaseCollectorNode { When any connected input nodes are active, the relay will set a connected repeater to active (by default).

    +
  • + If no inputs are connected, the relay will set a connected repeater to its mode when + its own mode is changed. Note, if any inputs are connected, then the above + will occur and the Relay's mode does not matter. +

  • Note, you can change which signals get sent on the above in the Properties. diff --git a/web/comfyui/node_mode_repeater.js b/web/comfyui/node_mode_repeater.js index 576a00f..3a0ac44 100644 --- a/web/comfyui/node_mode_repeater.js +++ b/web/comfyui/node_mode_repeater.js @@ -92,9 +92,9 @@ class NodeModeRepeater extends BaseCollectorNode { }); } } - onModeChange() { + onModeChange(from, to) { var _a, _b; - super.onModeChange(); + super.onModeChange(from, to); const linkedNodes = getConnectedInputNodesAndFilterPassThroughs(this).filter(node => node.type !== NodeTypesString.NODE_MODE_RELAY); if (linkedNodes.length) { for (const node of linkedNodes) {