diff --git a/.gitignore b/.gitignore index 56ed55ee1..df6adbe4b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ temp/ custom_nodes/ !custom_nodes/example_node.py.example extra_model_paths.yaml -.vs/ +/.vs diff --git a/.vs/ComfyUI/FileContentIndex/read.lock b/.vs/ComfyUI/FileContentIndex/read.lock new file mode 100644 index 000000000..e69de29bb diff --git a/.vs/ComfyUI/v17/.suo b/.vs/ComfyUI/v17/.suo new file mode 100644 index 000000000..564078dfd Binary files /dev/null and b/.vs/ComfyUI/v17/.suo differ diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 000000000..f8b488856 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 000000000..6e79ddaa6 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,11 @@ +{ + "ExpandedNodes": [ + "", + "\\web", + "\\web\\extensions", + "\\web\\extensions\\core", + "\\web\\scripts" + ], + "SelectedNode": "\\web\\scripts\\widgets.js", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 000000000..3bcc9c10f Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/web/extensions/core/widgetInputs.js b/web/extensions/core/widgetInputs.js index d571f00a9..f55abfc45 100644 --- a/web/extensions/core/widgetInputs.js +++ b/web/extensions/core/widgetInputs.js @@ -284,8 +284,8 @@ app.registerExtension({ } } - if (widget.type === "number") { - addSeedControlWidget(this, widget, "fixed_seed"); + if (widget.type === "combo") { + addSeedControlWidget(this, widget, "fixed seed"); } // When our value changes, update other widgets to reflect our changes diff --git a/web/scripts/app.js b/web/scripts/app.js index dfa7cd02c..a26c3547a 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -371,6 +371,96 @@ class ComfyApp { }); } + /** + * Handle mouse + * + * Move group by header + */ + #addProcessMouseHandler() { + const self = this; + + const origProcessMouseDown = LGraphCanvas.prototype.processMouseDown; + LGraphCanvas.prototype.processMouseDown = function(e) { + const res = origProcessMouseDown.apply(this, arguments); + + this.selected_group_moving = false; + + if (this.selected_group && !this.selected_group_resizing) { + var font_size = + this.selected_group.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE; + var height = font_size * 1.4; + + // Move group by header + if (LiteGraph.isInsideRectangle(e.canvasX, e.canvasY, this.selected_group.pos[0], this.selected_group.pos[1], this.selected_group.size[0], height)) { + this.selected_group_moving = true; + } + } + + return res; + } + + const origProcessMouseMove = LGraphCanvas.prototype.processMouseMove; + LGraphCanvas.prototype.processMouseMove = function(e) { + const orig_selected_group = this.selected_group; + + if (this.selected_group && !this.selected_group_resizing && !this.selected_group_moving) { + this.selected_group = null; + } + + const res = origProcessMouseMove.apply(this, arguments); + + if (orig_selected_group && !this.selected_group_resizing && !this.selected_group_moving) { + this.selected_group = orig_selected_group; + } + + return res; + }; + } + + /** + * Draws group header bar + */ + #addDrawGroupsHandler() { + const self = this; + + const origDrawGroups = LGraphCanvas.prototype.drawGroups; + LGraphCanvas.prototype.drawGroups = function(canvas, ctx) { + if (!this.graph) { + return; + } + + var groups = this.graph._groups; + + ctx.save(); + ctx.globalAlpha = 0.7 * this.editor_alpha; + + for (var i = 0; i < groups.length; ++i) { + var group = groups[i]; + + if (!LiteGraph.overlapBounding(this.visible_area, group._bounding)) { + continue; + } //out of the visible area + + ctx.fillStyle = group.color || "#335"; + ctx.strokeStyle = group.color || "#335"; + var pos = group._pos; + var size = group._size; + ctx.globalAlpha = 0.25 * this.editor_alpha; + ctx.beginPath(); + var font_size = + group.font_size || LiteGraph.DEFAULT_GROUP_FONT_SIZE; + ctx.rect(pos[0] + 0.5, pos[1] + 0.5, size[0], font_size * 1.4); + ctx.fill(); + ctx.globalAlpha = this.editor_alpha; + } + + ctx.restore(); + + const res = origDrawGroups.apply(this, arguments); + return res; + } + } + /** * Draws node highlights (executing, drag drop) and progress bar */ @@ -518,6 +608,8 @@ class ComfyApp { canvasEl.tabIndex = "1"; document.body.prepend(canvasEl); + this.#addProcessMouseHandler(); + this.graph = new LGraph(); const canvas = (this.canvas = new LGraphCanvas(canvasEl, this.graph)); this.ctx = canvasEl.getContext("2d"); @@ -561,6 +653,7 @@ class ComfyApp { setInterval(() => localStorage.setItem("workflow", JSON.stringify(this.graph.serialize())), 1000); this.#addDrawNodeHandler(); + this.#addDrawGroupsHandler(); this.#addApiUpdateHandlers(); this.#addDropHandler(); this.#addPasteHandler(); @@ -590,7 +683,10 @@ class ComfyApp { const nodeData = defs[nodeId]; const node = Object.assign( function ComfyNode() { - const inputs = nodeData["input"]["required"]; + var inputs = nodeData["input"]["required"]; + if (nodeData["input"]["optional"] != undefined){ + inputs = Object.assign({}, nodeData["input"]["required"], nodeData["input"]["optional"]) + } const config = { minWidth: 1, minHeight: 1 }; for (const inputName in inputs) { const inputData = inputs[inputName]; @@ -611,8 +707,10 @@ class ComfyApp { } } - for (const output of nodeData["output"]) { - this.addOutput(output, output); + for (const o in nodeData["output"]) { + const output = nodeData["output"][o]; + const outputName = nodeData["output_name"][o] || output; + this.addOutput(outputName, output); } const s = this.computeSize(); @@ -763,7 +861,7 @@ class ComfyApp { if (node.widgets) { for (const widget of node.widgets) { // Allow widgets to run callbacks after a prompt has been queued - // e.g. seed control after every gen + // e.g. random seed after every gen if (widget.afterQueued) { widget.afterQueued(); } @@ -808,6 +906,31 @@ class ComfyApp { } this.extensions.push(extension); } + + /** + * Refresh combo list on whole nodes + */ + async refreshComboInNodes() { + const defs = await api.getNodeDefs(); + + for(let nodeNum in this.graph._nodes) { + const node = this.graph._nodes[nodeNum]; + + const def = defs[node.type]; + + for(const widgetNum in node.widgets) { + const widget = node.widgets[widgetNum] + + if(widget.type == "combo" && def["input"]["required"][widget.name] !== undefined) { + widget.options.values = def["input"]["required"][widget.name][0]; + + if(!widget.options.values.includes(widget.value)) { + widget.value = widget.options.values[0]; + } + } + } + } + } } export const app = new ComfyApp(); diff --git a/web/scripts/widgets.js b/web/scripts/widgets.js index 2e085b9d8..dbaa44908 100644 --- a/web/scripts/widgets.js +++ b/web/scripts/widgets.js @@ -10,17 +10,16 @@ function getNumberDefaults(inputData, defaultStep) { return { val: defaultVal, config: { min, max, step: 10.0 * step } }; } -export function addSeedControlWidget(node, targetWidget, defaultValue = "fixed seed", values) { +export function addSeedControlWidget(node, targetWidget, defauly, options) { const seedControl = node.addWidget("combo", "seed control after generating", "fixed seed", function (v) { }, { values: ["fixed seed", "increment", "decrement", "randomize"] },) seedControl.afterQueued = () => { - var v = seedControl.value; switch (v) { case ("fixed seed"): - console.log("Fixed Seed"); + console.log("fixed seed"); break; case ("increment"): targetWidget.value += 1;