mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 10:12:11 +00:00
Add UI code for configuring subgraphNode widgets (#5826)
The third PR for managing display of widgets on subgraph nodes. This is the one that actually makes the functionality usable and user visible. Adds - A right-side modal for configuring which widgets are promoted, accessed by right click or selection toolbar - This menu allows for re-arranging widget order by dragging and dropping. - Indicators inside the subgraph for which widgets have been promoted. - Context menu options for promoting or demoting widget inside of a subgraph. <img width="767" height="694" alt="image" src="https://github.com/user-attachments/assets/4f78645d-7b26-48ba-8c49-78f4807e89e8" /> <img width="784" height="435" alt="image" src="https://github.com/user-attachments/assets/7005c730-a732-481e-befb-57019a8a31a7" /> Known issues - Some preview widgets are not added to a node until a draw operation occurs. The code does not yet have a way of determining which nodes should have draw operations forced to facilitate initial widget creation. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5826-Add-UI-code-for-configuring-subgraphNode-widgets-27c6d73d36508146accbf395e5bcd36a) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -1862,13 +1862,13 @@ export class LGraphCanvas
|
||||
this.#dirty()
|
||||
}
|
||||
|
||||
openSubgraph(subgraph: Subgraph): void {
|
||||
openSubgraph(subgraph: Subgraph, fromNode: SubgraphNode): void {
|
||||
const { graph } = this
|
||||
if (!graph) throw new NullGraphError()
|
||||
|
||||
const options = {
|
||||
bubbles: true,
|
||||
detail: { subgraph, closingGraph: graph },
|
||||
detail: { subgraph, closingGraph: graph, fromNode },
|
||||
cancelable: true
|
||||
}
|
||||
const mayContinue = this.canvas.dispatchEvent(
|
||||
@@ -2794,7 +2794,7 @@ export class LGraphCanvas
|
||||
if (pos[1] < 0 && !inCollapse) {
|
||||
node.onNodeTitleDblClick?.(e, pos, this)
|
||||
} else if (node instanceof SubgraphNode) {
|
||||
this.openSubgraph(node.subgraph)
|
||||
this.openSubgraph(node.subgraph, node)
|
||||
}
|
||||
|
||||
node.onDblClick?.(e, pos, this)
|
||||
@@ -8007,7 +8007,7 @@ export class LGraphCanvas
|
||||
if (Object.keys(this.selected_nodes).length > 1) {
|
||||
options.push(
|
||||
{
|
||||
content: 'Convert to Subgraph 🆕',
|
||||
content: 'Convert to Subgraph',
|
||||
callback: () => {
|
||||
if (!this.selectedItems.size)
|
||||
throw new Error('Convert to Subgraph: Nothing selected.')
|
||||
@@ -8042,7 +8042,7 @@ export class LGraphCanvas
|
||||
} else {
|
||||
options = [
|
||||
{
|
||||
content: 'Convert to Subgraph 🆕',
|
||||
content: 'Convert to Subgraph',
|
||||
callback: () => {
|
||||
// find groupnodes, degroup and select children
|
||||
if (this.selectedItems.size) {
|
||||
|
||||
@@ -3749,6 +3749,13 @@ export class LGraphNode
|
||||
return !isHidden
|
||||
}
|
||||
|
||||
updateComputedDisabled() {
|
||||
if (!this.widgets) return
|
||||
for (const widget of this.widgets)
|
||||
widget.computedDisabled =
|
||||
widget.disabled || this.getSlotFromWidget(widget)?.link != null
|
||||
}
|
||||
|
||||
drawWidgets(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
{ lowQuality = false, editorAlpha = 1 }: DrawWidgetsOptions
|
||||
@@ -3762,6 +3769,7 @@ export class LGraphNode
|
||||
ctx.save()
|
||||
ctx.globalAlpha = editorAlpha
|
||||
|
||||
this.updateComputedDisabled()
|
||||
for (const widget of widgets) {
|
||||
if (!this.isWidgetVisible(widget)) continue
|
||||
|
||||
@@ -3771,9 +3779,6 @@ export class LGraphNode
|
||||
: LiteGraph.WIDGET_OUTLINE_COLOR
|
||||
|
||||
widget.last_y = y
|
||||
// Disable widget if it is disabled or if the value is passed from socket connection.
|
||||
widget.computedDisabled =
|
||||
widget.disabled || this.getSlotFromWidget(widget)?.link != null
|
||||
|
||||
ctx.strokeStyle = outlineColour
|
||||
ctx.fillStyle = '#222'
|
||||
|
||||
@@ -70,6 +70,7 @@ export class LiteGraphGlobal {
|
||||
|
||||
WIDGET_BGCOLOR = '#222'
|
||||
WIDGET_OUTLINE_COLOR = '#666'
|
||||
WIDGET_PROMOTED_OUTLINE_COLOR = '#BF00FF'
|
||||
WIDGET_ADVANCED_OUTLINE_COLOR = 'rgba(56, 139, 253, 0.8)'
|
||||
WIDGET_TEXT_COLOR = '#DDD'
|
||||
WIDGET_SECONDARY_TEXT_COLOR = '#999'
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { LGraphGroup } from '@/lib/litegraph/src/LGraphGroup'
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { ConnectingLink } from '@/lib/litegraph/src/interfaces'
|
||||
import type { Subgraph } from '@/lib/litegraph/src/subgraph/Subgraph'
|
||||
import type { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
|
||||
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
|
||||
|
||||
export interface LGraphCanvasEventMap {
|
||||
@@ -14,6 +15,11 @@ export interface LGraphCanvasEventMap {
|
||||
/** The old active graph, or `null` if there was no active graph. */
|
||||
oldGraph: LGraph | Subgraph | null | undefined
|
||||
}
|
||||
'subgraph-opened': {
|
||||
subgraph: Subgraph
|
||||
closingGraph: LGraph
|
||||
fromNode: SubgraphNode
|
||||
}
|
||||
|
||||
'litegraph:canvas':
|
||||
| { subType: 'before-change' | 'after-change' }
|
||||
|
||||
@@ -168,7 +168,7 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
|
||||
canvas: LGraphCanvas
|
||||
): void {
|
||||
if (button.name === 'enter_subgraph') {
|
||||
canvas.openSubgraph(this.subgraph)
|
||||
canvas.openSubgraph(this.subgraph, this)
|
||||
} else {
|
||||
super.onTitleButtonClick(button, canvas)
|
||||
}
|
||||
|
||||
@@ -308,6 +308,13 @@ export interface IBaseWidget<
|
||||
|
||||
hidden?: boolean
|
||||
advanced?: boolean
|
||||
/**
|
||||
* This property is automatically computed on graph change
|
||||
* and should not be changed.
|
||||
* Promoted widgets have a colored border
|
||||
* @see /core/graph/subgraph/proxyWidget.registerProxyWidgets
|
||||
*/
|
||||
promoted?: boolean
|
||||
|
||||
tooltip?: string
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
|
||||
computedDisabled?: boolean
|
||||
hidden?: boolean
|
||||
advanced?: boolean
|
||||
promoted?: boolean
|
||||
tooltip?: string
|
||||
element?: HTMLElement
|
||||
callback?(
|
||||
@@ -146,6 +147,7 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
|
||||
}
|
||||
|
||||
get outline_color() {
|
||||
if (this.promoted) return LiteGraph.WIDGET_PROMOTED_OUTLINE_COLOR
|
||||
return this.advanced
|
||||
? LiteGraph.WIDGET_ADVANCED_OUTLINE_COLOR
|
||||
: LiteGraph.WIDGET_OUTLINE_COLOR
|
||||
|
||||
Reference in New Issue
Block a user