From 9d1c610b8975b13ff3b311d5db7b06a583f14cd9 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 187d54a1..d33760df 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 40ad2d4a102106b3e0fd8438af24277c3e7cb5cd 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 d00a2fbe..d1bd730b 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 73c4ba11fafb7088da6504f8be551b763e5474bb 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 a08d4668..31d91836 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 c975fef6206e8f87e3f35c4738848e9d893e0d21 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 31d91836..33c03ca1 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 eae159eb4c061e7de5680008690fef838eef8e20 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 33c03ca1..5f5cc035 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 d1bd730b..34e31726 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 19ce3df8c009b5b4f8e91005bb314371c211d5ce 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 5f5cc035..55aded62 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 6c69853afd447ec33b146f57dc3b28999c8537ec 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 55aded62..94bea9ab 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 d6a3c0d424c7e49bd114a019b333d8dadb68ef0f 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 0399ac72..b1892fc2 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 a3516225f9488b82c6c309d7f00dc3705607733d 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 ce97b549..6032d4cc 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 e3566679bd18af0da00004472eec1836639d036e 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 c3efa22a..4189a48c 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 37beea0af55228c565b9e129928218aff45eb3f5 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 877f4643..449531b8 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 bada50f132a39568364bd0ecde2e73fa9deadbf3 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 449531b8..77d979ac 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 3f52e7cbb16c3469cc54f751d4b3fe9354b294cf 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 d311a2a0..df6adbe4 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 865af776..3764c984 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 b1892fc2..2f5e7322 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 d1a9c6c6..2acc5f2c 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();