extends GraphNode @export var min_gap: float = 0.5 # editable value in inspector for the minimum gap between min and max var undo_redo: UndoRedo var button_states = {} signal open_help signal inlet_removed signal node_moved func _ready() -> void: var sliders := _get_all_hsliders(self) #finds all sliders #links sliders to this script for slider in sliders: slider.value_changed.connect(_on_slider_value_changed.bind(slider)) #link all buttons for undo redo get_all_buttons() #add button to title bar var titlebar = self.get_titlebar_hbox() #add randomise button if sliders.size() > 0: var rnd_btn = Button.new() rnd_btn.text = "!" rnd_btn.tooltip_text = "Randomise Slider Values" rnd_btn.connect("pressed", Callable(self, "_randomise_sliders")) #pass key (process name) when button is pressed titlebar.add_child(rnd_btn) #add help button var btn = Button.new() btn.text = "?" btn.tooltip_text = "Open help for " + self.title btn.connect("pressed", Callable(self, "_open_help")) #pass key (process name) when button is pressed titlebar.add_child(btn) await get_tree().process_frame #reset_size() self.position_offset_changed.connect(_on_position_offset_changed) if self.has_node("addremoveinlets"): var addremove = self.get_node("addremoveinlets") addremove.add_inlet.connect(add_inlet_to_node) addremove.remove_inlet.connect(remove_inlet_from_node) func _get_all_hsliders(node: Node) -> Array: #moves through all children recusively to find nested sliders var result: Array = [] for child in node.get_children(): if child is HSlider: result.append(child) elif child.has_method("get_children"): result += _get_all_hsliders(child) return result func get_all_buttons() -> void: for child in get_children(): if child is OptionButton: button_states[child] = child.selected child.item_selected.connect(button_changed.bind(child)) elif child is CheckButton: button_states[child] = child.button_pressed child.toggled.connect(button_changed.bind(child)) func _on_slider_value_changed(value: float, changed_slider: HSlider) -> void: #checks if the slider moved has min or max meta data var is_min = changed_slider.get_meta("min") var is_max = changed_slider.get_meta("max") var is_outputduration = false if changed_slider.has_meta("outputduration"): is_outputduration = changed_slider.get_meta("outputduration") #if not exits function if not is_min and not is_max: return var sliders := _get_all_hsliders(self) for other_slider in sliders: if other_slider == changed_slider: continue if is_min and other_slider.get_meta("max"): var max_value: float = other_slider.value if changed_slider.value > max_value - min_gap: changed_slider.value = max_value - min_gap elif is_max and other_slider.get_meta("min"): var min_value: float = other_slider.value if changed_slider.value < min_value + min_gap: changed_slider.value = min_value + min_gap #set output duration meta if this is the output duration slider if is_outputduration: set_meta("outputduration", value) func _open_help(): open_help.emit(self.get_meta("command"), self.title) func add_inlet_to_node(): #called when the + button is pressed on an addremoveinlets node in the graphnode var inlet_count = self.get_input_port_count() var child_count = self.get_child_count() #check if the number of children is less than the new inlet count if child_count < inlet_count + 1: #if so add a new control node for the inlet to connect to var control = Control.new() control.custom_minimum_size.y = 57 #give it this meta so it can be found and removed later if needed control.set_meta("dummynode", true) add_child(control) #move the ui for adding/removing inlets to the bottom of the node move_child(get_node("addremoveinlets"), get_child_count() - 1) #add the inlet using the same parameters as the first inlet set_slot(inlet_count, true, get_input_port_type(0), get_input_port_color(0), false, 0, get_input_port_color(0)) func remove_inlet_from_node(): var inlet_count = self.get_input_port_count() var child_count = self.get_child_count() #emit a signal to the graphedit script to remove any connections to this inlet inlet_removed.emit(self.get_name(), inlet_count - 1) #remove the inlet note inlet idx starts at 0 hence inlet_count -1 set_slot(inlet_count - 1, false, get_input_port_type(0), get_input_port_color(0), false, 0, get_input_port_color(0)) #check if a dummy control node has been added to make this inlet -2 because bottom node is the ui for adding removing inlets and idx starts at 0 if get_child(child_count - 2).has_meta("dummynode"): #remove the dummy node get_child(child_count - 2).queue_free() #wait a frame for it to be removed await get_tree().process_frame #update the size of the graphnode to shrink to fit smaller ui update_minimum_size() size.y = get_combined_minimum_size().y func _on_position_offset_changed(): node_moved.emit(self, Rect2(position, size)) func _randomise_sliders(): undo_redo.create_action("Randomise Sliders") var sliders := _get_all_hsliders(self) #finds all sliders #links sliders to this script for slider in sliders: var minimum = slider.min_value var maximum = slider.max_value var expo = slider.exp_edit var rnd = randf() var rnd_value if expo: rnd_value = minimum * pow(maximum / minimum, rnd) else: rnd_value = (rnd * (maximum - minimum)) + minimum undo_redo.add_do_method(set_slider_value.bind(slider, rnd_value)) undo_redo.add_undo_method(set_slider_value.bind(slider, slider.value)) undo_redo.commit_action() func set_slider_value(slider: HSlider, value: float) -> void: slider.value = value func button_changed(value, button) -> void: if button_states[button] != value: undo_redo.create_action("Change Button Value") undo_redo.add_do_method(set_button_value.bind(value, button)) undo_redo.add_undo_method(set_button_value.bind(button_states[button], button)) undo_redo.commit_action() func set_button_value(value, button) -> void: if button is OptionButton: button.selected = value elif button is CheckButton: button.set_pressed_no_signal(value) button_states[button] = value