Simplifies the preset-chip picker (Smart Resize / Smart Batch Resize) to a single canvas implementation - drops the dual DOM-widget path, so chips stay positioned correctly under "Longest side (px)" in both classic and Nodes 2.0 rendering instead of jumping to the bottom of the node. Adds a shared setWidgetVisible() helper so dynamic show/hide (Counter start, the hidden customtext output on every node) actually works under Nodes 2.0's Vue reactivity - it previously only worked in classic canvas mode. Fixes two silent Nodes 2.0 rendering bugs: widgets only repaint via their own triggerDraw(), not setDirtyCanvas(), so the active preset chip and status-box text were going visually stale after an update even though the underlying value was correct. And Nodes 2.0's WidgetLegacy bridge permanently stamps a widget.width that classic mode's own click hit-test then reads forever after - once a node had ever rendered under Nodes 2.0, classic mode silently lost clicks on the right side of a wide node. Both fixed by keeping widget state in sync on every draw() instead of trusting it to survive across renderer switches. Also centers section-divider labels with flanking lines (was label-left/line-right) and brightens the line color, which had become nearly invisible under Nodes 2.0's extra canvas scaling. README: reorders node sections into actual pipeline order (Prompt Controller -> Profile Switch -> Resize -> Resolution Multiplier -> Batch Resize, standalone tool last instead of mid-list), adds a Nodes 2.0 compatibility screenshot, and refreshes the Smart Batch Resize screenshot to match its current UI.
97 lines
3.8 KiB
JavaScript
97 lines
3.8 KiB
JavaScript
// Draw-only widgets (no mouse/click handling) shared across CraftKit nodes.
|
|
// type: "custom" is deliberate — it is not a name ComfyUI's Nodes 2.0 Vue
|
|
// widget registry recognizes, so Vue falls through to its WidgetLegacy
|
|
// bridge, which calls our draw() unmodified in both classic LiteGraph and
|
|
// Nodes 2.0. computeSize MUST return [width, height] (passing width through)
|
|
// rather than a hardcoded value — a fixed/wrong computeSize previously broke
|
|
// node layout on click when this was tried without care (see the comment on
|
|
// the preset-chip widget in smart_resize.js's git history).
|
|
//
|
|
// draw() intentionally ignores its own `widgetWidth` parameter and reads
|
|
// `node.size[0]` instead. LiteGraph caches a `.width` on custom-typed widget
|
|
// objects the first time it lays them out and reuses that cached value on
|
|
// later draws — for a widget added before the node reaches its final size
|
|
// (e.g. before later Python widgets are added, or before an explicit
|
|
// node.setSize() call), that cache goes stale and draw() keeps receiving the
|
|
// old, too-narrow width forever, making the divider line/status box stop
|
|
// partway across the node instead of spanning it. node.size[0] is always
|
|
// live, so reading it directly sidesteps the stale cache entirely.
|
|
|
|
const DIVIDER_HEIGHT = 20;
|
|
|
|
export function createDividerWidget(label) {
|
|
return {
|
|
name: `_div_${label}`,
|
|
type: "custom",
|
|
value: null,
|
|
serialize: false,
|
|
options: {},
|
|
computeSize(width) {
|
|
return [width, DIVIDER_HEIGHT];
|
|
},
|
|
draw(ctx, node, widgetWidth, y, height) {
|
|
const w = node?.size?.[0] || widgetWidth;
|
|
const margin = 14;
|
|
const gap = 8;
|
|
ctx.save();
|
|
ctx.font = "bold 10px sans-serif";
|
|
ctx.textBaseline = "middle";
|
|
ctx.textAlign = "center";
|
|
const cy = y + height / 2;
|
|
const cx = w / 2;
|
|
const textW = ctx.measureText(label).width;
|
|
ctx.fillStyle = "#888";
|
|
ctx.fillText(label, cx, cy);
|
|
// #555 rather than a more subtle #333 — Nodes 2.0 renders this canvas
|
|
// at 2x internal scale and then CSS-scales it again with the graph
|
|
// zoom, which softens a thin line enough that #333 became invisible
|
|
// there (classic mode draws at native resolution and stayed sharp).
|
|
ctx.strokeStyle = "#555";
|
|
ctx.lineWidth = 1;
|
|
ctx.beginPath();
|
|
ctx.moveTo(margin, cy);
|
|
ctx.lineTo(cx - textW / 2 - gap, cy);
|
|
ctx.moveTo(cx + textW / 2 + gap, cy);
|
|
ctx.lineTo(w - margin, cy);
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
},
|
|
};
|
|
}
|
|
|
|
const STATUS_HEIGHT = 24;
|
|
|
|
export function createStatusWidget(placeholderText) {
|
|
return {
|
|
name: "_status",
|
|
type: "custom",
|
|
value: null,
|
|
serialize: false,
|
|
options: {},
|
|
_text: "",
|
|
computeSize(width) {
|
|
return [width, STATUS_HEIGHT];
|
|
},
|
|
draw(ctx, node, widgetWidth, y, height) {
|
|
const w = node?.size?.[0] || widgetWidth;
|
|
const margin = 14;
|
|
const innerW = w - margin * 2;
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
if (ctx.roundRect) ctx.roundRect(margin, y + 2, innerW, height - 4, 4);
|
|
else ctx.rect(margin, y + 2, innerW, height - 4);
|
|
ctx.fillStyle = "#111";
|
|
ctx.fill();
|
|
ctx.strokeStyle = this._text ? "#3a3a3a" : "#222";
|
|
ctx.lineWidth = 1;
|
|
ctx.stroke();
|
|
ctx.font = "11px sans-serif";
|
|
ctx.textAlign = "center";
|
|
ctx.textBaseline = "middle";
|
|
ctx.fillStyle = this._text ? "#f28f41" : "#666";
|
|
ctx.fillText(this._text || placeholderText, w / 2, y + height / 2);
|
|
ctx.restore();
|
|
},
|
|
};
|
|
}
|