Files
2025-05-24 21:35:21 +08:00

517 lines
18 KiB
JavaScript

import { app } from "../../../scripts/app.js";
class BaseNode extends LGraphNode {
static defaultComfyClass = "BaseNode";
constructor(title, comfyClass) {
super(title);
this.isVirtualNode = false;
this.configuring = false;
this.__constructed__ = false;
this.widgets = this.widgets || [];
this.properties = this.properties || {};
this.comfyClass = comfyClass || this.constructor.comfyClass || BaseNode.defaultComfyClass;
setTimeout(() => {
this.checkAndRunOnConstructed();
});
}
checkAndRunOnConstructed() {
if (!this.__constructed__) {
this.onConstructed();
}
return this.__constructed__;
}
onConstructed() {
if (this.__constructed__) return false;
this.type = this.type ?? undefined;
this.__constructed__ = true;
return this.__constructed__;
}
configure(info) {
this.configuring = true;
super.configure(info);
for (const w of this.widgets || []) {
w.last_y = w.last_y || 0;
}
this.configuring = false;
}
static setUp() {
if (!this.type) {
throw new Error(`Missing type for ${this.name}: ${this.title}`);
}
LiteGraph.registerNodeType(this.type, this);
if (this._category) {
this.category = this._category;
}
}
}
const MODE_BYPASS = 4;
const MODE_MUTE = 2;
const MODE_ALWAYS = 0;
app.registerExtension({
name: "Switcher.Mode",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "MuterSwitcher") {
const INPUTS = ["ON_TRUE", "on_true", "ON_FALSE", "on_false"];
// 定义节点的默认属性
nodeType.default_properties = {
ON_TRUE_Mode: "mute",
on_true_Mode: "mute",
ON_FALSE_Mode: "mute",
on_false_Mode: "mute"
};
// 定义属性的类型和选项
if (!nodeType["@ON_TRUE_Mode"]) {
nodeType["@ON_TRUE_Mode"] = { type: "combo", values: ["mute", "bypass"] };
nodeType["@on_true_Mode"] = { type: "combo", values: ["mute", "bypass"] };
nodeType["@ON_FALSE_Mode"] = { type: "combo", values: ["mute", "bypass"] };
nodeType["@on_false_Mode"] = { type: "combo", values: ["mute", "bypass"] };
}
// 添加模式选择属性
nodeType.prototype.getExtraMenuOptions = function(_, options) {
// 添加菜单选项
INPUTS.forEach((input, index) => {
const submenu = {
content: `${input}_Mode`,
submenu: {
options: [
{
content: "Mute",
callback: () => {
this.properties[`${input}_Mode`] = "mute";
this.setDirtyCanvas(true);
}
},
{
content: "Bypass",
callback: () => {
this.properties[`${input}_Mode`] = "bypass";
this.setDirtyCanvas(true);
}
}
]
}
};
options.push(submenu);
});
};
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function() {
const result = onNodeCreated?.apply(this, arguments);
// 初始化属性
this.properties = this.properties || {};
INPUTS.forEach(input => {
this.properties[`${input}_Mode`] = this.properties[`${input}_Mode`] || "mute";
});
const booleanWidget = this.widgets?.find(w => w.name === "boolean");
if (booleanWidget) {
const originalCallback = booleanWidget.callback;
booleanWidget.callback = (value) => {
// 获取所有连接的节点
const nodes = INPUTS.map((_, i) => this.getConnectedNode(i));
// 设置各个节点的模式
nodes.forEach((node, index) => {
if (node) {
const isTrue = index < 2;
const mode = this.properties[`${INPUTS[index]}_Mode`];
if (isTrue) {
node.mode = value ? MODE_ALWAYS : (mode === "mute" ? MODE_MUTE : MODE_BYPASS);
} else {
node.mode = value ? (mode === "mute" ? MODE_MUTE : MODE_BYPASS) : MODE_ALWAYS;
}
node.setDirtyCanvas(true, true);
}
});
originalCallback?.(value);
};
}
return result;
};
nodeType.prototype.getConnectedNode = function(slot) {
if (this.inputs && this.inputs[slot] && this.inputs[slot].link) {
const link = app.graph.links[this.inputs[slot].link];
if (link) {
return app.graph.getNodeById(link.origin_id);
}
}
return null;
};
}
}
});
app.registerExtension({
name: "GroupSwitcher",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "GroupSwitcher") {
const GROUPS = ["GROUP_A", "GROUP_B"];
// 定义节点的默认属性
nodeType.default_properties = {
GROUP_A_Mode: "mute",
GROUP_B_Mode: "mute",
groupA: "",
groupB: ""
};
// 定义属性的类型和选项
if (!nodeType["@GROUP_A_Mode"]) {
GROUPS.forEach(group => {
nodeType[`@${group}_Mode`] = {
type: "combo",
values: ["mute", "bypass"]
};
});
}
function recomputeInsideNodesForGroup(group) {
const nodes = group.graph._nodes;
group._nodes.length = 0;
// 获取所有节点的边界
const nodeBoundings = {};
for (const node of app.graph._nodes) {
nodeBoundings[node.id] = node.getBounding();
}
// 计算组内节点
for (const node of nodes) {
const node_bounding = nodeBoundings[node.id];
if (!node_bounding || !LiteGraph.overlapBounding(group._bounding, node_bounding)) {
continue;
}
group._nodes.push(node);
}
}
// 获取所有组并更新组内节点
function getGroups() {
const groups = [...app.graph._groups];
for (const group of groups) {
recomputeInsideNodesForGroup(group);
}
return groups;
}
// 获取所有组名称
function getGroupNames() {
return getGroups().map(g => g.title).sort();
}
// 添加模式选择属性
nodeType.prototype.getExtraMenuOptions = function(_, options) {
GROUPS.forEach(group => {
const submenu = {
content: `${group}_Mode`,
submenu: {
options: [
{
content: "Mute",
callback: () => {
this.properties[`${group}_Mode`] = "mute";
this.setDirtyCanvas(true);
}
},
{
content: "Bypass",
callback: () => {
this.properties[`${group}_Mode`] = "bypass";
this.setDirtyCanvas(true);
}
}
]
}
};
options.push(submenu);
});
};
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function() {
const result = onNodeCreated?.apply(this, arguments);
// 初始化属性
this.properties = this.properties || {};
GROUPS.forEach(group => {
this.properties[`${group}_Mode`] = this.properties[`${group}_Mode`] || "mute";
});
// 添加组选择下拉框
const widgetA = this.addWidget("combo", "Group A", this.properties.groupA || "", (v) => {
this.properties.groupA = v;
}, { values: getGroupNames() });
const widgetB = this.addWidget("combo", "Group B", this.properties.groupB || "", (v) => {
this.properties.groupB = v;
}, { values: getGroupNames() });
// 获取 boolean widget 并添加回调
const booleanWidget = this.widgets?.find(w => w.name === "boolean");
if (booleanWidget) {
const originalCallback = booleanWidget.callback;
booleanWidget.callback = (value) => {
this.switchGroups(value);
originalCallback?.(value);
};
}
this.updateGroupList = () => {
const groups = getGroupNames();
if (widgetA && widgetB) {
widgetA.options.values = groups;
widgetB.options.values = groups;
this.setDirtyCanvas(true, false);
}
};
// 监听画布变化
const self = this;
app.canvas.onDrawBackground = (() => {
const original = app.canvas.onDrawBackground;
return function() {
self.updateGroupList();
return original?.apply(this, arguments);
};
})();
return result;
};
nodeType.prototype.computeSize = function() {
const widgetHeight = 24;
const padding = 4;
const width = 180;
const height = (this.widgets?.length || 0) * widgetHeight + padding * 2;
return [width, height];
};
// 修改组切换功能,使用新的组节点计算逻辑
nodeType.prototype.switchGroups = function(value) {
const groups = getGroups();
const groupA = groups.find(g => g.title === this.properties.groupA);
const groupB = groups.find(g => g.title === this.properties.groupB);
if (groupA) {
const modeA = this.properties.GROUP_A_Mode;
groupA._nodes.forEach(node => {
node.mode = value ? MODE_ALWAYS : (modeA === "mute" ? MODE_MUTE : MODE_BYPASS);
node.setDirtyCanvas(true, true);
});
}
if (groupB) {
const modeB = this.properties.GROUP_B_Mode;
groupB._nodes.forEach(node => {
node.mode = !value ? MODE_ALWAYS : (modeB === "mute" ? MODE_MUTE : MODE_BYPASS);
node.setDirtyCanvas(true, true);
});
}
app.graph.setDirtyCanvas(true, false);
};
}
}
});
class GroupDetectorNode extends BaseNode {
static type = "🎈GroupDetector";
static title = "🎈Group Detector";
static category = "🎈LAOGOU/Switch";
static _category = "🎈LAOGOU/Switch";
static comfyClass = "🎈GroupDetector";
constructor(title = GroupDetectorNode.title) {
super(title, GroupDetectorNode.comfyClass);
this.isVirtualNode = true;
this.size = [50, 26];
this.shape = LiteGraph.ROUND_SHAPE;
this.addOutput("output", "*");
this.mode = MODE_ALWAYS;
this._lastMode = this.mode; // 记录上一次的状态
// 监听画布变化,只在状态改变时同步
const self = this;
app.canvas.onDrawBackground = (() => {
const original = app.canvas.onDrawBackground;
return function() {
// 只在状态发生变化时同步
if (self.mode !== self._lastMode) {
const group = self.getCurrentGroup();
if (group) {
group._nodes.forEach(n => {
if (n !== self) {
n.mode = self.mode;
n.setDirtyCanvas(true, true);
}
});
}
self._lastMode = self.mode;
}
return original?.apply(this, arguments);
};
})();
this.onConstructed();
}
// 重写 onModeChanged 方法来响应状态变化
onModeChanged(mode) {
super.onModeChanged?.(mode);
const group = this.getCurrentGroup();
if (group) {
group._nodes.forEach(n => {
if (n !== this) {
n.mode = mode;
n.setDirtyCanvas(true, true);
}
});
}
this._lastMode = mode;
}
getCurrentGroup() {
const groups = [...app.graph._groups];
for (const group of groups) {
const nodes = group.graph._nodes;
group._nodes.length = 0;
for (const n of nodes) {
if (LiteGraph.overlapBounding(group._bounding, n.getBounding())) {
group._nodes.push(n);
}
}
if (group._nodes.includes(this)) {
return group;
}
}
return null;
}
}
app.registerExtension({
name: "GroupDetector",
registerCustomNodes() {
GroupDetectorNode.setUp();
}
});
class StateTransferNode extends BaseNode {
static type = "🎈StateTransfer";
static title = "🎈State Transfer";
static category = "🎈LAOGOU/Switch";
static _category = "🎈LAOGOU/Switch";
static comfyClass = "🎈StateTransfer";
constructor(title = StateTransferNode.title) {
super(title, StateTransferNode.comfyClass);
this.isVirtualNode = true;
this.size = [100, 26];
this.shape = LiteGraph.ROUND_SHAPE;
// 添加初始输入和输出
this.addInput("input_1", "*");
this.addOutput("output", "*");
// 默认状态为开启
this.mode = MODE_ALWAYS;
// 监听画布变化,同步状态
const self = this;
app.canvas.onDrawBackground = (() => {
const original = app.canvas.onDrawBackground;
return function() {
self.updateConnectedNodesState();
return original?.apply(this, arguments);
};
})();
this.onConstructed();
}
// 更新连接节点的状态
updateConnectedNodesState() {
this.inputs.forEach(input => {
if (input.link) {
const link = app.graph.links[input.link];
if (link) {
const sourceNode = app.graph.getNodeById(link.origin_id);
if (sourceNode) {
// 直接设置节点的 mode 属性
sourceNode.mode = this.mode;
sourceNode.setDirtyCanvas(true, true);
}
}
}
});
}
// 处理连接变化
onConnectionsChange(type, index, connected, link_info) {
if (!link_info || type !== LiteGraph.INPUT) return;
const stackTrace = new Error().stack;
// 处理断开连接
if (!connected) {
if (!stackTrace.includes('LGraphNode.prototype.connect') &&
!stackTrace.includes('LGraphNode.connect') &&
!stackTrace.includes('loadGraphData')) {
this.removeInput(index);
}
}
// 重新编号输入端口
let inputIndex = 1;
this.inputs.forEach(input => {
const newName = `input_${inputIndex}`;
if (input.name !== newName) {
input.name = newName;
}
inputIndex++;
});
// 如果最后一个端口被连接,添加新端口
const lastInput = this.inputs[this.inputs.length - 1];
if (lastInput?.link != null) {
this.addInput(`input_${inputIndex}`, "*");
}
this.setDirtyCanvas(true, true);
}
// 添加初始化方法
onNodeCreated() {
const result = super.onNodeCreated?.apply(this, arguments);
// 确保至少有一个输入端口
if (!this.inputs.find(input => input.name === "input_1")) {
this.addInput("input_1", "*");
}
return result;
}
}
app.registerExtension({
name: "StateTransfer",
registerCustomNodes() {
StateTransferNode.setUp();
}
});