Key-checked refresh (anti-flicker) + group bypass/mute targets
This commit is contained in:
+59
-29
@@ -16,27 +16,42 @@ function getPanelMode(node) {
|
||||
return getModeWidget(node)?.value ?? "widgets";
|
||||
}
|
||||
|
||||
/** Resolve target nodes whose title starts with "<panelTitle>:" and item part is non-empty. */
|
||||
/** Resolve target nodes/groups whose title starts with "<panelTitle>:" and item part is non-empty. */
|
||||
function resolveTargets(panelNode) {
|
||||
const prefix = panelNode.title;
|
||||
if (!prefix) return [];
|
||||
const needle = prefix + ":";
|
||||
return (app.graph._nodes || []).filter((n) => {
|
||||
if (n.id === panelNode.id) return false;
|
||||
if (!n.title || !n.title.startsWith(needle)) return false;
|
||||
const item = n.title.slice(needle.length).trim();
|
||||
return item.length > 0;
|
||||
const mode = getPanelMode(panelNode);
|
||||
const targets = [];
|
||||
// Nodes
|
||||
(app.graph._nodes || []).forEach((n) => {
|
||||
if (n.id === panelNode.id) return;
|
||||
if (!n.title || !n.title.startsWith(needle)) return;
|
||||
const name = n.title.slice(needle.length).trim();
|
||||
if (name.length > 0) targets.push({ kind: "node", ref: n, name });
|
||||
});
|
||||
// Groups — only relevant in bypass/mute modes (widgets mode targets boolean widgets)
|
||||
if (mode !== "widgets") {
|
||||
(app.graph._groups || []).forEach((g) => {
|
||||
if (!g.title || !g.title.startsWith(needle)) return;
|
||||
const name = g.title.slice(needle.length).trim();
|
||||
if (name.length > 0) targets.push({ kind: "group", ref: g, name });
|
||||
});
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
/** Extract item name (part after ":") from a target node title. */
|
||||
function itemName(panelNode, targetNode) {
|
||||
const prefix = panelNode.title + ":";
|
||||
return targetNode.title.slice(prefix.length).trim();
|
||||
}
|
||||
|
||||
/** Get current real state of a target node for a given panel mode. */
|
||||
function currentRealValue(targetNode, mode) {
|
||||
/** Get current real state of a target (node or group) for a given panel mode. */
|
||||
function currentRealValue(target, mode) {
|
||||
if (target.kind === "group") {
|
||||
const g = target.ref;
|
||||
if (typeof g.recomputeInsideNodes === "function") g.recomputeInsideNodes();
|
||||
const members = g._nodes || [];
|
||||
if (members.length === 0) return false;
|
||||
const m = mode === "bypass" ? 2 : 4;
|
||||
return members.every((n) => n.mode === m);
|
||||
}
|
||||
const targetNode = target.ref;
|
||||
if (mode === "bypass") return targetNode.mode === 2;
|
||||
if (mode === "mute") return targetNode.mode === 4;
|
||||
// widgets: first boolean widget value
|
||||
@@ -53,8 +68,18 @@ function hasBooleanWidget(targetNode) {
|
||||
);
|
||||
}
|
||||
|
||||
/** Apply a toggle value to a target node. */
|
||||
function applyValue(targetNode, mode, value) {
|
||||
/** Apply a toggle value to a target (node or group). */
|
||||
function applyValue(target, mode, value) {
|
||||
if (target.kind === "group") {
|
||||
if (mode === "widgets") return; // groups are never included in widgets mode
|
||||
const g = target.ref;
|
||||
if (typeof g.recomputeInsideNodes === "function") g.recomputeInsideNodes();
|
||||
const m = value ? (mode === "bypass" ? 2 : 4) : 0;
|
||||
(g._nodes || []).forEach((n) => { n.mode = m; });
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
return;
|
||||
}
|
||||
const targetNode = target.ref;
|
||||
if (mode === "bypass") {
|
||||
targetNode.mode = value ? 2 : 0;
|
||||
} else if (mode === "mute") {
|
||||
@@ -87,7 +112,7 @@ const PANELS_CHECK_MS = 150;
|
||||
function relevantKey(panel) {
|
||||
const mode = getPanelMode(panel);
|
||||
const names = resolveTargets(panel)
|
||||
.map((t) => itemName(panel, t).toLowerCase())
|
||||
.map((t) => t.name.toLowerCase())
|
||||
.sort();
|
||||
return (panel.title || "") + "\u0000" + mode + "\u0000" + names.join("\u0000");
|
||||
}
|
||||
@@ -179,16 +204,13 @@ function buildPanel(panelNode) {
|
||||
|
||||
// Sort case-insensitively by item name
|
||||
targets.sort((a, b) => {
|
||||
const na = itemName(panelNode, a).toLowerCase();
|
||||
const nb = itemName(panelNode, b).toLowerCase();
|
||||
const na = a.name.toLowerCase();
|
||||
const nb = b.name.toLowerCase();
|
||||
return na.localeCompare(nb);
|
||||
});
|
||||
|
||||
// Build rows data
|
||||
let rows = targets.map((t) => {
|
||||
const name = itemName(panelNode, t);
|
||||
return { node: t, name };
|
||||
});
|
||||
let rows = targets.map((t) => ({ target: t, name: t.name }));
|
||||
|
||||
// Limit
|
||||
const overflow = rows.length > MAX_ITEMS ? rows.length - MAX_ITEMS : 0;
|
||||
@@ -210,7 +232,7 @@ function buildPanel(panelNode) {
|
||||
}
|
||||
|
||||
// Render rows
|
||||
rows.forEach(({ node: t, name }) => {
|
||||
rows.forEach(({ target: t, name }) => {
|
||||
const row = document.createElement("div");
|
||||
row.style.cssText =
|
||||
"display:flex;align-items:center;justify-content:space-between;" +
|
||||
@@ -219,8 +241,16 @@ function buildPanel(panelNode) {
|
||||
|
||||
// Determine enabled state
|
||||
let disabled = false;
|
||||
if (mode === "widgets" && !hasBooleanWidget(t)) {
|
||||
let disabledTip = "";
|
||||
if (t.kind === "group") {
|
||||
if (typeof t.ref.recomputeInsideNodes === "function") t.ref.recomputeInsideNodes();
|
||||
if ((t.ref._nodes || []).length === 0) {
|
||||
disabled = true;
|
||||
disabledTip = "グループ内にノードがありません";
|
||||
}
|
||||
} else if (mode === "widgets" && !hasBooleanWidget(t.ref)) {
|
||||
disabled = true;
|
||||
disabledTip = "booleanウィジェットがありません";
|
||||
}
|
||||
|
||||
// Label
|
||||
@@ -230,7 +260,7 @@ function buildPanel(panelNode) {
|
||||
"font-size:12px;" + (disabled ? "color:#555;" : "color:#ccc;");
|
||||
label.textContent = name;
|
||||
if (disabled) {
|
||||
label.title = "booleanウィジェットがありません";
|
||||
label.title = disabledTip;
|
||||
}
|
||||
row.appendChild(label);
|
||||
|
||||
@@ -337,9 +367,9 @@ function buildPanel(panelNode) {
|
||||
let prevChange = null;
|
||||
let prevNodeAdded = null;
|
||||
let prevNodeRemoved = null;
|
||||
const onChangeWrapper = (g) => { prevChange?.(g); scheduleRefresh(); };
|
||||
const onNodeAddedWrapper = (n) => { prevNodeAdded?.(n); scheduleRefresh(); };
|
||||
const onNodeRemovedWrapper = (n) => { prevNodeRemoved?.(n); scheduleRefresh(); };
|
||||
const onChangeWrapper = (g) => { prevChange?.(g); schedulePanelsCheck(); };
|
||||
const onNodeAddedWrapper = (n) => { prevNodeAdded?.(n); schedulePanelsCheck(); };
|
||||
const onNodeRemovedWrapper = (n) => { prevNodeRemoved?.(n); schedulePanelsCheck(); };
|
||||
|
||||
function installGraphHooks(g) {
|
||||
if (!g || panelNode.__hooksInstalled) return;
|
||||
|
||||
Reference in New Issue
Block a user