Dynamically create context menu sub-folders based on folder structure of nodes.

This commit is contained in:
2025-02-24 18:33:04 -07:00
parent 76cb82acd9
commit dc33aca6a0
11 changed files with 82 additions and 79 deletions

View File

@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""
Standardized Comparison Node:
- Compares two input values using a selected operator (==, !=, >, <, >=, <=).
- Outputs a result of 1 (True) or 0 (False).
- Uses a global update timer for processing.
- Supports an additional 'Input Type' dropdown to choose between 'Number' and 'String'.
"""
from OdenGraphQt import BaseNode
from Qt import QtCore
class ComparisonNode(BaseNode):
__identifier__ = 'bunny-lab.io.comparison_node'
NODE_NAME = 'Comparison Node'
def __init__(self):
super(ComparisonNode, self).__init__()
self.add_input('A')
self.add_input('B')
self.add_output('Result')
# Add the Input Type dropdown first.
self.add_combo_menu('input_type', 'Input Type', items=['Number', 'String'])
self.add_combo_menu('operator', 'Operator', items=[
'Equal (==)', 'Not Equal (!=)', 'Greater Than (>)',
'Less Than (<)', 'Greater Than or Equal (>=)', 'Less Than or Equal (<=)'
])
# Replace calc_result with a standardized "value" text input.
self.add_text_input('value', 'Value', text='0')
self.value = 0
self.set_name("Comparison Node")
self.processing = False # Guard for process_input
# Set default properties explicitly
self.set_property('input_type', 'Number')
self.set_property('operator', 'Equal (==)')
def process_input(self):
if self.processing:
return
self.processing = True
# Retrieve input values; if no connection or None, default to "0"
input_a = self.input(0)
input_b = self.input(1)
a_raw = (input_a.connected_ports()[0].node().get_property('value')
if input_a.connected_ports() else "0")
b_raw = (input_b.connected_ports()[0].node().get_property('value')
if input_b.connected_ports() else "0")
a_raw = a_raw if a_raw is not None else "0"
b_raw = b_raw if b_raw is not None else "0"
# Get input type property
input_type = self.get_property('input_type')
# Convert values based on input type
if input_type == 'Number':
try:
a_val = float(a_raw)
except (ValueError, TypeError):
a_val = 0.0
try:
b_val = float(b_raw)
except (ValueError, TypeError):
b_val = 0.0
elif input_type == 'String':
a_val = str(a_raw)
b_val = str(b_raw)
else:
try:
a_val = float(a_raw)
except (ValueError, TypeError):
a_val = 0.0
try:
b_val = float(b_raw)
except (ValueError, TypeError):
b_val = 0.0
operator = self.get_property('operator')
# Perform the comparison
result = {
'Equal (==)': a_val == b_val,
'Not Equal (!=)': a_val != b_val,
'Greater Than (>)': a_val > b_val,
'Less Than (<)': a_val < b_val,
'Greater Than or Equal (>=)': a_val >= b_val,
'Less Than or Equal (<=)': a_val <= b_val
}.get(operator, False)
new_value = 1 if result else 0
self.value = new_value
self.set_property('value', str(self.value))
self.transmit_data(self.value)
self.processing = False
def on_input_connected(self, input_port, output_port):
pass
def on_input_disconnected(self, input_port, output_port):
pass
def property_changed(self, property_name):
pass
def receive_data(self, data, source_port_name=None):
pass
def transmit_data(self, data):
output_port = self.output(0)
if output_port and output_port.connected_ports():
for connected_port in output_port.connected_ports():
connected_node = connected_port.node()
if hasattr(connected_node, 'receive_data'):
try:
data_int = int(data)
connected_node.receive_data(data_int, source_port_name='Result')
except ValueError:
pass

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""
Standardized Data Node:
- Accepts and transmits values consistently.
- Updates its value based on a global update timer.
"""
from OdenGraphQt import BaseNode
from Qt import QtCore
class DataNode(BaseNode):
__identifier__ = 'bunny-lab.io.data_node'
NODE_NAME = 'Data Node'
def __init__(self):
super(DataNode, self).__init__()
self.add_input('Input')
self.add_output('Output')
self.add_text_input('value', 'Value', text='')
self.process_widget_event()
self.set_name("Data Node")
# Removed self-contained update timer; global timer now drives updates.
def post_create(self):
text_widget = self.get_widget('value')
if text_widget is not None:
try:
# Removed textChanged signal connection; global timer will call process_input.
pass
except Exception as e:
print("Error connecting textChanged signal:", e)
def process_widget_event(self, event=None):
current_text = self.get_property('value')
self.value = current_text
self.transmit_data(current_text)
def property_changed(self, property_name):
if property_name == 'value':
# Immediate update removed; relying on global timer.
pass
def process_input(self):
input_port = self.input(0)
output_port = self.output(0)
if input_port.connected_ports():
input_value = input_port.connected_ports()[0].node().get_property('value')
self.set_property('value', input_value)
self.transmit_data(input_value)
elif output_port.connected_ports():
self.transmit_data(self.get_property('value'))
def on_input_connected(self, input_port, output_port):
# Removed immediate update; global timer handles updates.
pass
def on_input_disconnected(self, input_port, output_port):
# Removed immediate update; global timer handles updates.
pass
def receive_data(self, data, source_port_name=None):
self.set_property('value', str(data))
self.transmit_data(data)
def transmit_data(self, data):
output_port = self.output(0)
if output_port and output_port.connected_ports():
for connected_port in output_port.connected_ports():
connected_node = connected_port.node()
if hasattr(connected_node, 'receive_data'):
connected_node.receive_data(data, source_port_name="Output")

View File

@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""
Standardized Math Operation Node:
- Performs mathematical operations (+, -, *, /, avg) on two inputs.
- Outputs the computed result.
- Uses a global update timer for processing (defined in borealis.py).
- Ensures it always has a "value" property that the Comparison Node can read.
"""
from OdenGraphQt import BaseNode
from Qt import QtCore
class MathOperationNode(BaseNode):
__identifier__ = 'bunny-lab.io.math_node'
NODE_NAME = 'Math Operation'
def __init__(self):
super(MathOperationNode, self).__init__()
self.add_input('A')
self.add_input('B')
self.add_output('Result')
# Drop-down to choose which operation we do:
self.add_combo_menu('operator', 'Operator', items=[
'Add', 'Subtract', 'Multiply', 'Divide', 'Average'
])
# A text field for showing the result to the user:
self.add_text_input('calc_result', 'Result', text='0')
# IMPORTANT: define a "value" property that the Comparison Node can read
# We do not necessarily need a text input for it, but adding it ensures
# it becomes an official property recognized by OdenGraphQt.
self.add_text_input('value', 'Internal Value', text='0')
# Keep a Python-side float of the current computed result:
self.value = 0
# Give the node a nice name:
self.set_name("Math Operation")
# Removed self-contained timer; global timer calls process_input().
def process_input(self):
# Attempt to read "value" from both inputs:
input_a = self.input(0)
input_b = self.input(1)
a_raw = input_a.connected_ports()[0].node().get_property('value') if input_a.connected_ports() else "0"
b_raw = input_b.connected_ports()[0].node().get_property('value') if input_b.connected_ports() else "0"
try:
a_val = float(a_raw)
except (ValueError, TypeError):
a_val = 0.0
try:
b_val = float(b_raw)
except (ValueError, TypeError):
b_val = 0.0
operator = self.get_property('operator')
if operator == 'Add':
result = a_val + b_val
elif operator == 'Subtract':
result = a_val - b_val
elif operator == 'Multiply':
result = a_val * b_val
elif operator == 'Divide':
result = a_val / b_val if b_val != 0 else 0.0
elif operator == 'Average':
result = (a_val + b_val) / 2.0
else:
result = 0.0
# If the computed result changed, update our internal properties and transmit
if self.value != result:
self.value = result
# Update the two text fields so the user sees the numeric result:
self.set_property('calc_result', str(result))
self.set_property('value', str(result)) # <= This is the critical step
# Let downstream nodes know there's new data:
self.transmit_data(result)
def on_input_connected(self, input_port, output_port):
pass
def on_input_disconnected(self, input_port, output_port):
pass
def property_changed(self, property_name):
pass
def receive_data(self, data, source_port_name=None):
pass
def transmit_data(self, data):
output_port = self.output(0)
if output_port and output_port.connected_ports():
for connected_port in output_port.connected_ports():
connected_node = connected_port.node()
if hasattr(connected_node, 'receive_data'):
try:
# Attempt to convert to int if possible, else float
data_int = int(data)
connected_node.receive_data(data_int, source_port_name='Result')
except ValueError:
connected_node.receive_data(data, source_port_name='Result')