54 lines
2.7 KiB
JavaScript
54 lines
2.7 KiB
JavaScript
// How a DOM panel claims its share of a node's height. No DOM and no
|
|
// ComfyUI imports in here, so it stays testable under node:test.
|
|
//
|
|
// The frontend arranges a node's widgets in one pass
|
|
// (LGraphNode._arrangeWidgets):
|
|
//
|
|
// if (w.computeSize) -> fixed height, kept OUT of the split
|
|
// else if (w.computeLayoutSize) -> joins distributeSpace(freeSpace, ...)
|
|
// else -> one standard widget row
|
|
//
|
|
// It is an else-if, so a widget declaring BOTH is pinned by computeSize and
|
|
// its computeLayoutSize is never called. Every stage, player and filmstrip in
|
|
// this pack derived that fixed height from the node's WIDTH, which is why
|
|
// dragging a node taller only added dead space underneath: the panel had
|
|
// already been given a height and excluded from the leftover-space split.
|
|
//
|
|
// The frontend mounts a DOM widget's element inside a frame: DomWidgets.vue
|
|
// insets it by `options.margin` per side (default 10), so the element gets
|
|
// 20 fewer CSS pixels of height than the layout hands the widget. Any floor
|
|
// meant to guarantee room for fixed-height content must add this allowance,
|
|
// or the panel's bottom edge renders clipped flat - which is how the LoRA
|
|
// stack's rounded bottom border once went missing.
|
|
export const WIDGET_FRAME = 20;
|
|
|
|
// distributeSpace reads a missing maxSize as Infinity, so declaring a floor
|
|
// with no ceiling means "take whatever is left" - which is exactly "fill the
|
|
// node". minWidth/minHeight accept a number or a function, for panels whose
|
|
// floor depends on state (the frame chooser is shorter until it has frames).
|
|
export function fillNodeHeight(widget, { minWidth = 0, minHeight = 0, minNodeSize } = {}) {
|
|
if (!widget) return widget;
|
|
const floor = (value) => {
|
|
const resolved = Number(typeof value === "function" ? value() : value);
|
|
return Number.isFinite(resolved) ? Math.max(0, resolved) : 0;
|
|
};
|
|
// Deleted, not overwritten: any own computeSize would win the else-if above.
|
|
delete widget.computeSize;
|
|
widget.computeLayoutSize = () => ({ minWidth: floor(minWidth), minHeight: floor(minHeight) });
|
|
widget.options ??= {};
|
|
if (minNodeSize) widget.options.minNodeSize = minNodeSize;
|
|
return widget;
|
|
}
|
|
|
|
// Grow a node to the height its widgets ask for. A workflow saved before a
|
|
// panel or card existed carries the node's old size, and the frontend keeps
|
|
// that size on load - the new panel is then squeezed under its floor and
|
|
// clipped flat. Returns true when the node was resized.
|
|
export function ensureNodeMinHeight(node) {
|
|
const min = Number(node?.computeSize?.()?.[1]);
|
|
const current = Number(node?.size?.[1]);
|
|
if (!Number.isFinite(min) || !Number.isFinite(current) || current >= min) return false;
|
|
node.setSize?.([node.size[0], min]);
|
|
return true;
|
|
}
|