Files
CraftopiaStudio-ComfyUI-Cra…/js/shared/preset_picker_widget.mjs
T
rubz c6c26a35fa fix: read live node width in draw() instead of a stale LiteGraph cache; cache-bust shared module imports
- LiteGraph caches a widget's .width the first time it lays a custom-typed
  widget out and reuses that cached value on every later draw() call. For a
  divider/status/preset widget added before the node reaches its final size,
  that cached width goes stale and never updates, making section-divider
  lines and the status box stop partway across the node instead of spanning
  it, and clipping/unevenly sizing the preset chips. All three shared
  widgets now read node.size[0] directly in draw() instead of trusting the
  widgetWidth parameter, which sidesteps the stale cache entirely.
- Add a ?v=2 query string to every import of the shared/*.mjs modules.
  aiohttp's static file server doesn't send Cache-Control: no-store for
  these (unlike the top-level registered extension .js files), so browsers
  were free to keep serving an old cached copy even across a hard reload.
  A versioned import URL forces a fresh fetch regardless of cache state.
2026-08-13 16:29:25 +02:00

126 lines
4.6 KiB
JavaScript

import { app } from "../../../scripts/app.js";
import { isVueNodes } from "./nodes2.mjs";
const PRESET_ROW_HEIGHT = 22;
function createClassicPresetWidget(node, targetWidget, presets) {
const widget = {
name: "size_presets",
type: "custom",
value: null,
serialize: false,
options: {},
_rects: [],
computeSize(width) {
return [width, PRESET_ROW_HEIGHT];
},
draw(ctx, node, widgetWidth, y, height) {
// Read the live node width rather than the (possibly stale-cached)
// widgetWidth parameter — see the comment in canvas_widgets.mjs.
const w = node?.size?.[0] || widgetWidth;
const margin = 14;
const gap = 5;
const innerW = Math.max(40, w - margin * 2);
const n = presets.length;
const cellW = Math.max(10, (innerW - gap * (n - 1)) / n);
const h = Math.min(height - 2, 18);
const top = y + (height - h) / 2;
const current = targetWidget.value;
this._rects = [];
ctx.save();
ctx.font = "11px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
for (let i = 0; i < n; i++) {
const x = margin + i * (cellW + gap);
const active = Number(current) === presets[i];
ctx.beginPath();
if (ctx.roundRect) ctx.roundRect(x, top, cellW, h, 4);
else ctx.rect(x, top, cellW, h);
ctx.fillStyle = active ? "#f28f41" : "#2a2a2a";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = active ? "#f28f41" : "#555";
ctx.stroke();
ctx.fillStyle = active ? "#111" : "#ccc";
ctx.fillText(String(presets[i]), x + cellW / 2, top + h / 2 + 0.5);
this._rects.push({ x1: x, x2: x + cellW, y1: top, y2: top + h, size: presets[i] });
}
ctx.restore();
},
mouse(event, pos, node) {
if (event.type !== "pointerdown" && event.type !== "mousedown") return false;
const [lx, ly] = pos;
for (const r of this._rects) {
if (lx >= r.x1 && lx <= r.x2 && ly >= r.y1 && ly <= r.y2) {
targetWidget.value = r.size;
targetWidget.callback?.(r.size, app.canvas, node);
node.setDirtyCanvas(true, true);
return true;
}
}
return false;
},
};
return node.addCustomWidget(widget);
}
function createVuePresetWidget(node, targetWidget, presets) {
const root = document.createElement("div");
root.style.display = "flex";
root.style.gap = "5px";
root.style.padding = "0 14px";
root.style.width = "100%";
root.style.boxSizing = "border-box";
const buttons = presets.map((size) => {
const btn = document.createElement("button");
btn.textContent = String(size);
btn.style.flex = "1";
btn.style.padding = "4px 0";
btn.style.borderRadius = "4px";
btn.style.border = "1px solid #555";
btn.style.background = "#2a2a2a";
btn.style.color = "#ccc";
btn.style.fontSize = "11px";
btn.style.fontFamily = "sans-serif";
btn.style.cursor = "pointer";
const syncActive = () => {
const active = Number(targetWidget.value) === size;
btn.style.background = active ? "#f28f41" : "#2a2a2a";
btn.style.borderColor = active ? "#f28f41" : "#555";
btn.style.color = active ? "#111" : "#ccc";
};
btn.addEventListener("click", () => {
targetWidget.value = size;
targetWidget.callback?.(size, app.canvas, node);
for (const b of buttons) b.syncActive?.();
node.setDirtyCanvas(true, true);
});
btn.syncActive = syncActive;
syncActive();
root.appendChild(btn);
return btn;
});
const widget = node.addDOMWidget("size_presets", "craftkit_preset_picker", root, {
serialize: false,
hideOnZoom: false,
});
// Fixed-height row, not a flexible grower — same reasoning as Pixaroma's
// button-row DOM widget.
widget.computeLayoutSize = undefined;
return widget;
}
export function createPresetPickerWidget(node, targetWidget, presets) {
return isVueNodes()
? createVuePresetWidget(node, targetWidget, presets)
: createClassicPresetWidget(node, targetWidget, presets);
}