Disable addDOMWidget replacement for now

It looks like it kind of break different dom-related widgets. The final goal should hopefully is somewhat achieve desirable backward-compatible with native ComfyuUI dom widget implementation.
This commit is contained in:
Trung0246
2024-01-16 15:11:37 -08:00
committed by GitHub
parent b4aaa3ad0e
commit 3637b748cc
5 changed files with 553 additions and 243 deletions
+403 -59
View File
@@ -13,8 +13,10 @@ import builtins
import json
import copy
import functools
import itertools
import copy
import re
import uuid
# Self Code
from . import utils as lib0246
@@ -22,6 +24,7 @@ from . import utils as lib0246
# 3rd Party
import aiohttp.web
import natsort
import toposort
# ComfyUI
from server import PromptServer
@@ -327,9 +330,11 @@ def junction_unpack_raw(
return base_dict
def update_hold_db(key, data):
if data is not None:
Hold.HOLD_DB[key]["data"].extend(data)
return [None] if not Hold.HOLD_DB[key]["data"] else Hold.HOLD_DB[key]["data"]
if key in Hold.HOLD_DB:
if data is not None:
Hold.HOLD_DB[key]["data"].extend(data)
return [None] if not Hold.HOLD_DB[key]["data"] else Hold.HOLD_DB[key]["data"]
return [None]
def junction_pack_loop(_junc_in, name, value):
_junc_in[("type", name)] = type(value).__name__
@@ -911,46 +916,72 @@ class Hold:
CATEGORY = "0246"
def execute(self, _data_in = None, _id = None, _hold = None, _mode = None, _key_id = None, **kwargs):
_data_in = kwargs.get(next(filter(lambda x: x.startswith("_data_in"), kwargs.keys())), _data_in)
mode = _mode[0] if _mode else None
for key in kwargs:
if key.startswith("_data_in"):
_data_in = kwargs[key]
break
if _id[0] not in Hold.HOLD_DB:
Hold.HOLD_DB[_id[0]] = {
if isinstance(_id, list):
_id = str(_id[0]) if len(_id) > 0 else None
if isinstance(_hold, list):
_hold = _hold[0] if len(_hold) > 0 else None
if isinstance(_mode, list):
_mode = _mode[0] if len(_mode) > 0 else None
if isinstance(_key_id, list):
_key_id = str(_key_id[0]) if len(_key_id) > 0 else None
if _id not in Hold.HOLD_DB:
Hold.HOLD_DB[_id] = {
"track": PROMPT_ID,
"data": []
}
if Hold.HOLD_DB[_id[0]]["track"] != PROMPT_ID:
Hold.HOLD_DB[_id[0]]["track"] = PROMPT_ID
ui_text = f"Id: {_id}, "
if mode != "save":
Hold.HOLD_DB[_id[0]]["data"] = []
ext_db = _key_id in Hold.HOLD_DB
ui_text = f"Id: {_id[0]}, "
# Check if _key_id is specified and process accordingly
if _key_id and len(_key_id[0]) > 0:
if mode == "clear":
Hold.HOLD_DB[_key_id[0]]["data"] = []
result = update_hold_db(_key_id[0], _data_in)
ui_text += f"Size: {lib0246.len_zero_arr(result)}, Key: {_key_id[0]}, "
# Check if _hold is specified and process accordingly
elif _hold and _hold[0]:
result = _data_in if _data_in is not None else [None]
ui_text += f"Size: {lib0246.len_zero_arr(result)}, Passed, "
else:
# Update the outputs and HOLD_DB for _id if specified
if _id:
result = update_hold_db(_id[0], None if (mode == "ignore" and len(Hold.HOLD_DB[_id[0]]["data"]) > 0) else _data_in)
BASE_EXECUTOR.outputs[_id[0]] = Hold.HOLD_DB[_id[0]]["data"]
ui_text += f"Size: {len(result)}, "
if mode == "clear":
Hold.HOLD_DB[_id[0]]["data"] = []
result = None
if _hold:
result = Hold.HOLD_DB[_id]["data"]
if ext_db:
if _mode == "clear":
Hold.HOLD_DB[_key_id]["data"].clear()
elif _mode == "ignore":
result = Hold.HOLD_DB[_key_id]["data"]
elif _mode == "save":
Hold.HOLD_DB[_id]["data"].extend(Hold.HOLD_DB[_key_id]["data"])
if _mode != "save":
Hold.HOLD_DB[_id]["data"].clear()
Hold.HOLD_DB[_id]["data"].extend(_data_in)
ui_text += f"Passed, Size: {len(result)}, "
elif ext_db:
result = _data_in
if _data_in is None or (
Hold.HOLD_DB[_key_id]["track"] == PROMPT_ID and
len(Hold.HOLD_DB[_key_id]["data"]) > 0
):
if _mode == "ignore":
result = Hold.HOLD_DB[_key_id]["data"]
else:
result = update_hold_db(_key_id, _data_in)
ui_text += f"Key: {_key_id}, Size: {len(result)}, "
elif _data_in and len(_data_in) > 0:
if Hold.HOLD_DB[_id]["track"] != PROMPT_ID:
Hold.HOLD_DB[_id]["track"] = PROMPT_ID
if _mode != "save":
Hold.HOLD_DB[_id]["data"].clear()
result = []
elif _mode == "clear":
result = _data_in
Hold.HOLD_DB[_id]["data"] = _data_in
else:
ui_text += f"None, "
result = [None]
result = update_hold_db(_id, _data_in)
ui_text += f"Size: {len(result)}, "
ui_text += f"Track: {Hold.HOLD_DB[_id[0]]['track']}"
if not result or len(result) == 0:
result = [None]
ui_text += f"Track: {Hold.HOLD_DB[_id]['track']}"
return {
"ui": {
@@ -1127,7 +1158,10 @@ class Beautify:
CATEGORY = "0246"
def execute(self, data = None, mode = None, **kwargs):
data = kwargs.get(next(filter(lambda x: x.startswith("data"), kwargs.keys())), data)
for key in kwargs:
if key.startswith("data"):
data = kwargs[key]
break
raw_mode = 0
res_str = None
@@ -1967,7 +2001,11 @@ class Hub:
name_data = {}
curr_nodes = _workflow[0]["workflow"]["nodes"]
self_index = next(i for i, _ in enumerate(curr_nodes) if _["id"] == int(_id[0]))
self_index = None
for i, _ in enumerate(curr_nodes):
if _["id"] == int(_id[0]):
self_index = i
break
curr_extra = _workflow[0]["workflow"]["extra"]
for i, pin in enumerate(curr_nodes[self_index]["outputs"]):
@@ -2036,45 +2074,351 @@ class Hub:
######################################################################################
CLOUD_METHOD = {
"text": {
"func": False, # Can be used as function
"text": None, # Cannot be used as function if None
"pin": None,
"weight": {
"bind": False, # Can affect other clouds if itself is affected
"many": False, # Can output multiple clouds
"sole": False # Can only exist once for same kind within a group
},
"weight": {
"func": True,
"bind": False,
"many": False,
"sole": True,
"sole": True, # Can only exist once for same kind within a group
},
"rand": {
"func": True,
"bind": True,
"many": True,
"sole": True,
},
"cycle": {
"func": True,
"bind": True,
"many": True,
"sole": True,
},
"merge": {
"func": True,
"bind": True,
"many": False,
"sole": True,
},
}
def group_query_inst(group_dict, group_id, group_list = None, inst_curr = None):
inst_curr = set() if inst_curr is None else inst_curr
group_list = list(group_dict.keys()) if group_list is None else group_list
stack = [group_id]
seen = set()
while len(stack) > 0:
track_group = stack.pop()
if track_group in seen:
continue
seen.add(track_group)
if "group" in group_dict[track_group]:
stack.extend(group_dict[track_group]["group"])
if "inst" in group_dict[track_group]:
for track_inst in group_dict[track_group]["inst"]:
inst_curr.add(track_inst)
return inst_curr
class CloudFunc:
def __init__(self, kind):
self.func = getattr(CloudFunc, f"func_{kind}")
"""
{
eval # Evaluated data
data # Persistent data
order # Current isntance order
index # Current instance result index
change # Whether whole cloud changed
}
"""
@classmethod
def func_text(cls, obj, inst_id, pass_state, state):
return obj.inst[inst_id]["widgets_values"][0]
@classmethod
def func_weight(cls, obj, inst_id, pass_state, state):
# [TODO] Escape special characters for _[0]
return list(map(lambda _: f"({_[0]}: {_[1]})", itertools.product(pass_state["data"], obj.inst[inst_id]["widgets_values"][0])))
@classmethod
def func_rand(cls, obj, inst_id, pass_state, state):
res = []
if inst_id not in state["data"]:
state["data"][inst_id] = {
"rand": random.Random(),
"seed_mode": [],
"seed_data": [],
"seed_count": 0
}
curr_state = state["data"][inst_id]
curr_state["seed_count"] = len(obj.inst[inst_id]["widgets_values"][0])
curr_seed_len = len(curr_state["seed_data"])
if curr_state["seed_count"] > curr_seed_len:
curr_state["seed_data"].extend([None] * (curr_state["seed_count"] - curr_seed_len))
curr_state["seed_mode"].extend([None] * (curr_state["seed_count"] - curr_seed_len))
elif curr_state["seed_count"] < curr_seed_len:
curr_state["seed_data"] = curr_state["seed_data"][:curr_state["seed_count"]]
curr_state["seed_mode"] = curr_state["seed_mode"][:curr_state["seed_count"]]
for i, curr_count, curr_seed, curr_mode in zip(itertools.count(start=0, step=1), *obj.inst[inst_id]["widgets_values"]):
if curr_state["seed_data"][i] is None or \
curr_state["seed_mode"][i] != curr_mode or \
state["change"]:
curr_state["seed_data"][i] = curr_seed
curr_state["seed_mode"][i] = curr_mode
curr_state["rand"].seed(curr_seed)
else:
match curr_mode:
case "fix":
curr_state["rand"].seed(curr_seed)
case "add":
curr_state["seed_data"][i] += 1
curr_state["rand"].seed(curr_state["seed_data"][i])
case "sub":
curr_state["seed_data"][i] -= 1
curr_state["rand"].seed(curr_state["seed_data"][i])
case _:
# Default to "rand" mode
pass
choice_list: list = copy.copy(pass_state["data"])
for i in range(curr_count):
curr_choice = curr_state["rand_inst"].choice(choice_list)
res.append(curr_choice)
choice_list.remove(curr_choice)
for i in pass_state["index"]:
pass_state["index"][i] = None
return res
@classmethod
def func_cycle(cls, obj, inst_id, pass_state, state):
res = []
if inst_id not in state["data"]:
state["data"][inst_id] = {
"track_step": [],
"track_data": [],
"track_count": 0
}
curr_state = state["data"][inst_id]
curr_state["track_count"] = len(obj.inst[inst_id]["widgets_values"][0])
curr_track_len = len(curr_state["track_data"])
if curr_state["track_count"] > curr_track_len:
curr_state["track_data"].extend([None] * (curr_state["track_count"] - curr_track_len))
curr_state["track_step"].extend([None] * (curr_state["track_count"] - curr_track_len))
elif curr_state["track_count"] < curr_track_len:
curr_state["track_data"] = curr_state["track_data"][:curr_state["track_count"]]
curr_state["track_step"] = curr_state["track_step"][:curr_state["track_count"]]
for i, curr_offset, curr_step, curr_space, curr_count in zip(itertools.count(start=0, step=1), *obj.inst[inst_id]["widgets_values"]):
if curr_state["track_data"][i] is None or \
curr_state["track_step"][i] != curr_step or \
state["change"]:
curr_state["track_data"][i] = curr_offset
curr_state["track_step"][i] = curr_step
else:
curr_state["track_data"][i] += curr_step
for i in range(curr_state["track_data"][i], curr_count * curr_space, curr_space):
res.append(pass_state["data"][i % len(pass_state["data"])])
for i in pass_state["index"]:
# result append to res should be already in order so no need special handling
pass_state["index"][i] = None
return res
@classmethod
def func_merge(cls, obj, inst_id, pass_state, state):
res = []
for i, curr_delim in zip(itertools.count(start=0, step=1), *obj.inst[inst_id]["widgets_values"]):
res.append(curr_delim.join(pass_state["data"]))
for i in pass_state["index"]:
pass_state["index"][i] = None
return res
class CloudData:
def __init__(self):
self.inst = []
self.group = {}
self.db = {}
def dict_to_data(self, curr_id, inst_list, group_dict, db_dict = None, kwargs = None):
if kwargs is not None:
self.id = curr_id
if db_dict is not None:
self.db.update(db_dict)
self.db[curr_id] = self.db.get(curr_id, {})
for inst in inst_list:
old_id = inst["id"]
new_id = str(uuid.uuid4())
match inst["kind"]:
case "pin" if kwargs is not None:
curr_value = None
for key in kwargs:
curr_int = key.split(":")[0]
if curr_int.isnumeric() and int(curr_int) == inst["widgets_values"][0]:
curr_value = kwargs[key][0]
break
match curr_value:
case CloudData():
self.dict_to_data(curr_value.id, curr_value.inst, curr_value.group, curr_value.db, None)
for group_id in group_dict:
if "inst" in group_dict[group_id]:
try:
curr_index = group_dict[group_id]["inst"].index(old_id)
group_dict[group_id]["inst"][curr_index:curr_index + 1] = map(lambda _: _["id"], curr_value.inst)
except ValueError:
pass
continue
case str() | int() | float():
self.inst.append({
"id": new_id,
"kind": "text",
"widgets_values": [str(curr_value)],
"widgets_names": [f"cloud:_:{new_id}:text:text_input"]
})
case _:
self.inst.append(inst)
if old_id.isnumeric():
inst["id"] = new_id
self.db[curr_id][new_id] = old_id
for param in kwargs:
if param.startswith("cloud:"):
for inst in self.inst:
for i in range(self.inst["widgets_values"]):
if self.inst["widgets_names"][i] == param:
self.inst["widgets_values"][i] = kwargs[param]
break
for old_id, group_data in group_dict.items():
if "inst" in group_data:
new_list = []
for i, inst_id in enumerate(group_data["inst"]):
if not inst_id.isnumeric():
new_list.append(inst_id)
else:
for curr_inst_id in self.db[curr_id].keys():
if self.db[curr_id][curr_inst_id] == inst_id:
new_list.append(curr_inst_id)
break
if len(new_list) > 0:
group_data["inst"] = new_list
else:
del group_data["inst"]
if "group" in group_data:
for i, inner_old_id in enumerate(group_data["group"]):
new_id = str(uuid.uuid4())
if not inner_old_id.split(":")[-1].isnumeric():
group_data["group"][i] = inner_old_id
else:
for curr_group_id in self.db[curr_id].keys():
if self.db[curr_id][curr_group_id] == inner_old_id:
group_data["group"][i] = curr_group_id
break
new_id = str(uuid.uuid4())
if not old_id.split(":")[-1].isnumeric():
self.group[old_id] = group_data
else:
for curr_group_id in self.db[curr_id].keys():
if self.db[curr_id][curr_group_id] == old_id:
self.group[curr_group_id] = group_data
break
else:
self.group[new_id] = group_data
for curr_group_id in self.db[curr_id].keys():
if self.db[curr_id][curr_group_id] == old_id:
break
else:
self.db[curr_id][new_id] = old_id
@classmethod
def text_to_dict(cls, text):
pass
def text_to_data(self, text):
pass
def data_eval(self):
sort_data = self.sort()
state_data = []
func_data = {}
for inst_id in self.inst:
func_data[inst_id["id"]] = CloudData(inst_id["kind"]) if \
isinstance(inst_id["kind"], str) else \
inst_id["kind"]
def sort(self):
# inst = kwargs["cloud:cloud"][0]["inst"]
# group = kwargs["cloud:cloud"][0]["group"]
inst = self.inst
group = self.group
dep = {}
for group_id in group:
inst_list = group_query_inst(group, group_id)
inst_dep_list_prim = []
inst_dep_list_func = []
inst_dep_list_bind = []
inst_kind_set = set()
for inst_id in inst_list:
if inst_id not in dep:
dep[inst_id] = []
inst_curr_kind = next(filter(lambda _: _["id"] == inst_id, inst))["kind"]
if CLOUD_METHOD[inst_curr_kind] is None:
inst_dep_list_prim.append(inst_id)
else:
if inst_curr_kind in inst_kind_set and CLOUD_METHOD[inst_curr_kind]["sole"]:
raise Exception(f"Cannot have multiple {inst_curr_kind} cloud to same group {group_id}.")
(inst_dep_list_bind if CLOUD_METHOD[inst_curr_kind]["bind"] else inst_dep_list_func).append(inst_id)
if isinstance(inst_curr_kind, str):
inst_kind_set.add(inst_curr_kind)
for inst_id in inst_dep_list_func:
dep[inst_id].extend(inst_dep_list_prim)
idx_db = {}
for inst_id in inst_dep_list_bind:
dep[inst_id].extend(inst_dep_list_prim)
dep[inst_id].extend(inst_dep_list_func)
idx_db[inst_id] = inst.index(next(filter(lambda _: _["id"] == inst_id, inst)))
for a_inst_id in inst_dep_list_bind:
for b_inst_id in inst_dep_list_bind:
if idx_db[a_inst_id] > idx_db[b_inst_id] and idx_db[a_inst_id] != idx_db[b_inst_id]:
dep[a_inst_id].append(b_inst_id)
for inst_id in inst:
if inst_id["id"] not in dep:
dep[inst_id["id"]] = []
return {
"idx": toposort.toposort_flatten(dep),
"dep": dep
}
def __str__(self):
return f"CloudData({self.inst}, {self.group}, {self.db})"
def __repr__(self):
return f"CloudData({json.dumps(self.inst, indent=2)}, {json.dumps(self.group, indent=2)}, {json.dumps(self.db, indent=2)})"
class Cloud:
@classmethod
def INPUT_TYPES(s):
return {
"required": lib0246.WildDict(),
"optional": {
"_cloud_in": ("CLOUD_PIPE", ),
# "_cloud_in": ("CLOUD_PIPE", ),
"cloud": ("CLOUD_DATA", )
},
"hidden": {
@@ -2091,18 +2435,18 @@ class Cloud:
FUNCTION = "execute"
CATEGORY = "0246"
def execute(self, _id = None, _prompt = None, _workflow = None, _cloud_in = None, **kwargs):
print(kwargs)
return ([None], )
def text_to_cloud(self):
pass
def cloud_to_text(self):
pass
def execute(self, _id = None, _prompt = None, _workflow = None, **kwargs):
res = CloudData()
res.dict_to_data(_id[0], kwargs["cloud:cloud"][0]["inst"], kwargs["cloud:cloud"][0]["group"], None, kwargs)
return {
"ui": {
"text": [[""]]
},
"result": [[res]]
}
######################################################################################
class Meta:
@classmethod
def INPUT_TYPES(s):
+2 -1
View File
@@ -1,2 +1,3 @@
wrapt
natsort
natsort
toposort
+1
View File
@@ -20,6 +20,7 @@ try:
except:
subprocess.Popen([sys.executable, "-m", "pip", "install", "wrapt"]).wait()
subprocess.Popen([sys.executable, "-m", "pip", "install", "natsort"]).wait()
subprocess.Popen([sys.executable, "-m", "pip", "install", "toposort"]).wait()
wrapt = __import__("wrapt")
natsort = __import__("natsort")
+3 -4
View File
@@ -304,9 +304,6 @@ app.registerExtension({
serialize: false
});
}
}, function (mode) {
if (mode === 0b100000)
this.self.setSize(this.self.computeSize());
});
wg0246.setup_log(nodeType.prototype, true);
} break;
@@ -543,9 +540,10 @@ app.registerExtension({
}
});
Hub.prototype.hubSize = function () {
Hub.prototype.hubSize = function (extra = 0) {
const curr_size = this.computeSize();
curr_size[0] = this.size[0] < 350 ? 350 : this.size[0];
// curr_size[1] += extra - 32;
this.setSize(curr_size);
};
@@ -780,6 +778,7 @@ app.registerExtension({
}
delete this.hub.node_widget[curr_id];
}
// [TODO] For some reason there's trailing space_widget
const space_widget_index = this.widgets.indexOf(this.hub.space_widget[curr_id]);
if (space_widget_index > -1)
this.widgets.splice(space_widget_index, 1);
+144 -179
View File
@@ -1257,7 +1257,7 @@ function node_mouse_pos(node) {
];
}
function calc_flex(node, widget, width) {
function calc_flex(node, width) {
node.flex_data = node.flex_data ?? {};
node.flex_data.share_count = 0;
node.flex_data.share_weight = [];
@@ -1275,11 +1275,17 @@ function calc_flex(node, widget, width) {
node.flex_data.share_min_h.push(Number.isFinite(node.widgets[i]?.flex?.real_min_h) && node.widgets[i]?.flex?.real_min_h > 0 ? node.widgets[i]?.flex?.real_min_h : null);
node.flex_data.share_max_h.push(Number.isFinite(node.widgets[i]?.flex?.real_max_h) && node.widgets[i]?.flex?.real_max_h > 0 ? node.widgets[i]?.flex?.real_max_h : null);
++ node.flex_data.share_count;
if (node.widgets[i] === widget)
node.widgets[i].flex.index = node.flex_data.share_count - 1;
node.widgets[i].flex.index = node.flex_data.share_count - 1;
node.flex_data.left_h += 4;
} else
node.flex_data.off_h += (node.widgets[i]?.computedHeight ?? node.widgets[i]?.computeSize?.(width ?? LiteGraph.NODE_WIDGET_WIDTH)?.[1] ?? LiteGraph.NODE_WIDGET_HEIGHT) + 4;
node.flex_data.slot_c = Math.max(node.inputs?.length ?? 0, node.outputs?.length ?? 0);
node.flex_data.slot_h = (node.flex_data.slot_c + 0.2) * LiteGraph.NODE_SLOT_HEIGHT + (node.flex_data.slot_c === 0 ? 32 : 10);
node.flex_data.take_h = node.flex_data.off_h + node.flex_data.left_h + node.flex_data.slot_h;
node.size[1] = Math.max(
node.flex_data.share_min_h.reduce((a, b) => a + b, node.flex_data.take_h + node.flex_data.img_h),
(app.canvas.resizing_node === node) ? app.canvas.graph_mouse[1] - node.pos[1] : node.size[1]
);
}
let PROCESS_WIDGET_NODE;
@@ -1329,12 +1335,7 @@ export function widget_flex(node, widget, options = {}) {
});
lib0246.hijack(widget, "computeSize", function (width) {
// if (window.test_func)
// return window.test_func.call(this, width, node, calc_flex, lib0246, PROCESS_WIDGET_NODE);
if (!this.mark) {
const slot_count = Math.max(node.inputs?.length ?? 0, node.outputs?.length ?? 0),
slot_h = (slot_count + 0.2) * LiteGraph.NODE_SLOT_HEIGHT;
this.self.flex.temp_h = 0;
if (PROCESS_WIDGET_NODE && PROCESS_WIDGET_NODE.isPointInside(app.canvas.graph_mouse[0], app.canvas.graph_mouse[1])) {
// Intentional double-ifs
@@ -1348,32 +1349,22 @@ export function widget_flex(node, widget, options = {}) {
}
// Don't ask why how I came up with this. This took a week of brain power.
this.self.flex.real_y = this.self.flex.real_y ?? 0;
this.self.flex.margin_tail_real_y = this.self.flex.margin_tail_y;
this.self.flex.real_max_h = Infinity;
this.self.flex.real_min_h = this.self.flex.min_h ?? 0;
let raw_size = node.size?.[1] ?? this.self.flex.real_min_h;
// dom_flag = width === undefined
calc_flex(node, this.self, width);
if (!node.flex_data)
calc_flex(node, width);
if (!node.imgs || node.widgets.find(_ => _.name === ANIM_PREVIEW_WIDGET))
node.flex_data.img_h = 0;
if (app.canvas.resizing_node === node) {
raw_size = app.canvas.graph_mouse[1] - node.pos[1];
const min_h = node.flex_data.share_min_h.reduce((a, b) => a + b, slot_h + 10 + node.flex_data.off_h + node.flex_data.img_h);
if (raw_size < min_h)
raw_size = min_h;
node.size[1] = raw_size;
}
// [TODO] Caching this?
this.self.flex.real_h = lib0246.calc_spread(
node.flex_data.share_count,
raw_size - node.flex_data.off_h - slot_h - 10 - node.flex_data.left_h - node.flex_data.img_h,
node.size[1] - node.flex_data.take_h - node.flex_data.img_h,
node.flex_data.share_weight,
node.flex_data.share_min_h,
node.flex_data.share_max_h
@@ -1387,29 +1378,24 @@ export function widget_flex(node, widget, options = {}) {
}
});
if (node.configure && !node.configure[lib0246.HIJACK_MARK]) {
let temp_compute_size, temp_compute_flag = false;
lib0246.hijack(node, "configure", function (data) {
if (!node.computeSize[lib0246.HIJACK_MARK]) {
lib0246.hijack(node, "computeSize", function () {
const node = this.self;
if (!this.mark) {
temp_compute_size = this.self.computeSize;
temp_compute_flag = true;
const hold_w = data.size[0], hold_h = data.size[1];
this.self.computeSize = function () {
return [hold_w, hold_h];
};
}
}, function (mode) {
if (mode === 0b100000 && temp_compute_flag) {
temp_compute_flag = false;
this.self.size = this.self.computeSize();
this.self.computeSize = temp_compute_size;
if (!node.size) {
this.stop = true;
this.res = [LiteGraph.NODE_MIN_WIDTH, 100];
return;
}
calc_flex(node, node.size[0]);
}
});
lib0246.hijack(node, "onResize", function (size) {
if (!this.mark && Number.isFinite(this.self.flex_data.force_h)) {
this.self.size[1] = this.self.flex_data.force_h;
this.self.flex_data.force_h = null;
lib0246.hijack(node, "setSize", function (size) {
const node = this.self;
if (!this.mark && Number.isFinite(node?.flex_data?.force_h)) {
size[1] = node.flex_data.force_h;
node.flex_data.force_h = null;
}
});
@@ -1466,7 +1452,7 @@ export function DOM_WIDGET(data_type, data_name, element, options = {}) {
widget.flex.hold_draw[3] <= 0 ||
widget.type === "converted-widget";
this.element.hidden = hidden;
this.element.style.display = hidden ? "none" : null;
this.element.style.display = hidden ? "none" : "inherit";
if (hidden) {
widget.options.onHide?.(widget);
return;
@@ -1556,7 +1542,7 @@ export function DOM_WIDGET(data_type, data_name, element, options = {}) {
return widget;
}
//*
/*
Object.defineProperty(LGraphNode.prototype, "addDOMWidget", {
// Secret A/B testing ;)
// If no one complaining then it works I guess
@@ -1584,7 +1570,6 @@ Object.defineProperty(LGraphNode.prototype, "addDOMWidget", {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function eval_state(db, state, node, widget, event, pos) {
for (let i = 0; i < db.length; i += 2) {
if (Array.isArray(db[i])) {
@@ -3135,7 +3120,7 @@ export function hub_setup_widget(node, data, id) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function cloud_group_query_inst(group_curr, group_dict, group_list, inst_id) {
function cloud_inst_query_group(group_curr, group_dict, group_list, inst_id) {
let stack = [];
for (let ii = 0; ii < group_list.length; ++ ii)
if (group_dict[group_list[ii]]?.inst?.includes?.(inst_id)) {
@@ -3143,6 +3128,19 @@ function cloud_group_query_inst(group_curr, group_dict, group_list, inst_id) {
stack.push(group_list[ii]);
}
cloud_group_query_group(group_curr, group_dict, group_list, stack);
return group_curr;
}
function cloud_group_query_inst(inst_curr, group_dict, group_id) {
let stack = [group_id];
while (stack.length > 0) {
const temp = group_dict[stack.pop()];
if (temp?.inst)
inst_curr.push(...temp.inst);
if (temp?.group)
stack.push(...temp.group);
}
return inst_curr;
}
function cloud_group_query_group(group_curr, group_dict, group_list, group_stack) {
@@ -3158,6 +3156,7 @@ function cloud_group_query_group(group_curr, group_dict, group_list, group_stack
seen.add(group_list[ii]);
}
}
return group_curr;
}
function shelf_layout(
@@ -3205,7 +3204,7 @@ function shelf_layout(
group_y = 0;
for (; i < key_list.length; ++ i) {
let group_curr = [];
cloud_group_query_inst(group_curr, group_dict, group_list, key_list[i]);
cloud_inst_query_group(group_curr, group_dict, group_list, key_list[i]);
const text_data = ctx.measureText(view_dict[key_list[i]]);
@@ -3509,7 +3508,7 @@ function cloud_widget_build_basic(node, widget, inst_id, name, input, data) {
}
if (data !== null)
for (let i = 0; i < widget.cloud.widgets[inst_id].length; ++ i)
widget.cloud.widgets[inst_id][i].value = data.widgets_values[i];
widget.cloud.widgets[inst_id][i].value = data.widgets_values[i][0];
}
function cloud_widget_select_basic(node, inst_id, name, flag) {
@@ -3562,7 +3561,7 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
node.widgets.splice(node.widgets.length - 1, 1);
if (data !== null)
this.cloud.widgets[inst_id][0].options.setValue(data.widgets_values[0]);
this.cloud.widgets[inst_id][0].options.setValue(data.widgets_values[0][0]);
} break;
case "text_list": {
} break;
@@ -3593,16 +3592,6 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
case "rand": {
this.cloud.widgets[inst_id] = [
{
name: `cloud:${name}:${inst_id}:rand:count`,
type: "number",
value: 1,
options: {
min: 1,
max: Number.MAX_SAFE_INTEGER,
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:rand:seed`,
type: "number",
value: 1,
@@ -3612,6 +3601,16 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:rand:count`,
type: "number",
value: 1,
options: {
min: 1,
max: Number.MAX_SAFE_INTEGER,
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:rand:mode`,
type: "combo",
@@ -3624,7 +3623,7 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
},
}
];
cloud_widget_build_basic(node, this, inst_id, `cloud:${name}:${inst_id}:rand:count`, input, data);
cloud_widget_build_basic(node, this, inst_id, `cloud:${name}:${inst_id}:rand:seed`, input, data);
} break;
case "cycle": {
this.cloud.widgets[inst_id] = [
@@ -3648,6 +3647,26 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:cycle:space`,
type: "number",
value: 0,
options: {
min: Number.MIN_SAFE_INTEGER,
max: Number.MAX_SAFE_INTEGER,
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:rand:count`,
type: "number",
value: 1,
options: {
min: 1,
max: Number.MAX_SAFE_INTEGER,
step: 10,
precision: 0
},
}, {
name: `cloud:${name}:${inst_id}:cycle:mode`,
type: "combo",
@@ -3658,7 +3677,7 @@ function cloud_build(node, kind, data = null, input = null, full = null) {
},
}
];
this.cloud.widgets[inst_id][2].afterQueued = cloud_after_func.bind(this, node, inst_id, this.cloud.widgets[inst_id][1]);
this.cloud.widgets[inst_id][3].afterQueued = cloud_after_func.bind(this, node, inst_id, this.cloud.widgets[inst_id][1]);
cloud_widget_build_basic(node, this, inst_id, `cloud:${name}:${inst_id}:cycle:offset`, input, data);
} break;
case "pin": {
@@ -3706,7 +3725,7 @@ function cloud_select(node, inst_id, flag) {
cloud_widget_select_basic.call(this, node, inst_id, `cloud:${name}:${inst_id}:weight:weight_input`, flag);
} break;
case "rand": {
cloud_widget_select_basic.call(this, node, inst_id, `cloud:${name}:${inst_id}:rand:count`, flag);
cloud_widget_select_basic.call(this, node, inst_id, `cloud:${name}:${inst_id}:rand:seed`, flag);
} break;
case "cycle": {
cloud_widget_select_basic.call(this, node, inst_id, `cloud:${name}:${inst_id}:cycle:offset`, flag);
@@ -3718,9 +3737,7 @@ function cloud_select(node, inst_id, flag) {
this.options?.select?.(node, inst_id, flag);
} break;
}
if (this.cloud.select.size === 1) {
// node.widgets.find(_ => _.name === "base:inst_group_order").value =
}
node.computeSize();
}
const CLOUD_KIND = ["text", "text_list", "text_file_list", "text_file_json", "weight", "rand", "cycle", "merge"];
@@ -3849,8 +3866,8 @@ function cloud_build_group(node, mode, second = null, color = undefined) {
}
} break;
}
cloud_clean_group(this.cloud.data.group);
}
cloud_clean_group(this.cloud.data.group);
}
function cloud_remove_group(node, group_id, mode) {
@@ -3922,6 +3939,10 @@ function cloud_clean_group(group_dict) {
} else if (!valid_group.has(key))
delete group_dict[key];
}
// for (let group_id in group_dict)
// if (cloud_group_query_inst([], group_dict, group_id).length < 2)
// delete group_dict[group_id];
}
function cloud_clean_dupe(group_dict) {
@@ -3993,7 +4014,7 @@ export function CLOUD_WIDGET(data_type, data_name, options = {}) {
for (let i = 0; i < this.cloud.data.inst.length; ++ i)
if (this.cloud.widgets[this.cloud.data.inst[i].id])
for (let j = 0; j < this.cloud.widgets[this.cloud.data.inst[i].id].length; ++ j) {
this.cloud.data.inst[i].widgets_values[j] = this.cloud.widgets[this.cloud.data.inst[i].id][j].value;
this.cloud.data.inst[i].widgets_values[j] = [this.cloud.widgets[this.cloud.data.inst[i].id][j].value];
this.cloud.data.inst[i].widgets_names[j] = this.cloud.widgets[this.cloud.data.inst[i].id][j].name;
}
return {
@@ -4248,7 +4269,7 @@ export function cloud_menu(name, options) {
if (cloud_widget.cloud.data.inst.find(_ => _.id === inst_id).kind !== "pin")
cloud_widget.remove(node, inst_id);
cloud_widget.cloud.select.clear();
node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
// node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
app.canvas.setDirty(true);
}
}, {
@@ -4260,7 +4281,7 @@ export function cloud_menu(name, options) {
cloud_widget.cloud.select.add(cloud_widget.cloud.data.inst[i].id);
cloud_widget.select(node, cloud_widget.cloud.data.inst[i].id, true);
}
node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
// node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
app.canvas.setDirty(true);
}
}, {
@@ -4272,45 +4293,45 @@ export function cloud_menu(name, options) {
cloud_widget.select(node, cloud_widget.cloud.data.inst[i].id, false);
cloud_widget.cloud.select.delete(cloud_widget.cloud.data.inst[i].id);
}
node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
// node.setSize([node.size[0], Math.max(node.computeSize()[1], node.size[1])]);
app.canvas.setDirty(true);
}
},
null, {
content: "[0246.Cloud] ✔️ first_group_id ➡️ picked clouds",
callback: (value, options, evt, menu, node) => {
node.widgets.find(w => w.name === `cloud:${name}`)
.build_group(node, node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value, null);
node.widgets.find(w => w.name === `cloud:${name}`).build_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value,
null
);
}
}, {
content: "[0246.Cloud] 🗑️ second_group_id ➡️ picked clouds",
callback: (value, options, evt, menu, node) => {
node.widgets.find(w => w.name === `cloud:${name}`)
.remove_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value,
null
);
node.widgets.find(w => w.name === `cloud:${name}`).remove_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value,
null
);
}
}, {
content: "[0246.Cloud] ✔️ first_group_id ➡️ second_group_id",
callback: (value, options, evt, menu, node) => {
node.widgets.find(w => w.name === `cloud:${name}`)
.build_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value
);
node.widgets.find(w => w.name === `cloud:${name}`).build_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value
);
}
}, {
content: "[0246.Cloud] 🗑️ second_group_id ➡️ first_group_id",
callback: (value, options, evt, menu, node) => {
node.widgets.find(w => w.name === `cloud:${name}`)
.remove_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value,
node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value
);
node.widgets.find(w => w.name === `cloud:${name}`).remove_group(
node,
node.widgets.find(w => w.name === `cloud:${name}:second_group_id`).value,
node.widgets.find(w => w.name === `cloud:${name}:first_group_id`).value
);
}
},
null, {
@@ -4371,7 +4392,7 @@ function reset_hijack_widget(node) {
}
}
const NODE_PARENT = Symbol("node_parent");
export const NODE_PARENT = Symbol("node_parent");
function hijack_widget_name(node, widget) {
if (node.comfyClass === "0246.Hub" && widget[NODE_PARENT])
@@ -4382,7 +4403,7 @@ function hijack_widget_name(node, widget) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
window.test = 0;
app.registerExtension({
name: "0246.Widget",
async init() {
@@ -4405,82 +4426,24 @@ app.registerExtension({
if (!this.mark) {
const node = arguments[0];
if (node.comfyClass === "0246.Hub") {
node.hub.temp_y = node.hub.temp_y ?? {};
const io_height = Math.max(node?.inputs?.length ?? 0, node?.outputs?.length ?? 0) * 24;
node.hub.curr_y = io_height;
let compute_height = node.size[1],
widget_count = 0;
for (; widget_count < node.widgets.length; ++ widget_count) {
if (
node.widgets[widget_count] === app.graph.getNodeById(node.hub?.data?.node_list?.[0])?.widgets?.[0] ||
node.widgets[widget_count].type === "space_title"
)
break;
node.hub.curr_y += LiteGraph.NODE_WIDGET_HEIGHT + 4;
}
if (node.hub.sole_space) {
node.hub.curr_y += LiteGraph.NODE_WIDGET_HEIGHT + 8 - node.hub.sole_widget.length * 4;
++ widget_count;
}
for (let i = 0; i < node.hub.sole_widget.length; ++ i, ++ widget_count) {
const curr_widget = node.hub.sole_widget[i];
if (curr_widget.y !== undefined)
node.hub.temp_y[widget_count] = curr_widget.y;
curr_widget.y = node.hub.curr_y;
node.hub.curr_y += LiteGraph.NODE_WIDGET_HEIGHT + 4; // [TODO] Maybe add checks like below
}
if (node.hub.data)
for (let i = 0; i < node.hub.data.node_list.length; ++ i) {
const curr_node = app.graph.getNodeById(node.hub.data.node_list[i]);
if (node.widgets.length <= widget_count || !curr_node)
break;
node.widgets[widget_count ++].y = node.hub.curr_y;
node.hub.curr_y += LiteGraph.NODE_WIDGET_HEIGHT + 4;
for (let j = 0; j < curr_node.widgets.length; ++ j, ++ widget_count) {
const curr_widget = curr_node.widgets[j];
if (curr_widget.y !== undefined)
node.hub.temp_y[widget_count] = curr_widget.y;
curr_widget.y = node.hub.curr_y;
if (curr_widget.flex) {
curr_widget.flex.real_w = node.size[0];
curr_widget.flex.real_y = node.hub.curr_y;
node.hub.curr_y += curr_widget.flex.temp_h;
} else if (curr_widget.computedHeight) {
node.hub.curr_y += curr_widget.computedHeight + 4;
compute_height += curr_widget.computedHeight;
} else if (curr_widget.openpose) {
node.hub.curr_y += node.size[0];
} else if (curr_widget.painter_wrap) {
node.hub.curr_y += Math.max((
curr_widget.painter_toolbox = curr_widget.painter_toolbox ?? document.querySelector("div.painter_drawning_box")
).clientHeight / app.canvas.ds.scale + 4, node.size[0]);
app.canvas.setDirty(true);
} else if (curr_widget.computeSize) {
const curr_height = curr_widget.computeSize(node.size[0], node)[1]; // compute_height, raw_height - io_height + flex_height
node.hub.curr_y += curr_height + 4;
} else
node.hub.curr_y += LiteGraph.NODE_WIDGET_HEIGHT + 4;
}
}
}
} else {
const node = arguments[0];
if (node.comfyClass === "0246.Hub") {
let curr_size = node.computeSize();
for (let i = 0; i < node.widgets.length; ++ i) {
if (node.hub.temp_y[i] !== undefined)
node.widgets[i].y = node.hub.temp_y[i];
else
node.widgets[i].y = undefined;
delete node.hub.temp_y[i];
}
curr_size[0] = node.size[0];
curr_size[1] = node.hub.curr_y + 2;
node.setSize(curr_size);
// [TODO] Temporary. Probably we wants to rebuild widget list dynamically
// for (let i = 7; i < node.widgets.length; ++ i) {
// let found = false;
// for (let id in node.hub.node_widget)
// if (
// node.hub.node_widget[id].indexOf(node.widgets[i]) > -1 ||
// this.hub.sole_widget.includes(node.widgets[i])
// ) {
// found = true;
// break;
// }
// if (!found && node.widgets[i].type !== "space_title")
// node.widgets.splice(i --, 1);
// }
// calc_flex(node, node.size[0]);
// console.log(node.size);
node.hubSize();
// app.canvas.setDirty(true);
}
}
});
@@ -4561,20 +4524,22 @@ app.registerExtension({
const first_group_widget = node.addWidget("combo", `cloud:${inputName}:first_group_id`, "_", () => {}, {
serialize: false,
values: function (widget) {
let res = ["_", "global", `local:${node.id}`];
for (let key in cloud_widget.cloud.data.group) {
if (key === "global" || key === `local:${node.id}`)
continue;
else
res.push(key);
}
return res;
// let res = ["_", "global", `local:${node.id}`];
// for (let key in cloud_widget.cloud.data.group) {
// if (key === "global" || key === `local:${node.id}`)
// continue;
// else
// res.push(key);
// }
// return res;
return ["_", ...Object.keys(cloud_widget.cloud.data.group ?? {})];
}
});
const second_group_widget = node.addWidget("combo", `cloud:${inputName}:second_group_id`, "_", () => {}, {
const second_group_widget = node.addWidget("combo", `cloud:${inputName}:second_group_id`, "", () => {}, {
serialize: false,
values: function (widget) {
return ["_", ...Object.keys(cloud_widget.cloud.data.group ?? {})];
// return ["_", ...Object.keys(cloud_widget.cloud.data.group ?? {})];
return Object.keys(cloud_widget.cloud.data.group ?? {});
}
});
@@ -4627,7 +4592,7 @@ app.registerExtension({
});
lib0246.hijack(node, "clone", function () {
const node = this.self;
const node = this.res;
if (this.mark)
for (let j = 0; j < node.widgets.length; ++ j)
if (node.widgets[j].type === "CLOUD_DATA")