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",