diff --git a/Rayko_Load_Images_From_Dir.py b/Rayko_Load_Images_From_Dir.py index 533c4dd..60c9f58 100644 --- a/Rayko_Load_Images_From_Dir.py +++ b/Rayko_Load_Images_From_Dir.py @@ -15,6 +15,7 @@ import os import glob +import json import torch import numpy as np import folder_paths @@ -27,6 +28,7 @@ class RSLoadImagesFromDir: def INPUT_TYPES(cls) -> Dict[str, Dict[str, Any]]: return { "required": { + "node_data": ("STRING", {"default": "{}", "hidden": True}), "folder_path": ("STRING", {"default": "", "multiline": False}), "filter_type": (["*.*", "*.png", "*.jpg", "*.jpeg", "*.webp", "*.bmp", "*.gif", "custom"], {"default": "*.png"}), "start_index": ("INT", {"default": 1, "min": 1, "max": 999999, "step": 1}), @@ -46,12 +48,24 @@ class RSLoadImagesFromDir: def load_images( self, - folder_path: str, - filter_type: str, - start_index: int, - end_index: int, + node_data: str = "{}", + folder_path: str = "", + filter_type: str = "*.png", + start_index: int = 1, + end_index: int = 1, custom_filter: str = "*.png" ): + try: + data = json.loads(node_data) if node_data else {} + if data: + folder_path = data.get("folder_path", folder_path) + filter_type = data.get("filter_type", filter_type) + start_index = data.get("start_index", start_index) + end_index = data.get("end_index", end_index) + custom_filter = data.get("custom_filter", custom_filter) + except Exception: + pass + if not folder_path or not os.path.isdir(folder_path): raise ValueError(f"Invalid folder path: {folder_path}") diff --git a/web/rs_load_images_dir.js b/web/rs_load_images_dir.js index b905f85..099b393 100644 --- a/web/rs_load_images_dir.js +++ b/web/rs_load_images_dir.js @@ -30,44 +30,52 @@ app.registerExtension({ node.setSize([NODE_WIDTH, MIN_HEIGHT_NORMAL]); node.min_size = [NODE_WIDTH, MIN_HEIGHT_NORMAL]; + const wNodeData = node.widgets?.find(w => w.name === "node_data"); const wPath = node.widgets?.find(w => w.name === "folder_path"); const wFilter = node.widgets?.find(w => w.name === "filter_type"); const wStart = node.widgets?.find(w => w.name === "start_index"); const wEnd = node.widgets?.find(w => w.name === "end_index"); const wCustom = node.widgets?.find(w => w.name === "custom_filter"); - [wPath, wFilter, wStart, wEnd, wCustom].forEach(w => { + [wNodeData, wPath, wFilter, wStart, wEnd, wCustom].forEach(w => { if (w) { w.hidden = true; if (w.element) w.element.style.display = "none"; } }); - if (wPath) wPath.serializeValue = () => node.data.folder_path; - if (wFilter) wFilter.serializeValue = () => node.data.filter_type; - if (wStart) wStart.serializeValue = () => parseInt(node.data.start_index); - if (wEnd) wEnd.serializeValue = () => parseInt(node.data.end_index); - if (wCustom) wCustom.serializeValue = () => node.data.custom_filter; - - if (wPath?.value) node.data.folder_path = wPath.value; - if (wFilter?.value) node.data.filter_type = wFilter.value; - if (wStart?.value) node.data.start_index = parseInt(wStart.value); - if (wEnd?.value) node.data.end_index = parseInt(wEnd.value); - if (wCustom?.value) node.data.custom_filter = wCustom.value; + if (wNodeData) { + try { + const savedData = JSON.parse(wNodeData.value || "{}"); + if (savedData && typeof savedData === 'object') { + node.data = { ...node.data, ...savedData }; + } + } catch (e) {} + + wNodeData.serializeValue = () => { + node.syncData(); + return JSON.stringify(node.data); + }; + } node.uiElements = []; node.dropdownMenu = null; node.customModal = null; - const syncData = () => { + node.syncData = function() { if (wPath) wPath.value = node.data.folder_path; if (wFilter) wFilter.value = node.data.filter_type; if (wStart) wStart.value = parseInt(node.data.start_index); if (wEnd) wEnd.value = parseInt(node.data.end_index); if (wCustom) wCustom.value = node.data.custom_filter; - if (node.graph) node.graph.changeTracker?.dispatchEvent(new Event("change")); - node.setDirtyCanvas(true, true); + if (wNodeData) { + wNodeData.value = JSON.stringify(node.data); + } + + if (node.graph) { + node.graph.changeTracker?.dispatchEvent(new Event("change")); + } }; const updateNodeSize = () => { @@ -91,6 +99,21 @@ app.registerExtension({ this.setDirtyCanvas(true, true); }; + const onConfigure = node.onConfigure; + node.onConfigure = function(o) { + if (onConfigure) onConfigure.apply(this, arguments); + if (wNodeData && wNodeData.value) { + try { + const restoredData = JSON.parse(wNodeData.value); + if (restoredData) { + node.data = { ...node.data, ...restoredData }; + node.syncData(); + updateNodeSize(); + } + } catch (e) {} + } + }; + const closeDropdown = (e) => { if (node.dropdownMenu && !node.dropdownMenu.contains(e.target)) { node.dropdownMenu.remove(); @@ -155,11 +178,9 @@ app.registerExtension({ user-select: none; -moz-user-select: none; display: inline-flex; align-items: center; justify-content: center; `; - btnPaste.onmousedown = (e) => e.preventDefault(); btnPaste.onmouseup = (e) => e.preventDefault(); btnPaste.oncontextmenu = (e) => e.preventDefault(); - btnPaste.onmouseover = () => { if (!btnPaste.disabled) btnPaste.style.background = "#3a3a3a"; }; btnPaste.onmouseout = () => { if (!btnPaste.disabled) btnPaste.style.background = "#2a2a2a"; }; @@ -182,7 +203,6 @@ app.registerExtension({ btnPaste.style.color = "#4CAF50"; } } catch (err) { - console.log("Clipboard read blocked by browser:", err); btnPaste.textContent = "⌨️ Ctrl+V"; btnPaste.style.borderColor = "#FF9800"; btnPaste.style.color = "#FF9800"; @@ -265,18 +285,14 @@ app.registerExtension({ const truncatePath = (ctx, path, maxWidth) => { if (!path) return "Folder not selected"; - const ellipsis = "..."; - if (ctx.measureText(path).width <= maxWidth) { return path; } - let truncated = path; while (truncated.length > 0 && ctx.measureText(ellipsis + truncated).width > maxWidth) { truncated = truncated.substring(1); } - return ellipsis + truncated; }; @@ -310,27 +326,21 @@ app.registerExtension({ const padding = 10; const rowHeight = 23; const borderRadius = 3; - let currentY = 35 + 60; ctx.font = "12px sans-serif"; ctx.textBaseline = "middle"; const pathDisplayHeight = 20; - const pathDisplayY = currentY; - ctx.fillStyle = "#1a1a1a"; ctx.strokeStyle = "#333"; - drawRoundedRect(ctx, padding, pathDisplayY, w - padding * 2, pathDisplayHeight, borderRadius); + drawRoundedRect(ctx, padding, currentY, w - padding * 2, pathDisplayHeight, borderRadius); const pathText = node.data.folder_path || "Folder not selected"; - const maxTextWidth = w - padding * 2 - 10; - const displayPath = truncatePath(ctx, pathText, maxTextWidth); - + const displayPath = truncatePath(ctx, pathText, w - padding * 2 - 10); ctx.fillStyle = node.data.folder_path ? "#aaa" : "#666"; ctx.textAlign = "left"; - ctx.fillText(displayPath, padding + 5, pathDisplayY + pathDisplayHeight / 2); - + ctx.fillText(displayPath, padding + 5, currentY + pathDisplayHeight / 2); currentY += pathDisplayHeight + 7; ctx.fillStyle = "#2a2a2a"; @@ -339,7 +349,6 @@ app.registerExtension({ ctx.fillStyle = "#2196F3"; ctx.textAlign = "center"; ctx.fillText("📁 Select folder", w / 2, currentY + rowHeight / 2); - this.uiElements.push({ type: "btn_folder", x: padding, y: currentY, w: w - padding * 2, h: rowHeight }); currentY += rowHeight + 7; @@ -350,7 +359,6 @@ app.registerExtension({ ctx.fillStyle = "#4CAF50"; ctx.textAlign = "center"; ctx.fillText(filterLabel, w / 2, currentY + rowHeight / 2); - this.uiElements.push({ type: "btn_filter", x: padding, y: currentY, w: w - padding * 2, h: rowHeight }); currentY += rowHeight + 7; @@ -427,16 +435,12 @@ app.registerExtension({ for (const el of this.uiElements) { if (x >= el.x && x <= el.x + el.w && y >= el.y && y <= el.y + el.h) { if (el.type === "btn_folder") { - showCustomPrompt( - "Enter folder path", - this.data.folder_path, - (result) => { - if (result !== null) { - this.data.folder_path = result.trim(); - syncData(); - } + showCustomPrompt("Enter folder path", this.data.folder_path, (result) => { + if (result !== null) { + this.data.folder_path = result.trim(); + node.syncData(); } - ); + }); return true; } @@ -463,7 +467,7 @@ app.registerExtension({ item.onclick = (e) => { e.stopPropagation(); this.data.filter_type = f; - syncData(); + node.syncData(); updateNodeSize(); menu.remove(); this.dropdownMenu = null; @@ -487,63 +491,51 @@ app.registerExtension({ if (el.type === "btn_start_minus") { this.data.start_index = Math.max(1, parseInt(this.data.start_index) - 1); - syncData(); + node.syncData(); return true; } if (el.type === "btn_start_plus") { this.data.start_index = parseInt(this.data.start_index) + 1; - syncData(); + node.syncData(); return true; } if (el.type === "val_start") { - showCustomPrompt( - "Start index (min 1)", - String(this.data.start_index), - (result) => { - if (result !== null) { - this.data.start_index = Math.max(1, parseInt(result) || 1); - syncData(); - } + showCustomPrompt("Start index (min 1)", String(this.data.start_index), (result) => { + if (result !== null) { + this.data.start_index = Math.max(1, parseInt(result) || 1); + node.syncData(); } - ); + }); return true; } if (el.type === "btn_end_minus") { this.data.end_index = Math.max(1, parseInt(this.data.end_index) - 1); - syncData(); + node.syncData(); return true; } if (el.type === "btn_end_plus") { this.data.end_index = parseInt(this.data.end_index) + 1; - syncData(); + node.syncData(); return true; } if (el.type === "val_end") { - showCustomPrompt( - "End index", - String(this.data.end_index), - (result) => { - if (result !== null) { - this.data.end_index = Math.max(1, parseInt(result) || 1); - syncData(); - } + showCustomPrompt("End index", String(this.data.end_index), (result) => { + if (result !== null) { + this.data.end_index = Math.max(1, parseInt(result) || 1); + node.syncData(); } - ); + }); return true; } if (el.type === "val_custom") { - showCustomPrompt( - "Custom filter (e.g. *_mask.png)", - this.data.custom_filter, - (result) => { - if (result !== null) { - this.data.custom_filter = result.trim() || "*.png"; - syncData(); - } + showCustomPrompt("Custom filter (e.g. *_mask.png)", this.data.custom_filter, (result) => { + if (result !== null) { + this.data.custom_filter = result.trim() || "*.png"; + node.syncData(); } - ); + }); return true; } } @@ -565,7 +557,7 @@ app.registerExtension({ if (originalOnRemoved) originalOnRemoved.apply(this, arguments); }; - syncData(); + node.syncData(); updateNodeSize(); return result;