234 lines
6.9 KiB
JavaScript
234 lines
6.9 KiB
JavaScript
import { COLORS } from "./constants.js";
|
|
import { createPresetManager } from "./preset_manager.js";
|
|
import {
|
|
drawGroupBorder,
|
|
findWidget,
|
|
registerNode,
|
|
setInputDotColor,
|
|
waitForWidgets,
|
|
} from "./utils.js";
|
|
|
|
// --- Constants ---
|
|
|
|
const NODE_NAME = "PromptFaceBuilder";
|
|
|
|
const COMBO_FIELDS = [
|
|
"pupils",
|
|
"eye_state",
|
|
"gaze",
|
|
"blush",
|
|
"mouth_state",
|
|
"mouth_expression",
|
|
"emotion",
|
|
"head_angle",
|
|
];
|
|
|
|
const EYE_FIELDS = ["pupils", "gaze"];
|
|
const EYEWEAR_FIELDS = ["eyewear_override"];
|
|
const NAIL_COLOR_FIELDS = ["nail_color_override"];
|
|
const BOOL_FIELDS = [
|
|
"show_eyes",
|
|
"show_eyewear",
|
|
"show_body_details",
|
|
"show_nails",
|
|
"show_makeup",
|
|
];
|
|
|
|
// --- Capture / Recall ---
|
|
|
|
const captureState = (node) => {
|
|
const state = {};
|
|
for (const field of COMBO_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) state[field] = w.value ?? "";
|
|
}
|
|
|
|
for (const field of BOOL_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) state[field] = w.value ?? false;
|
|
}
|
|
return state;
|
|
};
|
|
|
|
const recallState = (node, state) => {
|
|
for (const field of [...COMBO_FIELDS, ...BOOL_FIELDS]) {
|
|
if (!(field in state)) continue;
|
|
const w = findWidget(node, field);
|
|
if (!w) continue;
|
|
w.value = state[field];
|
|
w.callback?.(state[field]);
|
|
}
|
|
|
|
updateEyeVisibility(node, findWidget(node, "show_eyes")?.value ?? true);
|
|
updateEyewearVisibility(
|
|
node,
|
|
findWidget(node, "show_eyewear")?.value ?? true,
|
|
);
|
|
updatePiercingsVisibility(
|
|
node,
|
|
findWidget(node, "show_body_details")?.value ?? true,
|
|
);
|
|
|
|
const showNails = findWidget(node, "show_nails")?.value ?? true;
|
|
const showMakeup = findWidget(node, "show_makeup")?.value ?? true;
|
|
updateNailsVisibility(node, showNails, showMakeup);
|
|
updateMakeupVisibility(node, showNails, showMakeup);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
// --- Visibility helpers ---
|
|
|
|
const updateEyeVisibility = (node, value) => {
|
|
for (const field of EYE_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) w.disabled = !value;
|
|
}
|
|
setInputDotColor(node, "eyes", value);
|
|
setInputDotColor(node, "eye_type", value);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
const updateEyewearVisibility = (node, value) => {
|
|
for (const field of EYEWEAR_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) w.disabled = !value;
|
|
}
|
|
setInputDotColor(node, "eyewear", value);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
const updatePiercingsVisibility = (node, value) => {
|
|
setInputDotColor(node, "facial_piercings", value);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
const updateNailsVisibility = (node, showNails, showMakeup) => {
|
|
for (const field of NAIL_COLOR_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) w.disabled = !showNails || !showMakeup;
|
|
}
|
|
setInputDotColor(node, "nail_type", showNails);
|
|
setInputDotColor(node, "nail_color", showNails && showMakeup);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
const updateMakeupVisibility = (node, showNails, showMakeup) => {
|
|
for (const field of NAIL_COLOR_FIELDS) {
|
|
const w = findWidget(node, field);
|
|
if (w) w.disabled = !showNails || !showMakeup;
|
|
}
|
|
setInputDotColor(node, "makeup", showMakeup);
|
|
setInputDotColor(node, "makeup_modifiers", showMakeup);
|
|
setInputDotColor(node, "nail_color", showNails && showMakeup);
|
|
|
|
if (node.graph) node.graph.setDirtyCanvas(true, true);
|
|
};
|
|
|
|
// --- Attach ---
|
|
|
|
const attachFaceBuilder = (node) => {
|
|
// --- Toggles ---
|
|
|
|
const showEyesWidget = findWidget(node, "show_eyes");
|
|
if (showEyesWidget) {
|
|
const original = showEyesWidget.callback;
|
|
showEyesWidget.callback = function (value) {
|
|
if (original) original.call(this, value);
|
|
updateEyeVisibility(node, value);
|
|
};
|
|
updateEyeVisibility(node, showEyesWidget.value ?? true);
|
|
}
|
|
|
|
const showEyewearWidget = findWidget(node, "show_eyewear");
|
|
if (showEyewearWidget) {
|
|
const original = showEyewearWidget.callback;
|
|
showEyewearWidget.callback = function (value) {
|
|
if (original) original.call(this, value);
|
|
updateEyewearVisibility(node, value);
|
|
};
|
|
updateEyewearVisibility(node, showEyewearWidget.value ?? true);
|
|
}
|
|
|
|
const showPiercingsWidget = findWidget(node, "show_body_details");
|
|
if (showPiercingsWidget) {
|
|
const original = showPiercingsWidget.callback;
|
|
showPiercingsWidget.callback = function (value) {
|
|
if (original) original.call(this, value);
|
|
updatePiercingsVisibility(node, value);
|
|
};
|
|
updatePiercingsVisibility(node, showPiercingsWidget.value ?? true);
|
|
}
|
|
|
|
const showNailsWidget = findWidget(node, "show_nails");
|
|
const showMakeupWidget = findWidget(node, "show_makeup");
|
|
if (showNailsWidget) {
|
|
const original = showNailsWidget.callback;
|
|
showNailsWidget.callback = function (value) {
|
|
if (original) original.call(this, value);
|
|
updateNailsVisibility(node, value, showMakeupWidget.value ?? true);
|
|
};
|
|
updateNailsVisibility(
|
|
node,
|
|
showNailsWidget.value ?? true,
|
|
showMakeupWidget.value ?? true,
|
|
);
|
|
}
|
|
if (showMakeupWidget) {
|
|
const original = showMakeupWidget.callback;
|
|
showMakeupWidget.callback = function (value) {
|
|
if (original) original.call(this, value);
|
|
updateMakeupVisibility(node, showNailsWidget.value ?? true, value);
|
|
};
|
|
updateMakeupVisibility(
|
|
node,
|
|
showNailsWidget.value ?? true,
|
|
showMakeupWidget.value ?? true,
|
|
);
|
|
}
|
|
|
|
// --- Borders ---
|
|
|
|
const groups = [
|
|
{ from: "show_eyes", to: "gaze" },
|
|
{ from: "show_eyewear", to: "eyewear_override" },
|
|
{ from: "show_body_details", to: "show_body_details" },
|
|
{ from: "show_nails", to: "nail_color_override" },
|
|
{ from: "show_makeup", to: "show_makeup" },
|
|
];
|
|
const original = node.onDrawForeground;
|
|
node.onDrawForeground = function (ctx) {
|
|
if (original) original.call(this, ctx);
|
|
|
|
for (const group of groups) {
|
|
drawGroupBorder(
|
|
ctx,
|
|
node,
|
|
group.from,
|
|
group.to,
|
|
COLORS.toggle_on,
|
|
COLORS.toggle_off,
|
|
);
|
|
}
|
|
};
|
|
|
|
// --- Preset manager ---
|
|
|
|
const { presetRow, exportImportRow } = createPresetManager(node, {
|
|
nodeLabel: NODE_NAME,
|
|
onCapture: () => captureState(node),
|
|
onRecall: (state) => recallState(node, state),
|
|
});
|
|
|
|
node.widgets.push(presetRow);
|
|
node.widgets.push(exportImportRow);
|
|
};
|
|
|
|
// --- Registration ---
|
|
|
|
registerNode(NODE_NAME, (node) => waitForWidgets(node, attachFaceBuilder));
|