node_logic.gd 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. extends GraphNode
  2. @export var min_gap: float = 0.5 # editable value in inspector for the minimum gap between min and max
  3. var undo_redo: UndoRedo
  4. var button_states = {}
  5. signal open_help
  6. signal inlet_removed
  7. signal node_moved
  8. func _ready() -> void:
  9. var sliders := _get_all_hsliders(self) #finds all sliders
  10. #links sliders to this script
  11. for slider in sliders:
  12. slider.value_changed.connect(_on_slider_value_changed.bind(slider))
  13. #link all buttons for undo redo
  14. get_all_buttons()
  15. #add button to title bar
  16. var titlebar = self.get_titlebar_hbox()
  17. #add randomise button
  18. if sliders.size() > 0:
  19. var rnd_btn = Button.new()
  20. rnd_btn.text = "!"
  21. rnd_btn.tooltip_text = "Randomise Slider Values"
  22. rnd_btn.connect("pressed", Callable(self, "_randomise_sliders")) #pass key (process name) when button is pressed
  23. titlebar.add_child(rnd_btn)
  24. #add help button
  25. var btn = Button.new()
  26. btn.text = "?"
  27. btn.tooltip_text = "Open help for " + self.title
  28. btn.connect("pressed", Callable(self, "_open_help")) #pass key (process name) when button is pressed
  29. titlebar.add_child(btn)
  30. if has_meta("allow_bypass") and get_meta("allow_bypass"):
  31. #add bypass
  32. var bypass_btn = Button.new()
  33. bypass_btn.text = "⏻"
  34. bypass_btn.tooltip_text = "Bypass node from thread processing"
  35. bypass_btn.pressed.connect(_bypass_node)
  36. titlebar.add_child(bypass_btn)
  37. await get_tree().process_frame
  38. #reset_size()
  39. self.position_offset_changed.connect(_on_position_offset_changed)
  40. if self.has_node("addremoveinlets"):
  41. var addremove = self.get_node("addremoveinlets")
  42. addremove.add_inlet.connect(add_inlet_to_node)
  43. addremove.remove_inlet.connect(remove_inlet_from_node)
  44. func _get_all_hsliders(node: Node) -> Array:
  45. #moves through all children recusively to find nested sliders
  46. var result: Array = []
  47. for child in node.get_children():
  48. if child is HSlider:
  49. result.append(child)
  50. elif child.has_method("get_children"):
  51. result += _get_all_hsliders(child)
  52. return result
  53. func get_all_buttons() -> void:
  54. for child in get_children():
  55. if child is OptionButton:
  56. button_states[child] = child.selected
  57. child.item_selected.connect(button_changed.bind(child))
  58. elif child is CheckButton:
  59. button_states[child] = child.button_pressed
  60. child.toggled.connect(button_changed.bind(child))
  61. func _on_slider_value_changed(value: float, changed_slider: HSlider) -> void:
  62. #checks if the slider moved has min or max meta data
  63. var is_min = changed_slider.get_meta("min")
  64. var is_max = changed_slider.get_meta("max")
  65. var is_outputduration = false
  66. if changed_slider.has_meta("outputduration"):
  67. is_outputduration = changed_slider.get_meta("outputduration")
  68. #if not exits function
  69. if not is_min and not is_max:
  70. return
  71. var sliders := _get_all_hsliders(self)
  72. for other_slider in sliders:
  73. if other_slider == changed_slider:
  74. continue
  75. if is_min and other_slider.get_meta("max"):
  76. var max_value: float = other_slider.value
  77. if changed_slider.value > max_value - min_gap:
  78. changed_slider.value = max_value - min_gap
  79. elif is_max and other_slider.get_meta("min"):
  80. var min_value: float = other_slider.value
  81. if changed_slider.value < min_value + min_gap:
  82. changed_slider.value = min_value + min_gap
  83. #set output duration meta if this is the output duration slider
  84. if is_outputduration:
  85. set_meta("outputduration", value)
  86. func _open_help():
  87. open_help.emit(self.get_meta("command"), self.title)
  88. func add_inlet_to_node():
  89. #called when the + button is pressed on an addremoveinlets node in the graphnode
  90. var inlet_count = self.get_input_port_count()
  91. var child_count = self.get_child_count()
  92. #check if the number of children is less than the new inlet count
  93. if child_count < inlet_count + 1:
  94. #if so add a new control node for the inlet to connect to
  95. var control = Control.new()
  96. control.custom_minimum_size.y = 57
  97. #give it this meta so it can be found and removed later if needed
  98. control.set_meta("dummynode", true)
  99. add_child(control)
  100. #move the ui for adding/removing inlets to the bottom of the node
  101. move_child(get_node("addremoveinlets"), get_child_count() - 1)
  102. #add the inlet using the same parameters as the first inlet
  103. set_slot(inlet_count, true, get_input_port_type(0), get_input_port_color(0), false, 0, get_input_port_color(0))
  104. func remove_inlet_from_node():
  105. var inlet_count = self.get_input_port_count()
  106. var child_count = self.get_child_count()
  107. #emit a signal to the graphedit script to remove any connections to this inlet
  108. inlet_removed.emit(self.get_name(), inlet_count - 1)
  109. #remove the inlet note inlet idx starts at 0 hence inlet_count -1
  110. set_slot(inlet_count - 1, false, get_input_port_type(0), get_input_port_color(0), false, 0, get_input_port_color(0))
  111. #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
  112. if get_child(child_count - 2).has_meta("dummynode"):
  113. #remove the dummy node
  114. get_child(child_count - 2).queue_free()
  115. #wait a frame for it to be removed
  116. await get_tree().process_frame
  117. #update the size of the graphnode to shrink to fit smaller ui
  118. update_minimum_size()
  119. size.y = get_combined_minimum_size().y
  120. func _on_position_offset_changed():
  121. node_moved.emit(self, Rect2(position, size))
  122. func _randomise_sliders():
  123. undo_redo.create_action("Randomise Sliders")
  124. var sliders := _get_all_hsliders(self) #finds all sliders
  125. #links sliders to this script
  126. for slider in sliders:
  127. var minimum = slider.min_value
  128. var maximum = slider.max_value
  129. var expo = slider.exp_edit
  130. var rnd = randf()
  131. var rnd_value
  132. if expo:
  133. rnd_value = minimum * pow(maximum / minimum, rnd)
  134. else:
  135. rnd_value = (rnd * (maximum - minimum)) + minimum
  136. undo_redo.add_do_method(set_slider_value.bind(slider, rnd_value))
  137. undo_redo.add_undo_method(set_slider_value.bind(slider, slider.value))
  138. undo_redo.commit_action()
  139. func set_slider_value(slider: HSlider, value: float) -> void:
  140. slider.value = value
  141. func button_changed(value, button) -> void:
  142. if button_states[button] != value:
  143. undo_redo.create_action("Change Button Value")
  144. undo_redo.add_do_method(set_button_value.bind(value, button))
  145. undo_redo.add_undo_method(set_button_value.bind(button_states[button], button))
  146. undo_redo.commit_action()
  147. func set_button_value(value, button) -> void:
  148. if button is OptionButton:
  149. button.selected = value
  150. elif button is CheckButton:
  151. button.set_pressed_no_signal(value)
  152. button_states[button] = value
  153. func _bypass_node() -> void:
  154. if has_meta("bypassed") and get_meta("bypassed"):
  155. set_meta("bypassed", false)
  156. self.modulate = Color(1.0, 1.0, 1.0)
  157. else:
  158. set_meta("bypassed", true)
  159. self.modulate = Color(1.0, 1.0, 1.0, 0.5)