Merge branch 'comfyanonymous:master' into image-to-mask
This commit is contained in:
commit
45b907fbf1
|
@ -8,3 +8,4 @@ temp/
|
|||
custom_nodes/
|
||||
!custom_nodes/example_node.py.example
|
||||
extra_model_paths.yaml
|
||||
/.vs
|
||||
|
|
10
README.md
10
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
|
||||
|
||||
|
@ -92,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?
|
||||
|
||||
|
|
2
nodes.py
2
nodes.py
|
@ -940,6 +940,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():
|
||||
|
|
|
@ -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
|
||||
|
@ -45,6 +45,70 @@ const colorPalettes = {
|
|||
"EVENT_LINK_COLOR": "#A86",
|
||||
"CONNECTING_LINK_COLOR": "#AFA",
|
||||
},
|
||||
"comfy_base": {
|
||||
"fg-color": "#fff",
|
||||
"bg-color": "#202020",
|
||||
"comfy-menu-bg": "#353535",
|
||||
"comfy-input-bg": "#222",
|
||||
"input-text": "#ddd",
|
||||
"descrip-text": "#999",
|
||||
"drag-text": "#ccc",
|
||||
"error-text": "#ff4444",
|
||||
"border-color": "#4e4e4e"
|
||||
}
|
||||
},
|
||||
},
|
||||
"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": "#DDD",
|
||||
"comfy-menu-bg": "#F5F5F5",
|
||||
"comfy-input-bg": "#C9C9C9",
|
||||
"input-text": "#222",
|
||||
"descrip-text": "#444",
|
||||
"drag-text": "#555",
|
||||
"error-text": "#F44336",
|
||||
"border-color": "#CCC"
|
||||
}
|
||||
},
|
||||
},
|
||||
"solarized": {
|
||||
|
@ -52,49 +116,60 @@ 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
|
||||
"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
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const id = "Comfy.ColorPalette";
|
||||
const idCustomColorPalettes = "Comfy.CustomColorPalettes";
|
||||
const defaultColorPaletteId = "palette_1";
|
||||
const defaultColorPaletteId = "dark";
|
||||
const els = {}
|
||||
// const ctxMenu = LiteGraph.ContextMenu;
|
||||
app.registerExtension({
|
||||
|
@ -236,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;
|
||||
|
@ -251,6 +328,13 @@ app.registerExtension({
|
|||
}
|
||||
}
|
||||
}
|
||||
// Sets the color of ComfyUI elements
|
||||
if (colorPalette.colors.comfy_base) {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,12 +255,17 @@
|
|||
* @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 );
|
||||
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)
|
||||
if (base_class.constructor.name) {
|
||||
delete this.Nodes[base_class.constructor.name];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -269,36 +276,47 @@
|
|||
*/
|
||||
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;
|
||||
const base_class =
|
||||
type.constructor === String &&
|
||||
this.registered_node_types[type] !== "anonymous"
|
||||
? this.registered_node_types[type]
|
||||
: type;
|
||||
|
||||
var sCN = base_class.constructor.type;
|
||||
const class_type = base_class.constructor.type;
|
||||
|
||||
if (typeof slot_type == "string"){
|
||||
var aTypes = slot_type.split(",");
|
||||
let allTypes = [];
|
||||
if (typeof slot_type === "string") {
|
||||
allTypes = slot_type.split(",");
|
||||
} else if (slot_type == this.EVENT || slot_type == this.ACTION) {
|
||||
var aTypes = ["_event_"];
|
||||
allTypes = ["_event_"];
|
||||
} else {
|
||||
var aTypes = ["*"];
|
||||
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 = "*";
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
// check if is a new type
|
||||
if (!out) {
|
||||
if (!this.slot_types_in.includes(sT.toLowerCase())){
|
||||
this.slot_types_in.push(sT.toLowerCase());
|
||||
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());
|
||||
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<aSource.length;sI++){
|
||||
for(dI=0;dI<aDest.length;dI++){
|
||||
for(var sI=0;sI<aSource.length;sI++){
|
||||
for(var dI=0;dI<aDest.length;dI++){
|
||||
if (aSource[sI]=="_event_") aSource[sI] = LiteGraph.EVENT;
|
||||
if (aDest[sI]=="_event_") aDest[sI] = LiteGraph.EVENT;
|
||||
if (aSource[sI]=="*") aSource[sI] = 0;
|
||||
|
@ -3987,8 +4006,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<aSource.length;sI++){
|
||||
for(dI=0;dI<aDest.length;dI++){
|
||||
for(var sI=0;sI<aSource.length;sI++){
|
||||
for(var dI=0;dI<aDest.length;dI++){
|
||||
if (aSource[sI]=="*") aSource[sI] = 0;
|
||||
if (aDest[sI]=="*") aDest[sI] = 0;
|
||||
if (aSource[sI] == aDest[dI]) {
|
||||
|
@ -4019,7 +4038,7 @@
|
|||
if (target_node && target_node.constructor === Number) {
|
||||
target_node = this.graph.getNodeById(target_node);
|
||||
}
|
||||
target_slot = target_node.findInputSlotByType(target_slotType, false, true);
|
||||
var target_slot = target_node.findInputSlotByType(target_slotType, false, true);
|
||||
if (target_slot >= 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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -937,6 +949,11 @@ class ComfyApp {
|
|||
widget.value = widget.value.slice(7);
|
||||
}
|
||||
}
|
||||
if (widget.name == "control_after_generate") {
|
||||
if (widget.value == true) {
|
||||
widget.value = "randomize";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1090,7 +1107,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));
|
||||
|
|
|
@ -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",
|
||||
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
|
||||
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;
|
||||
}
|
||||
targetWidget.value = Math.floor(Math.random() * ((max ?? 9999999999) - (min ?? 0) + 1) + (min ?? 0));
|
||||
} else {
|
||||
targetWidget.value = Math.floor(Math.random() * 1125899906842624);
|
||||
}
|
||||
/*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;
|
||||
};
|
||||
return randomize;
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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) {
|
||||
|
@ -25,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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue