@@ -71,6 +71,7 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
71
71
selected_transition_index = -1 ;
72
72
selected_node = StringName ();
73
73
selected_nodes.clear ();
74
+ connected_nodes.clear ();
74
75
_update_mode ();
75
76
_update_graph ();
76
77
}
@@ -214,6 +215,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
214
215
}
215
216
216
217
selected_nodes.insert (selected_node);
218
+ _update_connected_nodes (selected_node);
217
219
218
220
Ref<AnimationNode> anode = state_machine->get_node (selected_node);
219
221
EditorNode::get_singleton ()->push_item (anode.ptr (), " " , true );
@@ -277,6 +279,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
277
279
selected_transition_to = transition_lines[closest].to_node ;
278
280
selected_transition_index = closest;
279
281
282
+ // Update connected_nodes for the selected transition.
283
+ connected_nodes.clear ();
284
+ connected_nodes.insert (selected_transition_from);
285
+ connected_nodes.insert (selected_transition_to);
286
+
280
287
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition (closest);
281
288
if (!state_machine->is_transition_across_group (closest)) {
282
289
EditorNode::get_singleton ()->push_item (tr.ptr (), " " , true );
@@ -377,6 +384,48 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
377
384
_update_mode ();
378
385
}
379
386
387
+ if (mb.is_valid () && mb->is_pressed () && mb->get_button_index () == MouseButton::LEFT) {
388
+ StringName clicked_node;
389
+ for (int i = node_rects.size () - 1 ; i >= 0 ; i--) {
390
+ if (node_rects[i].node .has_point (mb->get_position ())) {
391
+ clicked_node = node_rects[i].node_name ;
392
+ break ;
393
+ }
394
+ }
395
+
396
+ if (clicked_node != StringName ()) {
397
+ if (selected_nodes.has (clicked_node) && mb->is_shift_pressed ()) {
398
+ selected_nodes.erase (clicked_node);
399
+ } else {
400
+ if (!mb->is_shift_pressed ()) {
401
+ selected_nodes.clear ();
402
+ }
403
+ selected_nodes.insert (clicked_node);
404
+ }
405
+ selected_node = clicked_node;
406
+ } else {
407
+ // Clicked on empty space.
408
+ selected_nodes.clear ();
409
+ selected_node = StringName ();
410
+ }
411
+
412
+ _update_connected_nodes (selected_node);
413
+ state_machine_draw->queue_redraw ();
414
+ _update_mode ();
415
+
416
+ if (clicked_node != StringName ()) {
417
+ Ref<AnimationNode> anode = state_machine->get_node (clicked_node);
418
+ EditorNode::get_singleton ()->push_item (anode.ptr (), " " , true );
419
+ dragging_selected_attempt = true ;
420
+ dragging_selected = false ;
421
+ drag_from = mb->get_position ();
422
+ snap_x = StringName ();
423
+ snap_y = StringName ();
424
+ }
425
+
426
+ return ;
427
+ }
428
+
380
429
Ref<InputEventMouseMotion> mm = p_event;
381
430
382
431
// Pan window
@@ -860,11 +909,15 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
860
909
connecting = false ;
861
910
}
862
911
863
- void AnimationNodeStateMachineEditor::_connection_draw (const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_is_across_group) {
912
+ void AnimationNodeStateMachineEditor::_connection_draw (const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_is_across_group, float p_opacity ) {
864
913
Color line_color = p_enabled ? theme_cache.transition_color : theme_cache.transition_disabled_color ;
865
914
Color icon_color = p_enabled ? theme_cache.transition_icon_color : theme_cache.transition_icon_disabled_color ;
866
915
Color highlight_color = p_enabled ? theme_cache.highlight_color : theme_cache.highlight_disabled_color ;
867
916
917
+ line_color.a *= p_opacity;
918
+ icon_color.a *= p_opacity;
919
+ highlight_color.a *= p_opacity;
920
+
868
921
if (p_travel) {
869
922
line_color = highlight_color;
870
923
}
@@ -877,6 +930,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
877
930
if (p_fade_ratio > 0.0 ) {
878
931
Color fade_line_color = highlight_color;
879
932
fade_line_color.set_hsv (1.0 , fade_line_color.get_s (), fade_line_color.get_v ());
933
+ fade_line_color.a *= p_opacity;
880
934
state_machine_draw->draw_line (p_from, p_from.lerp (p_to, p_fade_ratio), fade_line_color, 2 );
881
935
}
882
936
@@ -921,6 +975,25 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(const Vector2 &p_fr
921
975
}
922
976
}
923
977
978
+ Ref<StyleBox> AnimationNodeStateMachineEditor::_adjust_stylebox_opacity (Ref<StyleBox> p_style, float p_opacity) {
979
+ Ref<StyleBox> style = p_style->duplicate ();
980
+ if (style->is_class (" StyleBoxFlat" )) {
981
+ Ref<StyleBoxFlat> flat_style = style;
982
+ Color bg_color = flat_style->get_bg_color ();
983
+ Color border_color = flat_style->get_border_color ();
984
+ Color shadow_color = flat_style->get_shadow_color ();
985
+
986
+ bg_color.a *= p_opacity;
987
+ border_color.a *= p_opacity;
988
+ shadow_color.a *= p_opacity;
989
+
990
+ flat_style->set_bg_color (bg_color);
991
+ flat_style->set_border_color (border_color);
992
+ flat_style->set_shadow_color (shadow_color);
993
+ }
994
+ return style;
995
+ }
996
+
924
997
void AnimationNodeStateMachineEditor::_state_machine_draw () {
925
998
AnimationTree *tree = AnimationTreeEditor::get_singleton ()->get_animation_tree ();
926
999
if (!tree) {
@@ -1112,7 +1185,30 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
1112
1185
for (int i = 0 ; i < transition_lines.size (); i++) {
1113
1186
TransitionLine tl = transition_lines[i];
1114
1187
if (!tl.hidden ) {
1115
- _connection_draw (tl.from , tl.to , tl.mode , !tl.disabled , tl.selected , tl.travel , tl.fade_ratio , tl.auto_advance , tl.is_across_group );
1188
+ float opacity = 0.2 ; // Default to reduced opacity.
1189
+
1190
+ if (selected_transition_from != StringName () && selected_transition_to != StringName ()) {
1191
+ // A transition is selected.
1192
+ if ((tl.from_node == selected_transition_from && tl.to_node == selected_transition_to) || (tl.from_node == selected_transition_to && tl.to_node == selected_transition_from)) {
1193
+ opacity = 1.0 ; // Full opacity for the selected transition pair.
1194
+ }
1195
+ } else if (!connected_nodes.is_empty ()) {
1196
+ // A node is selected.
1197
+ if (connected_nodes.has (selected_node)) {
1198
+ // Only keep full opacity for transitions directly connected to the selected node.
1199
+ if (tl.from_node == selected_node || tl.to_node == selected_node) {
1200
+ opacity = 1.0 ;
1201
+ }
1202
+ } else {
1203
+ // If no node is selected, all transitions are at full opacity.
1204
+ opacity = 1.0 ;
1205
+ }
1206
+ } else {
1207
+ // If nothing is selected, all transitions are at full opacity.
1208
+ opacity = 1.0 ;
1209
+ }
1210
+
1211
+ _connection_draw (tl.from , tl.to , tl.mode , !tl.disabled , tl.selected , tl.travel , tl.fade_ratio , tl.auto_advance , tl.is_across_group , opacity);
1116
1212
}
1117
1213
}
1118
1214
@@ -1129,39 +1225,55 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
1129
1225
Vector2 offset = nr.node .position ;
1130
1226
int h = nr.node .size .height ;
1131
1227
1132
- // prepre rect
1228
+ float opacity = 1.0 ;
1229
+ if (selected_transition_from != StringName () && selected_transition_to != StringName ()) {
1230
+ // A transition is selected.
1231
+ if (name != selected_transition_from && name != selected_transition_to) {
1232
+ opacity = 0.2 ;
1233
+ }
1234
+ } else if (!connected_nodes.is_empty () && !connected_nodes.has (name)) {
1235
+ // A node is selected.
1236
+ opacity = 0.2 ;
1237
+ }
1133
1238
1134
- // now scroll it to draw
1135
- Ref<StyleBox> node_frame_style = is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame ;
1136
- state_machine_draw->draw_style_box (node_frame_style, nr.node );
1239
+ Ref<StyleBox> original_style = is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame ;
1240
+ Ref<StyleBox> node_style = _adjust_stylebox_opacity (original_style, opacity);
1241
+
1242
+ state_machine_draw->draw_style_box (node_style, nr.node );
1137
1243
1138
1244
if (!is_selected && AnimationNodeStateMachine::START_NODE == name) {
1139
- state_machine_draw->draw_style_box (theme_cache.node_frame_start , nr.node );
1245
+ Ref<StyleBox> start_style = _adjust_stylebox_opacity (theme_cache.node_frame_start , opacity);
1246
+ state_machine_draw->draw_style_box (start_style, nr.node );
1140
1247
}
1141
1248
if (!is_selected && AnimationNodeStateMachine::END_NODE == name) {
1142
- state_machine_draw->draw_style_box (theme_cache.node_frame_end , nr.node );
1249
+ Ref<StyleBox> end_style = _adjust_stylebox_opacity (theme_cache.node_frame_end , opacity);
1250
+ state_machine_draw->draw_style_box (end_style, nr.node );
1143
1251
}
1144
1252
if (playing && (blend_from == name || current == name || travel_path.has (name))) {
1145
- state_machine_draw->draw_style_box (theme_cache.node_frame_playing , nr.node );
1253
+ Ref<StyleBox> playing_style = _adjust_stylebox_opacity (theme_cache.node_frame_playing , opacity);
1254
+ state_machine_draw->draw_style_box (playing_style, nr.node );
1146
1255
}
1147
1256
1148
- offset.x += node_frame_style ->get_offset ().x ;
1257
+ offset.x += original_style ->get_offset ().x ;
1149
1258
1150
1259
nr.play .position = offset + Vector2 (0 , (h - theme_cache.play_node ->get_height ()) / 2 ).floor ();
1151
1260
nr.play .size = theme_cache.play_node ->get_size ();
1152
1261
1262
+ Color color_mod = Color (1 , 1 , 1 , opacity);
1153
1263
if (hovered_node_name == name && hovered_node_area == HOVER_NODE_PLAY) {
1154
- state_machine_draw->draw_texture (theme_cache.play_node , nr.play .position , theme_cache.highlight_color );
1264
+ state_machine_draw->draw_texture (theme_cache.play_node , nr.play .position , theme_cache.highlight_color * color_mod );
1155
1265
} else {
1156
- state_machine_draw->draw_texture (theme_cache.play_node , nr.play .position );
1266
+ state_machine_draw->draw_texture (theme_cache.play_node , nr.play .position , color_mod );
1157
1267
}
1158
1268
1159
1269
offset.x += sep + theme_cache.play_node ->get_width ();
1160
1270
1161
1271
nr.name .position = offset + Vector2 (0 , (h - theme_cache.node_title_font ->get_height (theme_cache.node_title_font_size )) / 2 ).floor ();
1162
1272
nr.name .size = Vector2 (name_string_size, theme_cache.node_title_font ->get_height (theme_cache.node_title_font_size ));
1163
1273
1164
- state_machine_draw->draw_string (theme_cache.node_title_font , nr.name .position + Vector2 (0 , theme_cache.node_title_font ->get_ascent (theme_cache.node_title_font_size )), name, HORIZONTAL_ALIGNMENT_LEFT, -1 , theme_cache.node_title_font_size , theme_cache.node_title_font_color );
1274
+ Color font_color = theme_cache.node_title_font_color ;
1275
+ font_color.a *= opacity;
1276
+ state_machine_draw->draw_string (theme_cache.node_title_font , nr.name .position + Vector2 (0 , theme_cache.node_title_font ->get_ascent (theme_cache.node_title_font_size )), name, HORIZONTAL_ALIGNMENT_LEFT, -1 , theme_cache.node_title_font_size , font_color);
1165
1277
offset.x += name_string_size + sep;
1166
1278
1167
1279
nr.can_edit = needs_editor;
@@ -1170,9 +1282,9 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
1170
1282
nr.edit .size = theme_cache.edit_node ->get_size ();
1171
1283
1172
1284
if (hovered_node_name == name && hovered_node_area == HOVER_NODE_EDIT) {
1173
- state_machine_draw->draw_texture (theme_cache.edit_node , nr.edit .position , theme_cache.highlight_color );
1285
+ state_machine_draw->draw_texture (theme_cache.edit_node , nr.edit .position , theme_cache.highlight_color * color_mod );
1174
1286
} else {
1175
- state_machine_draw->draw_texture (theme_cache.edit_node , nr.edit .position );
1287
+ state_machine_draw->draw_texture (theme_cache.edit_node , nr.edit .position , color_mod );
1176
1288
}
1177
1289
}
1178
1290
}
@@ -1201,6 +1313,23 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
1201
1313
state_machine_play_pos->queue_redraw ();
1202
1314
}
1203
1315
1316
+ void AnimationNodeStateMachineEditor::_update_connected_nodes (const StringName &p_node) {
1317
+ connected_nodes.clear ();
1318
+ if (p_node != StringName ()) {
1319
+ connected_nodes.insert (p_node);
1320
+
1321
+ Vector<StringName> nodes_to = state_machine->get_nodes_with_transitions_to (p_node);
1322
+ for (const StringName &node_to : nodes_to) {
1323
+ connected_nodes.insert (node_to);
1324
+ }
1325
+
1326
+ Vector<StringName> nodes_from = state_machine->get_nodes_with_transitions_from (p_node);
1327
+ for (const StringName &node_from : nodes_from) {
1328
+ connected_nodes.insert (node_from);
1329
+ }
1330
+ }
1331
+ }
1332
+
1204
1333
void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual (const String &p_name, float p_ratio) {
1205
1334
AnimationTree *tree = AnimationTreeEditor::get_singleton ()->get_animation_tree ();
1206
1335
if (!tree) {
0 commit comments