From fb486c15c3b80940d142394b38125f7fb011f0b4 Mon Sep 17 00:00:00 2001 From: flyingshutter Date: Thu, 6 Apr 2023 19:02:28 +0200 Subject: [PATCH 01/13] make LoadImagesMask work with non RGBA images --- nodes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nodes.py b/nodes.py index 187d54a11..d33760dfc 100644 --- a/nodes.py +++ b/nodes.py @@ -915,6 +915,8 @@ class LoadImageMask: input_dir = folder_paths.get_input_directory() image_path = os.path.join(input_dir, image) i = Image.open(image_path) + if i.getbands() != ("R", "G", "B", "A"): + i = i.convert("RGBA") mask = None c = channel[0].upper() if c in i.getbands(): From 334b8dbebf98d888c99826a090562680deb4bb76 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Tue, 11 Apr 2023 01:08:01 -0400 Subject: [PATCH 02/13] use variables in css stylesheet --- web/style.css | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/web/style.css b/web/style.css index d00a2fbe2..d1bd730b8 100644 --- a/web/style.css +++ b/web/style.css @@ -1,6 +1,13 @@ :root { --fg-color: #000; --bg-color: #fff; + --comfy-menu-bg: #353535; + --comfy-input-bg: #222; + --input-text: #ddd; + --descrip-text: #999; + --drag-text: #ccc; + --error-text: #ff4444; + --border-color: #4e4e4e; } @media (prefers-color-scheme: dark) { @@ -39,8 +46,8 @@ body { position: fixed; /* Stay in place */ z-index: 100; /* Sit on top */ padding: 30px 30px 10px 30px; - background-color: #353535; /* Modal background */ - color: #ff4444; + background-color: var(--comfy-menu-bg); /* Modal background */ + color: var(--error-text); box-shadow: 0px 0px 20px #888888; border-radius: 10px; top: 50%; @@ -82,8 +89,8 @@ body { display: flex; flex-direction: column; align-items: center; - color: #999; - background-color: #353535; + color: var(--descrip-text); + background-color: var(--comfy-menu-bg); font-family: sans-serif; padding: 10px; border-radius: 0 8px 8px 8px; @@ -103,7 +110,7 @@ body { .comfy-menu-btns button { font-size: 10px; width: 50%; - color: #999 !important; + color: var(--descrip-text) !important; } .comfy-menu > button { @@ -114,10 +121,10 @@ body { .comfy-menu-btns button, .comfy-menu .comfy-list button, .comfy-modal button{ - color: #ddd; - background-color: #222; + color: var(--input-text); + background-color: var(--comfy-input-bg); border-radius: 8px; - border-color: #4e4e4e; + border-color: var(--border-color); border-style: solid; margin-top: 2px; } @@ -136,7 +143,7 @@ body { font-size: 12px; font-family: sans-serif; letter-spacing: 2px; - color: #cccccc; + color: var(--drag-text); text-shadow: 1px 0 1px black; position: absolute; top: 0; @@ -152,7 +159,7 @@ body { } .comfy-list { - color: #999; + color: var(--descrip-text); background-color: #333; margin-bottom: 10px; border-color: #4e4e4e; @@ -163,7 +170,7 @@ body { overflow-y: scroll; max-height: 100px; min-height: 25px; - background-color: #222; + background-color: var(--comfy-input-bg); padding: 5px; } @@ -206,16 +213,16 @@ button.comfy-queue-btn { .comfy-modal.comfy-manage-templates { text-align: center; font-family: sans-serif; - color: #999; + color: var(--descrip-text); z-index: 99; } .comfy-modal input, .comfy-modal select { - color: #ddd; - background-color: #222; + color: var(--input-text); + background-color: var(--comfy-input-bg); border-radius: 8px; - border-color: #4e4e4e; + border-color: var(--border-color); border-style: solid; font-size: inherit; } @@ -240,7 +247,7 @@ button.comfy-queue-btn { .graphdialog .name { font-size: 14px; font-family: sans-serif; - color: #999999; + color: var(--descrip-text); } .graphdialog button { @@ -251,10 +258,10 @@ button.comfy-queue-btn { } .graphdialog input, .graphdialog textarea, .graphdialog select { - background-color: #222; + background-color: var(--comfy-input-bg); border: 2px solid; - border-color: #444444; - color: #ddd; + border-color: var(--border-color); + color: var(--input-text); border-radius: 12px 0 0 12px; } From c458f7d9b44e04b25e08fa854b9cb62c3c96963d Mon Sep 17 00:00:00 2001 From: EllangoK Date: Tue, 11 Apr 2023 11:38:55 -0400 Subject: [PATCH 03/13] colorPalette modifies comfyUI as well --- web/extensions/core/colorPalette.js | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index a08d46684..31d918366 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -45,6 +45,17 @@ const colorPalettes = { "EVENT_LINK_COLOR": "#A86", "CONNECTING_LINK_COLOR": "#AFA", }, + "comfy_base": { + "fg-color": "#000", + "bg-color": "#fff", + "comfy-menu-bg": "#353535", + "comfy-input-bg": "#222", + "input-text": "#ddd", + "descrip-text": "#999", + "drag-text": "#ccc", + "error-text": "#ff4444", + "border-color": "#4e4e4e" + } }, }, "solarized": { @@ -88,6 +99,17 @@ const colorPalettes = { "EVENT_LINK_COLOR": "#268bd2", "CONNECTING_LINK_COLOR": "#859900", }, + "comfy_base": { + "fg-color": "#fdf6e3", // Base3 + "bg-color": "#002b36", // Base03 + "comfy-menu-bg": "#073642", // Base02 + "comfy-input-bg": "#002b36", // Base03 + "input-text": "#93a1a1", // Base1 + "descrip-text": "#586e75", // Base01 + "drag-text": "#839496", // Base0 + "error-text": "#dc322f", // Solarized Red + "border-color": "#657b83" // Base00 + } }, } }; @@ -251,6 +273,22 @@ app.registerExtension({ } } } + if (colorPalette.colors.comfy_base) { + const stylesheet = document.styleSheets[1]; + + for (let i = 0; i < stylesheet.cssRules.length; i++) { + const rule = stylesheet.cssRules[i]; + const selectorText = rule.selectorText; + + if (selectorText && selectorText === ":root") { + console.log("Found :root rule"); + for (const key in colorPalette.colors.comfy_base) { + rule.style.setProperty('--' + key, colorPalette.colors.comfy_base[key]); + } + break; + } + } + } app.canvas.draw(true, true); } }; From e1f8b7b24d013c128cbfa8cb2f8c0012d1f7b5ad Mon Sep 17 00:00:00 2001 From: EllangoK Date: Tue, 11 Apr 2023 12:09:15 -0400 Subject: [PATCH 04/13] fix node slot colors for solarized previously many dupes, and same colors as base --- web/extensions/core/colorPalette.js | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 31d918366..33c03ca18 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -63,41 +63,41 @@ const colorPalettes = { "name": "Solarized", "colors": { "node_slot": { - "CLIP": "#859900", // Green - "CLIP_VISION": "#6c71c4", // Indigo - "CLIP_VISION_OUTPUT": "#859900", // Green - "CONDITIONING": "#d33682", // Magenta - "CONTROL_NET": "#cb4b16", // Orange - "IMAGE": "#dc322f", // Red - "LATENT": "#268bd2", // Blue - "MASK": "#073642", // Base02 - "MODEL": "#cb4b16", // Orange - "STYLE_MODEL": "#073642", // Base02 - "UPSCALE_MODEL": "#6c71c4", // Indigo - "VAE": "#586e75", // Base1 + "CLIP": "#2AB7CA", // light blue + "CLIP_VISION": "#6c71c4", // blue violet + "CLIP_VISION_OUTPUT": "#859900", // olive green + "CONDITIONING": "#d33682", // magenta + "CONTROL_NET": "#d1ffd7", // light mint green + "IMAGE": "#5940bb", // deep blue violet + "LATENT": "#268bd2", // blue + "MASK": "#CCC9E7", // light purple-gray + "MODEL": "#dc322f", // red + "STYLE_MODEL": "#1a998a", // teal + "UPSCALE_MODEL": "#054A29", // dark green + "VAE": "#facfad", // light pink-orange }, "litegraph_base": { - "NODE_TITLE_COLOR": "#fdf6e3", - "NODE_SELECTED_TITLE_COLOR": "#b58900", + "NODE_TITLE_COLOR": "#fdf6e3", // Base3 + "NODE_SELECTED_TITLE_COLOR": "#A9D400", "NODE_TEXT_SIZE": 14, - "NODE_TEXT_COLOR": "#657b83", + "NODE_TEXT_COLOR": "#657b83", // Base00 "NODE_SUBTEXT_SIZE": 12, - "NODE_DEFAULT_COLOR": "#586e75", - "NODE_DEFAULT_BGCOLOR": "#073642", - "NODE_DEFAULT_BOXCOLOR": "#839496", + "NODE_DEFAULT_COLOR": "#094656", + "NODE_DEFAULT_BGCOLOR": "#073642", // Base02 + "NODE_DEFAULT_BOXCOLOR": "#839496", // Base0 "NODE_DEFAULT_SHAPE": "box", - "NODE_BOX_OUTLINE_COLOR": "#fdf6e3", + "NODE_BOX_OUTLINE_COLOR": "#fdf6e3", // Base3 "DEFAULT_SHADOW_COLOR": "rgba(0,0,0,0.5)", "DEFAULT_GROUP_FONT": 24, - "WIDGET_BGCOLOR": "#002b36", - "WIDGET_OUTLINE_COLOR": "#839496", - "WIDGET_TEXT_COLOR": "#fdf6e3", - "WIDGET_SECONDARY_TEXT_COLOR": "#93a1a1", + "WIDGET_BGCOLOR": "#002b36", // Base03 + "WIDGET_OUTLINE_COLOR": "#839496", // Base0 + "WIDGET_TEXT_COLOR": "#fdf6e3", // Base3 + "WIDGET_SECONDARY_TEXT_COLOR": "#93a1a1", // Base1 - "LINK_COLOR": "#2aa198", - "EVENT_LINK_COLOR": "#268bd2", - "CONNECTING_LINK_COLOR": "#859900", + "LINK_COLOR": "#2aa198", // Solarized Cyan + "EVENT_LINK_COLOR": "#268bd2", // Solarized Blue + "CONNECTING_LINK_COLOR": "#859900", // Solarized Green }, "comfy_base": { "fg-color": "#fdf6e3", // Base3 From 182bc15f03b0e786f523ab755d6ef8dc0671cb70 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Tue, 11 Apr 2023 13:11:39 -0400 Subject: [PATCH 05/13] adds light theme, fixes multiline css --- web/extensions/core/colorPalette.js | 61 +++++++++++++++++++++++++++-- web/style.css | 4 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 33c03ca18..5f5cc0355 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -5,9 +5,9 @@ import { api } from "/scripts/api.js"; // Manage color palettes const colorPalettes = { - "palette_1": { - "id": "palette_1", - "name": "Palette 1", + "dark": { + "id": "dark", + "name": "Dark (Default)", "colors": { "node_slot": { "CLIP": "#FFD500", // bright yellow @@ -58,6 +58,59 @@ const colorPalettes = { } }, }, + "light": { + "id": "light", + "name": "Light", + "colors": { + "node_slot": { + "CLIP": "#FFA726", // orange + "CLIP_VISION": "#5C6BC0", // indigo + "CLIP_VISION_OUTPUT": "#8D6E63", // brown + "CONDITIONING": "#EF5350", // red + "CONTROL_NET": "#66BB6A", // green + "IMAGE": "#42A5F5", // blue + "LATENT": "#AB47BC", // purple + "MASK": "#9CCC65", // light green + "MODEL": "#7E57C2", // deep purple + "STYLE_MODEL": "#D4E157", // lime + "VAE": "#FF7043", // deep orange + }, + "litegraph_base": { + "NODE_TITLE_COLOR": "#222", + "NODE_SELECTED_TITLE_COLOR": "#000", + "NODE_TEXT_SIZE": 14, + "NODE_TEXT_COLOR": "#444", + "NODE_SUBTEXT_SIZE": 12, + "NODE_DEFAULT_COLOR": "#F7F7F7", + "NODE_DEFAULT_BGCOLOR": "#F5F5F5", + "NODE_DEFAULT_BOXCOLOR": "#CCC", + "NODE_DEFAULT_SHAPE": "box", + "NODE_BOX_OUTLINE_COLOR": "#000", + "DEFAULT_SHADOW_COLOR": "rgba(0,0,0,0.1)", + "DEFAULT_GROUP_FONT": 24, + + "WIDGET_BGCOLOR": "#D4D4D4", + "WIDGET_OUTLINE_COLOR": "#999", + "WIDGET_TEXT_COLOR": "#222", + "WIDGET_SECONDARY_TEXT_COLOR": "#555", + + "LINK_COLOR": "#4CAF50", + "EVENT_LINK_COLOR": "#FF9800", + "CONNECTING_LINK_COLOR": "#2196F3", + }, + "comfy_base": { + "fg-color": "#222", + "bg-color": "#FFF", + "comfy-menu-bg": "#F5F5F5", + "comfy-input-bg": "#C9C9C9", + "input-text": "#222", + "descrip-text": "#444", + "drag-text": "#555", + "error-text": "#F44336", + "border-color": "#CCC" + } + }, + }, "solarized": { "id": "solarized", "name": "Solarized", @@ -116,7 +169,7 @@ const colorPalettes = { const id = "Comfy.ColorPalette"; const idCustomColorPalettes = "Comfy.CustomColorPalettes"; -const defaultColorPaletteId = "palette_1"; +const defaultColorPaletteId = "dark"; const els = {} // const ctxMenu = LiteGraph.ContextMenu; app.registerExtension({ diff --git a/web/style.css b/web/style.css index d1bd730b8..34e31726c 100644 --- a/web/style.css +++ b/web/style.css @@ -32,8 +32,8 @@ body { } .comfy-multiline-input { - background-color: var(--bg-color); - color: var(--fg-color); + background-color: var(--comfy-input-bg); + color: var(--input-text); overflow: hidden; overflow-y: auto; padding: 2px; From 57be70b04ac1cba042c2a073b04cff3d31bc1c44 Mon Sep 17 00:00:00 2001 From: EllangoK Date: Tue, 11 Apr 2023 13:24:32 -0400 Subject: [PATCH 06/13] simplify setting color of root, fixes fg and bg --- web/extensions/core/colorPalette.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 5f5cc0355..55aded62a 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -46,8 +46,8 @@ const colorPalettes = { "CONNECTING_LINK_COLOR": "#AFA", }, "comfy_base": { - "fg-color": "#000", - "bg-color": "#fff", + "fg-color": "#fff", + "bg-color": "#202020", "comfy-menu-bg": "#353535", "comfy-input-bg": "#222", "input-text": "#ddd", @@ -311,10 +311,12 @@ app.registerExtension({ const loadColorPalette = async (colorPalette) => { colorPalette = await completeColorPalette(colorPalette); if (colorPalette.colors) { + // Sets the colors of node slots and links if (colorPalette.colors.node_slot) { Object.assign(app.canvas.default_connection_color_byType, colorPalette.colors.node_slot); Object.assign(LGraphCanvas.link_type_colors, colorPalette.colors.node_slot); } + // Sets the colors of the LiteGraph objects if (colorPalette.colors.litegraph_base) { // Everything updates correctly in the loop, except the Node Title and Link Color for some reason app.canvas.node_title_color = colorPalette.colors.litegraph_base.NODE_TITLE_COLOR; @@ -326,20 +328,11 @@ app.registerExtension({ } } } + // Sets the color of ComfyUI elements if (colorPalette.colors.comfy_base) { - const stylesheet = document.styleSheets[1]; - - for (let i = 0; i < stylesheet.cssRules.length; i++) { - const rule = stylesheet.cssRules[i]; - const selectorText = rule.selectorText; - - if (selectorText && selectorText === ":root") { - console.log("Found :root rule"); - for (const key in colorPalette.colors.comfy_base) { - rule.style.setProperty('--' + key, colorPalette.colors.comfy_base[key]); - } - break; - } + const rootStyle = document.documentElement.style; + for (const key in colorPalette.colors.comfy_base) { + rootStyle.setProperty('--' + key, colorPalette.colors.comfy_base[key]); } } app.canvas.draw(true, true); From ee8ca5096726bfbdb389c368d4471fdf6c8c884e Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Tue, 11 Apr 2023 23:23:06 -0400 Subject: [PATCH 07/13] Change colour of background in light theme. --- web/extensions/core/colorPalette.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/extensions/core/colorPalette.js b/web/extensions/core/colorPalette.js index 55aded62a..94bea9ab3 100644 --- a/web/extensions/core/colorPalette.js +++ b/web/extensions/core/colorPalette.js @@ -100,7 +100,7 @@ const colorPalettes = { }, "comfy_base": { "fg-color": "#222", - "bg-color": "#FFF", + "bg-color": "#DDD", "comfy-menu-bg": "#F5F5F5", "comfy-input-bg": "#C9C9C9", "input-text": "#222", From a64d858356c9ad6b666752adecd6a7d3989f2a46 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:49:32 +0100 Subject: [PATCH 08/13] Add support for dropping images from urls --- web/scripts/app.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/web/scripts/app.js b/web/scripts/app.js index 0399ac722..b1892fc2a 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -362,8 +362,20 @@ class ComfyApp { if (n && n.onDragDrop && (await n.onDragDrop(event))) { return; } - + // Dragging from Chrome->Firefox there is a file but its a bmp, so ignore that + if (event.dataTransfer.files.length && event.dataTransfer.files[0].type !== "image/bmp") { await this.handleFile(event.dataTransfer.files[0]); + } else { + // Try loading the first URI in the transfer list + const validTypes = ["text/uri-list", "text/x-moz-url"]; + const match = [...event.dataTransfer.types].find((t) => validTypes.find(v => t === v)); + if (match) { + const uri = event.dataTransfer.getData(match)?.split("\n")?.[0]; + if (uri) { + await this.handleFile(await (await fetch(uri)).blob()); + } + } + } }); // Always clear over node on drag leave @@ -1090,7 +1102,7 @@ class ComfyApp { importA1111(this.graph, pngInfo.parameters); } } - } else if (file.type === "application/json" || file.name.endsWith(".json")) { + } else if (file.type === "application/json" || file.name?.endsWith(".json")) { const reader = new FileReader(); reader.onload = () => { this.loadGraphData(JSON.parse(reader.result)); From dadfac7d074d8f2cf30330f93076d8f27facd439 Mon Sep 17 00:00:00 2001 From: pythongosssss <125205205+pythongosssss@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:52:19 +0100 Subject: [PATCH 09/13] Changed default name to be the node type not title --- web/extensions/core/saveImageExtraOutput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/extensions/core/saveImageExtraOutput.js b/web/extensions/core/saveImageExtraOutput.js index ce97b5491..6032d4cc7 100644 --- a/web/extensions/core/saveImageExtraOutput.js +++ b/web/extensions/core/saveImageExtraOutput.js @@ -90,7 +90,7 @@ app.registerExtension({ const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined; if (!this.properties || !("Node name for S&R" in this.properties)) { - this.addProperty("Node name for S&R", this.title, "string"); + this.addProperty("Node name for S&R", this.constructor.type, "string"); } return r; From f177ad5e7598acc4b9cbd31291208a43c4747f94 Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Wed, 12 Apr 2023 17:40:52 -0400 Subject: [PATCH 10/13] Update litegraph from upstream. --- web/lib/litegraph.core.js | 142 +++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 49 deletions(-) diff --git a/web/lib/litegraph.core.js b/web/lib/litegraph.core.js index c3efa22a9..4189a48c0 100644 --- a/web/lib/litegraph.core.js +++ b/web/lib/litegraph.core.js @@ -142,6 +142,8 @@ pointerevents_method: "pointer", // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now) // TODO implement pointercancel, gotpointercapture, lostpointercapture, (pointerover, pointerout if necessary) + ctrl_shift_v_paste_connect_unselected_outputs: true, //[true!] allows ctrl + shift + v to paste nodes with the outputs of the unselected nodes connected with the inputs of the newly pasted nodes + /** * Register a node class so it can be listed when the user wants to create a new one * @method registerNodeType @@ -253,13 +255,18 @@ * @param {String|Object} type name of the node or the node constructor itself */ unregisterNodeType: function(type) { - var base_class = type.constructor === String ? this.registered_node_types[type] : type; - if(!base_class) - throw("node type not found: " + type ); - delete this.registered_node_types[base_class.type]; - if(base_class.constructor.name) - delete this.Nodes[base_class.constructor.name]; - }, + const base_class = + type.constructor === String + ? this.registered_node_types[type] + : type; + if (!base_class) { + throw "node type not found: " + type; + } + delete this.registered_node_types[base_class.type]; + if (base_class.constructor.name) { + delete this.Nodes[base_class.constructor.name]; + } + }, /** * Save a slot type and his node @@ -267,38 +274,49 @@ * @param {String|Object} type name of the node or the node constructor itself * @param {String} slot_type name of the slot type (variable type), eg. string, number, array, boolean, .. */ - registerNodeAndSlotType: function(type,slot_type,out){ + registerNodeAndSlotType: function(type, slot_type, out){ out = out || false; - var base_class = type.constructor === String && this.registered_node_types[type] !== "anonymous" ? this.registered_node_types[type] : type; - - var sCN = base_class.constructor.type; - - if (typeof slot_type == "string"){ - var aTypes = slot_type.split(","); - }else if (slot_type == this.EVENT || slot_type == this.ACTION){ - var aTypes = ["_event_"]; - }else{ - var aTypes = ["*"]; + const base_class = + type.constructor === String && + this.registered_node_types[type] !== "anonymous" + ? this.registered_node_types[type] + : type; + + const class_type = base_class.constructor.type; + + let allTypes = []; + if (typeof slot_type === "string") { + allTypes = slot_type.split(","); + } else if (slot_type == this.EVENT || slot_type == this.ACTION) { + allTypes = ["_event_"]; + } else { + allTypes = ["*"]; } - for (var i = 0; i < aTypes.length; ++i) { - var sT = aTypes[i]; //.toLowerCase(); - if (sT === ""){ - sT = "*"; + for (let i = 0; i < allTypes.length; ++i) { + let slotType = allTypes[i]; + if (slotType === "") { + slotType = "*"; } - var registerTo = out ? "registered_slot_out_types" : "registered_slot_in_types"; - if (typeof this[registerTo][sT] == "undefined") this[registerTo][sT] = {nodes: []}; - this[registerTo][sT].nodes.push(sCN); - + const registerTo = out + ? "registered_slot_out_types" + : "registered_slot_in_types"; + if (this[registerTo][slotType] === undefined) { + this[registerTo][slotType] = { nodes: [] }; + } + if (!this[registerTo][slotType].nodes.includes(class_type)) { + this[registerTo][slotType].nodes.push(class_type); + } + // check if is a new type - if (!out){ - if (!this.slot_types_in.includes(sT.toLowerCase())){ - this.slot_types_in.push(sT.toLowerCase()); + if (!out) { + if (!this.slot_types_in.includes(slotType.toLowerCase())) { + this.slot_types_in.push(slotType.toLowerCase()); this.slot_types_in.sort(); } - }else{ - if (!this.slot_types_out.includes(sT.toLowerCase())){ - this.slot_types_out.push(sT.toLowerCase()); + } else { + if (!this.slot_types_out.includes(slotType.toLowerCase())) { + this.slot_types_out.push(slotType.toLowerCase()); this.slot_types_out.sort(); } } @@ -1616,7 +1634,8 @@ var nRet = null; for (var i = nodes_list.length - 1; i >= 0; i--) { var n = nodes_list[i]; - if (n.isPointInside(x, y, margin)) { + var skip_title = n.constructor.title_mode == LiteGraph.NO_TITLE; + if (n.isPointInside(x, y, margin, skip_title)) { // check for lesser interest nodes (TODO check for overlapping, use the top) /*if (typeof n == "LGraphGroup"){ nRet = n; @@ -3967,8 +3986,8 @@ var aSource = (type+"").toLowerCase().split(","); var aDest = aSlots[i].type=="0"||aSlots[i].type=="*"?"0":aSlots[i].type; aDest = (aDest+"").toLowerCase().split(","); - for(sI=0;sI= 0 && target_slot !== null){ //console.debug("CONNbyTYPE type "+target_slotType+" for "+target_slot) return this.connect(slot, target_node, target_slot); @@ -4072,7 +4091,7 @@ if (source_node && source_node.constructor === Number) { source_node = this.graph.getNodeById(source_node); } - source_slot = source_node.findOutputSlotByType(source_slotType, false, true); + var source_slot = source_node.findOutputSlotByType(source_slotType, false, true); if (source_slot >= 0 && source_slot !== null){ //console.debug("CONNbyTYPE OUT! type "+source_slotType+" for "+source_slot) return source_node.connect(source_slot, this, slot); @@ -5184,6 +5203,7 @@ LGraphNode.prototype.executeAction = function(action) this.editor_alpha = 1; //used for transition this.pause_rendering = false; this.clear_background = true; + this.clear_background_color = "#222"; this.read_only = false; //if set to true users cannot modify the graph this.render_only_selected = true; @@ -6986,7 +7006,7 @@ LGraphNode.prototype.executeAction = function(action) block_default = true; } - if (e.code == "KeyC" && (e.metaKey || e.ctrlKey) && !e.shiftKey) { + if ((e.keyCode === 67) && (e.metaKey || e.ctrlKey) && !e.shiftKey) { //copy if (this.selected_nodes) { this.copyToClipboard(); @@ -6994,9 +7014,9 @@ LGraphNode.prototype.executeAction = function(action) } } - if (e.code == "KeyV" && (e.metaKey || e.ctrlKey) && !e.shiftKey) { + if ((e.keyCode === 86) && (e.metaKey || e.ctrlKey)) { //paste - this.pasteFromClipboard(); + this.pasteFromClipboard(e.shiftKey); } //delete or backspace @@ -7081,15 +7101,15 @@ LGraphNode.prototype.executeAction = function(action) var target_node = this.graph.getNodeById( link_info.origin_id ); - if (!target_node || !this.selected_nodes[target_node.id]) { - //improve this by allowing connections to non-selected nodes + if (!target_node) { continue; - } //not selected + } clipboard_info.links.push([ target_node._relative_id, link_info.origin_slot, //j, node._relative_id, - link_info.target_slot + link_info.target_slot, + target_node.id ]); } } @@ -7100,7 +7120,11 @@ LGraphNode.prototype.executeAction = function(action) ); }; - LGraphCanvas.prototype.pasteFromClipboard = function() { + LGraphCanvas.prototype.pasteFromClipboard = function(isConnectUnselected = false) { + // if ctrl + shift + v is off, return when isConnectUnselected is true (shift is pressed) to maintain old behavior + if (!LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs && isConnectUnselected) { + return; + } var data = localStorage.getItem("litegrapheditor_clipboard"); if (!data) { return; @@ -7149,7 +7173,16 @@ LGraphNode.prototype.executeAction = function(action) //create links for (var i = 0; i < clipboard_info.links.length; ++i) { var link_info = clipboard_info.links[i]; - var origin_node = nodes[link_info[0]]; + var origin_node; + var origin_node_relative_id = link_info[0]; + if (origin_node_relative_id != null) { + origin_node = nodes[origin_node_relative_id]; + } else if (LiteGraph.ctrl_shift_v_paste_connect_unselected_outputs && isConnectUnselected) { + var origin_node_id = link_info[4]; + if (origin_node_id) { + origin_node = this.graph.getNodeById(origin_node_id); + } + } var target_node = nodes[link_info[2]]; if( origin_node && target_node ) origin_node.connect(link_info[1], target_node, link_info[3]); @@ -8212,6 +8245,17 @@ LGraphNode.prototype.executeAction = function(action) this.ds.toCanvasContext(ctx); //render BG + if ( this.ds.scale < 1.5 && !bg_already_painted && this.clear_background_color ) + { + ctx.fillStyle = this.clear_background_color; + ctx.fillRect( + this.visible_area[0], + this.visible_area[1], + this.visible_area[2], + this.visible_area[3] + ); + } + if ( this.background_image && this.ds.scale > 0.5 && @@ -12274,7 +12318,7 @@ LGraphNode.prototype.executeAction = function(action) var aProps = LiteGraph.availableCanvasOptions; aProps.sort(); - for(pI in aProps){ + for(var pI in aProps){ var pX = aProps[pI]; panel.addWidget( "boolean", pX, graphcanvas[pX], {key: pX, on: "True", off: "False"}, fUpdate); } From 28e472aaed7be74fcb688b198306266c9637537b Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Wed, 12 Apr 2023 20:31:26 -0400 Subject: [PATCH 11/13] Add missing shortcuts from litegraph doc to README. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 877f46433..449531b86 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ Workflow examples can be found on the [Examples page](https://comfyanonymous.git - **Ctrl + A** select all nodes - **Ctrl + M** mute/unmute selected nodes - **Delete** or **Backspace** delete selected nodes +- **Space** Holding space key while moving the cursor moves the canvas around. It works when holding the mouse button down so it is easier to connect different nodes when the canvas gets too large. +- **Ctrl/Shift + Click** Add clicked node to selection. +- **Ctrl + C/Ctrl + V** - Copy and paste selected nodes, without maintaining the connection to the outputs of unselected nodes. +- **Ctrl + C/Ctrl + Shift + V** - Copy and paste selected nodes, and maintaining the connection from the outputs of unselected nodes to the inputs of the newly pasted nodes. +- Holding **Shift** and drag selected nodes - Move multiple selected nodes at the same time. # Installing From 2280498c4c58b003bafa9440db935f4167e1ea9b Mon Sep 17 00:00:00 2001 From: comfyanonymous Date: Wed, 12 Apr 2023 20:34:11 -0400 Subject: [PATCH 12/13] Add link to Arc instructions to readme. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 449531b86..77d979ac3 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,11 @@ Install the dependencies by opening your terminal inside the ComfyUI folder and: After this you should have everything installed and can proceed to running ComfyUI. +### Others: + +[Intel Arc](https://github.com/comfyanonymous/ComfyUI/discussions/476) + +Mac/MPS: There is basic support in the code but until someone makes some install instruction you are on your own. ### I already have another UI for Stable Diffusion installed do I really have to install all of these dependencies? From b062f87a7ea54d00c248abab49380db18fb6e20b Mon Sep 17 00:00:00 2001 From: FizzleDorf <1fizzledorf@gmail.com> Date: Wed, 12 Apr 2023 20:57:13 -0400 Subject: [PATCH 13/13] Seed controls added to Ksamplers (#296) Co-authored-by: flyingshutter --- .gitignore | 1 + web/extensions/core/widgetInputs.js | 8 ++-- web/scripts/app.js | 5 +++ web/scripts/widgets.js | 67 ++++++++++++++++++----------- 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index d311a2a09..df6adbe4b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ temp/ custom_nodes/ !custom_nodes/example_node.py.example extra_model_paths.yaml +/.vs diff --git a/web/extensions/core/widgetInputs.js b/web/extensions/core/widgetInputs.js index 865af7763..3764c9848 100644 --- a/web/extensions/core/widgetInputs.js +++ b/web/extensions/core/widgetInputs.js @@ -1,4 +1,4 @@ -import { ComfyWidgets, addRandomizeWidget } from "/scripts/widgets.js"; +import { ComfyWidgets, addValueControlWidget } from "/scripts/widgets.js"; import { app } from "/scripts/app.js"; const CONVERTED_TYPE = "converted-widget"; @@ -23,7 +23,7 @@ function hideWidget(node, widget, suffix = "") { return widget.origSerializeValue ? widget.origSerializeValue() : widget.value; }; - // Hide any linked widgets, e.g. seed+randomize + // Hide any linked widgets, e.g. seed+seedControl if (widget.linkedWidgets) { for (const w of widget.linkedWidgets) { hideWidget(node, w, ":" + widget.name); @@ -40,7 +40,7 @@ function showWidget(widget) { delete widget.origComputeSize; delete widget.origSerializeValue; - // Hide any linked widgets, e.g. seed+randomize + // Hide any linked widgets, e.g. seed+seedControl if (widget.linkedWidgets) { for (const w of widget.linkedWidgets) { showWidget(w); @@ -285,7 +285,7 @@ app.registerExtension({ } if (widget.type === "number") { - addRandomizeWidget(this, widget, "Random after every gen"); + addValueControlWidget(this, widget, "fixed"); } // When our value changes, update other widgets to reflect our changes diff --git a/web/scripts/app.js b/web/scripts/app.js index b1892fc2a..2f5e73220 100644 --- a/web/scripts/app.js +++ b/web/scripts/app.js @@ -949,6 +949,11 @@ class ComfyApp { widget.value = widget.value.slice(7); } } + if (widget.name == "control_after_generate") { + if (widget.value == true) { + widget.value = "randomize"; + } + } } } } diff --git a/web/scripts/widgets.js b/web/scripts/widgets.js index d1a9c6c6e..2acc5f2c0 100644 --- a/web/scripts/widgets.js +++ b/web/scripts/widgets.js @@ -10,37 +10,54 @@ function getNumberDefaults(inputData, defaultStep) { return { val: defaultVal, config: { min, max, step: 10.0 * step } }; } -export function addRandomizeWidget(node, targetWidget, name, defaultValue = false) { - const randomize = node.addWidget("toggle", name, defaultValue, function (v) {}, { - on: "enabled", - off: "disabled", - serialize: false, // Don't include this in prompt. - }); +export function addValueControlWidget(node, targetWidget, defaultValue = "randomize", values) { + const valueControl = node.addWidget("combo", "control_after_generate", defaultValue, function (v) { }, { + values: ["fixed", "increment", "decrement", "randomize"], + serialize: false, // Don't include this in prompt. + }); + valueControl.afterQueued = () => { - randomize.afterQueued = () => { - if (randomize.value) { - const min = targetWidget.options?.min; - let max = targetWidget.options?.max; - if (min != null || max != null) { - if (max) { - // limit max to something that javascript can handle - max = Math.min(1125899906842624, max); - } - targetWidget.value = Math.floor(Math.random() * ((max ?? 9999999999) - (min ?? 0) + 1) + (min ?? 0)); - } else { - targetWidget.value = Math.floor(Math.random() * 1125899906842624); - } + var v = valueControl.value; + + let min = targetWidget.options.min; + let max = targetWidget.options.max; + // limit to something that javascript can handle + max = Math.min(1125899906842624, max); + min = Math.max(-1125899906842624, min); + let range = (max - min) / (targetWidget.options.step / 10); + + //adjust values based on valueControl Behaviour + switch (v) { + case "fixed": + break; + case "increment": + targetWidget.value += targetWidget.options.step / 10; + break; + case "decrement": + targetWidget.value -= targetWidget.options.step / 10; + break; + case "randomize": + targetWidget.value = Math.floor(Math.random() * range) * (targetWidget.options.step / 10) + min; + default: + break; } - }; - return randomize; -} + /*check if values are over or under their respective + * ranges and set them to min or max.*/ + if (targetWidget.value < min) + targetWidget.value = min; + + if (targetWidget.value > max) + targetWidget.value = max; + } + return valueControl; +}; function seedWidget(node, inputName, inputData) { const seed = ComfyWidgets.INT(node, inputName, inputData); - const randomize = addRandomizeWidget(node, seed.widget, "Random seed after every gen", true); + const seedControl = addValueControlWidget(node, seed.widget, "randomize"); - seed.widget.linkedWidgets = [randomize]; - return { widget: seed, randomize }; + seed.widget.linkedWidgets = [seedControl]; + return seed; } const MultilineSymbol = Symbol();