mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 16:30:57 +00:00
When in app mode, widgets can be drawn with size different from the size of the parent node. Mouse events on legacy canvas widgets require that the client code query the current state of the node and widget to determine if any elements are being interacted with. This PR sets the `widget.width` property when a legacy canvas widget draw operation occurs so that custom nodes can properly resolve subsequent mouse events. At current, no core nodes exist that utilize legacy widgets. As a result the setup code to test this bug fix is slightly involved. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11574-Fix-legacy-widget-width-in-app-mode-34b6d73d365081caaa34c6204f8361f6) by [Unito](https://www.unito.io)
375 lines
10 KiB
Python
375 lines
10 KiB
Python
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
|
|
class LongComboDropdown:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {"option": ([f"Option {i}" for i in range(1_000)],)}}
|
|
|
|
RETURN_TYPES = ()
|
|
OUTPUT_NODE = True
|
|
FUNCTION = "long_combo_dropdown"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A long combo dropdown"
|
|
|
|
def long_combo_dropdown(self, option: str):
|
|
print(option)
|
|
|
|
|
|
class NodeWithOptionalInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {"required_input": ("IMAGE",)},
|
|
"optional": {"optional_input": ("IMAGE", {"default": None})},
|
|
}
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
FUNCTION = "node_with_optional_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with an optional input"
|
|
|
|
def node_with_optional_input(self, required_input, optional_input=None):
|
|
print(
|
|
f"Calling node with required_input: {required_input} and optional_input: {optional_input}"
|
|
)
|
|
return (required_input,)
|
|
|
|
|
|
class NodeWithOptionalComboInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"optional": {
|
|
"optional_combo_input": (
|
|
[f"Random Unique Option {time.time()}" for _ in range(8)],
|
|
{"default": None},
|
|
)
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING",)
|
|
FUNCTION = "node_with_optional_combo_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with an optional combo input that returns unique values every time INPUT_TYPES is called"
|
|
|
|
def node_with_optional_combo_input(self, optional_combo_input=None):
|
|
print(f"Calling node with optional_combo_input: {optional_combo_input}")
|
|
return (optional_combo_input,)
|
|
|
|
|
|
class NodeWithOnlyOptionalInput:
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"optional": {
|
|
"text": ("STRING", {"multiline": True, "dynamicPrompts": True}),
|
|
"clip": ("CLIP", {}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "node_with_only_optional_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with only optional input"
|
|
|
|
def node_with_only_optional_input(self, clip=None, text=None):
|
|
pass
|
|
|
|
|
|
class NodeWithOutputList:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {}}
|
|
|
|
RETURN_TYPES = (
|
|
"INT",
|
|
"INT",
|
|
)
|
|
RETURN_NAMES = (
|
|
"INTEGER OUTPUT",
|
|
"INTEGER LIST OUTPUT",
|
|
)
|
|
OUTPUT_IS_LIST = (
|
|
False,
|
|
True,
|
|
)
|
|
FUNCTION = "node_with_output_list"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with an output list"
|
|
|
|
def node_with_output_list(self):
|
|
return (1, [1, 2, 3])
|
|
|
|
|
|
class NodeWithForceInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"int_input": ("INT", {"forceInput": True}),
|
|
"int_input_widget": ("INT", {"default": 1}),
|
|
},
|
|
"optional": {"float_input": ("FLOAT", {"forceInput": True})},
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
OUTPUT_NODE = True
|
|
FUNCTION = "node_with_force_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a forced input"
|
|
|
|
def node_with_force_input(
|
|
self, int_input: int, int_input_widget: int, float_input: float = 0.0
|
|
):
|
|
print(
|
|
f"int_input: {int_input}, int_input_widget: {int_input_widget}, float_input: {float_input}"
|
|
)
|
|
|
|
|
|
class NodeWithDefaultInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"int_input": ("INT", {"defaultInput": True}),
|
|
"int_input_widget": ("INT", {"default": 1}),
|
|
},
|
|
"optional": {"float_input": ("FLOAT", {"defaultInput": True})},
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
OUTPUT_NODE = True
|
|
FUNCTION = "node_with_default_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a default input"
|
|
|
|
def node_with_default_input(
|
|
self, int_input: int, int_input_widget: int, float_input: float = 0.0
|
|
):
|
|
print(
|
|
f"int_input: {int_input}, int_input_widget: {int_input_widget}, float_input: {float_input}"
|
|
)
|
|
|
|
|
|
class NodeWithStringInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {"string_input": ("STRING",)}}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "node_with_string_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a string input"
|
|
|
|
def node_with_string_input(self, string_input: str):
|
|
print(f"string_input: {string_input}")
|
|
|
|
|
|
class NodeWithUnionInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"optional": {
|
|
"string_or_int_input": ("STRING,INT",),
|
|
"string_input": ("STRING", {"forceInput": True}),
|
|
"int_input": ("INT", {"forceInput": True}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
OUTPUT_NODE = True
|
|
FUNCTION = "node_with_union_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a union input"
|
|
|
|
def node_with_union_input(
|
|
self,
|
|
string_or_int_input: str | int = "",
|
|
string_input: str = "",
|
|
int_input: int = 0,
|
|
):
|
|
print(
|
|
f"string_or_int_input: {string_or_int_input}, string_input: {string_input}, int_input: {int_input}"
|
|
)
|
|
return {
|
|
"ui": {
|
|
"text": string_or_int_input,
|
|
}
|
|
}
|
|
|
|
|
|
class NodeWithBooleanInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {"boolean_input": ("BOOLEAN",)}}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "node_with_boolean_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a boolean input"
|
|
|
|
def node_with_boolean_input(self, boolean_input: bool):
|
|
print(f"boolean_input: {boolean_input}")
|
|
|
|
|
|
class SimpleSlider:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (
|
|
"FLOAT",
|
|
{
|
|
"display": "slider",
|
|
"default": 0.5,
|
|
"min": 0.0,
|
|
"max": 1.0,
|
|
"step": 0.001,
|
|
},
|
|
),
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("FLOAT",)
|
|
FUNCTION = "execute"
|
|
CATEGORY = "DevTools"
|
|
|
|
def execute(self, value):
|
|
return (value,)
|
|
|
|
|
|
class NodeWithSeedInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {"seed": ("INT", {"default": 0})}}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "node_with_seed_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node with a seed input"
|
|
OUTPUT_NODE = True
|
|
|
|
def node_with_seed_input(self, seed: int):
|
|
print(f"seed: {seed}")
|
|
|
|
|
|
class NodeWithValidation:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {"int_input": ("INT",)},
|
|
}
|
|
|
|
@classmethod
|
|
def VALIDATE_INPUTS(cls, int_input: int):
|
|
if int_input < 0:
|
|
raise ValueError("int_input must be greater than 0")
|
|
return True
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "execute"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = "A node that validates an input"
|
|
OUTPUT_NODE = True
|
|
|
|
def execute(self, int_input: int):
|
|
print(f"int_input: {int_input}")
|
|
return tuple()
|
|
|
|
|
|
class NodeWithV2ComboInput:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"combo_input": (
|
|
"COMBO",
|
|
{"options": ["A", "B"]},
|
|
),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("COMBO",)
|
|
FUNCTION = "node_with_v2_combo_input"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = (
|
|
"A node that outputs a combo type that adheres to the v2 combo input spec"
|
|
)
|
|
|
|
def node_with_v2_combo_input(self, combo_input: str):
|
|
return (combo_input,)
|
|
|
|
class NodeWithLegacyWidget:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": { "legacy_widget": ("INT", { "widgetType": "DEVTOOLSLEGACYWIDGET" }) }
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "node_with_legacy_widget"
|
|
CATEGORY = "DevTools"
|
|
DESCRIPTION = ("A node with a legacy widget")
|
|
|
|
def node_with_legacy_widget(self):
|
|
return ()
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"DevToolsLongComboDropdown": LongComboDropdown,
|
|
"DevToolsNodeWithOptionalInput": NodeWithOptionalInput,
|
|
"DevToolsNodeWithOptionalComboInput": NodeWithOptionalComboInput,
|
|
"DevToolsNodeWithOnlyOptionalInput": NodeWithOnlyOptionalInput,
|
|
"DevToolsNodeWithOutputList": NodeWithOutputList,
|
|
"DevToolsNodeWithForceInput": NodeWithForceInput,
|
|
"DevToolsNodeWithDefaultInput": NodeWithDefaultInput,
|
|
"DevToolsNodeWithStringInput": NodeWithStringInput,
|
|
"DevToolsNodeWithUnionInput": NodeWithUnionInput,
|
|
"DevToolsNodeWithBooleanInput": NodeWithBooleanInput,
|
|
"DevToolsSimpleSlider": SimpleSlider,
|
|
"DevToolsNodeWithSeedInput": NodeWithSeedInput,
|
|
"DevToolsNodeWithValidation": NodeWithValidation,
|
|
"DevToolsNodeWithV2ComboInput": NodeWithV2ComboInput,
|
|
"DevToolsNodeWithLegacyWidget": NodeWithLegacyWidget,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"DevToolsLongComboDropdown": "Long Combo Dropdown",
|
|
"DevToolsNodeWithOptionalInput": "Node With Optional Input",
|
|
"DevToolsNodeWithOptionalComboInput": "Node With Optional Combo Input",
|
|
"DevToolsNodeWithOnlyOptionalInput": "Node With Only Optional Input",
|
|
"DevToolsNodeWithOutputList": "Node With Output List",
|
|
"DevToolsNodeWithForceInput": "Node With Force Input",
|
|
"DevToolsNodeWithDefaultInput": "Node With Default Input",
|
|
"DevToolsNodeWithStringInput": "Node With String Input",
|
|
"DevToolsNodeWithUnionInput": "Node With Union Input",
|
|
"DevToolsNodeWithBooleanInput": "Node With Boolean Input",
|
|
"DevToolsSimpleSlider": "Simple Slider",
|
|
"DevToolsNodeWithSeedInput": "Node With Seed Input",
|
|
"DevToolsNodeWithValidation": "Node With Validation",
|
|
"DevToolsNodeWithV2ComboInput": "Node With V2 Combo Input",
|
|
"DevToolsNodeWithLegacyWidget": "Node With Legacy Widget",
|
|
}
|
|
|
|
__all__ = [
|
|
"LongComboDropdown",
|
|
"NodeWithOptionalInput",
|
|
"NodeWithOptionalComboInput",
|
|
"NodeWithOnlyOptionalInput",
|
|
"NodeWithOutputList",
|
|
"NodeWithForceInput",
|
|
"NodeWithDefaultInput",
|
|
"NodeWithStringInput",
|
|
"NodeWithUnionInput",
|
|
"NodeWithBooleanInput",
|
|
"SimpleSlider",
|
|
"NodeWithSeedInput",
|
|
"NodeWithValidation",
|
|
"NodeWithV2ComboInput",
|
|
"NODE_CLASS_MAPPINGS",
|
|
"NODE_DISPLAY_NAME_MAPPINGS",
|
|
]
|