None of the nodes showed description text in ComfyUI because ComfyUI reads obj_class.DESCRIPTION when it builds node_info - it does not read the class docstring, which is what these nodes had. Every registered node now carries a one-line DESCRIPTION, kept to 29-67 characters so it fits the limited space in ComfyUI Manager and the node search results. Image Transform Pro's four-sentence description is shortened to match. Descriptions are derived from each node's existing docstring, or from the README for the five classes that had no docstring (ImageBlendPro, ColorMatchBlend and the three Boolean switch nodes). README also updated for the recent changes: the New Nodes table now lists the real "Rotate & Scale" category, the XY placement direction is documented on both nodes (positive X right, positive Y up), and the v2.2.0 changelog records the placement convention, the node outputs and the MP_ImageTransform internal name.
110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
import random
|
|
import time
|
|
|
|
class DynamicValueRange:
|
|
"""
|
|
Automatically cycles through a range of values on each run.
|
|
Use to create diversity in settings across multiple generations.
|
|
"""
|
|
|
|
DESCRIPTION = "Step through a range of values, one per run."
|
|
|
|
# Class variable to track current values per node instance
|
|
_state = {}
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"min_value": ("FLOAT", {"default": 0.0, "min": -10000.0, "max": 10000.0, "step": 0.1}),
|
|
"max_value": ("FLOAT", {"default": 1.0, "min": -10000.0, "max": 10000.0, "step": 0.1}),
|
|
"step": ("FLOAT", {"default": 0.1, "min": 0.001, "max": 1000.0, "step": 0.01}),
|
|
"mode": (["increment", "decrement", "random"], {"default": "increment"}),
|
|
"on_cycle_complete": (["reverse", "jump"], {"default": "reverse"}),
|
|
"output_int": ("BOOLEAN", {"default": False}),
|
|
},
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID",
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ("FLOAT", "INT", "STRING")
|
|
RETURN_NAMES = ("value", "value_int", "value_str")
|
|
FUNCTION = "get_value"
|
|
CATEGORY = "MachinePaintingNodes/Util"
|
|
|
|
@classmethod
|
|
def IS_CHANGED(cls, **kwargs):
|
|
# Always return a different value to force re-execution
|
|
return float("nan")
|
|
|
|
def get_value(self, min_value, max_value, step, mode, on_cycle_complete, output_int, unique_id=None):
|
|
# Use unique_id to track state per node instance
|
|
node_id = str(unique_id) if unique_id else "default"
|
|
|
|
# Initialize state if not exists
|
|
if node_id not in DynamicValueRange._state:
|
|
DynamicValueRange._state[node_id] = {
|
|
"current": min_value,
|
|
"direction": 1, # 1 = forward, -1 = backward
|
|
}
|
|
|
|
state = DynamicValueRange._state[node_id]
|
|
|
|
# Handle random mode
|
|
if mode == "random":
|
|
# Calculate number of steps
|
|
num_steps = int((max_value - min_value) / step) + 1
|
|
random_step = random.randint(0, num_steps - 1)
|
|
value = min_value + (random_step * step)
|
|
value = min(max_value, max(min_value, value))
|
|
else:
|
|
# Get current value
|
|
value = state["current"]
|
|
|
|
# Ensure value is within range (in case settings changed)
|
|
value = min(max_value, max(min_value, value))
|
|
|
|
# Calculate next value for next run
|
|
if mode == "increment":
|
|
direction = state.get("direction", 1)
|
|
else: # decrement
|
|
direction = state.get("direction", -1)
|
|
if state.get("direction") is None or state.get("direction") == 1:
|
|
state["direction"] = -1
|
|
direction = -1
|
|
|
|
next_value = value + (step * direction)
|
|
|
|
# Check if we've hit the bounds
|
|
if next_value > max_value:
|
|
if on_cycle_complete == "reverse":
|
|
state["direction"] = -1
|
|
next_value = value - step
|
|
else: # jump
|
|
next_value = min_value
|
|
elif next_value < min_value:
|
|
if on_cycle_complete == "reverse":
|
|
state["direction"] = 1
|
|
next_value = value + step
|
|
else: # jump
|
|
next_value = max_value
|
|
|
|
# Clamp next value
|
|
next_value = min(max_value, max(min_value, next_value))
|
|
|
|
# Store for next run
|
|
state["current"] = next_value
|
|
|
|
# Round to avoid floating point errors
|
|
value = round(value, 6)
|
|
|
|
# Convert outputs
|
|
value_int = int(round(value))
|
|
value_str = str(value_int if output_int else value)
|
|
|
|
if output_int:
|
|
value = float(value_int)
|
|
|
|
return (value, value_int, value_str)
|