diff --git a/__init__.py b/__init__.py index 62059c0..5e5e098 100644 --- a/__init__.py +++ b/__init__.py @@ -2,12 +2,24 @@ from .install import setup setup() +import os + +NODE_CLASS_MAPPINGS = {} +NODE_DISPLAY_NAME_MAPPINGS = {} + +# 设置 web 目录 +WEB_DIRECTORY = os.path.join(os.path.dirname(os.path.realpath(__file__)), "web") + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"] + try: from .image_resolution_adjuster import ImageResolutionAdjuster from .color_picker import ColorPicker from .remove_empty_lines import RemoveEmptyLinesAndLeadingSpaces from .text_combiner import TextCombiner from .multiline_text_input import MultilineTextInput + from .click_popup import ClickPopup + # 节点映射 NODE_CLASS_MAPPINGS = { @@ -16,6 +28,7 @@ try: "RemoveEmptyLinesAndLeadingSpaces": RemoveEmptyLinesAndLeadingSpaces, "TextCombiner": TextCombiner, "MultilineTextInput": MultilineTextInput, + "ClickPopup": ClickPopup, } NODE_DISPLAY_NAME_MAPPINGS = { @@ -23,10 +36,16 @@ try: "ColorPicker": "Color Picker", "RemoveEmptyLinesAndLeadingSpaces": "Remove Empty Lines And Leading Spaces", "TextCombiner": "Text Combiner", - "MultilineTextInput": "Multiline Text Input" + "MultilineTextInput": "Multiline Text Input", + "ClickPopup": "Click Popup" } + + + + except ImportError as e: print(f"Error importing modules: {e}") print("Please restart ComfyUI after the installation is complete.") NODE_CLASS_MAPPINGS = {} NODE_DISPLAY_NAME_MAPPINGS = {} + diff --git a/__pycache__/__init__.cpython-311.pyc b/__pycache__/__init__.cpython-311.pyc index 7e30862..9059387 100644 Binary files a/__pycache__/__init__.cpython-311.pyc and b/__pycache__/__init__.cpython-311.pyc differ diff --git a/__pycache__/click_popup.cpython-311.pyc b/__pycache__/click_popup.cpython-311.pyc new file mode 100644 index 0000000..4818ffe Binary files /dev/null and b/__pycache__/click_popup.cpython-311.pyc differ diff --git a/__pycache__/image_resolution_adjuster.cpython-311.pyc b/__pycache__/image_resolution_adjuster.cpython-311.pyc index 0aacb76..58bafcd 100644 Binary files a/__pycache__/image_resolution_adjuster.cpython-311.pyc and b/__pycache__/image_resolution_adjuster.cpython-311.pyc differ diff --git a/__pycache__/text_combiner.cpython-311.pyc b/__pycache__/text_combiner.cpython-311.pyc index c5c679c..0462ab7 100644 Binary files a/__pycache__/text_combiner.cpython-311.pyc and b/__pycache__/text_combiner.cpython-311.pyc differ diff --git a/click_popup.py b/click_popup.py new file mode 100644 index 0000000..8e61918 --- /dev/null +++ b/click_popup.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Filename: click_popup.py +# Developer: jammyfu +# Category: 🎨Painting👓Coder/🔧Utils + +class ClickPopup: + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "button": ("BOOLEAN", {"default": False}), + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("message",) + FUNCTION = "show_popup" + CATEGORY = "🎨Painting👓Coder/🔧Utils" + + def show_popup(self, button): + return ("Button clicked!",) + +# 添加到 ComfyUI 节点注册 +NODE_CLASS_MAPPINGS = { + "ClickPopup": ClickPopup, +} \ No newline at end of file diff --git a/image_resolution_adjuster.py b/image_resolution_adjuster.py index 553e543..68039a9 100644 --- a/image_resolution_adjuster.py +++ b/image_resolution_adjuster.py @@ -11,13 +11,6 @@ import folder_paths import json import os -# 尝试导入 gradio,如果失败则使用基础的颜色选择器 -try: - import gradio as gr - HAS_GRADIO = True -except ImportError: - HAS_GRADIO = False - print("Gradio not found, using basic color picker") def resize_image(image, target_width, target_height, method='contain', background_color='#000000'): """Resize an image while maintaining aspect ratio. diff --git a/text_combiner.py b/text_combiner.py index 35f7c3c..8339f0c 100644 --- a/text_combiner.py +++ b/text_combiner.py @@ -3,22 +3,20 @@ # Developer: jammyfu # Category: 🎨Painting👓Coder/📝Text -import comfy +import re class TextCombiner: - def __init__(self): - self.input_count = 1 # 初始输入节点数量 - @classmethod def INPUT_TYPES(s): return { "required": { - "text_1": ("STRING", {"multiline": True}), - "refresh": ("BOOLEAN", {"default": False}), - }, - "optional": { - "text_2": ("STRING", {"multiline": True}), # 只保留一个可选输入 + "separator": ("STRING", { + "default": ",", + "multiline": False, + "placeholder": "支持正则表达式和转义字符,如: ,|\\n,留空则用空格连接" + }), }, + "optional": {} } RETURN_TYPES = ("STRING",) @@ -26,38 +24,52 @@ class TextCombiner: FUNCTION = "combine_text" CATEGORY = "🎨Painting👓Coder/📝Text" - CONTEXT_MENU = { - "refresh_node": ["Refresh Node", "refresh_node"], - "add_input": ["Add Input", "add_input"], - } - - def combine_text(self, text_1, refresh=False, **kwargs): - # 检查是否需要添加新的输入 - if kwargs.get(f"text_{self.input_count + 1}"): - self.add_input() - - # 组合所有非空文本 - texts = [text_1] + [v for k, v in kwargs.items() if v and v.strip()] - combined_text = ", ".join(t.strip() for t in texts if t.strip()) - return (combined_text,) - - def add_input(self): - self.input_count += 1 - # 动态更新 INPUT_TYPES - self.INPUT_TYPES = lambda s: { - "required": { - "text_1": ("STRING", {"multiline": True}), - "refresh": ("BOOLEAN", {"default": False}), - }, - "optional": { - f"text_{i}": ("STRING", {"multiline": True}) - for i in range(2, self.input_count + 2) # +2 是为了总是多一个空输入 - }, - } - return {"refresh": True} - - def refresh_node(self): - return {"refresh": True} + def combine_text(self, separator=",", **kwargs): + try: + # 检查分隔符是否为空 + if not separator.strip(): + # 如果为空,使用空格作为分隔符 + actual_separator = " " + is_newline_separator = False + else: + # 处理转义字符 + actual_separator = bytes(separator, "utf-8").decode("unicode_escape") + # 检查分隔符是否包含换行相关字符 + is_newline_separator = bool(re.search(r'\\[rn]|[\r\n]', actual_separator)) + + # 收集所有非空文本 + texts = [] + for i in range(1, len(kwargs) + 1): + key = f"text_{i}" + if key in kwargs and kwargs[key] is not None: + input_text = kwargs[key] + # 标准化输入文本的换行符 + input_text = input_text.replace('\r\n', '\n').replace('\r', '\n') + + # 使用正则表达式分割输入文本 + split_texts = re.split(actual_separator, input_text) if actual_separator != " " else [input_text] + # 过滤空字符串并添加到结果列表,保留纯空格字符串 + texts.extend(t.rstrip('\n').rstrip('\r') for t in split_texts if t is not None) + + # 根据分隔符类型选择拼接方式 + if is_newline_separator: + # 如果分隔符包含换行,使用换行符拼接 + combined_text = '\n'.join(t if t.strip() else '""' for t in texts) if texts else "等待输入文本" + elif not separator.strip(): + # 如果分隔符为空,使用单个空格拼接 + combined_text = ' '.join(t if t.strip() else '""' for t in texts) if texts else "等待输入文本" + else: + # 否则使用逗号和空格拼接 + combined_text = ", ".join(t if t.strip() else '""' for t in texts) if texts else "等待输入文本" + + return (combined_text,) + + except re.error as e: + # 如果正则表达式无效,返回错误信息 + return (f"正则表达式错误: {str(e)}",) + except Exception as e: + # 处理其他可能的错误 + return (f"错误: {str(e)}",) # 添加到 ComfyUI 节点注册 NODE_CLASS_MAPPINGS = { diff --git a/web/js/click_popup.js b/web/js/click_popup.js new file mode 100644 index 0000000..5079460 --- /dev/null +++ b/web/js/click_popup.js @@ -0,0 +1,26 @@ +import { app } from "/scripts/app.js"; + +app.registerExtension({ + name: "Comfy.PaintingCoder.ClickPopup", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeData.name === "ClickPopup") { + // 添加按钮点击事件处理 + const onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function () { + const result = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined; + + // 获取按钮部件 + const buttonWidget = this.widgets?.find(w => w.name === "button"); + if (buttonWidget) { + buttonWidget.callback = () => { + alert("Button clicked!"); + // 触发按钮点击后重置状态 + buttonWidget.value = false; + }; + } + + return result; + }; + } + } +}); \ No newline at end of file diff --git a/web/js/text_combiner.js b/web/js/text_combiner.js new file mode 100644 index 0000000..e1f7e9f --- /dev/null +++ b/web/js/text_combiner.js @@ -0,0 +1,57 @@ +import { app } from "/scripts/app.js"; + +app.registerExtension({ + name: "Comfy.PaintingCoder.TextCombiner", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + if (nodeData.name === "TextCombiner") { + const onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function() { + const result = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined; + + // 初始化状态 + this.lastConnectedCount = 0; + + // 添加第一个输入点 + console.log("初始化:添加第一个输入点"); + this.addInput("text_1", "STRING"); + + return result; + }; + + nodeType.prototype.onConnectionsChange = function(connectionType, slot, isConnected) { + if (connectionType === 1) { // 输入连接 + console.log(`连接变化 - 槽位: ${slot}, 已连接: ${isConnected}`); + + const connectedCount = this.inputs.reduce((count, input) => + count + (input.link ? 1 : 0), 0); + + console.log(`当前连接数量: ${connectedCount}, 上次连接数量: ${this.lastConnectedCount}`); + + if (connectedCount !== this.lastConnectedCount) { + this.lastConnectedCount = connectedCount; + const targetCount = connectedCount + 1; + console.log(`目标输入点数量: ${targetCount}`); + + while (this.inputs.length < targetCount) { + const newIndex = this.inputs.length + 1; + console.log(`添加新输入点: text_${newIndex}`); + this.addInput(`text_${newIndex}`, "STRING"); + } + + while (this.inputs.length > Math.max(targetCount, 1)) { + const lastInput = this.inputs[this.inputs.length - 1]; + if (!lastInput.link) { + console.log(`移除输入点: ${this.inputs.length}`); + this.removeInput(this.inputs.length - 1); + } + } + + console.log(`更新节点大小,当前输入点数量: ${this.inputs.length}`); + this.setSize(this.computeSize()); + app.graph.setDirtyCanvas(true); + } + } + }; + } + } +}); \ No newline at end of file