diff --git a/Rayko_Prompts.py b/Rayko_Prompts.py index 2401e5c..859409a 100644 --- a/Rayko_Prompts.py +++ b/Rayko_Prompts.py @@ -24,6 +24,7 @@ class RSPrompts: }, "optional": { "text_input": ("STRING", {"forceInput": True}), + "disable_text_input": ("BOOLEAN", {"default": False, "label": "πŸ”˜ Disable text input"}), "pause_for_edit": ("BOOLEAN", {"default": False, "label": "⏸️ Pause for manual edit"}), }, "hidden": { @@ -37,17 +38,22 @@ class RSPrompts: CATEGORY = "🦊 RaykoStudio" DESCRIPTION = "Text encoder with visual prompt controls and pause-for-edit mode." - def encode_prompts(self, clip, pause_for_edit=False, text="", text_input=None, unique_id=None): - current_text = text_input if text_input is not None else text + def encode_prompts(self, clip, disable_text_input=False, pause_for_edit=False, text="", text_input=None, unique_id=None): + if disable_text_input: + current_text = text + effective_text_input = None + else: + current_text = text_input if text_input is not None else text + effective_text_input = text_input - if text_input is not None and not pause_for_edit and unique_id: + if effective_text_input is not None and not pause_for_edit and unique_id: from server import PromptServer PromptServer.instance.send_sync("rs.prompt.update", { "node_id": unique_id, "prompt": current_text }) - if pause_for_edit and text_input is not None and current_text and unique_id: + if pause_for_edit and effective_text_input is not None and effective_text_input and unique_id: print(f"[RS Prompts 🦊] Pause mode enabled for node {unique_id}") PENDING_PROMPTS[unique_id] = { diff --git a/package.json b/package.json index 1d2d0a0..a850ab9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ComfyUI_RaykoStudio", - "version": "0.17.4", + "version": "0.17.5", "description": "Set of custom nodes for ComfyUI providing additional image processing capabilities", "author": "Raykosan", "license": "MIT", diff --git a/pyproject.toml b/pyproject.toml index 167db36..6b2398c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "ComfyUI_RaykoStudio" description = "Set of custom nodes for ComfyUI providing additional image processing capabilities" -version = "0.17.4" +version = "0.17.5" license = { file = "LICENSE" } dependencies = ["torch>=1.7.0", "numpy>=1.19.0", "Pillow>=8.0.0", "freetype-py>=2.5.1"] diff --git a/web/rs_prompts.js b/web/rs_prompts.js index f403d49..022463f 100644 --- a/web/rs_prompts.js +++ b/web/rs_prompts.js @@ -33,7 +33,7 @@ styleBlock.innerHTML = ` display: inline-flex; align-items: center; cursor: pointer; - gap: 8px; + gap: 6px; } .rs-toggle-switch input { opacity: 0; @@ -44,18 +44,18 @@ styleBlock.innerHTML = ` .rs-toggle-slider { position: relative; display: inline-block; - width: 40px; - height: 20px; + width: 36px; + height: 18px; background-color: #444; - border-radius: 20px; + border-radius: 18px; transition: 0.3s; cursor: pointer; } .rs-toggle-slider:before { position: absolute; content: ""; - height: 16px; - width: 16px; + height: 14px; + width: 14px; left: 2px; bottom: 2px; background-color: white; @@ -66,7 +66,7 @@ styleBlock.innerHTML = ` background-color: #28a745; } input:checked + .rs-toggle-slider:before { - transform: translateX(20px); + transform: translateX(18px); } .rs-toggle-label { font-size: 11px; @@ -108,11 +108,16 @@ app.registerExtension({ const textWidget = node.widgets?.find(w => w.name === "text"); const pauseWidget = node.widgets?.find(w => w.name === "pause_for_edit"); + const disableWidget = node.widgets?.find(w => w.name === "disable_text_input"); if (pauseWidget) { pauseWidget.hidden = true; } + if (disableWidget) { + disableWidget.hidden = true; + } + if (textWidget) textWidget.hidden = true; const enableWidgets = () => { @@ -127,6 +132,14 @@ app.registerExtension({ node.onConnectionsChange = function(slotType, slotIndex, isConnected, link, linkInfo) { if (origOnConnectionsChange) origOnConnectionsChange.apply(this, arguments); setTimeout(enableWidgets, 50); + setTimeout(() => updateStatusIndicator(), 10); + setTimeout(() => { + if (pauseModeEnabled && !canPauseBeActive()) { + pauseModeEnabled = false; + if (pauseWidget) pauseWidget.value = false; + updateUIForPauseMode(false); + } + }, 10); }; let waitingOverlay = null; @@ -158,7 +171,20 @@ app.registerExtension({ const root = mkEl("div", "display:flex;flex-direction:column;height:100%;padding:0;margin:0;box-sizing:border-box;overflow:hidden;position:relative;"); - const controlBar = mkEl("div", "display:flex;align-items:center;justify-content:space-between;padding:6px 8px;background:#1a1a1a;border-bottom:1px solid #333;gap:8px;"); + const disableRow = mkEl("div", "display:flex;align-items:center;justify-content:flex-start;padding:4px 6px 2px 6px;background:#1a1a1a;"); + const disableToggleContainer = mkEl("label", "rs-toggle-switch"); + const disableToggleInput = document.createElement("input"); + disableToggleInput.type = "checkbox"; + const disableToggleSlider = mkEl("span", "rs-toggle-slider"); + const disableToggleLabel = mkEl("span", "rs-toggle-label"); + disableToggleLabel.textContent = "πŸ”˜ Disable text input"; + + disableToggleContainer.appendChild(disableToggleInput); + disableToggleContainer.appendChild(disableToggleSlider); + disableToggleContainer.appendChild(disableToggleLabel); + disableRow.appendChild(disableToggleContainer); + + const pauseRow = mkEl("div", "display:flex;align-items:center;justify-content:space-between;padding:2px 6px 4px 6px;background:#1a1a1a;border-bottom:1px solid #333;gap:4px;"); const toggleContainer = mkEl("label", "rs-toggle-switch"); const toggleInput = document.createElement("input"); @@ -171,12 +197,14 @@ app.registerExtension({ toggleContainer.appendChild(toggleSlider); toggleContainer.appendChild(toggleLabel); - const statusIndicator = mkEl("div", "font-size:10px;padding:2px 6px;border-radius:4px;background:#2a2a2a;color:#888;"); - statusIndicator.textContent = "⚑ Normal mode"; + const statusIndicator = mkEl("div", "font-size:10px;padding:2px 6px;border-radius:4px;background:#2a2a2a;color:#ccc;"); + statusIndicator.textContent = "πŸ“ Local prompt"; - controlBar.appendChild(toggleContainer); - controlBar.appendChild(statusIndicator); - root.appendChild(controlBar); + pauseRow.appendChild(toggleContainer); + pauseRow.appendChild(statusIndicator); + + root.appendChild(disableRow); + root.appendChild(pauseRow); const customTextarea = document.createElement("textarea"); customTextarea.className = "rs-custom-textarea"; @@ -258,6 +286,37 @@ app.registerExtension({ if (size[1] < 350) size[1] = 350; }; + const hasTextInputConnection = () => { + return node.inputs?.some(i => i.name === "text_input" && i.link !== null) || false; + }; + + const canPauseBeActive = () => { + const hasConnection = hasTextInputConnection(); + const isDisabled = disableToggleInput.checked; + return hasConnection && !isDisabled; + }; + + const updateStatusIndicator = () => { + if (pauseModeEnabled) { + statusIndicator.innerHTML = `⏸️ WAITING FOR EDIT`; + statusIndicator.style.background = "#1a3a1a"; + return; + } + + const hasConnection = hasTextInputConnection(); + const isDisabled = disableToggleInput.checked; + + if (!hasConnection) { + statusIndicator.innerHTML = `πŸ“ Local prompt`; + } else if (hasConnection && !isDisabled) { + statusIndicator.innerHTML = `πŸ”Œ External input`; + } else if (hasConnection && isDisabled) { + statusIndicator.innerHTML = `πŸ“ Local prompt`; + } + + statusIndicator.style.background = "#2a2a2a"; + }; + const updateUIForPauseMode = (isPaused) => { if (isPaused) { clearBtn.disabled = true; @@ -278,8 +337,8 @@ app.registerExtension({ rejectEditBtn.style.cursor = "pointer"; customTextarea.style.border = "2px solid #28a745"; - statusIndicator.innerHTML = "⏸️ WAITING FOR EDIT"; - statusIndicator.style.background = "#1a3a1a"; + + updateStatusIndicator(); showWaitingOverlay(); } else { @@ -301,25 +360,57 @@ app.registerExtension({ rejectEditBtn.style.cursor = "not-allowed"; customTextarea.style.border = "1px solid #444"; - statusIndicator.innerHTML = "⚑ Active"; - statusIndicator.style.background = "#2a2a2a"; + + updateStatusIndicator(); + removeWaitingOverlay(); } }; + if (disableWidget) { + disableToggleInput.checked = disableWidget.value; + + if (disableToggleInput.checked) { + disableToggleLabel.textContent = "πŸ”΄ Disable text input"; + } else { + disableToggleLabel.textContent = "πŸ”˜ Disable text input"; + } + + updateStatusIndicator(); + + disableToggleInput.addEventListener("change", (e) => { + disableWidget.value = e.target.checked; + if (disableWidget.callback) disableWidget.callback(e.target.checked); + + if (e.target.checked) { + disableToggleLabel.textContent = "πŸ”΄ Disable text input"; + } else { + disableToggleLabel.textContent = "πŸ”˜ Disable text input"; + } + + if (pauseModeEnabled && !canPauseBeActive()) { + pauseModeEnabled = false; + if (pauseWidget) pauseWidget.value = false; + toggleInput.checked = false; + updateUIForPauseMode(false); + } + + updateStatusIndicator(); + + node.graph?.setDirtyCanvas(true, true); + }); + } + + if (pauseWidget) { + toggleInput.checked = pauseWidget.value; + } + toggleInput.addEventListener("change", (e) => { - pauseModeEnabled = e.target.checked; if (pauseWidget) { pauseWidget.value = e.target.checked; if (pauseWidget.callback) pauseWidget.callback(e.target.checked); } - if (pauseModeEnabled) { - statusIndicator.innerHTML = "πŸ”˜ Pause ON"; - statusIndicator.style.background = "#3a2a1a"; - } else { - statusIndicator.innerHTML = "⚑ Active"; - statusIndicator.style.background = "#2a2a2a"; - } + node.graph?.setDirtyCanvas(true, true); }); acceptEditBtn.addEventListener("click", async () => { @@ -332,6 +423,7 @@ app.registerExtension({ prompt: currentPrompt }) }); + pauseModeEnabled = false; updateUIForPauseMode(false); node.graph?.setDirtyCanvas(true, true); }); @@ -344,6 +436,7 @@ app.registerExtension({ node_id: node.id.toString() }) }); + pauseModeEnabled = false; updateUIForPauseMode(false); node.graph?.setDirtyCanvas(true, true); }); @@ -454,7 +547,12 @@ app.registerExtension({ if (event.detail.node_id == node.id) { customTextarea.value = event.detail.prompt; if (textWidget) textWidget.value = event.detail.prompt; - updateUIForPauseMode(true); + if (canPauseBeActive()) { + pauseModeEnabled = true; + toggleInput.checked = true; + if (pauseWidget) pauseWidget.value = true; + updateUIForPauseMode(true); + } node.graph?.setDirtyCanvas(true, true); } }); @@ -471,14 +569,6 @@ app.registerExtension({ updateUIForPauseMode(false); - if (pauseWidget && pauseWidget.value !== undefined) { - toggleInput.checked = pauseWidget.value; - if (pauseWidget.value) { - statusIndicator.innerHTML = "πŸ”˜ Pause ON"; - statusIndicator.style.background = "#3a2a1a"; - } - } - return result; }; }