From b351cffddf544a3ced3438b3deb2811027c503d4 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Sat, 23 Sep 2023 21:22:33 +0200 Subject: [PATCH] Fix theme access and improve UX in AnimationTree editor --- editor/editor_themes.cpp | 62 +++- editor/gui/scene_tree_editor.cpp | 15 +- editor/gui/scene_tree_editor.h | 1 - .../animation_blend_tree_editor_plugin.cpp | 12 +- .../animation_blend_tree_editor_plugin.h | 1 - .../animation_state_machine_editor.cpp | 325 +++++++++--------- .../plugins/animation_state_machine_editor.h | 63 +++- scene/animation/animation_blend_space_1d.cpp | 4 +- scene/animation/animation_blend_space_2d.cpp | 4 +- 9 files changed, 292 insertions(+), 195 deletions(-) diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 98f0f70101b..c5ab3698e20 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -2014,17 +2014,6 @@ Ref create_editor_theme(const Ref p_theme) { graphn_sb_titlebar_selected->set_expand_margin(SIDE_TOP, 2 * EDSCALE); Ref graphn_sb_slot = make_empty_stylebox(12, 0, 12, 0); - // StateMachine. - const int sm_margin_side = 10; - Ref smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width); - smgraphsb->set_border_width_all(border_width); - smgraphsb->set_border_color(graphnode_bg); - Ref smgraphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width); - smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width); - smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9)); - smgraphsbselected->set_shadow_size(8 * EDSCALE); - smgraphsbselected->set_shadow_color(shadow_color); - theme->set_stylebox("panel", "GraphElement", graphn_sb_panel); theme->set_stylebox("panel_selected", "GraphElement", graphn_sb_panel_selected); theme->set_stylebox("titlebar", "GraphElement", graphn_sb_titlebar); @@ -2059,8 +2048,55 @@ Ref create_editor_theme(const Ref p_theme) { port_icon->set_size_override(Size2(12, 12)); theme->set_icon("port", "GraphNode", port_icon); - theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb); - theme->set_stylebox("state_machine_selected_frame", "GraphNode", smgraphsbselected); + // StateMachine graph + theme->set_stylebox("panel", "GraphStateMachine", style_tree_bg); + theme->set_stylebox("error_panel", "GraphStateMachine", style_tree_bg); + theme->set_color("error_color", "GraphStateMachine", error_color); + + const int sm_margin_side = 10 * EDSCALE; + + Ref sm_node_style = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), sm_margin_side, 24 * EDSCALE, sm_margin_side, gn_margin_bottom, corner_width); + sm_node_style->set_border_width_all(border_width); + sm_node_style->set_border_color(graphnode_bg); + + Ref sm_node_selected_style = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), sm_margin_side, 24 * EDSCALE, sm_margin_side, gn_margin_bottom, corner_width); + sm_node_selected_style->set_border_width_all(2 * EDSCALE + border_width); + sm_node_selected_style->set_border_color(accent_color * Color(1, 1, 1, 0.9)); + sm_node_selected_style->set_shadow_size(8 * EDSCALE); + sm_node_selected_style->set_shadow_color(shadow_color); + + Ref sm_node_playing_style = sm_node_selected_style->duplicate(); + sm_node_playing_style->set_border_color(warning_color); + sm_node_playing_style->set_shadow_color(warning_color * Color(1, 1, 1, 0.2)); + + theme->set_stylebox("node_frame", "GraphStateMachine", sm_node_style); + theme->set_stylebox("node_frame_selected", "GraphStateMachine", sm_node_selected_style); + theme->set_stylebox("node_frame_playing", "GraphStateMachine", sm_node_playing_style); + + Ref sm_node_start_style = sm_node_style->duplicate(); + sm_node_start_style->set_border_width_all(1 * EDSCALE); + sm_node_start_style->set_border_color(success_color.lightened(0.24)); + theme->set_stylebox("node_frame_start", "GraphStateMachine", sm_node_start_style); + + Ref sm_node_end_style = sm_node_style->duplicate(); + sm_node_end_style->set_border_width_all(1 * EDSCALE); + sm_node_end_style->set_border_color(error_color); + theme->set_stylebox("node_frame_end", "GraphStateMachine", sm_node_end_style); + + theme->set_font("node_title_font", "GraphStateMachine", theme->get_font(SNAME("font"), SNAME("Label"))); + theme->set_font_size("node_title_font_size", "GraphStateMachine", theme->get_font_size(SNAME("font_size"), SNAME("Label"))); + theme->set_color("node_title_font_color", "GraphStateMachine", font_color); + + theme->set_color("transition_color", "GraphStateMachine", font_color); + theme->set_color("transition_disabled_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.2)); + theme->set_color("transition_icon_color", "GraphStateMachine", Color(1, 1, 1)); + theme->set_color("transition_icon_disabled_color", "GraphStateMachine", Color(1, 1, 1, 0.2)); + theme->set_color("highlight_color", "GraphStateMachine", accent_color); + theme->set_color("highlight_disabled_color", "GraphStateMachine", accent_color * Color(1, 1, 1, 0.6)); + theme->set_color("guideline_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.3)); + + theme->set_color("playback_color", "GraphStateMachine", font_color); + theme->set_color("playback_background_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.3)); // GridContainer theme->set_constant("v_separation", "GridContainer", Math::round(widget_default_margin.y - 2 * EDSCALE)); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index f483539ba27..fff46904454 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -1564,14 +1564,6 @@ void SceneTreeDialog::set_valid_types(const Vector &p_valid) { show_all_nodes->show(); } -void SceneTreeDialog::_update_theme() { - filter->set_right_icon(tree->get_editor_theme_icon(SNAME("Search"))); - for (TextureRect *trect : valid_type_icons) { - trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0)); - trect->set_texture(EditorNode::get_singleton()->get_class_icon(trect->get_meta("type"))); - } -} - void SceneTreeDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { @@ -1585,11 +1577,14 @@ void SceneTreeDialog::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { connect("confirmed", callable_mp(this, &SceneTreeDialog::_select)); - _update_theme(); } break; case NOTIFICATION_THEME_CHANGED: { - _update_theme(); + filter->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + for (TextureRect *trect : valid_type_icons) { + trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0)); + trect->set_texture(EditorNode::get_singleton()->get_class_icon(trect->get_meta("type"))); + } } break; case NOTIFICATION_EXIT_TREE: { diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index f38c76a21aa..0df0c3a1c32 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -188,7 +188,6 @@ class SceneTreeDialog : public ConfirmationDialog { void _selected_changed(); void _filter_changed(const String &p_filter); void _show_all_nodes_changed(bool p_button_pressed); - void _update_theme(); protected: void _notification(int p_what); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index f28c989ac1e..157278e4bc0 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -263,7 +263,8 @@ void AnimationNodeBlendTreeEditor::update_graph() { mb->get_popup()->connect("index_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_anim_selected).bind(options, E), CONNECT_DEFERRED); } - Ref sb = node->get_theme_stylebox(SNAME("panel"), SNAME("GraphNode")); + // TODO: Avoid using strings, expose a method on GraphNode instead. + Ref sb = node->get_theme_stylebox(SNAME("panel")); Color c = sb->get_border_color(); Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0); mono_color.a = 0.85; @@ -831,16 +832,10 @@ void AnimationNodeBlendTreeEditor::_update_editor_settings() { graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning"))); } -void AnimationNodeBlendTreeEditor::_update_theme() { - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); - error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); -} - void AnimationNodeBlendTreeEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_editor_settings(); - _update_theme(); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { @@ -848,7 +843,8 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { - _update_theme(); + error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); if (is_visible_in_tree()) { update_graph(); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 49c8d951efc..12b709515f6 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -127,7 +127,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing); void _update_editor_settings(); - void _update_theme(); EditorFileDialog *open_file = nullptr; Ref file_loaded; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index a16d689e3dd..8a1c4ec61e7 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -38,7 +38,6 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" -#include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" #include "editor/gui/editor_file_dialog.h" #include "scene/animation/animation_blend_tree.h" @@ -53,6 +52,7 @@ #include "scene/main/window.h" #include "scene/resources/style_box_flat.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" bool AnimationNodeStateMachineEditor::can_edit(const Ref &p_node) { Ref ansm = p_node; @@ -179,8 +179,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Refget_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name - Ref line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")); - + // TODO: Avoid using strings, expose a method on LineEdit. + Ref line_sb = name_edit->get_theme_stylebox(SNAME("normal")); Rect2 edit_rect = node_rects[i].name; edit_rect.position -= line_sb->get_offset(); edit_rect.size += line_sb->get_minimum_size(); @@ -447,8 +447,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Refgrab_focus(); - String new_over_node; - int new_over_node_what = -1; + String new_hovered_node_name; + HoveredNodeArea new_hovered_node_area = HOVER_NODE_NONE; if (tool_select->is_pressed()) { for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order. @@ -457,20 +457,20 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Refget_position())) { - new_over_node = node_rects[i].node_name; + new_hovered_node_name = node_rects[i].node_name; if (node_rects[i].play.has_point(mm->get_position())) { - new_over_node_what = 0; + new_hovered_node_area = HOVER_NODE_PLAY; } else if (node_rects[i].edit.has_point(mm->get_position())) { - new_over_node_what = 1; + new_hovered_node_area = HOVER_NODE_EDIT; } break; } } } - if (new_over_node != over_node || new_over_node_what != over_node_what) { - over_node = new_over_node; - over_node_what = new_over_node_what; + if (new_hovered_node_name != hovered_node_name || new_hovered_node_area != hovered_node_area) { + hovered_node_name = new_hovered_node_name; + hovered_node_area = new_hovered_node_area; state_machine_draw->queue_redraw(); } @@ -534,6 +534,23 @@ Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Poi return cursor_shape; } +String AnimationNodeStateMachineEditor::get_tooltip(const Point2 &p_pos) const { + if (hovered_node_name == StringName()) { + return AnimationTreeNodeEditorPlugin::get_tooltip(p_pos); + } + + String tooltip_text; + if (hovered_node_area == HOVER_NODE_PLAY) { + tooltip_text = vformat(TTR("Play/Travel to %s"), hovered_node_name); + } else if (hovered_node_area == HOVER_NODE_EDIT) { + tooltip_text = vformat(TTR("Edit %s"), hovered_node_name); + } else { + tooltip_text = hovered_node_name; + } + + return tooltip_text; +} + void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); if (!tree) { @@ -543,24 +560,29 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { menu->clear(); animations_menu->clear(); animations_to_add.clear(); - List classes; - classes.sort_custom(); - - ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); - menu->add_submenu_item(TTR("Add Animation"), "animations"); + List animation_names; if (tree->has_node(tree->get_animation_player())) { AnimationPlayer *ap = Object::cast_to(tree->get_node(tree->get_animation_player())); if (ap) { - List names; - ap->get_animation_list(&names); - for (List::Element *E = names.front(); E; E = E->next()) { - animations_menu->add_icon_item(get_editor_theme_icon("Animation"), E->get()); - animations_to_add.push_back(E->get()); - } + ap->get_animation_list(&animation_names); } } + menu->add_submenu_item(TTR("Add Animation"), "animations"); + if (animation_names.is_empty()) { + menu->set_item_disabled(menu->get_item_idx_from_text(TTR("Add Animation")), true); + } else { + for (const StringName &name : animation_names) { + animations_menu->add_icon_item(theme_cache.animation_icon, name); + animations_to_add.push_back(name); + } + } + + List classes; + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + classes.sort_custom(); + for (List::Element *E = classes.front(); E; E = E->next()) { String name = String(E->get()).replace_first("AnimationNode", ""); if (name == "Animation" || name == "StartState" || name == "EndState") { @@ -823,44 +845,29 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action } 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) { - Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label")); - Color icon_color(1, 1, 1); - Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); - - if (!p_enabled) { - linecolor.a *= 0.2; - icon_color.a *= 0.2; - accent.a *= 0.6; - } - - const Ref icons[] = { - get_editor_theme_icon(SNAME("TransitionImmediateBig")), - get_editor_theme_icon(SNAME("TransitionSyncBig")), - get_editor_theme_icon(SNAME("TransitionEndBig")), - get_editor_theme_icon(SNAME("TransitionImmediateAutoBig")), - get_editor_theme_icon(SNAME("TransitionSyncAutoBig")), - get_editor_theme_icon(SNAME("TransitionEndAutoBig")) - }; - const int ICON_COUNT = sizeof(icons) / sizeof(*icons); - - if (p_selected) { - state_machine_draw->draw_line(p_from, p_to, accent, 6); - } + 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; if (p_travel) { - linecolor = accent; + line_color = highlight_color; } - state_machine_draw->draw_line(p_from, p_to, linecolor, 2); + if (p_selected) { + state_machine_draw->draw_line(p_from, p_to, highlight_color, 6, true); + } + state_machine_draw->draw_line(p_from, p_to, line_color, 2, true); if (p_fade_ratio > 0.0) { - Color fade_linecolor = accent; - fade_linecolor.set_hsv(1.0, fade_linecolor.get_s(), fade_linecolor.get_v()); - state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_linecolor, 2); + Color fade_line_color = highlight_color; + fade_line_color.set_hsv(1.0, fade_line_color.get_s(), fade_line_color.get_v()); + state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_line_color, 2); } + + const int ICON_COUNT = sizeof(theme_cache.transition_icons) / sizeof(*theme_cache.transition_icons); int icon_index = p_mode + (p_auto_advance ? ICON_COUNT / 2 : 0); ERR_FAIL_COND(icon_index >= ICON_COUNT); - Ref icon = icons[icon_index]; + Ref icon = theme_cache.transition_icons[icon_index]; Transform2D xf; xf.columns[0] = (p_to - p_from).normalized(); @@ -904,34 +911,12 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { return; } - Ref playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); - - Ref style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode")); - Ref style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode")); - - Ref font = get_theme_font(SNAME("title_font"), SNAME("GraphNode")); - int font_size = get_theme_font_size(SNAME("title_font_size"), SNAME("GraphNode")); - Color font_color = get_theme_color(SNAME("title_color"), SNAME("GraphNode")); - Ref play = get_editor_theme_icon(SNAME("Play")); - Ref edit = get_editor_theme_icon(SNAME("Edit")); - Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor)); - Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label")); - linecolor.a *= 0.3; - Ref playing_overlay = get_theme_stylebox(SNAME("position"), SNAME("GraphNode")); - - Ref start_overlay = style->duplicate(); - start_overlay->set_border_width_all(1 * EDSCALE); - start_overlay->set_border_color(Color::html("#80f6cf")); - - Ref end_overlay = style->duplicate(); - end_overlay->set_border_width_all(1 * EDSCALE); - end_overlay->set_border_color(Color::html("#f26661")); - bool playing = false; StringName current; StringName blend_from; Vector travel_path; + Ref playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (playback.is_valid()) { playing = playback->is_playing(); current = playback->get_current_node(); @@ -940,7 +925,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } if (state_machine_draw->has_focus()) { - state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false); + state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.highlight_color, false); } int sep = 3 * EDSCALE; @@ -955,29 +940,30 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE; if (snap_x != StringName()) { Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; - state_machine_draw->draw_line(from, to, linecolor, 2); + state_machine_draw->draw_line(from, to, theme_cache.guideline_color, 2); } if (snap_y != StringName()) { Vector2 to = (state_machine->get_node_position(snap_y) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; - state_machine_draw->draw_line(from, to, linecolor, 2); + state_machine_draw->draw_line(from, to, theme_cache.guideline_color, 2); } } //pre pass nodes so we know the rectangles for (const StringName &E : nodes) { - Ref anode = state_machine->get_node(E); String name = E; - bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); - Ref sb = selected_nodes.has(E) ? style_selected : style; + int name_string_size = theme_cache.node_title_font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.node_title_font_size).width; - Size2 s = sb->get_minimum_size(); - int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; - s.width += strsize; - s.height += MAX(font->get_height(font_size), play->get_height()); - s.width += sep + play->get_width(); + Ref anode = state_machine->get_node(name); + bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); + bool is_selected = selected_nodes.has(name); + + Size2 s = (is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame)->get_minimum_size(); + s.width += name_string_size; + s.height += MAX(theme_cache.node_title_font->get_height(theme_cache.node_title_font_size), theme_cache.play_node->get_height()); + s.width += sep + theme_cache.play_node->get_width(); if (needs_editor) { - s.width += sep + edit->get_width(); + s.width += sep + theme_cache.edit_node->get_width(); } Vector2 offset; @@ -1028,8 +1014,8 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, 0.0, false, false); } - Ref tr_reference_icon = get_editor_theme_icon(SNAME("TransitionImmediateBig")); - float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8); + // TransitionImmediateBig + float tr_bidi_offset = int(theme_cache.transition_icons[0]->get_height() * 0.8); //draw transition lines for (int i = 0; i < state_machine->get_transition_count(); i++) { @@ -1117,62 +1103,60 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { //draw actual nodes for (int i = 0; i < node_rects.size(); i++) { String name = node_rects[i].node_name; + int name_string_size = theme_cache.node_title_font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.node_title_font_size).width; + Ref anode = state_machine->get_node(name); bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode); - Ref sb = selected_nodes.has(name) ? style_selected : style; - int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width; - NodeRect &nr = node_rects.write[i]; + bool is_selected = selected_nodes.has(name); + NodeRect &nr = node_rects.write[i]; Vector2 offset = nr.node.position; int h = nr.node.size.height; //prepre rect //now scroll it to draw - state_machine_draw->draw_style_box(sb, nr.node); + Ref 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); - if (state_machine->start_node == name) { - state_machine_draw->draw_style_box(sb == style_selected ? style_selected : start_overlay, nr.node); + if (!is_selected && state_machine->start_node == name) { + state_machine_draw->draw_style_box(theme_cache.node_frame_start, nr.node); } - - if (state_machine->end_node == name) { - state_machine_draw->draw_style_box(sb == style_selected ? style_selected : end_overlay, nr.node); + if (!is_selected && state_machine->end_node == name) { + state_machine_draw->draw_style_box(theme_cache.node_frame_end, nr.node); } - if (playing && (blend_from == name || current == name || travel_path.has(name))) { - state_machine_draw->draw_style_box(playing_overlay, nr.node); + state_machine_draw->draw_style_box(theme_cache.node_frame_playing, nr.node); } - offset.x += sb->get_offset().x; + offset.x += node_frame_style->get_offset().x; - nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor(); - nr.play.size = play->get_size(); + nr.play.position = offset + Vector2(0, (h - theme_cache.play_node->get_height()) / 2).floor(); + nr.play.size = theme_cache.play_node->get_size(); - Ref play_tex = play; - - if (over_node == name && over_node_what == 0) { - state_machine_draw->draw_texture(play_tex, nr.play.position, accent); + 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); } else { - state_machine_draw->draw_texture(play_tex, nr.play.position); + state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position); } - offset.x += sep + play->get_width(); + offset.x += sep + theme_cache.play_node->get_width(); - nr.name.position = offset + Vector2(0, (h - font->get_height(font_size)) / 2).floor(); - nr.name.size = Vector2(strsize, font->get_height(font_size)); + 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(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color); - offset.x += strsize + sep; + 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); + offset.x += name_string_size + sep; nr.can_edit = needs_editor; if (needs_editor) { - nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor(); - nr.edit.size = edit->get_size(); + nr.edit.position = offset + Vector2(0, (h - theme_cache.edit_node->get_height()) / 2).floor(); + nr.edit.size = theme_cache.edit_node->get_size(); - if (over_node == name && over_node_what == 1) { - state_machine_draw->draw_texture(edit, nr.edit.position, accent); + 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); } else { - state_machine_draw->draw_texture(edit, nr.edit.position); + state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position); } } } @@ -1229,7 +1213,6 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String } const NodeRect &nr = node_rects[idx]; - if (nr.can_edit) { return; // It is not AnimationNodeAnimation. } @@ -1246,16 +1229,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String } to.y = from.y; - float c = p_ratio; - Color fg = get_theme_color(SNAME("font_color"), SNAME("Label")); - Color bg = fg; - bg.a *= 0.3; - - state_machine_play_pos->draw_line(from, to, bg, 2); - - to = from.lerp(to, c); - - state_machine_play_pos->draw_line(from, to, fg, 2); + state_machine_play_pos->draw_line(from, to, theme_cache.playback_background_color, 2); + to = from.lerp(to, p_ratio); + state_machine_play_pos->draw_line(from, to, theme_cache.playback_color, 2); } void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() { @@ -1298,30 +1274,27 @@ void AnimationNodeStateMachineEditor::_update_graph() { void AnimationNodeStateMachineEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: - case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: - case NOTIFICATION_TRANSLATION_CHANGED: { - error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); - error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); + case NOTIFICATION_THEME_CHANGED: { + panel->add_theme_style_override("panel", theme_cache.panel_style); + error_panel->add_theme_style_override("panel", theme_cache.error_panel_style); + error_label->add_theme_color_override("font_color", theme_cache.error_color); - tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect"))); - tool_create->set_icon(get_editor_theme_icon(SNAME("ToolAddNode"))); - tool_connect->set_icon(get_editor_theme_icon(SNAME("ToolConnect"))); + tool_select->set_icon(theme_cache.tool_icon_select); + tool_create->set_icon(theme_cache.tool_icon_create); + tool_connect->set_icon(theme_cache.tool_icon_connect); switch_mode->clear(); - switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionImmediate")), TTR("Immediate")); - switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionSync")), TTR("Sync")); - switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionEnd")), TTR("At End")); + switch_mode->add_icon_item(theme_cache.transition_icon_immediate, TTR("Immediate")); + switch_mode->add_icon_item(theme_cache.transition_icon_sync, TTR("Sync")); + switch_mode->add_icon_item(theme_cache.transition_icon_end, TTR("At End")); - auto_advance->set_icon(get_editor_theme_icon(SNAME("AutoPlay"))); + auto_advance->set_icon(theme_cache.play_icon_auto); - tool_erase->set_icon(get_editor_theme_icon(SNAME("Remove"))); + tool_erase->set_icon(theme_cache.tool_icon_erase); play_mode->clear(); - play_mode->add_icon_item(get_editor_theme_icon(SNAME("PlayTravel")), TTR("Travel")); - play_mode->add_icon_item(get_editor_theme_icon(SNAME("Play")), TTR("Immediate")); + play_mode->add_icon_item(theme_cache.play_icon_travel, TTR("Travel")); + play_mode->add_icon_item(theme_cache.play_icon_start, TTR("Immediate")); } break; case NOTIFICATION_PROCESS: { @@ -1486,7 +1459,8 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } break; case NOTIFICATION_VISIBILITY_CHANGED: { - over_node = StringName(); + hovered_node_name = StringName(); + hovered_node_area = HOVER_NODE_NONE; set_process(is_visible_in_tree()); } break; } @@ -1638,6 +1612,56 @@ void AnimationNodeStateMachineEditor::_bind_methods() { ClassDB::bind_method("_delete_selected", &AnimationNodeStateMachineEditor::_delete_selected); ClassDB::bind_method("_delete_all", &AnimationNodeStateMachineEditor::_delete_all); ClassDB::bind_method("_delete_tree_draw", &AnimationNodeStateMachineEditor::_delete_tree_draw); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, panel_style, "panel", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, error_panel_style, "error_panel", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, error_color, "error_color", "GraphStateMachine"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_select, "ToolSelect", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_create, "ToolAddNode", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_connect, "ToolConnect", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_erase, "Remove", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_immediate, "TransitionImmediate", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_sync, "TransitionSync", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_end, "TransitionEnd", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_start, "Play", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_travel, "PlayTravel", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_auto, "AutoPlay", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, animation_icon, "Animation", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame, "node_frame", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_selected, "node_frame_selected", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_playing, "node_frame_playing", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_start, "node_frame_start", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_end, "node_frame_end", "GraphStateMachine"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_FONT, AnimationNodeStateMachineEditor, node_title_font, "node_title_font", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_FONT_SIZE, AnimationNodeStateMachineEditor, node_title_font_size, "node_title_font_size", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, node_title_font_color, "node_title_font_color", "GraphStateMachine"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_node, "Play", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, edit_node, "Edit", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_color, "transition_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_disabled_color, "transition_disabled_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_color, "transition_icon_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_disabled_color, "transition_icon_disabled_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_color, "highlight_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_disabled_color, "highlight_disabled_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, guideline_color, "guideline_color", "GraphStateMachine"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[0], "TransitionImmediateBig", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[1], "TransitionSyncBig", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[2], "TransitionEndBig", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[3], "TransitionImmediateAutoBig", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[4], "TransitionSyncAutoBig", "EditorIcons"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[5], "TransitionEndAutoBig", "EditorIcons"); + + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, playback_color, "playback_color", "GraphStateMachine"); + BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, playback_background_color, "playback_background_color", "GraphStateMachine"); } AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = nullptr; @@ -1803,15 +1827,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { Button *delete_all = delete_window->add_button(TTR("Delete All"), true); delete_all->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_all)); - - over_node_what = -1; - dragging_selected_attempt = false; - connecting = false; - selected_transition_index = -1; - - last_active = false; - - error_time = 0; } void EditorAnimationMultiTransitionEdit::add_transition(const StringName &p_from, const StringName &p_to, Ref p_transition) { diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index e289ddd5928..949fa84bcec 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -78,6 +78,53 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; + struct ThemeCache { + Ref panel_style; + Ref error_panel_style; + Color error_color; + + Ref tool_icon_select; + Ref tool_icon_create; + Ref tool_icon_connect; + Ref tool_icon_erase; + + Ref transition_icon_immediate; + Ref transition_icon_sync; + Ref transition_icon_end; + + Ref play_icon_start; + Ref play_icon_travel; + Ref play_icon_auto; + + Ref animation_icon; + + Ref node_frame; + Ref node_frame_selected; + Ref node_frame_playing; + Ref node_frame_start; + Ref node_frame_end; + + Ref node_title_font; + int node_title_font_size = 0; + Color node_title_font_color; + + Ref play_node; + Ref edit_node; + + Color transition_color; + Color transition_disabled_color; + Color transition_icon_color; + Color transition_icon_disabled_color; + Color highlight_color; + Color highlight_disabled_color; + Color guideline_color; + + Ref transition_icons[6]{}; + + Color playback_color; + Color playback_background_color; + } theme_cache; + bool updating = false; static AnimationNodeStateMachineEditor *singleton; @@ -176,11 +223,17 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { StringName selected_transition_from; StringName selected_transition_to; - int selected_transition_index; + int selected_transition_index = -1; void _add_transition(const bool p_nested_action = false); - StringName over_node; - int over_node_what = -1; + enum HoveredNodeArea { + HOVER_NODE_NONE = -1, + HOVER_NODE_PLAY = 0, + HOVER_NODE_EDIT = 1, + }; + + StringName hovered_node_name; + HoveredNodeArea hovered_node_area = HOVER_NODE_NONE; String prev_name; void _name_edited(const String &p_text); @@ -240,9 +293,13 @@ protected: public: static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } + virtual bool can_edit(const Ref &p_node) override; virtual void edit(const Ref &p_node) override; + virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override; + virtual String get_tooltip(const Point2 &p_pos) const override; + AnimationNodeStateMachineEditor(); }; diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index f53be5b8f92..1e0584e1dbe 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -177,12 +177,12 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref AnimationNodeBlendSpace1D::get_blend_point_node(int p_point) const { - ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref()); + ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Ref()); return blend_points[p_point].node; } diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 5715516a7f0..ff0be091ac9 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -114,12 +114,12 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref AnimationNodeBlendSpace2D::get_blend_point_node(int p_point) const { - ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref()); + ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Ref()); return blend_points[p_point].node; }