280 lines
10 KiB
JavaScript
280 lines
10 KiB
JavaScript
// ComfyUI-KikoTools - Empty Latent Batch with Swap Button
|
||
import { app } from "../../scripts/app.js";
|
||
|
||
app.registerExtension({
|
||
name: "comfyassets.EmptyLatentBatch",
|
||
async beforeRegisterNodeDef(nodeType, nodeData, _app) {
|
||
if (nodeData.name === "EmptyLatentBatch") {
|
||
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
||
nodeType.prototype.onNodeCreated = function () {
|
||
if (onNodeCreated) onNodeCreated.apply(this, []);
|
||
|
||
// Helper function to extract resolution from formatted preset string
|
||
this.extractResolutionFromPreset = function (presetValue) {
|
||
if (presetValue === "custom") return null;
|
||
|
||
// If it contains formatting metadata, extract the resolution part
|
||
if (presetValue.includes(" - ")) {
|
||
// Format is: "1024×1024 - 1:1 (1.0MP) - SDXL"
|
||
return presetValue.split(" - ")[0];
|
||
}
|
||
|
||
// Otherwise assume it's already a raw resolution
|
||
return presetValue;
|
||
};
|
||
|
||
// Create swap button as DOM widget
|
||
this.createSwapButton();
|
||
|
||
// Override preset callback to update width/height widgets when preset changes
|
||
const presetWidget = this.widgets.find((w) => w.name === "preset");
|
||
if (presetWidget) {
|
||
const originalCallback = presetWidget.callback;
|
||
presetWidget.callback = function (
|
||
value,
|
||
graphcanvas,
|
||
node,
|
||
pos,
|
||
event,
|
||
) {
|
||
// Call original callback first
|
||
if (originalCallback) {
|
||
originalCallback.call(this, value, graphcanvas, node, pos, event);
|
||
}
|
||
|
||
// Update width/height widgets based on preset
|
||
const widthWidget = node.widgets.find((w) => w.name === "width");
|
||
const heightWidget = node.widgets.find((w) => w.name === "height");
|
||
|
||
if (widthWidget && heightWidget && value !== "custom") {
|
||
// Extract raw resolution from formatted preset
|
||
const rawResolution = node.extractResolutionFromPreset(value);
|
||
|
||
// Define all available presets from our preset system
|
||
const presetDimensions = {
|
||
// SDXL Presets
|
||
"1024×1024": [1024, 1024],
|
||
"896×1152": [896, 1152],
|
||
"832×1216": [832, 1216],
|
||
"768×1344": [768, 1344],
|
||
"640×1536": [640, 1536],
|
||
"1152×896": [1152, 896],
|
||
"1216×832": [1216, 832],
|
||
"1344×768": [1344, 768],
|
||
"1536×640": [1536, 640],
|
||
// FLUX Presets
|
||
"1920×1080": [1920, 1080],
|
||
"1536×1536": [1536, 1536],
|
||
"1280×768": [1280, 768],
|
||
"768×1280": [768, 1280],
|
||
"1440×1080": [1440, 1080],
|
||
"1080×1440": [1080, 1440],
|
||
"1728×1152": [1728, 1152],
|
||
"1152×1728": [1152, 1728],
|
||
// Ultra-Wide Presets
|
||
"2560×1080": [2560, 1080],
|
||
"2048×768": [2048, 768],
|
||
"1792×768": [1792, 768],
|
||
"2304×768": [2304, 768],
|
||
"1080×2560": [1080, 2560],
|
||
"768×2048": [768, 2048],
|
||
"768×1792": [768, 1792],
|
||
"768×2304": [768, 2304],
|
||
// Qwen Presets
|
||
"1328×1328": [1328, 1328],
|
||
"1664×928": [1664, 928],
|
||
"928×1664": [928, 1664],
|
||
"1472×1104": [1472, 1104],
|
||
"1104×1472": [1104, 1472],
|
||
"1584×1056": [1584, 1056],
|
||
"1056×1584": [1056, 1584],
|
||
"2080×688": [2080, 688],
|
||
"688×2080": [688, 2080],
|
||
};
|
||
|
||
if (rawResolution && presetDimensions[rawResolution]) {
|
||
const [w, h] = presetDimensions[rawResolution];
|
||
widthWidget.value = w;
|
||
heightWidget.value = h;
|
||
|
||
// Trigger widget callbacks to update the UI
|
||
if (widthWidget.callback) {
|
||
widthWidget.callback(w, graphcanvas, node, pos, event);
|
||
}
|
||
if (heightWidget.callback) {
|
||
heightWidget.callback(h, graphcanvas, node, pos, event);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
// Add swap functionality
|
||
this.swapDimensions = function () {
|
||
const widthWidget = this.widgets.find((w) => w.name === "width");
|
||
const heightWidget = this.widgets.find((w) => w.name === "height");
|
||
const presetWidget = this.widgets.find((w) => w.name === "preset");
|
||
|
||
if (widthWidget && heightWidget && presetWidget) {
|
||
// Handle preset swapping first
|
||
if (presetWidget.value !== "custom") {
|
||
const currentPreset = presetWidget.value;
|
||
|
||
// Extract raw resolution from formatted preset
|
||
const rawResolution =
|
||
this.extractResolutionFromPreset(currentPreset);
|
||
if (!rawResolution) return;
|
||
|
||
// Parse current preset dimensions (handle both × and x separators)
|
||
let w, h;
|
||
if (rawResolution.includes("×")) {
|
||
[w, h] = rawResolution.split("×").map((v) => parseInt(v));
|
||
} else if (rawResolution.includes("x")) {
|
||
[w, h] = rawResolution.split("x").map((v) => parseInt(v));
|
||
} else {
|
||
return; // Invalid preset format
|
||
}
|
||
|
||
const swappedRawPreset = `${h}×${w}`;
|
||
|
||
// Find the formatted version of the swapped preset from available options
|
||
const availablePresets =
|
||
presetWidget.options.values || presetWidget.options;
|
||
let swappedFormattedPreset = null;
|
||
|
||
for (const option of availablePresets) {
|
||
if (option === "custom") continue;
|
||
const extractedRes = this.extractResolutionFromPreset(option);
|
||
if (extractedRes === swappedRawPreset) {
|
||
swappedFormattedPreset = option;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (swappedFormattedPreset) {
|
||
// Swapped preset exists, use the formatted version
|
||
presetWidget.value = swappedFormattedPreset;
|
||
widthWidget.value = h;
|
||
heightWidget.value = w;
|
||
if (presetWidget.callback) {
|
||
presetWidget.callback(
|
||
swappedFormattedPreset,
|
||
app.canvas,
|
||
this,
|
||
[0, 0],
|
||
null
|
||
);
|
||
}
|
||
if (widthWidget.callback) {
|
||
widthWidget.callback(widthWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
if (heightWidget.callback) {
|
||
heightWidget.callback(heightWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
} else {
|
||
// Swapped preset doesn't exist, switch to custom and swap manual values
|
||
presetWidget.value = "custom";
|
||
widthWidget.value = h;
|
||
heightWidget.value = w;
|
||
|
||
if (presetWidget.callback) {
|
||
presetWidget.callback("custom", app.canvas, this, [0, 0], null);
|
||
}
|
||
if (widthWidget.callback) {
|
||
widthWidget.callback(widthWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
if (heightWidget.callback) {
|
||
heightWidget.callback(heightWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
}
|
||
} else {
|
||
// Custom preset - just swap the width and height values
|
||
const tempWidth = widthWidget.value;
|
||
widthWidget.value = heightWidget.value;
|
||
heightWidget.value = tempWidth;
|
||
|
||
// Trigger widget change events
|
||
if (widthWidget.callback) {
|
||
widthWidget.callback(widthWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
if (heightWidget.callback) {
|
||
heightWidget.callback(heightWidget.value, app.canvas, this, [0, 0], null);
|
||
}
|
||
}
|
||
|
||
// Mark the graph as changed
|
||
this.graph?.setDirtyCanvas(true, true);
|
||
}
|
||
};
|
||
};
|
||
|
||
// Create swap button as DOM widget
|
||
nodeType.prototype.createSwapButton = function () {
|
||
// Create button container
|
||
const buttonContainer = document.createElement("div");
|
||
buttonContainer.style.cssText = `
|
||
padding: 4px;
|
||
text-align: center;
|
||
`;
|
||
|
||
// Create swap button
|
||
const swapButton = document.createElement("button");
|
||
swapButton.innerHTML = "↔️ Swap W×H";
|
||
swapButton.style.cssText = `
|
||
background: #4A90E2;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
padding: 6px 12px;
|
||
cursor: pointer;
|
||
font-size: 11px;
|
||
font-weight: bold;
|
||
transition: background 0.2s;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||
`;
|
||
|
||
// Button hover effects
|
||
swapButton.addEventListener("mouseenter", () => {
|
||
swapButton.style.background = "#5BA0F2";
|
||
swapButton.style.transform = "translateY(-1px)";
|
||
swapButton.style.boxShadow = "0 3px 6px rgba(0,0,0,0.3)";
|
||
});
|
||
|
||
swapButton.addEventListener("mouseleave", () => {
|
||
swapButton.style.background = "#4A90E2";
|
||
swapButton.style.transform = "translateY(0)";
|
||
swapButton.style.boxShadow = "0 2px 4px rgba(0,0,0,0.2)";
|
||
});
|
||
|
||
// Button click effect and functionality
|
||
swapButton.addEventListener("mousedown", () => {
|
||
swapButton.style.background = "#3A80D2";
|
||
swapButton.style.transform = "translateY(1px)";
|
||
swapButton.style.boxShadow = "0 1px 2px rgba(0,0,0,0.2)";
|
||
});
|
||
|
||
swapButton.addEventListener("mouseup", () => {
|
||
swapButton.style.background = "#5BA0F2";
|
||
swapButton.style.transform = "translateY(-1px)";
|
||
swapButton.style.boxShadow = "0 3px 6px rgba(0,0,0,0.3)";
|
||
});
|
||
|
||
// Main click functionality
|
||
swapButton.addEventListener("click", () => {
|
||
this.swapDimensions();
|
||
});
|
||
|
||
buttonContainer.appendChild(swapButton);
|
||
|
||
// Add as DOM widget
|
||
this.swapButtonWidget = this.addDOMWidget(
|
||
"swap_button",
|
||
"div",
|
||
buttonContainer
|
||
);
|
||
};
|
||
|
||
}
|
||
},
|
||
});
|