diff --git a/material_maker/nodes/generic/generic.gd b/material_maker/nodes/generic/generic.gd index 3d45cc546..05519e505 100644 --- a/material_maker/nodes/generic/generic.gd +++ b/material_maker/nodes/generic/generic.gd @@ -10,6 +10,9 @@ var preview : ColorRect var preview_timer : Timer = Timer.new() var generic_button : TextureButton +## Metadata references for remote-annotated controls +var remote_linked_meta : Dictionary[String, Dictionary] + const SETTINGS_NODE_CLOSE_BUTTON := "node_close_button" const GENERIC_ICON : Texture2D = preload("res://material_maker/icons/add_generic.tres") @@ -289,7 +292,7 @@ static func get_parameter_tooltip(p : Dictionary, parameter_value = null) -> Str return wrap_string(tooltip) static func create_parameter_control(p : Dictionary, accept_float_expressions : bool) -> Control: - var control = null + var control : Control = null if !p.has("type"): return null if p.type == "float": @@ -350,6 +353,7 @@ static func create_parameter_control(p : Dictionary, accept_float_expressions : for f in p.filters: control.add_filter(f) control.tooltip_text = get_parameter_tooltip(p) + MMGraphNodeRemote.setup_linked_control_signals(control) return control func save_preview_widget() -> void: @@ -429,6 +433,7 @@ func update_node() -> void: var minimum_line_height = get_theme_constant("minimum_line_height", "MM_Node") if has_theme_constant("minimum_line_height", "MM_Node") else 25 # Clean node clear_all_slots() + save_remote_metadata() save_preview_widget() for c in get_children(): remove_child(c) @@ -511,6 +516,7 @@ func update_node() -> void: var label : String = p.name var first : bool = true control.name = label + restore_remote_metadata(control) controls[control.name] = control if p.has("label"): label = p.label @@ -713,3 +719,20 @@ func update_from_locale() -> void: func _on_minimum_size_changed() -> void: size = get_combined_minimum_size() + +## Save metadata references for remote-annotated controls +func save_remote_metadata() -> void: + for c in controls: + if is_instance_valid(controls[c]) and controls[c].has_meta("linked_parameters"): + if not remote_linked_meta.has(c): + remote_linked_meta[c] = {} + remote_linked_meta[c].graph = controls[c].get_meta("graph") + remote_linked_meta[c].linked_parameters = controls[c].get_meta("linked_parameters") + +## Restore remote annotations +func restore_remote_metadata(control : Control) -> void: + if remote_linked_meta.has(control.name): + control.set_meta("graph", remote_linked_meta[control.name].graph) + control.set_meta("linked_parameters", remote_linked_meta[control.name].linked_parameters) + else: + MMGraphNodeRemote.setdown_linked_control_signals(control) diff --git a/material_maker/nodes/remote/remote.gd b/material_maker/nodes/remote/remote.gd index 09cb444db..8fc2670f2 100644 --- a/material_maker/nodes/remote/remote.gd +++ b/material_maker/nodes/remote/remote.gd @@ -81,6 +81,7 @@ func update_node() -> void: for i in range(parameter_count): var p = generator.get_parameter_defs()[i] var control = create_parameter_control(p, false) + setdown_linked_control_signals(control) if control != null: control.name = p.name controls[control.name] = control @@ -149,6 +150,7 @@ func rearrange_parameter(from : int, to : int, is_after : bool) -> void: func remove_parameter(widget_name : String) -> void: old_state = generator.serialize().duplicate(true) + annotate_linked_controls(widget_name, false) generator.remove_parameter(widget_name) undo_redo_register_change("Remove parameter", old_state) @@ -245,6 +247,7 @@ func on_parameter_changed(p, v) -> void: super.on_parameter_changed(p, v) if generator.name == "gen_parameter" and generator.get_parent() is MMGenBase: generator.get_parent().set_parameter(p, v) + annotate_linked_controls(p, true) func on_enter_widget(widget) -> void: var w = generator.get_widget(widget.name) @@ -335,3 +338,75 @@ func _notification(what: int) -> void: match what: NOTIFICATION_DRAG_END: grid.get_children().map(func(c): c.modulate = Color.WHITE) + +func annotate_linked_controls(p : String, is_setup : bool) -> void: + var widget : Dictionary = generator.get_widget(p) + if not widget.is_empty() and widget.type == "linked_control": + for w in widget.linked_widgets: + var node : GraphNode = get_parent().get_node(NodePath("node_" + w.node)) + var control : Control = node.controls[w.widget] + var linked_params : Array[Dictionary] + + if is_setup: + if control.has_meta("linked_parameters"): + linked_params = control.get_meta("linked_parameters") + linked_params.append( + {"remote": self, "param": controls[widget.name]}) + control.set_meta("graph", get_parent()) + control.set_meta("linked_parameters", linked_params) + setup_linked_control_signals(control) + else: + control.remove_meta("graph") + control.remove_meta("linked_parameters") + setdown_linked_control_signals(control) + +## Draw link(s) from [param linked_control] to linked remote parameter control(s). +static func on_linked_control_entered(linked_control : Control) -> void: + if linked_control.has_meta("linked_parameters"): + var linked_params : Array[Dictionary] = linked_control.get_meta("linked_parameters") + var new_links : Array[MMNodeLink] + for l in linked_params: + if l.param: + var link : MMNodeLink = MMNodeLink.new(linked_control.get_meta("graph")) + link.show_link(l.param, linked_control) + new_links.append(link) + var _links : Dictionary[String, Array] + if linked_control.has_meta("links"): + _links = linked_control.get_meta("links") + _links[linked_control.name] = new_links + linked_control.set_meta("links", _links) + +## Hide link(s) from [param linked_control] to linked remote parameter control(s) +static func on_linked_control_exited(linked_control : Control) -> void: + if linked_control.has_meta("links"): + var _links : Dictionary[String, Array] = linked_control.get_meta("links") + if _links.has(linked_control.name): + var control_links : Array[MMNodeLink] = _links[linked_control.name] + for l in control_links: + l.queue_free() + _links.erase(linked_control.name) + +## Helper function to setup [signal mouse_entered] and [signal mouse_exited] +## signals for [param linked_control] to draw remote links. +static func setup_linked_control_signals(linked_control : Control) -> void: + var enter_f : Callable = on_linked_control_entered.bind(linked_control) + var exit_f : Callable = on_linked_control_exited.bind(linked_control) + + if not linked_control.mouse_entered.is_connected(enter_f): + linked_control.mouse_entered.connect(enter_f) + + if not linked_control.mouse_exited.is_connected(exit_f): + linked_control.mouse_exited.connect(exit_f) + +## Helper function to cleanup [signal mouse_entered] and [signal mouse_exited] +## signals for [param linked_control] to draw remote links. Opposite of +## [method setup_linked_control_signals] +static func setdown_linked_control_signals(linked_control : Control) -> void: + var enter_f : Callable = on_linked_control_entered.bind(linked_control) + var exit_f : Callable = on_linked_control_exited.bind(linked_control) + + if linked_control.mouse_entered.is_connected(enter_f): + linked_control.mouse_entered.disconnect(enter_f) + + if not linked_control.mouse_exited.is_connected(exit_f): + linked_control.mouse_exited.disconnect(exit_f) diff --git a/material_maker/nodes/switch/switch.gd b/material_maker/nodes/switch/switch.gd index d55cade62..7b43abf98 100644 --- a/material_maker/nodes/switch/switch.gd +++ b/material_maker/nodes/switch/switch.gd @@ -9,6 +9,7 @@ func _ready() -> void: func update_node() -> void: if generator == null or !generator.parameters.has("outputs") or !generator.parameters.has("choices"): return + save_remote_metadata() save_preview_widget() var new_fixed_lines = 3 if generator.editable else 1 if new_fixed_lines != fixed_lines: @@ -38,6 +39,8 @@ func update_node() -> void: control.max_value = l.max control.step = 1 control.custom_minimum_size.x = 75 + MMGraphNodeRemote.setup_linked_control_signals(control) + restore_remote_metadata(control) if l.has("tooltip"): control.tooltip_text = l.tooltip sizer.add_child(control)