mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	Merge pull request #98402 from vaner-org/highlight-node-neighbours
Reduce opacity of nodes with no shared transition when selecting an AnimationNodeStateMachine node
This commit is contained in:
		
						commit
						d6b20fd7e5
					
				
					 5 changed files with 174 additions and 16 deletions
				
			
		|  | @ -71,6 +71,7 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { | |||
| 		selected_transition_index = -1; | ||||
| 		selected_node = StringName(); | ||||
| 		selected_nodes.clear(); | ||||
| 		connected_nodes.clear(); | ||||
| 		_update_mode(); | ||||
| 		_update_graph(); | ||||
| 	} | ||||
|  | @ -214,6 +215,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | |||
| 				} | ||||
| 
 | ||||
| 				selected_nodes.insert(selected_node); | ||||
| 				_update_connected_nodes(selected_node); | ||||
| 
 | ||||
| 				Ref<AnimationNode> anode = state_machine->get_node(selected_node); | ||||
| 				EditorNode::get_singleton()->push_item(anode.ptr(), "", true); | ||||
|  | @ -277,6 +279,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | |||
| 			selected_transition_to = transition_lines[closest].to_node; | ||||
| 			selected_transition_index = closest; | ||||
| 
 | ||||
| 			// Update connected_nodes for the selected transition.
 | ||||
| 			connected_nodes.clear(); | ||||
| 			connected_nodes.insert(selected_transition_from); | ||||
| 			connected_nodes.insert(selected_transition_to); | ||||
| 
 | ||||
| 			Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest); | ||||
| 			if (!state_machine->is_transition_across_group(closest)) { | ||||
| 				EditorNode::get_singleton()->push_item(tr.ptr(), "", true); | ||||
|  | @ -377,6 +384,48 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv | |||
| 		_update_mode(); | ||||
| 	} | ||||
| 
 | ||||
| 	if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { | ||||
| 		StringName clicked_node; | ||||
| 		for (int i = node_rects.size() - 1; i >= 0; i--) { | ||||
| 			if (node_rects[i].node.has_point(mb->get_position())) { | ||||
| 				clicked_node = node_rects[i].node_name; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (clicked_node != StringName()) { | ||||
| 			if (selected_nodes.has(clicked_node) && mb->is_shift_pressed()) { | ||||
| 				selected_nodes.erase(clicked_node); | ||||
| 			} else { | ||||
| 				if (!mb->is_shift_pressed()) { | ||||
| 					selected_nodes.clear(); | ||||
| 				} | ||||
| 				selected_nodes.insert(clicked_node); | ||||
| 			} | ||||
| 			selected_node = clicked_node; | ||||
| 		} else { | ||||
| 			// Clicked on empty space.
 | ||||
| 			selected_nodes.clear(); | ||||
| 			selected_node = StringName(); | ||||
| 		} | ||||
| 
 | ||||
| 		_update_connected_nodes(selected_node); | ||||
| 		state_machine_draw->queue_redraw(); | ||||
| 		_update_mode(); | ||||
| 
 | ||||
| 		if (clicked_node != StringName()) { | ||||
| 			Ref<AnimationNode> anode = state_machine->get_node(clicked_node); | ||||
| 			EditorNode::get_singleton()->push_item(anode.ptr(), "", true); | ||||
| 			dragging_selected_attempt = true; | ||||
| 			dragging_selected = false; | ||||
| 			drag_from = mb->get_position(); | ||||
| 			snap_x = StringName(); | ||||
| 			snap_y = StringName(); | ||||
| 		} | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	Ref<InputEventMouseMotion> mm = p_event; | ||||
| 
 | ||||
| 	// Pan window
 | ||||
|  | @ -860,11 +909,15 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action | |||
| 	connecting = false; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 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) { | ||||
| 	Color line_color = p_enabled ? theme_cache.transition_color : theme_cache.transition_disabled_color; | ||||
| 	Color icon_color = p_enabled ? theme_cache.transition_icon_color : theme_cache.transition_icon_disabled_color; | ||||
| 	Color highlight_color = p_enabled ? theme_cache.highlight_color : theme_cache.highlight_disabled_color; | ||||
| 
 | ||||
| 	line_color.a *= p_opacity; | ||||
| 	icon_color.a *= p_opacity; | ||||
| 	highlight_color.a *= p_opacity; | ||||
| 
 | ||||
| 	if (p_travel) { | ||||
| 		line_color = highlight_color; | ||||
| 	} | ||||
|  | @ -877,6 +930,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co | |||
| 	if (p_fade_ratio > 0.0) { | ||||
| 		Color fade_line_color = highlight_color; | ||||
| 		fade_line_color.set_hsv(1.0, fade_line_color.get_s(), fade_line_color.get_v()); | ||||
| 		fade_line_color.a *= p_opacity; | ||||
| 		state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_line_color, 2); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -921,6 +975,25 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(const Vector2 &p_fr | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| Ref<StyleBox> AnimationNodeStateMachineEditor::_adjust_stylebox_opacity(Ref<StyleBox> p_style, float p_opacity) { | ||||
| 	Ref<StyleBox> style = p_style->duplicate(); | ||||
| 	if (style->is_class("StyleBoxFlat")) { | ||||
| 		Ref<StyleBoxFlat> flat_style = style; | ||||
| 		Color bg_color = flat_style->get_bg_color(); | ||||
| 		Color border_color = flat_style->get_border_color(); | ||||
| 		Color shadow_color = flat_style->get_shadow_color(); | ||||
| 
 | ||||
| 		bg_color.a *= p_opacity; | ||||
| 		border_color.a *= p_opacity; | ||||
| 		shadow_color.a *= p_opacity; | ||||
| 
 | ||||
| 		flat_style->set_bg_color(bg_color); | ||||
| 		flat_style->set_border_color(border_color); | ||||
| 		flat_style->set_shadow_color(shadow_color); | ||||
| 	} | ||||
| 	return style; | ||||
| } | ||||
| 
 | ||||
| void AnimationNodeStateMachineEditor::_state_machine_draw() { | ||||
| 	AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); | ||||
| 	if (!tree) { | ||||
|  | @ -1112,7 +1185,30 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | |||
| 	for (int i = 0; i < transition_lines.size(); i++) { | ||||
| 		TransitionLine tl = transition_lines[i]; | ||||
| 		if (!tl.hidden) { | ||||
| 			_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.fade_ratio, tl.auto_advance, tl.is_across_group); | ||||
| 			float opacity = 0.2; // Default to reduced opacity.
 | ||||
| 
 | ||||
| 			if (selected_transition_from != StringName() && selected_transition_to != StringName()) { | ||||
| 				// A transition is selected.
 | ||||
| 				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)) { | ||||
| 					opacity = 1.0; // Full opacity for the selected transition pair.
 | ||||
| 				} | ||||
| 			} else if (!connected_nodes.is_empty()) { | ||||
| 				// A node is selected.
 | ||||
| 				if (connected_nodes.has(selected_node)) { | ||||
| 					// Only keep full opacity for transitions directly connected to the selected node.
 | ||||
| 					if (tl.from_node == selected_node || tl.to_node == selected_node) { | ||||
| 						opacity = 1.0; | ||||
| 					} | ||||
| 				} else { | ||||
| 					// If no node is selected, all transitions are at full opacity.
 | ||||
| 					opacity = 1.0; | ||||
| 				} | ||||
| 			} else { | ||||
| 				// If nothing is selected, all transitions are at full opacity.
 | ||||
| 				opacity = 1.0; | ||||
| 			} | ||||
| 
 | ||||
| 			_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); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1129,31 +1225,45 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | |||
| 		Vector2 offset = nr.node.position; | ||||
| 		int h = nr.node.size.height; | ||||
| 
 | ||||
| 		//prepre rect
 | ||||
| 		float opacity = 1.0; | ||||
| 		if (selected_transition_from != StringName() && selected_transition_to != StringName()) { | ||||
| 			// A transition is selected.
 | ||||
| 			if (name != selected_transition_from && name != selected_transition_to) { | ||||
| 				opacity = 0.2; | ||||
| 			} | ||||
| 		} else if (!connected_nodes.is_empty() && !connected_nodes.has(name)) { | ||||
| 			// A node is selected.
 | ||||
| 			opacity = 0.2; | ||||
| 		} | ||||
| 
 | ||||
| 		//now scroll it to draw
 | ||||
| 		Ref<StyleBox> node_frame_style = is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame; | ||||
| 		state_machine_draw->draw_style_box(node_frame_style, nr.node); | ||||
| 		Ref<StyleBox> original_style = is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame; | ||||
| 		Ref<StyleBox> node_style = _adjust_stylebox_opacity(original_style, opacity); | ||||
| 
 | ||||
| 		state_machine_draw->draw_style_box(node_style, nr.node); | ||||
| 
 | ||||
| 		if (!is_selected && AnimationNodeStateMachine::START_NODE == name) { | ||||
| 			state_machine_draw->draw_style_box(theme_cache.node_frame_start, nr.node); | ||||
| 			Ref<StyleBox> start_style = _adjust_stylebox_opacity(theme_cache.node_frame_start, opacity); | ||||
| 			state_machine_draw->draw_style_box(start_style, nr.node); | ||||
| 		} | ||||
| 		if (!is_selected && AnimationNodeStateMachine::END_NODE == name) { | ||||
| 			state_machine_draw->draw_style_box(theme_cache.node_frame_end, nr.node); | ||||
| 			Ref<StyleBox> end_style = _adjust_stylebox_opacity(theme_cache.node_frame_end, opacity); | ||||
| 			state_machine_draw->draw_style_box(end_style, nr.node); | ||||
| 		} | ||||
| 		if (playing && (blend_from == name || current == name || travel_path.has(name))) { | ||||
| 			state_machine_draw->draw_style_box(theme_cache.node_frame_playing, nr.node); | ||||
| 			Ref<StyleBox> playing_style = _adjust_stylebox_opacity(theme_cache.node_frame_playing, opacity); | ||||
| 			state_machine_draw->draw_style_box(playing_style, nr.node); | ||||
| 		} | ||||
| 
 | ||||
| 		offset.x += node_frame_style->get_offset().x; | ||||
| 		offset.x += original_style->get_offset().x; | ||||
| 
 | ||||
| 		nr.play.position = offset + Vector2(0, (h - theme_cache.play_node->get_height()) / 2).floor(); | ||||
| 		nr.play.size = theme_cache.play_node->get_size(); | ||||
| 
 | ||||
| 		Color color_mod = Color(1, 1, 1, opacity); | ||||
| 		if (hovered_node_name == name && hovered_node_area == HOVER_NODE_PLAY) { | ||||
| 			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position, theme_cache.highlight_color); | ||||
| 			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position, theme_cache.highlight_color * color_mod); | ||||
| 		} else { | ||||
| 			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position); | ||||
| 			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position, color_mod); | ||||
| 		} | ||||
| 
 | ||||
| 		offset.x += sep + theme_cache.play_node->get_width(); | ||||
|  | @ -1161,7 +1271,9 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | |||
| 		nr.name.position = offset + Vector2(0, (h - theme_cache.node_title_font->get_height(theme_cache.node_title_font_size)) / 2).floor(); | ||||
| 		nr.name.size = Vector2(name_string_size, theme_cache.node_title_font->get_height(theme_cache.node_title_font_size)); | ||||
| 
 | ||||
| 		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); | ||||
| 		Color font_color = theme_cache.node_title_font_color; | ||||
| 		font_color.a *= opacity; | ||||
| 		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); | ||||
| 		offset.x += name_string_size + sep; | ||||
| 
 | ||||
| 		nr.can_edit = needs_editor; | ||||
|  | @ -1170,9 +1282,9 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | |||
| 			nr.edit.size = theme_cache.edit_node->get_size(); | ||||
| 
 | ||||
| 			if (hovered_node_name == name && hovered_node_area == HOVER_NODE_EDIT) { | ||||
| 				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position, theme_cache.highlight_color); | ||||
| 				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position, theme_cache.highlight_color * color_mod); | ||||
| 			} else { | ||||
| 				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position); | ||||
| 				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position, color_mod); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1201,6 +1313,23 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { | |||
| 	state_machine_play_pos->queue_redraw(); | ||||
| } | ||||
| 
 | ||||
| void AnimationNodeStateMachineEditor::_update_connected_nodes(const StringName &p_node) { | ||||
| 	connected_nodes.clear(); | ||||
| 	if (p_node != StringName()) { | ||||
| 		connected_nodes.insert(p_node); | ||||
| 
 | ||||
| 		Vector<StringName> nodes_to = state_machine->get_nodes_with_transitions_to(p_node); | ||||
| 		for (const StringName &node_to : nodes_to) { | ||||
| 			connected_nodes.insert(node_to); | ||||
| 		} | ||||
| 
 | ||||
| 		Vector<StringName> nodes_from = state_machine->get_nodes_with_transitions_from(p_node); | ||||
| 		for (const StringName &node_from : nodes_from) { | ||||
| 			connected_nodes.insert(node_from); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(const String &p_name, float p_ratio) { | ||||
| 	AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); | ||||
| 	if (!tree) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Rémi Verschelde
						Rémi Verschelde