diff --git a/web/extensions/core/subflow.js b/web/extensions/core/subflow.js
index d93fa8058..66a3aca8d 100644
--- a/web/extensions/core/subflow.js
+++ b/web/extensions/core/subflow.js
@@ -1,8 +1,4 @@
import { app } from "../../scripts/app.js";
-import { api } from "../../scripts/api.js";
-import { ComfyWidgets } from "/scripts/widgets.js";
-const CONFIG = Symbol();
-// const GET_CONFIG = Symbol();
import { GET_CONFIG } from "./widgetInputs.js";
function getConfig(widgetName) {
@@ -116,23 +112,6 @@ function getConfig(widgetName) {
app.registerExtension({
name: "Comfy.Subflow",
beforeRegisterNodeDef(nodeType, nodeData, app) {
-
- // console.log("in init")
- // LiteGraph.registerNodeType(
- // "InMemorySubflow",
- // Object.assign(InMemorySubflow, {
- // title: "InMemorySubflow",
- // })
- // );
-
- // LiteGraph.registerNodeType(
- // "FileSubflow",
- // Object.assign(FileSubflow, {
- // title: "FileSubflow",
- // })
- // );
-
- // FileSubflow.category = "utils";
const refreshPins = (node, subflow) => {
if(!subflow)
return;
@@ -157,28 +136,37 @@ app.registerExtension({
const exports = subflowNode.properties?.exports;
if (exports) {
let pinNum = 0;
- for (const inputRef of exports.inputs) {
- console.log(subflowNode.inputs);
- const input = subflowNode.inputs.find(q => q.name === inputRef);
+ for (const exportedInput of exports.inputs) {
+ const input = subflowNode.inputs.find(q => q.name === exportedInput.name);
if (!input) continue;
const { name, type, link, slot_index, ...extras } = input;
- console.log("Input");
- console.log(input);
- console.log(extras);
- if (extras.widget) {
- const w = extras.widget;
- const config = getConfig.call(this, input.name) ?? [input.type, w.options || {}];
- extras.widget[GET_CONFIG] = () => config;
- console.log(extras);
- console.log(input.type);
- }
+ // console.log("Input");
+ // console.log(input);
+ // console.log(extras);
+ // if (extras.widget) {
+ // // const w = extras.widget;
+ // // const config = getConfig.call(this, input.name) ?? [input.type, w.options || {}];
+ // // console.log(config);
+ // // extras.widget[GET_CONFIG] = () => config;
+ // // console.log(extras);
+ // // console.log(input.type);
+ // // console.log(subflowNode);
+ // // const convertedWidget = subflowNode.widgets.find((w) => w.name == inputRef);
+ // // node.widgets.push(convertedWidget);
+ // // const widgetIndex = subflowNode.inputs.findIndex(q => q.name === inputRef);
+ // // const widget = node.addWidget("number", inputRef, 1, ()=>{}, {min: 0, max:1, step:.1, round:.01, precision:2});
+ // // node.widgets.push({type: "number", name: inputRef, value: 1, callback: ()=>{}, options: {min: 0, max:1, step:.1, round:.01, precision:2}});
+ // console.log("adding widget", exportedInput.name);
+ // // convertToInput(node, widget, config);
+ // }
+
node.addInput(input.name, input.type, extras );
inputSlots.push([subflowNode.id, pinNum]);
pinNum++;
}
pinNum = 0;
- for (const outputRef of exports.outputs) {
- const output = subflowNode.outputs.find(q => q.name === outputRef);
+ for (const exportedOutput of exports.outputs) {
+ const output = subflowNode.outputs.find(q => q.name === exportedOutput.name);
if (!output) continue;
node.addOutput(output.name, output.type);
outputSlots.push([subflowNode.id, pinNum]);
@@ -190,11 +178,65 @@ app.registerExtension({
node.size[0] = 180;
};
- const refreshNode = async (node, subflow) => {
+ const refreshWidgets = (node, subflow, recoverValues) => {
+ if (!subflow)
+ return;
+
+ if (node.widgets) {
+ // Allow widgets to cleanup
+ let subflowWidget;
+ for (const w of node.widgets) {
+ if (w.type == "button") {
+ subflowWidget = w;
+ } else if (w.onRemove) {
+ w.onRemove();
+ }
+ }
+ node.widgets = [subflowWidget];
+ }
+
+ const subflowNodes = subflow.nodes;
+ let widgetIndex = 1;
+ for (const subflowNode of subflowNodes) {
+ const exports = subflowNode.properties?.exports;
+ if (exports) {
+
+ for (const exportedWidget of exports.widgets) {
+ let type = exportedWidget.config[0];
+ let options = type;
+ if (type instanceof Array) {
+ options = { values: type };
+ type = "combo";
+ } else {
+ options = exportedWidget.config[1];
+ }
+ if (type === "INT" || type === "FLOAT") {
+ type = "number";
+ }
+ const getWidgetCallback = (widgetIndex) => {
+ return (v) => {
+ console.log(node);
+ node.widgets_values[widgetIndex] = v;
+ }
+ };
+ let value = exportedWidget.value;
+ if (recoverValues) {
+ value = node.widgets_values[widgetIndex] ?? value;
+ }
+ node.addWidget(type, exportedWidget.name, value, getWidgetCallback(widgetIndex), options);
+ widgetIndex++;
+ }
+
+ }
+ }
+ };
+
+ const refreshNode = (node, subflow) => {
if (!subflow) return;
node.subflow = subflow;
refreshPins(node, subflow);
+ refreshWidgets(node, subflow, false);
node.size[0] = Math.max(100, LiteGraph.NODE_TEXT_SIZE * node.title.length * 0.45 + 160);
};
@@ -204,7 +246,8 @@ app.registerExtension({
// }
if (nodeData.name == "FileSubflow") {
- nodeType.prototype.refreshNode = function(subflow) { refreshNode(this, subflow); };
+ nodeType.prototype.onConfigure = function() { refreshWidgets(this, this.subflow, true); };
+ nodeType.prototype.refreshNode = function(subflow) { refreshNode(this, subflow); };
nodeType.prototype.getExportedOutput = function(slot) { return this.subflow.extras.outputSlots[slot]; }
nodeType.prototype.getExportedInput = function(slot) { return this.subflow.extras.inputSlots[slot]; }
diff --git a/web/lib/litegraph.core.js b/web/lib/litegraph.core.js
index 0cf4881d5..959a26c1f 100644
--- a/web/lib/litegraph.core.js
+++ b/web/lib/litegraph.core.js
@@ -12953,31 +12953,45 @@ LGraphNode.prototype.executeAction = function(action)
};
LGraphCanvas.onMenuNodeExport = function(value, options, e, menu, node) {
+ console.log(node);
if (!node) {
throw "no node passed";
}
- const getOption = ({ name, type, isExported }, pinType) => {
- const color = LGraphCanvas.link_type_colors[type];
- const innerHtml = `${name}${isExported ? " (exported)" : ""} `;
+ function getConfig(widgetName) {
+ const { nodeData } = this.constructor;
+ return nodeData?.input?.required[widgetName] ?? nodeData?.input?.optional?.[widgetName];
+ }
+
+ const getOption = (opt, pinType) => {
+ const color = LGraphCanvas.link_type_colors[opt.type];
+ const innerHtml = `${opt.name}${opt.isExported ? " (exported)" : ""} `;
return {
- name,
- type: pinType,
- content: innerHtml
+ pinType,
+ content: innerHtml,
+ ...opt
};
};
- let inputs = node.inputs ?? [];
+ let inputs = (node.inputs ?? []).filter((input) => !input.widget);
+ let widgets = (node.widgets ?? []).filter(({type}) => type != "button");
let outputs = node.outputs ?? [];
+ const isExported = (exports, v) => {
+ return exports.find(exp => exp.name == v.name) !== undefined;
+ };
if (node.properties?.exports?.inputs) {
- inputs = inputs.map( input => ( {...input, isExported: node.properties.exports.inputs.includes(input.name) }) );
+ inputs = inputs.map( input => ( {...input, isExported: isExported(node.properties.exports.inputs, input) }) );
+ }
+ if (node.properties?.exports?.widgets) {
+ widgets = widgets.map( widget => ( {...widget, isExported: isExported(node.properties.exports.widgets, widget) }) );
}
if (node.properties?.exports?.outputs) {
- outputs = outputs.map( output => ( {...output, isExported: node.properties.exports.outputs.includes(output.name) }) );
+ outputs = outputs.map( output => ( {...output, isExported: isExported(node.properties.exports.outputs, output) }) );
}
const exportableVars = [
...inputs.map((input) => getOption(input, "input")),
+ ...widgets.map((widget) => getOption(widget, "widget")),
null,
...outputs.map((output) => getOption(output, "output")),
];
@@ -12995,23 +13009,42 @@ LGraphNode.prototype.executeAction = function(action)
node.graph.beforeChange(/*?*/); //node
const exportVar = () => {
- if (!node.properties.exports) {
- node.properties.exports = { inputs: [], outputs: [] };
+ if(!node.properties.exports) {
+ node.properties.exports = {};
}
-
+ if (!node.properties.exports?.inputs) {
+ node.properties.exports.inputs = [];
+ }
+ if (!node.properties.exports?.widgets) {
+ node.properties.exports.widgets = [];
+ }
+ if (!node.properties.exports?.outputs) {
+ node.properties.exports.outputs = [];
+ }
+
const toggle = (arr, val) => {
- if (arr.includes(val)) {
- const i = arr.indexOf(val);
+ const i = arr.findIndex(ele => ele.name === val.name);
+ if ( i >= 0 ) {
arr.splice(i, 1);
} else {
- arr.push(val);
+ const extras = {};
+ // copy widget params
+ console.log(val);
+ if (val.options) {
+ extras.config = getConfig.call(node, val.name) ?? [val.type, val.options || {}];
+ extras.value = val.value;
+ console.log(extras.config);
+ }
+ arr.push({ name: val.name, ...extras });
}
};
- if (v.type == "input") {
- toggle(node.properties.exports.inputs, v.name);
- } else if (v.type == "output") {
- toggle(node.properties.exports.outputs, v.name);
+ if (v.pinType == "input") {
+ toggle(node.properties.exports.inputs, v);
+ } else if(v.pinType == "widget") {
+ toggle(node.properties.exports.widgets, v);
+ } else if (v.pinType == "output") {
+ toggle(node.properties.exports.outputs, v);
}
};
exportVar();
diff --git a/web/scripts/widgets.js b/web/scripts/widgets.js
index 4ef96516b..65cc1c6aa 100644
--- a/web/scripts/widgets.js
+++ b/web/scripts/widgets.js
@@ -570,7 +570,6 @@ export const ComfyWidgets = {
document.body.append(fileInput);
// Create the button widget for selecting the files
- console.log("adding widge")
uploadWidget = node.addWidget("button", "choose file with subflow", "subflow", () => {
fileInput.click();
});