diff --git a/src/core/graph/subgraph/proxyWidgetUtils.ts b/src/core/graph/subgraph/proxyWidgetUtils.ts new file mode 100644 index 000000000..97c6bf23b --- /dev/null +++ b/src/core/graph/subgraph/proxyWidgetUtils.ts @@ -0,0 +1,31 @@ +import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode' +import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets.ts' +import { parseProxyWidgets } from '@/schemas/proxyWidget' +import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore' + +function pushWidgets(node: SubgraphNode, ...widgets: [string, string][]) { + const pw = getProxyWidgets(node) + pw.push(...widgets) + node.properties.proxyWidgets = JSON.stringify(pw) +} +function getProxyWidgets(node: SubgraphNode) { + return parseProxyWidgets(node.properties.proxyWidgets) +} + +/** + * Enables display of a widget on the parent subgraphNode + * @param {{IBaseWidget}} widget - The widget to be promoted + * @param {{LGraphNode}} node - the node which owns the widget + */ +export function promoteWidget(widget: IBaseWidget, node: LGraphNode) { + const { navigationStack } = useSubgraphNavigationStore() + const subgraph = navigationStack.at(-1) + if (!subgraph) throw new Error("Can't promote widget when not in subgraph") + const parentGraph = navigationStack.at(-2) ?? subgraph.rootGraph + for (const onode of parentGraph.nodes) { + if (onode.type === subgraph.id && onode.isSubgraphNode()) { + pushWidgets(onode, [`${node.id}`, widget.name]) + } + } +} diff --git a/src/services/litegraphService.ts b/src/services/litegraphService.ts index 89e33965d..f01739c78 100644 --- a/src/services/litegraphService.ts +++ b/src/services/litegraphService.ts @@ -4,6 +4,7 @@ import { useSelectedLiteGraphItems } from '@/composables/canvas/useSelectedLiteG import { useNodeAnimatedImage } from '@/composables/node/useNodeAnimatedImage' import { useNodeCanvasImagePreview } from '@/composables/node/useNodeCanvasImagePreview' import { useNodeImage, useNodeVideo } from '@/composables/node/useNodeImage' +import { promoteWidget } from '@/core/graph/subgraph/proxyWidgetUtils' import { st, t } from '@/i18n' import { type IContextMenuValue, @@ -741,7 +742,7 @@ export const useLitegraphService = () => { ] } - node.prototype.getExtraMenuOptions = function (_, options) { + node.prototype.getExtraMenuOptions = function (canvas, options) { if (this.imgs) { // If this node has images then we add an open in new tab item let img @@ -788,7 +789,7 @@ export const useLitegraphService = () => { content: 'Bypass', callback: () => { toggleSelectedNodesMode(LGraphEventMode.BYPASS) - app.canvas.setDirty(true, true) + canvas.setDirty(true, true) } }) @@ -832,6 +833,18 @@ export const useLitegraphService = () => { } }) } + if (this.graph && !this.graph.isRootGraph) { + const [x, y] = canvas.canvas_mouse + const overWidget = this.getWidgetOnPos(x, y, true) + if (overWidget) { + options.unshift({ + content: `Promote Widget: ${overWidget.label ?? overWidget.name}`, + callback: () => { + promoteWidget(overWidget, this) + } + }) + } + } return [] }