mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-21 15:24:09 +00:00
Overhaul node computeSize - use actual text width (#962)
### Node resize overhaul - Precisely calculates node minimum size - Prevents input & output overlap - Prevents (normal*) widgets from rendering text over the edge of nodes - Performance impact was sub-millisecond for normal usage in a 500-node graph  _Minimum size for a few example node configurations_ ### Widgets - Converts hard-coded draw render values to class static properties - Adds widget button draw function for left/right arrow widgets _*_ Exception: `control_after_generate`, as it is not a true input / widget. A check may be added later to handle this special case.
This commit is contained in:
@@ -45,6 +45,7 @@ import {
|
||||
import { findFreeSlotOfType } from "./utils/collections"
|
||||
import { distributeSpace } from "./utils/spaceDistribution"
|
||||
import { toClass } from "./utils/type"
|
||||
import { BaseWidget } from "./widgets/BaseWidget"
|
||||
import { WIDGET_TYPE_MAP } from "./widgets/widgetMap"
|
||||
|
||||
// #region Types
|
||||
@@ -1529,7 +1530,7 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
||||
const ctorSize = this.constructor.size
|
||||
if (ctorSize) return [ctorSize[0], ctorSize[1]]
|
||||
|
||||
const { inputs, outputs } = this
|
||||
const { inputs, outputs, widgets } = this
|
||||
let rows = Math.max(
|
||||
inputs ? inputs.filter(input => !isWidgetInputSlot(input)).length : 1,
|
||||
outputs ? outputs.length : 1,
|
||||
@@ -1539,45 +1540,66 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
||||
// although it should be graphcanvas.inner_text_font size
|
||||
const font_size = LiteGraph.NODE_TEXT_SIZE
|
||||
|
||||
const title_width = compute_text_size(this.title)
|
||||
const padLeft = LiteGraph.NODE_TITLE_HEIGHT
|
||||
const padRight = padLeft * 0.33
|
||||
const title_width = padLeft + compute_text_size(this.title, this.titleFontStyle) + padRight
|
||||
let input_width = 0
|
||||
let widgetWidth = 0
|
||||
let output_width = 0
|
||||
|
||||
if (inputs) {
|
||||
for (const input of inputs) {
|
||||
const text = input.label || input.localized_name || input.name || ""
|
||||
const text_width = compute_text_size(text)
|
||||
if (input_width < text_width)
|
||||
input_width = text_width
|
||||
const text_width = compute_text_size(text, this.innerFontStyle)
|
||||
if (isWidgetInputSlot(input)) {
|
||||
const widget = this.getWidgetFromSlot(input)
|
||||
if (widget && !this.isWidgetVisible(widget)) continue
|
||||
|
||||
if (text_width > widgetWidth) widgetWidth = text_width
|
||||
} else {
|
||||
if (text_width > input_width) input_width = text_width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outputs) {
|
||||
for (const output of outputs) {
|
||||
const text = output.label || output.localized_name || output.name || ""
|
||||
const text_width = compute_text_size(text)
|
||||
const text_width = compute_text_size(text, this.innerFontStyle)
|
||||
if (output_width < text_width)
|
||||
output_width = text_width
|
||||
}
|
||||
}
|
||||
|
||||
size[0] = Math.max(input_width + output_width + 10, title_width)
|
||||
size[0] = Math.max(size[0], LiteGraph.NODE_WIDTH)
|
||||
if (this.widgets?.length)
|
||||
size[0] = Math.max(size[0], LiteGraph.NODE_WIDTH * 1.5)
|
||||
const minWidth = LiteGraph.NODE_WIDTH * (widgets?.length ? 1.5 : 1)
|
||||
// Text + slot width + centre padding
|
||||
const centrePadding = input_width && output_width ? 5 : 0
|
||||
const slotsWidth = input_width + output_width + (2 * LiteGraph.NODE_SLOT_HEIGHT) + centrePadding
|
||||
|
||||
// Total distance from edge of node to the inner edge of the widget 'previous' arrow button
|
||||
const widgetMargin = BaseWidget.margin + BaseWidget.arrowMargin + BaseWidget.arrowWidth
|
||||
const widgetPadding = BaseWidget.minValueWidth + (2 * widgetMargin)
|
||||
if (widgetWidth) widgetWidth += widgetPadding
|
||||
|
||||
size[0] = Math.max(slotsWidth, widgetWidth, title_width, minWidth)
|
||||
size[1] = (this.constructor.slot_start_y || 0) + rows * LiteGraph.NODE_SLOT_HEIGHT
|
||||
|
||||
// Get widget height & expand size if necessary
|
||||
let widgets_height = 0
|
||||
if (this.widgets?.length) {
|
||||
for (const widget of this.widgets) {
|
||||
if (widgets?.length) {
|
||||
for (const widget of widgets) {
|
||||
if (!this.isWidgetVisible(widget)) continue
|
||||
|
||||
let widget_height = 0
|
||||
if (widget.computeSize) {
|
||||
widget_height += widget.computeSize(size[0])[1]
|
||||
} else if (widget.computeLayoutSize) {
|
||||
widget_height += widget.computeLayoutSize(this).minHeight
|
||||
// Expand widget width if necessary
|
||||
const { minHeight, minWidth } = widget.computeLayoutSize(this)
|
||||
const widgetWidth = minWidth + widgetPadding
|
||||
if (widgetWidth > size[0]) size[0] = widgetWidth
|
||||
|
||||
widget_height += minHeight
|
||||
} else {
|
||||
widget_height += LiteGraph.NODE_WIDGET_HEIGHT
|
||||
}
|
||||
@@ -1594,10 +1616,9 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
||||
else
|
||||
size[1] += widgets_height
|
||||
|
||||
function compute_text_size(text: string) {
|
||||
return text
|
||||
? font_size * text.length * 0.6
|
||||
: 0
|
||||
function compute_text_size(text: string, fontStyle: string) {
|
||||
return LGraphCanvas._measureText?.(text, fontStyle) ??
|
||||
font_size * (text?.length ?? 0) * 0.6
|
||||
}
|
||||
|
||||
if (this.constructor.min_height && size[1] < this.constructor.min_height) {
|
||||
@@ -3375,7 +3396,7 @@ export class LGraphNode implements Positionable, IPinnable, IColorable {
|
||||
const show_text = !lowQuality
|
||||
ctx.save()
|
||||
ctx.globalAlpha = editorAlpha
|
||||
const margin = 15
|
||||
const { margin } = BaseWidget
|
||||
|
||||
for (const w of widgets) {
|
||||
if (!this.isWidgetVisible(w)) continue
|
||||
|
||||
Reference in New Issue
Block a user