diff --git a/README.md b/README.md index 842ba0d..67082b0 100644 --- a/README.md +++ b/README.md @@ -274,9 +274,20 @@ pipeKSampler input to generate xy plots using sampler and loader values. (Any va
advPlot range -adv_xyPlot input to generate plot syntax across a rang of values. +adv_xyPlot input to generate plot syntax across a range of values.
+
+ advPlot string + +adv_xyPlot input to generate plot syntax for strings via a delimiter. +
+ +
+ advPlot combo + +adv_xyPlot input to generate plot syntax for combos with various modes. +
## ttN/image diff --git a/js/ttNdynamicWidgets.js b/js/ttNdynamicWidgets.js index bb68586..394ccba 100644 --- a/js/ttNdynamicWidgets.js +++ b/js/ttNdynamicWidgets.js @@ -310,19 +310,38 @@ function widgetLogic(node, widget) { break; case 'mode': - let number_to_show2 = findWidgetByName(node, 'num_loras')?.value + 1 - for (let i = 0; i < number_to_show2; i++) { - if (widget.value === "simple") { - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_strength'), true) - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_model_strength')) - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_clip_strength')) - } else { - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_strength')) - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_model_strength'), true) - toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_clip_strength'), true)} - } - updateNodeHeight(node) - break; + if (node.type === "ttN pipeLoraStack") { + let number_to_show2 = findWidgetByName(node, 'num_loras')?.value + 1 + for (let i = 0; i < number_to_show2; i++) { + if (widget.value === "simple") { + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_strength'), true) + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_model_strength')) + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_clip_strength')) + } else { + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_strength')) + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_model_strength'), true) + toggleWidget(node, findWidgetByName(node, 'lora_'+i+'_clip_strength'), true)} + } + updateNodeHeight(node) + break; + } else if (node.type === "ttN advPlot combo") { + if (widget.value === 'all') { + toggleWidget(node, findWidgetByName(node, 'start_from')) + toggleWidget(node, findWidgetByName(node, 'end_with')) + toggleWidget(node, findWidgetByName(node, 'select')) + toggleWidget(node, findWidgetByName(node, 'selection')) + } else if (widget.value === 'range') { + toggleWidget(node, findWidgetByName(node, 'start_from'), true) + toggleWidget(node, findWidgetByName(node, 'end_with'), true) + toggleWidget(node, findWidgetByName(node, 'select')) + toggleWidget(node, findWidgetByName(node, 'selection')) + } else { + toggleWidget(node, findWidgetByName(node, 'start_from')) + toggleWidget(node, findWidgetByName(node, 'end_with')) + toggleWidget(node, findWidgetByName(node, 'select'), true) + toggleWidget(node, findWidgetByName(node, 'selection'), true) + } + } case 'empty_latent_aspect': if (widget.value !== 'width x height [custom]') { @@ -475,7 +494,8 @@ const getSetTitles = [ "tinyKSampler", "debugInput", "tinyLoader", - "advPlot range" + "advPlot range", + "advPlot combo", ]; function getSetters(node) { diff --git a/js/ttNwidgets.js b/js/ttNwidgets.js index 1e0bff0..1fdeaab 100644 --- a/js/ttNwidgets.js +++ b/js/ttNwidgets.js @@ -144,7 +144,7 @@ app.registerExtension({ overwriteSeedControl(nodeType) } } - if (["ttN textDebug", "ttN advPlot range", "ttN advPlot string", "ttN debugInput"].includes(nodeData.name)) { + if (["ttN textDebug", "ttN advPlot range", "ttN advPlot string", "ttN advPlot combo", "ttN debugInput"].includes(nodeData.name)) { addTextDisplay(nodeType) } if (nodeData.name.startsWith("ttN textCycle")) { diff --git a/js/ttNxyPlotAdv.js b/js/ttNxyPlotAdv.js index ef2aa21..3ecf6ab 100644 --- a/js/ttNxyPlotAdv.js +++ b/js/ttNxyPlotAdv.js @@ -320,30 +320,32 @@ function setPlotWidgetOptions(currentNode, searchType) { } } } - const int_widgets = [ - 'seed', - 'clip_skip', - 'steps', - 'start_at_step', - 'end_at_step', - 'empty_latent_width', - 'empty_latent_height', - 'noise_seed', - ] - const float_widgets = [ - 'cfg', - 'denoise', - 'strength_model', - 'strength_clip', - 'strength', - 'scale_by', - 'lora_strength' - ] + const widgetWidget = currentNode.widgets.find(w => w.name === 'widget'); const widgetWidgetValue = widgetWidget.value; if (searchType.includes('number')) { + const int_widgets = [ + 'seed', + 'clip_skip', + 'steps', + 'start_at_step', + 'end_at_step', + 'empty_latent_width', + 'empty_latent_height', + 'noise_seed', + ] + const float_widgets = [ + 'cfg', + 'denoise', + 'strength_model', + 'strength_clip', + 'strength', + 'scale_by', + 'lora_strength' + ] + const rangeModeWidget = currentNode.widgets.find(w => w.name === 'range_mode'); const rangeModeWidgetValue = rangeModeWidget.value; @@ -368,34 +370,71 @@ function setPlotWidgetOptions(currentNode, searchType) { rangeModeWidget.options.values = ['step_int', 'num_steps_int', 'step_float', 'num_steps_float'] } } + if (searchType.includes('combo')) { + const optionsWidget = optionNode.widgets.find(w => w.name === widgetWidgetValue) + if (optionsWidget) { + const values = optionsWidget.options.values + currentNode.widgets.find(w => w.name === 'start_from').options.values = values + currentNode.widgets.find(w => w.name === 'end_with').options.values = values + currentNode.widgets.find(w => w.name === 'select').options.values = values + } + } } const getSetWidgets = [ "node", "widget", + "start_from", + "end_with", ] function getSetters(node, searchType) { if (node.widgets) { - for (const w of node.widgets) { - if (getSetWidgets.includes(w.name)) { - setPlotWidgetOptions(node, searchType); - let widgetValue = w.value; + const gswidgets = node.widgets.filter(function(widget) { + return getSetWidgets.includes(widget.name); + }); + for (const w of gswidgets) { + setPlotWidgetOptions(node, searchType); + let widgetValue = w.value; - // Define getters and setters for widget values - Object.defineProperty(w, 'value', { - get() { - return widgetValue; - }, - set(newVal) { - if (newVal !== widgetValue) { - widgetValue = newVal; - setPlotWidgetOptions(node, searchType); - } - } - }); - } - } + // Define getters and setters for widget values + Object.defineProperty(w, 'value', { + get() { + return widgetValue; + }, + set(newVal) { + if (newVal !== widgetValue) { + widgetValue = newVal; + setPlotWidgetOptions(node, searchType); + } + } + }); + } + + const selectWidget = node.widgets.find(w => w.name === 'select') + if (selectWidget) { + console.log('here'); + let widgetValue = selectWidget.value; + let selectedWidget = node.widgets.find(w => w.name === 'selection'); + let selectedValue = selectedWidget.inputEl.value; + console.log(selectedValue); + + Object.defineProperty(selectWidget, 'value', { + get() { + return widgetValue; + }, + set(newVal) { + if (newVal !== widgetValue) { + widgetValue = newVal; + if (selectedWidget.inputEl.value.trim() === '') { + selectedWidget.inputEl.value = newVal; + } else { + selectedWidget.inputEl.value += "\n" + newVal; + } + } + } + }) + } } let mouseOver = node.mouseOver; Object.defineProperty(node, 'mouseOver', { @@ -448,5 +487,8 @@ app.registerExtension({ if (node_title === "advPlot string") { getSetters(node, ['text', 'customtext']); } + if (node_title === "advPlot combo") { + getSetters(node, ['combo',]); + } }, }); \ No newline at end of file diff --git a/ttNpy/tinyterraNodes.py b/ttNpy/tinyterraNodes.py index 0d2922f..20fa233 100644 --- a/ttNpy/tinyterraNodes.py +++ b/ttNpy/tinyterraNodes.py @@ -30,6 +30,7 @@ import hashlib from PIL import Image, ImageDraw, ImageFont from PIL.PngImagePlugin import PngInfo +import nodes import comfy.sd import execution import comfy.utils @@ -2734,6 +2735,84 @@ class ttN_advPlot_string: out = '\n'.join(plot_text) + return {"ui": {"text": out}, "result": (out,)} + +class ttN_advPlot_combo: + version = '1.0.0' + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "node": ([AnyType("Connect to xyPlot for options"),],{}), + "widget": ([AnyType("Select node for options"),],{}), + + "mode": (['all', 'range', 'select'],), + "start_from": ([AnyType("Select widget for options"),],), + "end_with": ([AnyType("Select widget for options"),],), + + "select": ([AnyType("Select widget for options"),],), + "selection": ("STRING", {"default":"","multiline": True}), + + "label_type": (['Values', 'Title and Values', 'ID, Title and Values'],{"default": "Values"}), + }, + "hidden": { + "ttNnodeVersion": ttN_advPlot_range.version, "prompt": "PROMPT", + } + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("plot_text",) + FUNCTION = "plot" + OUTPUT_NODE = True + + CATEGORY = "🌏 tinyterra/xyPlot" + + def plot(self, node, widget, mode, start_from, end_with, select, selection, label_type, prompt=None): + if '[' in node and ']' in node: + nodeid = node.split('[', 1)[1].split(']', 1)[0] + else: + return {"ui": {"text": ''}, "result": ('',)} + + label_map = { + 'Values': 'v_label', + 'Title and Values': 'tv_label', + 'ID, Title and Values': 'idtv_label', + } + label = label_map[label_type] + + plot_text = [] + + class_type = prompt[nodeid]['class_type'] + class_def = nodes.NODE_CLASS_MAPPINGS[class_type] + valid_inputs = class_def.INPUT_TYPES() + options = valid_inputs["required"][widget][0] or valid_inputs["optional"][widget][0] + + vals = [] + if mode == 'all': + vals = options + elif mode == 'range': + start_index = options.index(start_from) + stop_index = options.index(end_with) + 1 + if start_index > stop_index: + start_index, stop_index = stop_index, start_index + vals = options[start_index:stop_index] + elif mode == 'select': + selection = selection.split('\n') + for s in selection: + s.strip() + if s in options: + vals.append(s) + + for i, val in enumerate(vals): + line = f"[{nodeid}:{widget}='{val}']" + plot_text.append(f"<{i+1}:{label}>") + plot_text.append(line) + + out = '\n'.join(plot_text) + return {"ui": {"text": out}, "result": (out,)} #--------------------------------------------------------------ttN/xyPlot END-----------------------------------------------------------------------# @@ -3435,6 +3514,7 @@ TTN_VERSIONS = { # "advPlot merge": ttN_advPlot_merge.version, "advPlot range": ttN_advPlot_range.version, "advPlot string": ttN_advPlot_string.version, + "advPlot combo": ttN_advPlot_combo.version, "pipeEncodeConcat": ttN_pipeEncodeConcat.version, "multiLoraStack": ttN_pipeLoraStack.version, "multiModelMerge": ttN_multiModelMerge.version, @@ -3468,6 +3548,7 @@ NODE_CLASS_MAPPINGS = { # "ttN advPlot merge": ttN_advPlot_merge, "ttN advPlot range": ttN_advPlot_range, "ttN advPlot string": ttN_advPlot_string, + "ttN advPlot combo": ttN_advPlot_combo, "ttN pipeEDIT": ttN_pipe_EDIT, "ttN pipe2BASIC": ttN_pipe_2BASIC, "ttN pipe2DETAILER": ttN_pipe_2DETAILER, @@ -3518,6 +3599,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { # "ttN advPlot merge": "advPlot merge", "ttN advPlot range": "advPlot range", "ttN advPlot string": "advPlot string", + "ttN advPlot combo": "advPlot combo", #ttN/misc "ttN multiModelMerge": "multiModelMerge",