Adds the ability to change the relay signal, so one could essentially create an inverse relay. Fixes #102
This commit is contained in:
@@ -17,7 +17,6 @@ export class BaseCollectorNode extends BaseAnyInputConnectedNode {
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
this.addInput("", "*");
|
||||
this.addOutput("Output", "*");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,12 @@ import { app } from "../../scripts/app.js";
|
||||
import type {
|
||||
INodeInputSlot,
|
||||
INodeOutputSlot,
|
||||
IWidget,
|
||||
LGraphCanvas,
|
||||
LGraphNode,
|
||||
LLink,
|
||||
LiteGraph as TLiteGraph,
|
||||
Vector2,
|
||||
} from "../typings/litegraph.js";
|
||||
import type { NodeMode } from "../typings/comfy.js";
|
||||
import {
|
||||
@@ -18,6 +21,7 @@ import {
|
||||
import { wait } from "./shared_utils.js";
|
||||
import { BaseCollectorNode } from "./base_node_collector.js";
|
||||
import { NodeTypesString, stripRgthree } from "./constants.js";
|
||||
import { fitString } from "./utils_canvas.js";
|
||||
|
||||
declare const LiteGraph: typeof TLiteGraph;
|
||||
|
||||
@@ -25,6 +29,27 @@ const MODE_ALWAYS = 0;
|
||||
const MODE_MUTE = 2;
|
||||
const MODE_BYPASS = 4;
|
||||
const MODE_REPEATS = [MODE_MUTE, MODE_BYPASS];
|
||||
const MODE_IGNORE = -99; // MADE THIS UP.
|
||||
|
||||
const MODE_TO_OPTION = new Map([
|
||||
[MODE_ALWAYS, 'ACTIVE'],
|
||||
[MODE_MUTE, 'MUTE'],
|
||||
[MODE_BYPASS, 'BYPASS'],
|
||||
[MODE_IGNORE, 'IGNORE'],
|
||||
]);
|
||||
|
||||
const OPTION_TO_MODE = new Map([
|
||||
['ACTIVE', MODE_ALWAYS],
|
||||
['MUTE', MODE_MUTE],
|
||||
['BYPASS', MODE_BYPASS],
|
||||
['IGNORE',MODE_IGNORE],
|
||||
]);
|
||||
|
||||
const MODE_TO_PROPERTY = new Map([
|
||||
[MODE_MUTE, 'on_muted_inputs'],
|
||||
[MODE_BYPASS, 'on_bypassed_inputs'],
|
||||
[MODE_ALWAYS, 'on_any_active_inputs'],
|
||||
]);
|
||||
|
||||
/**
|
||||
* Like a BaseCollectorNode, this relay node connects to a Repeater and changes it mode (so it can go
|
||||
@@ -36,6 +61,21 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
static override type = NodeTypesString.NODE_MODE_RELAY;
|
||||
static override title = NodeTypesString.NODE_MODE_RELAY;
|
||||
|
||||
static "@on_muted_inputs" = {
|
||||
type: "combo",
|
||||
values: ["MUTE", "ACTIVE", "BYPASS", "NOTHING"],
|
||||
};
|
||||
|
||||
static "@on_bypassed_inputs" = {
|
||||
type: "combo",
|
||||
values: ["BYPASS", "ACTIVE", "MUTE", "NOTHING"],
|
||||
};
|
||||
|
||||
static "@on_any_active_inputs" = {
|
||||
type: "combo",
|
||||
values: ["BYPASS", "ACTIVE", "MUTE", "NOTHING"],
|
||||
};
|
||||
|
||||
constructor(title?: string) {
|
||||
super(title);
|
||||
|
||||
@@ -49,8 +89,40 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
color_off: "#a80",
|
||||
shape: LiteGraph.ARROW_SHAPE,
|
||||
});
|
||||
|
||||
this.properties['on_muted_inputs'] = 'MUTE';
|
||||
this.properties['on_bypassed_inputs'] = 'BYPASS';
|
||||
this.properties['on_any_active_inputs'] = 'ACTIVE';
|
||||
}
|
||||
|
||||
override onDrawForeground(ctx: CanvasRenderingContext2D, canvas: LGraphCanvas): void {
|
||||
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']})`;
|
||||
ctx.fillStyle = LiteGraph.WIDGET_SECONDARY_TEXT_COLOR;
|
||||
const oldFont = ctx.font;
|
||||
ctx.font = "italic " + (LiteGraph.NODE_SUBTEXT_SIZE - 2) + "px Arial";
|
||||
ctx.fillText(fitString(ctx, label, this.size[0] - 20), 15, this.size[1] - 6);
|
||||
ctx.font = oldFont;
|
||||
}
|
||||
}
|
||||
|
||||
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') {
|
||||
size[1] += 17;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
override onConnectOutput(
|
||||
outputIndex: number,
|
||||
inputType: string | -1,
|
||||
@@ -94,7 +166,7 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
-1,
|
||||
this.inputsPassThroughFollowing,
|
||||
);
|
||||
let mode: NodeMode | null = undefined;
|
||||
let mode: NodeMode | -99 | null = undefined;
|
||||
for (const inputNode of inputNodes) {
|
||||
// If we haven't set our mode to be, then let's set it. Otherwise, mode will stick if it
|
||||
// remains constant, otherwise, if we hit an ALWAYS, then we'll unmute all repeaters and
|
||||
@@ -111,13 +183,18 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
}
|
||||
|
||||
if (mode != null) {
|
||||
if (this.outputs?.length) {
|
||||
const outputNodes = getConnectedOutputNodesAndFilterPassThroughs(this);
|
||||
for (const outputNode of outputNodes) {
|
||||
outputNode.mode = mode;
|
||||
wait(16).then(() => {
|
||||
outputNode.setDirtyCanvas(true, true);
|
||||
});
|
||||
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_IGNORE) {
|
||||
if (this.outputs?.length) {
|
||||
const outputNodes = getConnectedOutputNodesAndFilterPassThroughs(this);
|
||||
for (const outputNode of outputNodes) {
|
||||
outputNode.mode = mode;
|
||||
wait(16).then(() => {
|
||||
outputNode.setDirtyCanvas(true, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,17 +213,23 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
<ul>
|
||||
<li><p>
|
||||
When all connected input nodes are muted, the relay will set a connected repeater to
|
||||
mute.
|
||||
mute (by default).
|
||||
</p></li>
|
||||
<li><p>
|
||||
When all connected input nodes are bypassed, the relay will set a connected repeater to
|
||||
bypass.
|
||||
bypass (by default).
|
||||
</p></li>
|
||||
<li><p>
|
||||
When any connected input nodes are active, the relay will set a connected repeater to
|
||||
active.
|
||||
active (by default).
|
||||
</p></li>
|
||||
</ul>
|
||||
<p>
|
||||
Note, you can change which signals get sent on the above in the <code>Properties</code>.
|
||||
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.
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ export class BaseCollectorNode extends BaseAnyInputConnectedNode {
|
||||
constructor(title) {
|
||||
super(title);
|
||||
this.inputsPassThroughFollowing = PassThroughFollowing.REROUTE_ONLY;
|
||||
this.addInput("", "*");
|
||||
this.addOutput("Output", "*");
|
||||
}
|
||||
clone() {
|
||||
|
||||
@@ -3,10 +3,29 @@ import { PassThroughFollowing, addConnectionLayoutSupport, getConnectedInputNode
|
||||
import { wait } from "./shared_utils.js";
|
||||
import { BaseCollectorNode } from "./base_node_collector.js";
|
||||
import { NodeTypesString, stripRgthree } from "./constants.js";
|
||||
import { fitString } from "./utils_canvas.js";
|
||||
const MODE_ALWAYS = 0;
|
||||
const MODE_MUTE = 2;
|
||||
const MODE_BYPASS = 4;
|
||||
const MODE_REPEATS = [MODE_MUTE, MODE_BYPASS];
|
||||
const MODE_IGNORE = -99;
|
||||
const MODE_TO_OPTION = new Map([
|
||||
[MODE_ALWAYS, 'ACTIVE'],
|
||||
[MODE_MUTE, 'MUTE'],
|
||||
[MODE_BYPASS, 'BYPASS'],
|
||||
[MODE_IGNORE, 'IGNORE'],
|
||||
]);
|
||||
const OPTION_TO_MODE = new Map([
|
||||
['ACTIVE', MODE_ALWAYS],
|
||||
['MUTE', MODE_MUTE],
|
||||
['BYPASS', MODE_BYPASS],
|
||||
['IGNORE', MODE_IGNORE],
|
||||
]);
|
||||
const MODE_TO_PROPERTY = new Map([
|
||||
[MODE_MUTE, 'on_muted_inputs'],
|
||||
[MODE_BYPASS, 'on_bypassed_inputs'],
|
||||
[MODE_ALWAYS, 'on_any_active_inputs'],
|
||||
]);
|
||||
class NodeModeRelay extends BaseCollectorNode {
|
||||
constructor(title) {
|
||||
super(title);
|
||||
@@ -20,6 +39,34 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
color_off: "#a80",
|
||||
shape: LiteGraph.ARROW_SHAPE,
|
||||
});
|
||||
this.properties['on_muted_inputs'] = 'MUTE';
|
||||
this.properties['on_bypassed_inputs'] = 'BYPASS';
|
||||
this.properties['on_any_active_inputs'] = 'ACTIVE';
|
||||
}
|
||||
onDrawForeground(ctx, canvas) {
|
||||
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']})`;
|
||||
ctx.fillStyle = LiteGraph.WIDGET_SECONDARY_TEXT_COLOR;
|
||||
const oldFont = ctx.font;
|
||||
ctx.font = "italic " + (LiteGraph.NODE_SUBTEXT_SIZE - 2) + "px Arial";
|
||||
ctx.fillText(fitString(ctx, label, this.size[0] - 20), 15, this.size[1] - 6);
|
||||
ctx.font = oldFont;
|
||||
}
|
||||
}
|
||||
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') {
|
||||
size[1] += 17;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
onConnectOutput(outputIndex, inputType, inputSlot, inputNode, inputIndex) {
|
||||
var _a, _b;
|
||||
@@ -34,7 +81,7 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
}, 500);
|
||||
}
|
||||
stabilize() {
|
||||
var _a;
|
||||
var _a, _b;
|
||||
if (!this.graph || !this.isAnyOutputConnected() || !this.isInputConnected(0)) {
|
||||
return;
|
||||
}
|
||||
@@ -55,13 +102,18 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
}
|
||||
}
|
||||
if (mode != null) {
|
||||
if ((_a = this.outputs) === null || _a === void 0 ? void 0 : _a.length) {
|
||||
const outputNodes = getConnectedOutputNodesAndFilterPassThroughs(this);
|
||||
for (const outputNode of outputNodes) {
|
||||
outputNode.mode = mode;
|
||||
wait(16).then(() => {
|
||||
outputNode.setDirtyCanvas(true, true);
|
||||
});
|
||||
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_IGNORE) {
|
||||
if ((_b = this.outputs) === null || _b === void 0 ? void 0 : _b.length) {
|
||||
const outputNodes = getConnectedOutputNodesAndFilterPassThroughs(this);
|
||||
for (const outputNode of outputNodes) {
|
||||
outputNode.mode = mode;
|
||||
wait(16).then(() => {
|
||||
outputNode.setDirtyCanvas(true, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,22 +131,40 @@ class NodeModeRelay extends BaseCollectorNode {
|
||||
<ul>
|
||||
<li><p>
|
||||
When all connected input nodes are muted, the relay will set a connected repeater to
|
||||
mute.
|
||||
mute (by default).
|
||||
</p></li>
|
||||
<li><p>
|
||||
When all connected input nodes are bypassed, the relay will set a connected repeater to
|
||||
bypass.
|
||||
bypass (by default).
|
||||
</p></li>
|
||||
<li><p>
|
||||
When any connected input nodes are active, the relay will set a connected repeater to
|
||||
active.
|
||||
active (by default).
|
||||
</p></li>
|
||||
</ul>
|
||||
<p>
|
||||
Note, you can change which signals get sent on the above in the <code>Properties</code>.
|
||||
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.
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
}
|
||||
NodeModeRelay.type = NodeTypesString.NODE_MODE_RELAY;
|
||||
NodeModeRelay.title = NodeTypesString.NODE_MODE_RELAY;
|
||||
NodeModeRelay["@on_muted_inputs"] = {
|
||||
type: "combo",
|
||||
values: ["MUTE", "ACTIVE", "BYPASS", "NOTHING"],
|
||||
};
|
||||
NodeModeRelay["@on_bypassed_inputs"] = {
|
||||
type: "combo",
|
||||
values: ["BYPASS", "ACTIVE", "MUTE", "NOTHING"],
|
||||
};
|
||||
NodeModeRelay["@on_any_active_inputs"] = {
|
||||
type: "combo",
|
||||
values: ["BYPASS", "ACTIVE", "MUTE", "NOTHING"],
|
||||
};
|
||||
app.registerExtension({
|
||||
name: "rgthree.NodeModeRepeaterHelper",
|
||||
registerCustomNodes() {
|
||||
|
||||
Reference in New Issue
Block a user