Files

336 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { app } from "../../scripts/app.js";
app.registerExtension({
name: "RS.MultiLatent",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name !== "RS_Image_MultiLatent") return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onNodeCreated = function() {
const result = onNodeCreated ? onNodeCreated.apply(this) : undefined;
initCustomPresets(this);
const minWidth = 260;
const minHeight = 310;
const origOnResize = this.onResize;
this.onResize = function(size) {
if (size[0] < minWidth) size[0] = minWidth;
if (size[1] < minHeight) size[1] = minHeight;
if (origOnResize) {
origOnResize.apply(this, [size]);
} else {
this.size = size;
this.setDirtyCanvas(true, true);
}
};
return result;
};
nodeType.prototype.onConfigure = function(info) {
const result = onConfigure ? onConfigure.apply(this, [info]) : undefined;
queueMicrotask(() => {
hideSystemWidgets(this);
if (this.updatePresetUI) {
this.updatePresetUI();
}
});
return result;
};
}
});
function hideSystemWidgets(node) {
const wActive = node.widgets.find(w => w.name === "active_preset");
const wStd = node.widgets.find(w => w.name === "preset_standard");
const wQwen = node.widgets.find(w => w.name === "preset_qwen");
const wKrea = node.widgets.find(w => w.name === "preset_krea2");
[wStd, wQwen, wKrea, wActive].forEach(w => {
if (w) {
w.type = "hidden";
w.hidden = true;
w.computeSize = () => [0, 0];
}
});
}
function saveNodeState(node) {
const wActive = node.widgets.find(w => w.name === "active_preset");
const wStd = node.widgets.find(w => w.name === "preset_standard");
const wQwen = node.widgets.find(w => w.name === "preset_qwen");
const wKrea = node.widgets.find(w => w.name === "preset_krea2");
if (wActive && wStd && wQwen && wKrea) {
const state = {
active: wActive.value,
std: wStd.value,
qwen: wQwen.value,
krea: wKrea.value
};
try {
localStorage.setItem(`rs_multilatent_${node.id}`, JSON.stringify(state));
} catch (e) {}
}
}
function loadNodeState(node) {
try {
const stateStr = localStorage.getItem(`rs_multilatent_${node.id}`);
if (stateStr) {
return JSON.parse(stateStr);
}
} catch (e) {}
return null;
}
function initCustomPresets(node) {
hideSystemWidgets(node);
const wActive = node.widgets.find(w => w.name === "active_preset");
const wStd = node.widgets.find(w => w.name === "preset_standard");
const wQwen = node.widgets.find(w => w.name === "preset_qwen");
const wKrea = node.widgets.find(w => w.name === "preset_krea2");
if (!wActive || !wStd || !wQwen || !wKrea) return;
const savedState = loadNodeState(node);
if (savedState) {
wActive.value = savedState.active;
wStd.value = savedState.std;
wQwen.value = savedState.qwen;
wKrea.value = savedState.krea;
}
const container = document.createElement("div");
container.style.display = "none";
container.style.flexDirection = "column";
container.style.gap = "4px";
container.style.padding = "4px 0";
container.style.width = "100%";
const placeholderDiv = document.createElement("div");
placeholderDiv.textContent = "SELECT A PRESET CATEGORY";
placeholderDiv.style.textAlign = "center";
placeholderDiv.style.fontSize = "10px";
placeholderDiv.style.color = "#00FF00";
placeholderDiv.style.padding = "2px 0";
placeholderDiv.style.fontWeight = "bold";
const buttonsContainer = document.createElement("div");
buttonsContainer.style.display = "flex";
buttonsContainer.style.gap = "8px";
buttonsContainer.style.width = "100%";
const infoDiv = document.createElement("div");
infoDiv.style.textAlign = "center";
infoDiv.style.padding = "6px 8px";
infoDiv.style.backgroundColor = "rgba(74, 158, 255, 0.1)";
infoDiv.style.borderRadius = "4px";
infoDiv.style.fontSize = "11px";
infoDiv.style.color = "#aaa";
infoDiv.style.fontWeight = "500";
const lists = [
{ id: "Standard", w: wStd, label: "STANDARD", color: "#4a9eff" },
{ id: "Qwen", w: wQwen, label: "QWEN", color: "#ff6b4a" },
{ id: "Krea2", w: wKrea, label: "KREA2", color: "#4aff9e" }
];
let currentOpen = null;
const buttons = [];
document.addEventListener("click", (e) => {
if (currentOpen && !container.contains(e.target)) {
currentOpen.remove();
currentOpen = null;
}
});
const updateInfo = () => {
const activeList = lists.find(l => l.id === wActive.value);
const presetValue = activeList ? activeList.w.value : "Not selected";
const orientationMatch = presetValue.match(/^(Square|Portrait|Landscape)\s*-\s*/);
const sizeMatch = presetValue.match(/(\d+)\s*[×x]\s*(\d+)/);
const aspectMatch = presetValue.match(/\(([^)]+)\)$/);
let infoText = "";
if (orientationMatch && sizeMatch) {
const orientation = orientationMatch[1];
const width = sizeMatch[1];
const height = sizeMatch[2];
const aspect = aspectMatch ? ` ${aspectMatch[1]}` : "";
infoText = `${orientation} - ${width}×${height}${aspect} — ${activeList ? activeList.label : ""}`;
} else {
infoText = presetValue;
}
infoDiv.textContent = infoText;
if (activeList) {
infoDiv.style.backgroundColor = `${activeList.color}15`;
infoDiv.style.color = activeList.color;
}
};
lists.forEach(list => {
const wrapper = document.createElement("div");
wrapper.style.flex = "1";
wrapper.style.position = "relative";
const btn = document.createElement("button");
btn.textContent = list.label;
btn.style.width = "100%";
btn.style.padding = "6px 4px";
btn.style.borderRadius = "4px";
btn.style.cursor = "pointer";
btn.style.fontSize = "10px";
btn.style.textAlign = "center";
btn.style.overflow = "hidden";
btn.style.textOverflow = "ellipsis";
btn.style.whiteSpace = "nowrap";
btn.style.transition = "all 0.15s";
btn.onclick = (e) => {
e.stopPropagation();
if (currentOpen) { currentOpen.remove(); currentOpen = null; }
wActive.value = list.id;
updateAllButtons();
updateInfo();
saveNodeState(node);
node.setDirtyCanvas(true, true);
const dropdown = document.createElement("div");
dropdown.style.position = "absolute";
dropdown.style.left = "0";
dropdown.style.width = "220px";
dropdown.style.maxHeight = "250px";
dropdown.style.overflowY = "auto";
dropdown.style.backgroundColor = "#1a1a1a";
dropdown.style.border = `1px solid ${list.color}`;
dropdown.style.borderRadius = "4px";
dropdown.style.boxShadow = "0 4px 12px rgba(0,0,0,0.8)";
dropdown.style.zIndex = "9999";
dropdown.style.fontSize = "11px";
const btnRect = btn.getBoundingClientRect();
const windowHeight = window.innerHeight;
const spaceBelow = windowHeight - btnRect.bottom;
const spaceAbove = btnRect.top;
if (spaceBelow < 250 && spaceAbove > spaceBelow) {
dropdown.style.bottom = "100%";
dropdown.style.marginBottom = "4px";
dropdown.style.maxHeight = `${Math.min(250, spaceAbove - 20)}px`;
} else {
dropdown.style.top = "100%";
dropdown.style.marginTop = "4px";
}
list.w.options.values.forEach(opt => {
const item = document.createElement("div");
item.textContent = opt;
item.style.padding = "6px 8px";
item.style.cursor = "pointer";
item.style.color = "#ddd";
item.style.borderBottom = "1px solid #2a2a2a";
item.style.whiteSpace = "nowrap";
item.style.overflow = "hidden";
item.style.textOverflow = "ellipsis";
item.onmouseenter = () => item.style.backgroundColor = "#333";
item.onmouseleave = () => item.style.backgroundColor = "transparent";
item.onclick = (ev) => {
ev.stopPropagation();
list.w.value = opt;
dropdown.remove();
currentOpen = null;
updateAllButtons();
updateInfo();
saveNodeState(node);
node.setDirtyCanvas(true, true);
};
dropdown.appendChild(item);
});
wrapper.appendChild(dropdown);
currentOpen = dropdown;
};
wrapper.appendChild(btn);
buttonsContainer.appendChild(wrapper);
buttons.push({ btn, list });
});
const updateAllButtons = () => {
buttons.forEach(({ btn, list }) => {
const isActive = wActive.value === list.id;
btn.style.border = `2px solid ${isActive ? list.color : "#555"}`;
btn.style.backgroundColor = isActive ? `${list.color}22` : "#1e1e1e";
btn.style.color = isActive ? "#fff" : "#777";
btn.style.fontWeight = isActive ? "bold" : "normal";
btn.title = list.w.value;
});
};
node.updatePresetUI = () => {
updateAllButtons();
updateInfo();
if (container.style.display === "none") {
container.style.display = "flex";
}
};
updateAllButtons();
updateInfo();
container.appendChild(placeholderDiv);
container.appendChild(buttonsContainer);
container.appendChild(infoDiv);
node.addDOMWidget("preset_ui", "preset_ui", container, {
serialize: false,
hideOnZoom: false,
computeSize: () => [node.size[0] - 20, 70]
});
const originalCallback = wActive.callback;
wActive.callback = function(value) {
if (originalCallback) originalCallback.apply(this, arguments);
updateAllButtons();
updateInfo();
saveNodeState(node);
};
container.style.display = "flex";
node.size = [260, 310];
}
document.addEventListener("visibilitychange", () => {
if (!document.hidden && app && app.graph) {
queueMicrotask(() => {
app.graph._nodes.forEach(node => {
if (node.type === "RS_Image_MultiLatent" && node.updatePresetUI) {
node.updatePresetUI();
}
});
});
}
});
window.addEventListener("focus", () => {
if (app && app.graph) {
queueMicrotask(() => {
app.graph._nodes.forEach(node => {
if (node.type === "RS_Image_MultiLatent" && node.updatePresetUI) {
node.updatePresetUI();
}
});
});
}
});