Show widget input inplace (#535)

* Show widget input inplace

* nit

* nit
This commit is contained in:
Chenlei Hu
2025-02-16 11:37:47 -05:00
committed by GitHub
parent 52a96a14d6
commit 1e71da9a38
3 changed files with 48 additions and 8 deletions

View File

@@ -4662,13 +4662,10 @@ export class LGraphCanvas implements ConnectionColorContext {
// render inputs and outputs
if (!node.collapsed) {
node.layoutSlots()
const slotsBounds = createBounds(
node.slots.map(slot => slot._layoutElement),
/** padding= */ 0,
)
const slotsBounds = node.layoutSlots()
const widgetStartY = slotsBounds ? slotsBounds[1] + slotsBounds[3] : 0
node.layoutWidgets({ widgetStartY })
node.layoutWidgetInputSlots()
node.drawSlots(ctx, {
connectingLink: this.connecting_links?.[0],

View File

@@ -33,9 +33,9 @@ import {
} from "./types/globalEnums"
import { BadgePosition, LGraphBadge } from "./LGraphBadge"
import { type LGraphNodeConstructor, LiteGraph } from "./litegraph"
import { isInRectangle, isInRect, snapPoint } from "./measure"
import { isInRectangle, isInRect, snapPoint, createBounds } from "./measure"
import { LLink } from "./LLink"
import { ConnectionColorContext, isINodeInputSlot, NodeInputSlot, NodeOutputSlot, serializeSlot, toNodeSlotClass } from "./NodeSlot"
import { ConnectionColorContext, isINodeInputSlot, isWidgetInputSlot, NodeInputSlot, NodeOutputSlot, serializeSlot, toNodeSlotClass } from "./NodeSlot"
import { WIDGET_TYPE_MAP } from "./widgets/widgetMap"
import { toClass } from "./utils/type"
import { LayoutElement } from "./utils/layout"
@@ -3218,17 +3218,26 @@ export class LGraphNode implements Positionable, IPinnable {
})
}
layoutSlots(): void {
layoutSlots(): ReadOnlyRect | null {
const slots: LayoutElement<INodeSlot>[] = []
for (const [i, slot] of this.inputs.entries()) {
/** Widget input slots are handled in {@link layoutWidgetInputSlots} */
if (isWidgetInputSlot(slot)) continue
this.layoutSlot(slot, {
slotIndex: i,
})
slots.push(slot._layoutElement)
}
for (const [i, slot] of this.outputs.entries()) {
this.layoutSlot(slot, {
slotIndex: i,
})
slots.push(slot._layoutElement)
}
return slots.length ? createBounds(slots, /** padding= */ 0) : null
}
#getMouseOverSlot(slot: INodeSlot): INodeSlot | null {
@@ -3345,4 +3354,30 @@ export class LGraphNode implements Positionable, IPinnable {
y += w.computedHeight
}
}
/**
* Lays out the node's widget input slots.
*/
layoutWidgetInputSlots(): void {
if (!this.widgets) return
const slotByWidgetName = new Map<string, INodeInputSlot & { index: number }>()
for (const [i, slot] of this.inputs.entries()) {
if (!isWidgetInputSlot(slot)) continue
slotByWidgetName.set(slot.widget?.name, { ...slot, index: i })
}
if (!slotByWidgetName.size) return
for (const widget of this.widgets) {
const slot = slotByWidgetName.get(widget.name)
if (!slot) continue
const actualSlot = this.inputs[slot.index]
const offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5
actualSlot.pos = [offset, widget.y + offset]
this.layoutSlot(actualSlot, { slotIndex: slot.index })
}
}
}

View File

@@ -45,6 +45,14 @@ export function toNodeSlotClass(slot: INodeSlot): NodeSlot {
throw new Error("Invalid slot type")
}
/**
* Whether this slot is an input slot and attached to a widget.
* @param slot - The slot to check.
*/
export function isWidgetInputSlot(slot: INodeSlot): boolean {
return isINodeInputSlot(slot) && !!slot.widget
}
export abstract class NodeSlot implements INodeSlot {
name: string
localized_name?: string