Files

155 lines
4.4 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 { COLORS, DISABLED_OPACITY } from "../constants.js";
import { fitString, hideWidget, hideWidgetInput } from "../utils.js";
import { app } from "/scripts/app.js";
// --- Constants ---
const ROW_HEIGHT = 20;
const ROW_MARGIN = 10;
const ICON_WIDTH = 28;
const INNER_MARGIN = 4;
// --- InlineTextToggleWidget ---
export class InlineTextToggleWidget {
constructor(name, textWidget, modeWidget) {
this.name = name;
this.type = "custom";
this.textWidget = textWidget;
this.modeWidget = modeWidget;
this.last_y = 0;
this._hitText = [0, 0];
this._hitIcon = [0, 0];
}
computeSize() {
return [0, ROW_HEIGHT];
}
// --- Draw ---
draw(ctx, node, width, posY, height) {
this.last_y = posY;
const h = height ?? ROW_HEIGHT;
const midY = posY + h * 0.5;
const margin = ROW_MARGIN;
const textWidth = width - margin * 2 - ICON_WIDTH - INNER_MARGIN;
const textX = margin;
const iconX = textX + textWidth + INNER_MARGIN;
const isDisabled = this.disabled;
ctx.save();
if (isDisabled) ctx.globalAlpha = DISABLED_OPACITY;
ctx.font = "11px monospace";
ctx.textBaseline = "middle";
// Text field background
ctx.fillStyle = "#222233";
ctx.beginPath();
ctx.roundRect(textX, posY + 2, textWidth, h - 4, 4);
ctx.fill();
const value = this.textWidget.value ?? "";
ctx.fillStyle = value ? COLORS.text : COLORS.inactive;
ctx.textAlign = "left";
const label = value || this.textWidget.label || this.name;
ctx.fillText(fitString(ctx, label, textWidth - 12), textX + 6, midY);
this._hitText = [textX, textWidth];
// Toggle icon
const isReplace = this.modeWidget.value;
ctx.fillStyle = isReplace ? COLORS.toggle_off : COLORS.toggle_on;
ctx.beginPath();
ctx.roundRect(iconX, posY + 2, ICON_WIDTH, h - 4, 4);
ctx.fill();
ctx.fillStyle = "#fff";
ctx.font = "12px sans-serif";
ctx.textAlign = "center";
ctx.fillText(isReplace ? "🔄" : "➕", iconX + ICON_WIDTH / 2, midY);
this._hitIcon = [iconX, ICON_WIDTH];
ctx.restore();
}
// --- Mouse ---
mouse(event, pos, node) {
if (this.disabled) return false;
const type = event.type;
if (type !== "pointerdown" && type !== "mousedown") return false;
const x = pos[0];
// Toggle icon click
if (this._inHit(x, this._hitIcon)) {
this.modeWidget.value = !this.modeWidget.value;
this.modeWidget.callback?.(this.modeWidget.value);
if (node.graph) node.graph.setDirtyCanvas(true, true);
return true;
}
// Text field click -> prompt
if (this._inHit(x, this._hitText)) {
app.canvas.prompt(
this.textWidget.label || this.name,
this.textWidget.value ?? "",
(v) => {
this.textWidget.value = v;
this.textWidget.callback?.(v);
if (node.graph) node.graph.setDirtyCanvas(true, true);
},
event,
);
return true;
}
return false;
}
// --- Utils ---
_inHit(x, hit) {
return x >= hit[0] && x <= hit[0] + hit[1];
}
}
// -- Extra --
export const replaceWithInlineTextToggle = (node, textWidget, modeWidget) => {
const helper = new InlineTextToggleWidget(
textWidget.name,
textWidget,
modeWidget,
);
// Build a brand new custom widget object
const newWidget = {
name: textWidget.name,
type: "custom",
value: textWidget.value, // Kept for compatibility, not used for render
get value() {
return textWidget.value;
},
set value(v) {
textWidget.value = v;
},
draw: (ctx, n, width, posY, height) =>
helper.draw(ctx, n, width, posY, height),
mouse: (event, pos, n) => helper.mouse(event, pos, n),
computeSize: () => helper.computeSize(),
serializeValue: textWidget.serializeValue,
};
const idx = node.widgets.indexOf(textWidget);
node.widgets[idx] = newWidget;
hideWidget(modeWidget, true);
hideWidgetInput(node, modeWidget);
return helper;
};