Skip to content

Commit 8e6c84f

Browse files
committed
Animated highlighted connections
1 parent 15ed529 commit 8e6c84f

5 files changed

Lines changed: 142 additions & 26 deletions

File tree

material_maker/nodes/base.gd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ func _draw() -> void:
250250
if control.get("modulate"):
251251
control.modulate.a = opacity
252252

253+
get_parent().get_node("HighlightsOverlay").update_connections()
254+
255+
253256
func draw_portgroup_stylebox(first_port : Vector2, last_port : Vector2) -> void:
254257
var stylebox_position: Vector2 = first_port + Vector2(-0.5,-0.5) * portgroup_width
255258
var stylebox_size: Vector2 = Vector2(portgroup_width, last_port.y - first_port.y + portgroup_width)

material_maker/panels/graph_edit/graph_edit.gd

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,18 +1086,6 @@ func _on_ButtonTransmitsSeed_toggled(button_pressed) -> void:
10861086

10871087
# Node selection
10881088

1089-
var highlighting_connections : bool = false
1090-
1091-
func highlight_connections() -> void:
1092-
if highlighting_connections:
1093-
return
1094-
highlighting_connections = true
1095-
while Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
1096-
await get_tree().process_frame
1097-
for c in get_connection_list():
1098-
set_connection_activity(c.from_node, c.from_port, c.to_node, c.to_port, 1.0 if get_node(NodePath(c.from_node)).selected or get_node(NodePath(c.to_node)).selected else 0.0)
1099-
highlighting_connections = false
1100-
11011089
func _on_GraphEdit_node_selected(node : GraphElement) -> void:
11021090
if node is MMGraphComment:
11031091
#print("Selecting enclosed nodes...")
@@ -1108,7 +1096,6 @@ func _on_GraphEdit_node_selected(node : GraphElement) -> void:
11081096
elif node is MMGraphCommentLine:
11091097
pass
11101098
else:
1111-
highlight_connections()
11121099
await get_tree().process_frame
11131100
if current_preview[0] != null:
11141101
for n in get_selected_nodes():
@@ -1127,7 +1114,6 @@ func _on_GraphEdit_node_selected(node : GraphElement) -> void:
11271114
mm_globals.main_window.update_menus()
11281115

11291116
func _on_GraphEdit_node_unselected(_node):
1130-
highlight_connections()
11311117
undoredo_move_node_selection_changed = true
11321118
mm_globals.main_window.update_menus()
11331119

material_maker/panels/graph_edit/graph_edit.tscn

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
[gd_scene load_steps=8 format=3 uid="uid://dy1u50we7gtru"]
1+
[gd_scene format=3 uid="uid://dy1u50we7gtru"]
22

33
[ext_resource type="Script" uid="uid://dkp4w3at1o6cm" path="res://material_maker/panels/graph_edit/graph_edit.gd" id="1"]
44
[ext_resource type="Texture2D" uid="uid://c0j4px4n72di5" path="res://material_maker/icons/icons.tres" id="2"]
55
[ext_resource type="Script" uid="uid://bne3k0g56crmy" path="res://material_maker/tools/undo_redo/undo_redo.gd" id="3"]
66
[ext_resource type="PackedScene" uid="uid://buj231c2gxm4o" path="res://material_maker/widgets/desc_button/desc_button.tscn" id="4"]
7+
[ext_resource type="Script" uid="uid://dlah77kjy12l6" path="res://material_maker/panels/graph_edit/highlights_overlay.gd" id="5_u5byk"]
78

89
[sub_resource type="AtlasTexture" id="3"]
910
atlas = ExtResource("2")
@@ -17,7 +18,17 @@ region = Rect2(15.4016, 47.1451, 16.7512, 17.8319)
1718
atlas = ExtResource("2")
1819
region = Rect2(0, 48, 16, 16)
1920

20-
[node name="GraphEdit" type="GraphEdit" groups=["mm_graphedit"]]
21+
[sub_resource type="Shader" id="Shader_u5byk"]
22+
code = "shader_type canvas_item;
23+
24+
void fragment() {
25+
COLOR = vec4(vec3(0.0), 0.25 * sin(UV.x - TIME * TAU) + 0.25);
26+
}"
27+
28+
[sub_resource type="ShaderMaterial" id="ShaderMaterial_nlxn2"]
29+
shader = SubResource("Shader_u5byk")
30+
31+
[node name="GraphEdit" type="GraphEdit" unique_id=175822157 groups=["mm_graphedit"]]
2132
anchors_preset = 15
2233
anchor_right = 1.0
2334
anchor_bottom = 1.0
@@ -34,11 +45,11 @@ show_menu = false
3445
show_zoom_label = true
3546
script = ExtResource("1")
3647

37-
[node name="Timer" type="Timer" parent="."]
48+
[node name="Timer" type="Timer" parent="." unique_id=654752788]
3849
wait_time = 0.2
3950
one_shot = true
4051

41-
[node name="GraphUI" type="HBoxContainer" parent="."]
52+
[node name="GraphUI" type="HBoxContainer" parent="." unique_id=45635343]
4253
top_level = true
4354
custom_minimum_size = Vector2(0, 25)
4455
layout_mode = 1
@@ -51,43 +62,48 @@ offset_bottom = 31.0
5162
grow_horizontal = 0
5263
alignment = 2
5364

54-
[node name="SubGraphUI" type="HBoxContainer" parent="GraphUI"]
65+
[node name="SubGraphUI" type="HBoxContainer" parent="GraphUI" unique_id=1847281688]
5566
layout_mode = 2
5667
size_flags_horizontal = 9
5768

58-
[node name="Label" type="LineEdit" parent="GraphUI/SubGraphUI"]
69+
[node name="Label" type="LineEdit" parent="GraphUI/SubGraphUI" unique_id=1166036264]
5970
custom_minimum_size = Vector2(150, 0)
6071
layout_mode = 2
6172
size_flags_horizontal = 9
6273

63-
[node name="Description" parent="GraphUI/SubGraphUI" instance=ExtResource("4")]
74+
[node name="Description" parent="GraphUI/SubGraphUI" unique_id=610946558 instance=ExtResource("4")]
6475
layout_mode = 2
6576

66-
[node name="ButtonTransmitsSeed" type="Button" parent="GraphUI/SubGraphUI"]
77+
[node name="ButtonTransmitsSeed" type="Button" parent="GraphUI/SubGraphUI" unique_id=1858333769]
6778
layout_mode = 2
6879
size_flags_horizontal = 9
6980
tooltip_text = "Affect children seeds"
7081
toggle_mode = true
7182
icon = SubResource("3")
7283

73-
[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI"]
84+
[node name="ButtonUp" type="Button" parent="GraphUI/SubGraphUI" unique_id=1608742490]
7485
layout_mode = 2
7586
size_flags_horizontal = 9
7687
tooltip_text = "Back to parent"
7788
icon = SubResource("4")
7889

79-
[node name="ButtonShowTree" type="Button" parent="GraphUI"]
90+
[node name="ButtonShowTree" type="Button" parent="GraphUI" unique_id=1663795300]
8091
layout_mode = 2
8192
tooltip_text = "Show hierarchy"
8293
icon = SubResource("5")
8394

84-
[node name="Control" type="Control" parent="GraphUI"]
95+
[node name="Control" type="Control" parent="GraphUI" unique_id=265307966]
8596
custom_minimum_size = Vector2(14, 0)
8697
layout_mode = 2
8798

88-
[node name="UndoRedo" type="Node" parent="."]
99+
[node name="UndoRedo" type="Node" parent="." unique_id=476880472]
89100
script = ExtResource("3")
90101

102+
[node name="HighlightsOverlay" type="Control" parent="." unique_id=2128156926]
103+
anchors_preset = 0
104+
script = ExtResource("5_u5byk")
105+
line_material = SubResource("ShaderMaterial_nlxn2")
106+
91107
[connection signal="connection_drag_ended" from="." to="." method="_on_connection_drag_ended"]
92108
[connection signal="connection_drag_started" from="." to="." method="_on_connection_drag_started"]
93109
[connection signal="connection_from_empty" from="." to="." method="request_popup" binds= [true]]
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
class_name HighlightsOverlay
2+
extends Control
3+
4+
5+
class AnimatedConnection extends Line2D:
6+
var connection : Dictionary
7+
8+
@onready var graph : MMGraphEdit = owner
9+
@export var line_material : ShaderMaterial
10+
11+
var active_connections : Array[Dictionary]
12+
var is_updating_connections : bool = false
13+
14+
func _ready() -> void:
15+
graph.child_order_changed.connect(_move_above_connections.call_deferred)
16+
graph.get_node("_connection_layer").draw.connect(queue_redraw)
17+
graph.get_node("_connection_layer").child_order_changed.connect(update_connections)
18+
graph.connection_drag_started.connect(update_connections.bind(1).unbind(3))
19+
graph.node_selected.connect(update_connections.unbind(1))
20+
graph.node_deselected.connect(update_connections.unbind(1))
21+
graph.gui_input.connect(_graph_gui_input)
22+
23+
func _draw() -> void:
24+
if get_children().is_empty():
25+
return
26+
27+
for line : AnimatedConnection in get_children():
28+
var conn : Dictionary = line.connection
29+
var positions : Dictionary[String, Vector2] = get_connection_positions(conn)
30+
if positions.is_empty():
31+
continue
32+
33+
line.visible = get_viewport_rect().intersects(
34+
Rect2(positions.from, positions.to - positions.from).abs())
35+
36+
line.points = graph._get_connection_line(positions.from, positions.to)
37+
line.width = graph.connection_lines_thickness
38+
39+
func _move_above_connections() -> void:
40+
graph.move_child(self, graph.get_node("_connection_layer").get_index() + 1)
41+
42+
func _graph_gui_input(e : InputEvent) -> void:
43+
if e is InputEventKey:
44+
update_connections(true)
45+
46+
func update_connections(should_hide_when_updating : bool = false) -> void:
47+
if is_updating_connections:
48+
return
49+
is_updating_connections = true
50+
51+
if should_hide_when_updating:
52+
hide()
53+
54+
while Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
55+
await get_tree().process_frame
56+
57+
active_connections.clear()
58+
for c in graph.get_connection_list():
59+
if (graph.get_node(NodePath(c.from_node)).selected
60+
or graph.get_node(NodePath(c.to_node)).selected):
61+
active_connections.append(c)
62+
await get_tree().process_frame
63+
create_animated_connections()
64+
65+
# Remove inactive/invalid animated conections
66+
if get_children().size():
67+
for anim_line : AnimatedConnection in get_children():
68+
if (anim_line.connection not in active_connections
69+
or get_connection_positions(anim_line.connection).is_empty()):
70+
remove_child(anim_line)
71+
anim_line.free()
72+
73+
queue_redraw()
74+
is_updating_connections = false
75+
show.call_deferred()
76+
77+
func create_animated_connections() -> void:
78+
if active_connections.size():
79+
for active_connection in active_connections:
80+
var positions : Dictionary[String, Vector2] = get_connection_positions(active_connection)
81+
if positions.is_empty():
82+
continue
83+
84+
var has_existing_connection : bool = false
85+
for c in get_children():
86+
if c.connection == active_connection:
87+
has_existing_connection = true
88+
break
89+
90+
if not has_existing_connection:
91+
var ac : AnimatedConnection = AnimatedConnection.new()
92+
ac.connection = active_connection
93+
ac.texture_mode = Line2D.LINE_TEXTURE_TILE
94+
ac.material = line_material
95+
ac.points = graph._get_connection_line(positions.from, positions.to)
96+
ac.width = graph.connection_lines_thickness
97+
add_child(ac)
98+
99+
func get_connection_positions(from_connection : Dictionary) -> Dictionary[String, Vector2]:
100+
var c : Dictionary = from_connection
101+
var positions : Dictionary[String, Vector2]
102+
if graph.has_node(NodePath(c.from_node)) and graph.has_node(NodePath(c.to_node)):
103+
var from_node : MMGraphNodeMinimal = graph.get_node(NodePath(c.from_node))
104+
var to_node : MMGraphNodeMinimal = graph.get_node(NodePath(c.to_node))
105+
if from_node and to_node:
106+
var from_pos : Vector2 = from_node.get_output_port_position(c.from_port)
107+
var to_pos : Vector2 = to_node.get_input_port_position(c.to_port)
108+
positions.from = from_pos * graph.zoom + from_node.position
109+
positions.to = to_pos * graph.zoom + to_node.position
110+
return positions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://dlah77kjy12l6

0 commit comments

Comments
 (0)