145 lines
4.3 KiB
JavaScript
145 lines
4.3 KiB
JavaScript
/**
|
|
* Dynamic Widget Visibility for ComfyUI
|
|
*
|
|
* Shows/hides widgets based on selector widget values.
|
|
* Mappings are loaded from mappings.json (generated by prestartup_script.py).
|
|
*
|
|
* Usage in node definitions:
|
|
* "voxel_size": ("FLOAT", {
|
|
* "default": 0.1,
|
|
* "visible_when": {"backend": ["blender_voxel"]},
|
|
* })
|
|
*/
|
|
import { app } from "../../../scripts/app.js";
|
|
|
|
console.log("[DynamicWidgets] Loading extension...");
|
|
|
|
// Will be populated from JSON
|
|
let MAPPINGS = null;
|
|
|
|
/**
|
|
* Fetch mappings from generated JSON
|
|
*/
|
|
async function loadMappings() {
|
|
const paths = [
|
|
"/extensions/ComfyUI-GeometryPack/js/mappings.json",
|
|
"/extensions/comfyui-geometrypack/js/mappings.json",
|
|
];
|
|
|
|
for (const path of paths) {
|
|
try {
|
|
const response = await fetch(path);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
MAPPINGS = data;
|
|
const nodeCount = Object.keys(data.nodes || {}).length;
|
|
console.log(`[DynamicWidgets] Loaded mappings for ${nodeCount} nodes from ${path}`);
|
|
return true;
|
|
}
|
|
} catch (e) {
|
|
// Try next path
|
|
}
|
|
}
|
|
console.warn("[DynamicWidgets] Could not load mappings.json - no dynamic widgets configured");
|
|
return false;
|
|
}
|
|
|
|
// Load mappings on startup
|
|
loadMappings();
|
|
|
|
/**
|
|
* Get the node configuration from mappings
|
|
*/
|
|
function getNodeConfig(nodeClass) {
|
|
if (!MAPPINGS || !MAPPINGS.nodes) return null;
|
|
return MAPPINGS.nodes[nodeClass] || null;
|
|
}
|
|
|
|
/**
|
|
* Update widget visibility based on selector value
|
|
*/
|
|
function updateWidgetVisibility(node, selectorName, selectedValue) {
|
|
const nodeConfig = getNodeConfig(node.comfyClass);
|
|
if (!nodeConfig || !nodeConfig.selectors) return;
|
|
|
|
const selectorConfig = nodeConfig.selectors[selectorName];
|
|
if (!selectorConfig) return;
|
|
|
|
// Get widgets that should be visible for this selector value
|
|
const visibleWidgets = selectorConfig[selectedValue] || [];
|
|
|
|
// Get all widgets controlled by this selector
|
|
const allControlledWidgets = new Set();
|
|
for (const widgets of Object.values(selectorConfig)) {
|
|
for (const w of widgets) {
|
|
allControlledWidgets.add(w);
|
|
}
|
|
}
|
|
|
|
console.log(`[DynamicWidgets] ${node.comfyClass}: ${selectorName}="${selectedValue}", visible=[${visibleWidgets.join(', ')}]`);
|
|
|
|
let visibilityChanged = false;
|
|
|
|
for (const widget of node.widgets || []) {
|
|
// Only control widgets that are in our mapping
|
|
if (!allControlledWidgets.has(widget.name)) continue;
|
|
|
|
const shouldShow = visibleWidgets.includes(widget.name);
|
|
const wasHidden = widget.hidden;
|
|
widget.hidden = !shouldShow;
|
|
|
|
if (wasHidden !== widget.hidden) {
|
|
visibilityChanged = true;
|
|
console.log(`[DynamicWidgets] Widget "${widget.name}": hidden=${widget.hidden}`);
|
|
}
|
|
}
|
|
|
|
if (visibilityChanged) {
|
|
node.setSize(node.computeSize());
|
|
app.graph.setDirtyCanvas(true, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set up visibility control for a selector widget
|
|
*/
|
|
function setupSelectorWidget(node, selectorName) {
|
|
const selectorWidget = node.widgets?.find(w => w.name === selectorName);
|
|
if (!selectorWidget) {
|
|
console.log(`[DynamicWidgets] Selector widget "${selectorName}" not found on ${node.comfyClass}`);
|
|
return;
|
|
}
|
|
|
|
// Store original callback
|
|
const originalCallback = selectorWidget.callback;
|
|
|
|
// Override callback to update visibility on change
|
|
selectorWidget.callback = function(value) {
|
|
if (originalCallback) originalCallback.call(this, value);
|
|
updateWidgetVisibility(node, selectorName, value);
|
|
};
|
|
|
|
// Initial visibility update (with delay to ensure widgets are created)
|
|
setTimeout(() => {
|
|
updateWidgetVisibility(node, selectorName, selectorWidget.value);
|
|
}, 50);
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "Comfy.DynamicWidgets",
|
|
|
|
nodeCreated(node) {
|
|
const nodeConfig = getNodeConfig(node.comfyClass);
|
|
if (!nodeConfig || !nodeConfig.selectors) return;
|
|
|
|
console.log(`[DynamicWidgets] Setting up node: ${node.comfyClass}`);
|
|
|
|
// Set up each selector
|
|
for (const selectorName of Object.keys(nodeConfig.selectors)) {
|
|
setupSelectorWidget(node, selectorName);
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log("[DynamicWidgets] Extension registered");
|