253 lines
8.2 KiB
JavaScript
253 lines
8.2 KiB
JavaScript
import { isNode as isAppendNode } from "../nodes/append.js";
|
|
import { isNode as isFrameRangeNode } from "../nodes/frame-range.js";
|
|
import { isImageOpsNativeUiClass } from "./classes.js";
|
|
import { markCanvasDirty } from "./canvas.js";
|
|
function syncWidgetElement(widget, value) {
|
|
const element = widget?.element;
|
|
if (!element) return;
|
|
if (typeof value === "boolean") {
|
|
if ("checked" in element) {
|
|
element.checked = value;
|
|
}
|
|
if ("value" in element) {
|
|
element.value = value ? "true" : "false";
|
|
}
|
|
return;
|
|
}
|
|
if ("value" in element) {
|
|
element.value = String(value);
|
|
}
|
|
}
|
|
function notifyWidgetChanged(widget, value) {
|
|
if (!widget) return;
|
|
try {
|
|
widget.callback?.(value);
|
|
} catch {
|
|
}
|
|
}
|
|
function findWidget(node, name) {
|
|
return node?.widgets?.find((w) => w?.name === name) ?? null;
|
|
}
|
|
function widgetNumber(node, name, fallback = 0) {
|
|
const value = findWidget(node, name)?.value;
|
|
const parsed = parseFloat(String(value ?? ""));
|
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
}
|
|
function widgetString(node, name, fallback = "") {
|
|
const value = findWidget(node, name)?.value;
|
|
return typeof value === "string" ? value : fallback;
|
|
}
|
|
function widgetBoolean(node, name, fallback = false) {
|
|
const value = findWidget(node, name)?.value;
|
|
if (typeof value === "boolean") return value;
|
|
if (typeof value === "number") return !!value;
|
|
if (typeof value === "string") return value.toLowerCase() === "true";
|
|
return fallback;
|
|
}
|
|
function hideWidgetForGood(node, widget, suffix = "") {
|
|
if (!widget) return;
|
|
widget.origType = widget.origType ?? widget.type;
|
|
widget.origComputeSize = widget.origComputeSize ?? widget.computeSize;
|
|
widget.origSerializeValue ?? (widget.origSerializeValue = widget.serializeValue);
|
|
widget.origHidden ?? (widget.origHidden = widget.hidden);
|
|
widget.hidden = true;
|
|
widget.visible = false;
|
|
widget.last_y = -4096;
|
|
widget.draw = () => {
|
|
};
|
|
widget.serialize = true;
|
|
widget.serializeValue = function() {
|
|
const original = widget.origSerializeValue;
|
|
if (typeof original === "function") {
|
|
try {
|
|
return original.call(widget);
|
|
} catch {
|
|
}
|
|
}
|
|
return widget.value;
|
|
};
|
|
try {
|
|
widget.options = {
|
|
...widget.options ?? {},
|
|
hidden: true,
|
|
canvasOnly: true,
|
|
serialize: true
|
|
};
|
|
} catch {
|
|
}
|
|
widget.computeSize = () => [0, -4];
|
|
const element = widget.element;
|
|
if (element) {
|
|
element.hidden = true;
|
|
element.style.display = "none";
|
|
}
|
|
if (widget.linkedWidgets) {
|
|
for (const linked of widget.linkedWidgets) {
|
|
hideWidgetForGood(node, linked, `:${widget.name}${suffix}`);
|
|
}
|
|
}
|
|
}
|
|
function hideWidgetsByName(node, name) {
|
|
if (!node?.widgets) return;
|
|
for (const widget of node.widgets) {
|
|
if (widget?.name && widget.name.toLowerCase() === name.toLowerCase()) {
|
|
hideWidgetForGood(node, widget);
|
|
}
|
|
}
|
|
}
|
|
function deduplicateColorWidgets(node) {
|
|
if (!node?.widgets) return;
|
|
const seen = /* @__PURE__ */ new Set();
|
|
for (const widget of node.widgets) {
|
|
if (!widget?.name) continue;
|
|
if (seen.has(widget.name)) {
|
|
hideWidgetForGood(node, widget);
|
|
} else {
|
|
seen.add(widget.name);
|
|
}
|
|
}
|
|
}
|
|
function setWidgetValue(widget, value, options = {}) {
|
|
if (!widget) return;
|
|
const notify = options.notify !== false;
|
|
const dirty = options.dirty !== false;
|
|
const changed = Number(widget.value) !== Number(value);
|
|
widget.value = value;
|
|
syncWidgetElement(widget, value);
|
|
if (changed) {
|
|
if (notify) notifyWidgetChanged(widget, value);
|
|
if (dirty) markCanvasDirty();
|
|
}
|
|
}
|
|
function setWidgetStringValue(widget, value, options = {}) {
|
|
if (!widget) return;
|
|
const notify = options.notify !== false;
|
|
const dirty = options.dirty !== false;
|
|
const changed = String(widget.value ?? "") !== String(value);
|
|
widget.value = value;
|
|
syncWidgetElement(widget, value);
|
|
if (changed) {
|
|
if (notify) notifyWidgetChanged(widget, value);
|
|
if (dirty) markCanvasDirty();
|
|
}
|
|
}
|
|
function setWidgetStringValuesByName(node, name, value, options = {}) {
|
|
for (const widget of node.widgets ?? []) {
|
|
if (widget?.name === name) setWidgetStringValue(widget, value, options);
|
|
}
|
|
}
|
|
function setWidgetBooleanValue(widget, value, options = {}) {
|
|
if (!widget) return;
|
|
const notify = options.notify !== false;
|
|
const dirty = options.dirty !== false;
|
|
const current = typeof widget.value === "boolean" ? widget.value : String(widget.value ?? "false").toLowerCase() === "true";
|
|
const changed = current !== value;
|
|
widget.value = value;
|
|
syncWidgetElement(widget, value);
|
|
if (changed) {
|
|
if (notify) notifyWidgetChanged(widget, value);
|
|
if (dirty) markCanvasDirty();
|
|
}
|
|
}
|
|
function setWidgetMixedValue(widget, value, options = {}) {
|
|
if (!widget) return;
|
|
const notify = options.notify !== false;
|
|
const dirty = options.dirty !== false;
|
|
const changed = typeof value === "number" ? Number(widget.value) !== Number(value) : typeof value === "boolean" ? (typeof widget.value === "boolean" ? widget.value : String(widget.value ?? "false").toLowerCase() === "true") !== value : String(widget.value ?? "") !== String(value);
|
|
widget.value = value;
|
|
syncWidgetElement(widget, value);
|
|
if (changed) {
|
|
if (notify) notifyWidgetChanged(widget, value);
|
|
if (dirty) markCanvasDirty();
|
|
}
|
|
}
|
|
function getWidgetInputSpec(node, name) {
|
|
const nodeData = node?.constructor?.nodeData;
|
|
const entry = nodeData?.input?.required?.[name] ?? nodeData?.input?.optional?.[name];
|
|
if (!Array.isArray(entry) || entry.length === 0) return null;
|
|
const options = entry[1];
|
|
return {
|
|
typeSpec: entry[0],
|
|
options: options && typeof options === "object" ? options : null
|
|
};
|
|
}
|
|
function isWidgetHidden(widget) {
|
|
if (!widget) return true;
|
|
if (widget.hidden === true) return true;
|
|
return Boolean(widget.options?.hidden);
|
|
}
|
|
function isCompNode(node) {
|
|
return String(node?.comfyClass ?? "") === "ImageOpsComp";
|
|
}
|
|
function shouldUseCompactIntWidget(node) {
|
|
return isFrameRangeNode(node) || isAppendNode(node) || isCompNode(node) || isImageOpsNativeUiClass(node.comfyClass);
|
|
}
|
|
function supportsCompactUi(node, widget) {
|
|
if (!widget?.name || widget.name === "preview" || isWidgetHidden(widget)) return false;
|
|
const spec = getWidgetInputSpec(node, widget.name);
|
|
if (!spec) return false;
|
|
if (Array.isArray(spec.typeSpec)) return true;
|
|
const kind = String(spec.typeSpec ?? "").trim().toUpperCase();
|
|
if (kind === "INT" && !shouldUseCompactIntWidget(node)) return false;
|
|
return kind === "BOOLEAN" || kind === "INT" || kind === "FLOAT" || kind === "STRING" || kind === "COLOR" || kind === "COMBO";
|
|
}
|
|
function listCompactUiWidgets(node) {
|
|
return (node?.widgets ?? []).filter((widget) => supportsCompactUi(node, widget));
|
|
}
|
|
function hideCompactUiWidgets(node) {
|
|
}
|
|
function cloneDefaultValue(value) {
|
|
if (value == null || typeof value !== "object") return value;
|
|
try {
|
|
return structuredClone(value);
|
|
} catch {
|
|
return JSON.parse(JSON.stringify(value));
|
|
}
|
|
}
|
|
function getWidgetDefaultValue(node, name) {
|
|
const nodeData = node?.constructor?.nodeData;
|
|
const entry = nodeData?.input?.required?.[name] ?? nodeData?.input?.optional?.[name];
|
|
if (!Array.isArray(entry)) return void 0;
|
|
const options = entry[1];
|
|
return options && typeof options === "object" ? cloneDefaultValue(options.default) : void 0;
|
|
}
|
|
function resetNodeWidgetsToDefaults(node) {
|
|
const resetNames = [];
|
|
for (const widget of node?.widgets ?? []) {
|
|
const name = widget?.name;
|
|
if (!name) continue;
|
|
const defaultValue = getWidgetDefaultValue(node, name);
|
|
if (defaultValue === void 0) continue;
|
|
if (typeof defaultValue === "boolean") {
|
|
setWidgetBooleanValue(widget, defaultValue);
|
|
} else if (typeof defaultValue === "number") {
|
|
setWidgetValue(widget, defaultValue);
|
|
} else if (typeof defaultValue === "string") {
|
|
setWidgetStringValue(widget, defaultValue);
|
|
} else {
|
|
widget.value = cloneDefaultValue(defaultValue);
|
|
}
|
|
resetNames.push(name);
|
|
}
|
|
return resetNames;
|
|
}
|
|
export {
|
|
deduplicateColorWidgets,
|
|
findWidget,
|
|
getWidgetDefaultValue,
|
|
getWidgetInputSpec,
|
|
hideCompactUiWidgets,
|
|
hideWidgetForGood,
|
|
hideWidgetsByName,
|
|
listCompactUiWidgets,
|
|
resetNodeWidgetsToDefaults,
|
|
setWidgetBooleanValue,
|
|
setWidgetMixedValue,
|
|
setWidgetStringValue,
|
|
setWidgetStringValuesByName,
|
|
setWidgetValue,
|
|
widgetBoolean,
|
|
widgetNumber,
|
|
widgetString
|
|
};
|