1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-07 12:30:27 +00:00

Fix theme access and improve UX in AnimationTree editor

This commit is contained in:
Yuri Sizov
2023-09-23 21:22:33 +02:00
parent c12d63556b
commit b351cffddf
9 changed files with 292 additions and 195 deletions

View File

@@ -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<AnimationNode> &p_node) {
Ref<AnimationNodeStateMachine> ansm = p_node;
@@ -179,8 +179,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
if (!read_only) {
if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
// TODO: Avoid using strings, expose a method on LineEdit.
Ref<StyleBox> 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 Ref<InputEv
if (mm.is_valid()) {
state_machine_draw->grab_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 Ref<InputEv
}
if (node_rects[i].node.has_point(mm->get_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<StringName> classes;
classes.sort_custom<StringName::AlphCompare>();
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
menu->add_submenu_item(TTR("Add Animation"), "animations");
List<StringName> animation_names;
if (tree->has_node(tree->get_animation_player())) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
if (ap) {
List<StringName> names;
ap->get_animation_list(&names);
for (List<StringName>::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<StringName> classes;
ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
classes.sort_custom<StringName::AlphCompare>();
for (List<StringName>::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<Texture2D> 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<Texture2D> icon = icons[icon_index];
Ref<Texture2D> 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<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
Ref<StyleBoxFlat> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode"));
Ref<StyleBoxFlat> style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode"));
Ref<Font> 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<Texture2D> play = get_editor_theme_icon(SNAME("Play"));
Ref<Texture2D> 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<StyleBox> playing_overlay = get_theme_stylebox(SNAME("position"), SNAME("GraphNode"));
Ref<StyleBoxFlat> start_overlay = style->duplicate();
start_overlay->set_border_width_all(1 * EDSCALE);
start_overlay->set_border_color(Color::html("#80f6cf"));
Ref<StyleBoxFlat> 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<StringName> travel_path;
Ref<AnimationNodeStateMachinePlayback> 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<AnimationNode> anode = state_machine->get_node(E);
String name = E;
bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
Ref<StyleBox> 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<AnimationNode> 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<Texture2D> 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<AnimationNode> anode = state_machine->get_node(name);
bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
Ref<StyleBox> 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<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);
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<Texture2D> 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<AnimationNodeStateMachineTransition> p_transition) {