diff --git a/javascript/sdppp-custom.js b/javascript/sdppp-custom.js index 65e3f75..733cd1e 100644 --- a/javascript/sdppp-custom.js +++ b/javascript/sdppp-custom.js @@ -28,7 +28,7 @@ */ -export default function(sdppp) { +export default function (sdppp) { /** * Handle SDPPP Get Document * 处理 SDPPP Get Document @@ -36,16 +36,18 @@ export default function(sdppp) { * only keep the first widget, set the output type to PS_DOCUMENT * 只保留第一个控件, 将输出类型设置为 PS_DOCUMENT */ - sdppp.widgetable.add('SDPPP Get Document', (node) => { - return { - title: node.title, - widgets: [{ - value: node.widgets[0].value, - outputType: "PS_DOCUMENT", - options: { - values: node.widgets[0].options.values() - } - }] + sdppp.widgetable.add('SDPPP Get Document', { + formatter: (node) => { + return { + title: node.title, + widgets: [{ + value: node.widgets[0].value, + outputType: "PS_DOCUMENT", + options: { + values: node.widgets[0].options.values() + } + }] + } } }) /** @@ -55,17 +57,19 @@ export default function(sdppp) { * only keep the first widget, set the output type to PS_LAYER * 只保留第一个控件, 将输出类型设置为 PS_LAYER */ - sdppp.widgetable.add('SDPPP Get Layer By ID', (node) => { - return { - title: node.title, - widgets: [{ - value: node.widgets[0].value, - outputType: "PS_LAYER", - options: { - values: node.widgets[0].options.values, - documentNodeID: sdppp.findDocumentNodeRecursive(node)?.id || 0 - } - }] + sdppp.widgetable.add('SDPPP Get Layer By ID', { + formatter: (node) => { + return { + title: node.title, + widgets: [{ + value: node.widgets[0].value, + outputType: "PS_LAYER", + options: { + values: node.widgets[0].options.values, + documentNodeID: sdppp.findDocumentNodeRecursive(node)?.id || 0 + } + }] + } } }) /** @@ -81,36 +85,38 @@ export default function(sdppp) { * If the first widget is a number type and suitable for dragging, only keep the first widget * 如果第一个控件是数字类型且其精度适用拖动控件,则只保留第一个控件 */ - sdppp.widgetable.add('PrimitiveNode', (node) => { - let title = node.title.startsWith("Primitive") ? nameByConnectedOutputOrTitle(node) : node.title; - if (!node.widgets || node.widgets.length == 0) { - return null; - } - let sliceNum = 2; - if (node.widgets.length == 2 && node.widgets[1].name == "control_after_generate" && node.widgets[1].value == 'fixed') { - sliceNum = 1; - } - let widgets = node.widgets.slice(0, sliceNum) - .map((widget, index) => { - let uiWeight = 12; - if (widget.type == "number" || widget.type == "combo") { - uiWeight = index == 0 ? (sliceNum == 2 ? 8 : 6) : 4 - } - if (widget.type == "toggle") { - uiWeight = 4; - } - return { - value: widget.value, - name: widget.label || widget.name, - outputType: widget.type || "string", - options: widget.options, - uiWeight: uiWeight - } - }) - .filter(Boolean) - return { - title, - widgets + sdppp.widgetable.add('PrimitiveNode', { + formatter: (node) => { + let title = node.title.startsWith("Primitive") ? nameByConnectedOutputOrTitle(node) : node.title; + if (!node.widgets || node.widgets.length == 0) { + return null; + } + let sliceNum = 2; + if (node.widgets.length == 2 && node.widgets[1].name == "control_after_generate" && node.widgets[1].value == 'fixed') { + sliceNum = 1; + } + let widgets = node.widgets.slice(0, sliceNum) + .map((widget, index) => { + let uiWeight = 12; + if (widget.type == "number" || widget.type == "combo") { + uiWeight = index == 0 ? (sliceNum == 2 ? 8 : 6) : 4 + } + if (widget.type == "toggle") { + uiWeight = 4; + } + return { + value: widget.value, + name: widget.label || widget.name, + outputType: widget.type || "string", + options: widget.options, + uiWeight: uiWeight + } + }) + .filter(Boolean) + return { + title, + widgets + } } }) /** @@ -120,27 +126,49 @@ export default function(sdppp) { * FastMute nodes only have one checkbox, so we can omit the widget name * FastMute节点只有一个勾选框,所以可以不保留控件名字 */ - sdppp.widgetable.add('*rgthree*', (node) => { - if (node.type.indexOf('Group') != -1) { + sdppp.widgetable.add('*rgthree*', { + formatter: (node) => { + if (node.type.indexOf('Group') != -1) { + return { + title: node.title, + widgets: node.widgets.map((widget) => ({ + value: fixRGthreeWidgetValue(widget.type, widget.value), + name: (widget.label || widget.name).replace(/^(enable[-_ ]?)?/gi, ''), + outputType: fixRGthreeWidgetType(widget.type), + options: widget.options, + uiWeight: 3 + })) + } + } return { title: node.title, widgets: node.widgets.map((widget) => ({ - value: widget.value, - name: (widget.label || widget.name).replace(/^(enable[-_ ]?)?/gi, ''), - outputType: widget.type || "toggle", - options: widget.options, - uiWeight: 3 + value: fixRGthreeWidgetValue(widget.type, widget.value), + name: node.type.indexOf('Group') != -1 ? (widget.label || widget.name) : '', + outputType: fixRGthreeWidgetType(widget.type), + options: widget.options })) } - } - return { - title: node.title, - widgets: node.widgets.map((widget) => ({ - value: widget.value, - name: node.type.indexOf('Group') != -1 ? (widget.label || widget.name) : '', - outputType: widget.type || "toggle", - options: widget.options - })) + function fixRGthreeWidgetValue(type, value) { + if (type == 'custom') { + return value.toggled + } + return value + } + function fixRGthreeWidgetType(type) { + if (type == 'custom') { + return 'toggle' + } + return type || 'toggle' + } + }, + setter: (node, widgetIndex, value) => { + if (node.widgets[widgetIndex].type == 'custom') { + if (node.widgets[widgetIndex].value.toggled != value) { + node.widgets[widgetIndex].doModeChange(); + } + return true + } } }) /** @@ -148,14 +176,16 @@ export default function(sdppp) { * 处理 LoadImage 节点 * */ - sdppp.widgetable.add('LoadImage', (node) => { - return { - title: node.title, - widgets: [{ - value: node.widgets[0].value, - outputType: "IMAGE_PATH", - options: node.widgets[0].options - }] + sdppp.widgetable.add('LoadImage', { + formatter: (node) => { + return { + title: node.title, + widgets: [{ + value: node.widgets[0].value, + outputType: "IMAGE_PATH", + options: node.widgets[0].options + }] + } } }) /** @@ -163,54 +193,60 @@ export default function(sdppp) { * 处理 LoadImageMask * */ - sdppp.widgetable.add('LoadImageMask', (node) => { - return { - title: node.title, - widgets: [{ - value: node.widgets[0].value, - outputType: "MASK_PATH", - options: node.widgets[0].options - }] + sdppp.widgetable.add('LoadImageMask', { + formatter: (node) => { + return { + title: node.title, + widgets: [{ + value: node.widgets[0].value, + outputType: "MASK_PATH", + options: node.widgets[0].options + }] + } } }) - sdppp.widgetable.add("CheckpointLoaderSimple", node=> { - return { - title: node.title, - widgets: [{ - value: node.widgets[0].value, - outputType: "combo", - options: node.widgets[0].options - }] + sdppp.widgetable.add("CheckpointLoaderSimple", { + formatter: (node) => { + return { + title: node.title, + widgets: [{ + value: node.widgets[0].value, + outputType: "combo", + options: node.widgets[0].options + }] + } } }) // 替换为Parameter处理 - sdppp.widgetable.add('ETN_Parameter', (node) => { - const outputTypeMap = { - 'number (integer)': { type: "number", step: 1 }, - 'prompt (positive)': { type: "text", subType: "positive-prompt" }, - 'toggle': { type: "toggle" }, - // ...其他类型映射 - }; - - const paramType = node.widgets[1].value; - const mappedType = outputTypeMap[paramType] || { type: paramType } || { type: "string" }; - - return { - title: node.title, - widgets: [{ - value: node.widgets[2].value, // 主值widget - name: node.widgets[0].value, // 参数名widget - outputType: mappedType.type, - options: { - ...node.widgets[2].options, - min: node.widgets[3].value, - max: node.widgets[4].value, - ...mappedType - }, - uiWeight: 12 // 独占整行 - }] + sdppp.widgetable.add('ETN_Parameter', { + formatter: (node) => { + const outputTypeMap = { + 'number (integer)': { type: "number", step: 1 }, + 'prompt (positive)': { type: "text", subType: "positive-prompt" }, + 'toggle': { type: "toggle" }, + // ...其他类型映射 + }; + + const paramType = node.widgets[1].value; + const mappedType = outputTypeMap[paramType] || { type: paramType } || { type: "string" }; + + return { + title: node.title, + widgets: [{ + value: node.widgets[2].value, // 主值widget + name: node.widgets[0].value, // 参数名widget + outputType: mappedType.type, + options: { + ...node.widgets[2].options, + min: node.widgets[3].value, + max: node.widgets[4].value, + ...mappedType + }, + uiWeight: 12 // 独占整行 + }] + } } }); } diff --git a/typescripts/src/plugins/common/tsx/WorkflowEdit.tsx b/typescripts/src/plugins/common/tsx/WorkflowEdit.tsx index 24328bb..d69ad06 100644 --- a/typescripts/src/plugins/common/tsx/WorkflowEdit.tsx +++ b/typescripts/src/plugins/common/tsx/WorkflowEdit.tsx @@ -86,7 +86,7 @@ export default function WorkflowEdit({ { onWidgetChange(fieldInfo.id, widgetIndex, v, fieldInfo); }} diff --git a/typescripts/src/sdsystem/comfy/graph-to-form.mts b/typescripts/src/sdsystem/comfy/graph-to-form.mts index cf15b0b..8a13ce1 100644 --- a/typescripts/src/sdsystem/comfy/graph-to-form.mts +++ b/typescripts/src/sdsystem/comfy/graph-to-form.mts @@ -1,94 +1,54 @@ import i18n from "../../common/i18n.mts"; import { sdpppX } from "../../common/sdpppX.mts"; import { SDPPPGraphForm } from "../../common/types"; - -const customNodeConvertersByWildcard: [string, NodeConverter][] = []; - -sdpppX.widgetable = sdpppX.widgetable || {}; -sdpppX.widgetable.add = function (name: string, fn: NodeConverter) { - customNodeConvertersByWildcard.push([name, fn]); -} +import { app } from "./comfy-globals.mts"; // Define a type for the converter function type NodeConverter = (node: any) => SDPPPGraphForm | null; +type WidgetValueSetter = (node: any, widgetIndex: any, value: any) => boolean; -// // Create an array of tuples with [RegExp, converter function] -// const customNodeConverters: [RegExp, NodeConverter][] = [ -// [/^LoadImage$/, (node: any) => ({ -// id: node.id, -// title: node.title, -// widgets: [{ -// value: node.widgets[0].value, -// outputType: "IMAGE" -// }] -// })], -// [/^LoadImageMask$/, (node: any) => ({ -// id: node.id, -// title: node.title, -// widgets: [{ -// value: node.widgets[0].value, -// outputType: "MASK" -// }] -// })], -// [/^SDPPP Get Layer By ID$/, (node: any) => ({ -// id: node.id, -// title: node.title, -// widgets: [{ -// value: node.widgets[0].value, -// outputType: "LAYER" -// }] -// })], -// [/^SDPPP Get Document$/, (node: any) => ({ -// id: node.id, -// title: node.title, -// widgets: [{ -// value: node.widgets[0].value, -// outputType: "DOCUMENT" -// }] -// })], -// [/\(rgthree\)/, (node: any) => ({ -// id: node.id, -// title: node.title, -// widgets: node.widgets.map((widget: any) => ({ -// value: widget.value, -// name: node.type.indexOf('Group') != -1 ? (widget.label || widget.name) : '', -// outputType: widget.type || "toggle", -// options: widget.options -// })) -// })], -// [/^PrimitiveNode$/, (node: any) => { -// let title = node.title.startsWith("Primitive") ? nameByTitleOrConnectedOutput(node) : node.title; -// if (!node.widgets || node.widgets.length == 0) { -// return null; -// } -// let widgets = node.widgets.slice(0, 2) -// .map((widget: any, index: number) => ({ -// value: widget.value, -// name: widget.label || widget.name, -// outputType: widget.type || "string", -// options: (widget.options), -// uiWeight: index == 0 ? 8 : 4 -// })) -// if (widgets[0].outputType == "number") { -// let isStepRangeTooBig = ((widgets[0].options.max - widgets[0].options.min) / widgets[0].options.step) > 1000; -// if (!isStepRangeTooBig) { -// widgets = widgets.slice(0, 1); -// } -// } -// return { -// id: node.id, -// title: title, -// widgets -// } -// }] -// ]; +const customNodeConvertersByWildcard: [string, { + formatter: NodeConverter, + setter: WidgetValueSetter | null +}][] = []; -function nameByTitleOrConnectedOutput(node: any) { - return node.outputs?.[0].widget?.name || node.title; +sdpppX.widgetable = sdpppX.widgetable || {}; +sdpppX.widgetable.add = function (name: string, fn: NodeConverter | { + formatter: NodeConverter, + setter: WidgetValueSetter +}) { + if (typeof fn === 'function') { + customNodeConvertersByWildcard.push([name, { + formatter: fn, + setter: null + }]); + } else { + customNodeConvertersByWildcard.push([name, fn]); + } +} + + +export function setWidgetValue(node: any, widgetIndex: any, value: any) { + const converter = customNodeConvertersByWildcard.find(([wildcard]) => { + return wildcardMatch(wildcard, node.type); + }); + let setted = false; + if (converter) { + const setter = converter[1].setter; + if (setter) { + setted = !!setter(node, widgetIndex, value); + } + } + if (!setted) { + node.widgets[widgetIndex].value = value; + node.widgets[widgetIndex].callback?.(value) + } + const workflowManager = app.workflowManager || app.extensionManager.workflow + workflowManager.activeWorkflow?.changeTracker.checkState() } export function findAvailableNodeInGraph(graph: any): SDPPPGraphForm[] { - return graph.nodes + return graph?.nodes .map((node: any) => { if (node.mode != 0) return; // muted or by passed if (!node.title || node.title.startsWith(".")) return; // hidden @@ -99,7 +59,7 @@ export function findAvailableNodeInGraph(graph: any): SDPPPGraphForm[] { }); if (converter) { try { - const converted = converter[1](node); + const converted = converter[1].formatter(node); if (converted) { converted.id = node.id; converted.uiWeightSum = converted.widgets.reduce((sum: number, widget: any) => sum + (widget.uiWeight || 12), 0); diff --git a/typescripts/src/sdsystem/comfy/popup/tsx/WorkflowEditWeb.tsx b/typescripts/src/sdsystem/comfy/popup/tsx/WorkflowEditWeb.tsx index 272c704..249b5e8 100644 --- a/typescripts/src/sdsystem/comfy/popup/tsx/WorkflowEditWeb.tsx +++ b/typescripts/src/sdsystem/comfy/popup/tsx/WorkflowEditWeb.tsx @@ -1,7 +1,7 @@ import React from "react" import WorkflowEdit from "../../../../plugins/common/tsx/WorkflowEdit" import { SDPPPGraphForm } from "../../../../common/types"; -import { findAvailableNodeInGraph } from "../../graph-to-form.mjs"; +import { findAvailableNodeInGraph, setWidgetValue } from "../../graph-to-form.mjs"; import { NumberWidget } from "./widgets/number"; import { ComboWidget } from "./widgets/combo"; import { ToggleWidget } from "./widgets/toggle"; @@ -166,10 +166,7 @@ export class WorkflowEditWrap extends React.Component<{ onWidgetChange: async (nodeid: number, widgetIndex: number, value: any, fieldInfo: SDPPPGraphForm) => { const node = app.graph.nodes.find((n: any) => n.id == nodeid); if (!node) return; - node.widgets[widgetIndex].value = value; - node.widgets[widgetIndex].callback(value) - const workflowManager = app.workflowManager || app.extensionManager.workflow - workflowManager.activeWorkflow?.changeTracker.checkState() + setWidgetValue(node, widgetIndex, value); // }, // onRun: async (size: number = 1) => { // for (let i = 0; i < size; i++) diff --git a/typescripts/src/sdsystem/comfy/socket/WorkflowCallee.mts b/typescripts/src/sdsystem/comfy/socket/WorkflowCallee.mts index 4acc220..9c80243 100644 --- a/typescripts/src/sdsystem/comfy/socket/WorkflowCallee.mts +++ b/typescripts/src/sdsystem/comfy/socket/WorkflowCallee.mts @@ -3,7 +3,7 @@ import { WorkflowCallerActions } from "../../../plugins/common/socket/WorkflowCa import { pageStore } from "../../common/models/photoshopModels.mjs"; import { api, app } from "../comfy-globals.mjs"; import { blankGraph } from "../defaultGraph.mjs"; -import { findAvailableNodeInGraph } from "../graph-to-form.mjs"; +import { findAvailableNodeInGraph, setWidgetValue } from "../graph-to-form.mjs"; import PreviewSender from "../PreviewSender.mjs"; interface WorkflowCalleePayload { @@ -156,9 +156,7 @@ export function WorkflowCalleeSocket(SocketClass: SocketConstructor) { params.values.forEach(({ nodeID, widgetIndex, value }) => { const node = app.graph.nodes.find((n: any) => n.id == nodeID); if (!node || value == node.widgets[widgetIndex].value) return; - node.widgets[widgetIndex].value = value; - node.widgets[widgetIndex].callback(value) - this.workflowManager.activeWorkflow?.changeTracker.checkState() + setWidgetValue(node, widgetIndex, value) }); } private async open(params: WorkflowCalleeActions['open']['params']) {