Path: blob/master/editor/animation/animation_blend_space_1d_editor.cpp
20969 views
/**************************************************************************/1/* animation_blend_space_1d_editor.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "animation_blend_space_1d_editor.h"3132#include "core/os/keyboard.h"33#include "editor/editor_node.h"34#include "editor/editor_string_names.h"35#include "editor/editor_undo_redo_manager.h"36#include "editor/gui/editor_file_dialog.h"37#include "editor/settings/editor_settings.h"38#include "editor/themes/editor_scale.h"39#include "scene/animation/animation_blend_tree.h"40#include "scene/gui/button.h"41#include "scene/gui/check_box.h"42#include "scene/gui/line_edit.h"43#include "scene/gui/option_button.h"44#include "scene/gui/panel_container.h"45#include "scene/gui/separator.h"46#include "scene/gui/spin_box.h"4748StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {49StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position";50return path;51}5253void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {54AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();55if (!tree) {56return;57}5859Ref<InputEventKey> k = p_event;6061if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {62if (selected_point != -1) {63if (!read_only) {64_erase_selected();65}66accept_event();67}68}6970Ref<InputEventMouseButton> mb = p_event;7172if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {73if (!read_only) {74menu->clear(false);75animations_menu->clear();76animations_to_add.clear();7778LocalVector<StringName> classes;79ClassDB::get_inheriters_from_class("AnimationRootNode", classes);80classes.sort_custom<StringName::AlphCompare>();8182menu->add_submenu_node_item(TTR("Add Animation"), animations_menu);8384List<StringName> names;85tree->get_animation_list(&names);8687for (const StringName &E : names) {88animations_menu->add_icon_item(get_editor_theme_icon(SNAME("Animation")), E);89animations_to_add.push_back(E);90}9192for (const StringName &E : classes) {93String name = String(E).replace_first("AnimationNode", "");94if (name == "Animation" || name == "StartState" || name == "EndState") {95continue;96}9798int idx = menu->get_item_count();99menu->add_item(vformat(TTR("Add %s"), name), idx);100menu->set_item_metadata(idx, E);101}102103Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();104if (clipb.is_valid()) {105menu->add_separator();106menu->add_item(TTR("Paste"), MENU_PASTE);107}108menu->add_separator();109menu->add_item(TTR("Load..."), MENU_LOAD_FILE);110111menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());112menu->reset_size();113menu->popup();114115add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;116add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());117add_point_pos += blend_space->get_min_space();118119if (snap->is_pressed()) {120add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());121}122}123}124125if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed() && mb->get_button_index() == MouseButton::LEFT) {126blend_space_draw->queue_redraw(); // why not127128// try to see if a point can be selected129selected_point = -1;130_update_tool_erase();131132for (int i = 0; i < points.size(); i++) {133if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) {134selected_point = i;135136Ref<AnimationNode> node = blend_space->get_blend_point_node(i);137EditorNode::get_singleton()->push_item(node.ptr(), "", true);138139if (mb->is_double_click() && AnimationTreeEditor::get_singleton()->can_edit(node)) {140_open_editor();141return;142}143144dragging_selected_attempt = true;145drag_from = mb->get_position();146_update_tool_erase();147_update_edited_point_pos();148return;149}150}151152// If no point was selected, select host BlendSpace1D node.153if (selected_point == -1) {154EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);155}156}157158if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {159if (!read_only) {160if (dragging_selected) {161// move162float point = blend_space->get_blend_point_position(selected_point);163point += drag_ofs.x;164165if (snap->is_pressed()) {166point = Math::snapped(point, blend_space->get_snap());167}168169updating = true;170EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();171undo_redo->create_action(TTR("Move Node Point"));172undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);173undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));174undo_redo->add_do_method(this, "_update_space");175undo_redo->add_undo_method(this, "_update_space");176undo_redo->add_do_method(this, "_update_edited_point_pos");177undo_redo->add_undo_method(this, "_update_edited_point_pos");178undo_redo->commit_action();179updating = false;180}181182dragging_selected_attempt = false;183dragging_selected = false;184blend_space_draw->queue_redraw();185}186}187188// *set* the blend189if (mb.is_valid() && mb->is_pressed() && !dragging_selected_attempt && ((tool_select->is_pressed() && mb->is_shift_pressed()) || tool_blend->is_pressed()) && mb->get_button_index() == MouseButton::LEFT) {190float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;191blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();192blend_pos += blend_space->get_min_space();193194tree->set(get_blend_position_path(), blend_pos);195196dragging_blend_position = true;197blend_space_draw->queue_redraw();198}199200if (mb.is_valid() && !mb->is_pressed() && dragging_blend_position && mb->get_button_index() == MouseButton::LEFT) {201dragging_blend_position = false;202}203204Ref<InputEventMouseMotion> mm = p_event;205206if (mm.is_valid() && dragging_selected_attempt) {207dragging_selected = true;208drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0));209blend_space_draw->queue_redraw();210_update_edited_point_pos();211}212213if (mm.is_valid() && dragging_blend_position && !dragging_selected_attempt && ((tool_select->is_pressed() && mm->is_shift_pressed()) || tool_blend->is_pressed()) && (mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {214float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;215blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();216blend_pos += blend_space->get_min_space();217218tree->set(get_blend_position_path(), blend_pos);219220blend_space_draw->queue_redraw();221}222}223224void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {225AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();226if (!tree) {227return;228}229230Color linecolor = get_theme_color(SceneStringName(font_color), SNAME("Label"));231Color linecolor_soft = linecolor;232linecolor_soft.a *= 0.5;233234Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));235int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));236Ref<Texture2D> icon = get_editor_theme_icon(SNAME("KeyValue"));237Ref<Texture2D> icon_selected = get_editor_theme_icon(SNAME("KeySelected"));238239Size2 s = blend_space_draw->get_size();240241if (blend_space_draw->has_focus()) {242Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));243blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);244}245246blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor, Math::round(EDSCALE));247248if (blend_space->get_min_space() < 0) {249float point = 0.0;250point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());251point *= s.width;252253float x = point;254255blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor, Math::round(EDSCALE));256blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);257blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft, Math::round(EDSCALE));258}259260if (snap->is_pressed()) {261linecolor_soft.a = linecolor.a * 0.1;262263if (blend_space->get_snap() > 0) {264int prev_idx = -1;265266for (int i = 0; i < s.x; i++) {267float v = blend_space->get_min_space() + i * (blend_space->get_max_space() - blend_space->get_min_space()) / s.x;268int idx = int(v / blend_space->get_snap());269270if (i > 0 && prev_idx != idx) {271blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft, Math::round(EDSCALE));272}273274prev_idx = idx;275}276}277}278279points.clear();280281for (int i = 0; i < blend_space->get_blend_point_count(); i++) {282float point = blend_space->get_blend_point_position(i);283284if (!read_only) {285if (dragging_selected && selected_point == i) {286point += drag_ofs.x;287if (snap->is_pressed()) {288point = Math::snapped(point, blend_space->get_snap());289}290}291}292293point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());294point *= s.width;295296points.push_back(point);297298Vector2 gui_point = Vector2(point, s.height / 2.0);299300gui_point -= (icon->get_size() / 2.0);301302gui_point = gui_point.floor();303304if (i == selected_point) {305blend_space_draw->draw_texture(icon_selected, gui_point);306} else {307blend_space_draw->draw_texture(icon, gui_point);308}309}310311// blend position312{313Color color;314if (tool_blend->is_pressed()) {315color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));316} else {317color = linecolor;318color.a *= 0.5;319}320321float point = tree->get(get_blend_position_path());322323point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());324point *= s.width;325326Vector2 gui_point = Vector2(point, s.height / 2.0);327328float mind = 5 * EDSCALE;329float maxd = 15 * EDSCALE;330blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, Math::round(2 * EDSCALE));331blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, Math::round(2 * EDSCALE));332blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, Math::round(2 * EDSCALE));333blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, Math::round(2 * EDSCALE));334}335}336337void AnimationNodeBlendSpace1DEditor::_update_space() {338if (updating) {339return;340}341342updating = true;343344max_value->set_value(blend_space->get_max_space());345min_value->set_value(blend_space->get_min_space());346347sync->set_pressed(blend_space->is_using_sync());348interpolation->select(blend_space->get_blend_mode());349350label_value->set_text(blend_space->get_value_label());351352snap_value->set_value(blend_space->get_snap());353354blend_space_draw->queue_redraw();355356updating = false;357}358359void AnimationNodeBlendSpace1DEditor::_config_changed(double) {360if (updating) {361return;362}363364updating = true;365EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();366undo_redo->create_action(TTR("Change BlendSpace1D Config"));367undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());368undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());369undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value());370undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());371undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value());372undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());373undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());374undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());375undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());376undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());377undo_redo->add_do_method(this, "_update_space");378undo_redo->add_undo_method(this, "_update_space");379undo_redo->commit_action();380updating = false;381382blend_space_draw->queue_redraw();383}384385void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {386if (updating) {387return;388}389390updating = true;391EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();392undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS);393undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text());394undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label());395undo_redo->add_do_method(this, "_update_space");396undo_redo->add_undo_method(this, "_update_space");397undo_redo->commit_action();398updating = false;399}400401void AnimationNodeBlendSpace1DEditor::_snap_toggled() {402blend_space_draw->queue_redraw();403}404405void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {406file_loaded = ResourceLoader::load(p_file);407if (file_loaded.is_valid()) {408_add_menu_type(MENU_LOAD_FILE_CONFIRM);409} else {410EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));411}412}413414void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {415Ref<AnimationRootNode> node;416if (p_index == MENU_LOAD_FILE) {417open_file->clear_filters();418List<String> filters;419ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);420for (const String &E : filters) {421open_file->add_filter("*." + E);422}423open_file->popup_file_dialog();424return;425} else if (p_index == MENU_LOAD_FILE_CONFIRM) {426node = file_loaded;427file_loaded.unref();428} else if (p_index == MENU_PASTE) {429node = EditorSettings::get_singleton()->get_resource_clipboard();430} else {431String type = menu->get_item_metadata(p_index);432433Object *obj = ClassDB::instantiate(type);434ERR_FAIL_NULL(obj);435AnimationNode *an = Object::cast_to<AnimationNode>(obj);436ERR_FAIL_NULL(an);437438node = Ref<AnimationNode>(an);439}440441if (node.is_null()) {442EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));443return;444}445446updating = true;447EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();448undo_redo->create_action(TTR("Add Node Point"));449undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);450undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());451undo_redo->add_do_method(this, "_update_space");452undo_redo->add_undo_method(this, "_update_space");453undo_redo->commit_action();454updating = false;455456blend_space_draw->queue_redraw();457}458459void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {460Ref<AnimationNodeAnimation> anim;461anim.instantiate();462463anim->set_animation(animations_to_add[p_index]);464465updating = true;466EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();467undo_redo->create_action(TTR("Add Animation Point"));468undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);469undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());470undo_redo->add_do_method(this, "_update_space");471undo_redo->add_undo_method(this, "_update_space");472undo_redo->commit_action();473updating = false;474475blend_space_draw->queue_redraw();476}477478void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {479if (p_tool == 0) {480tool_erase->show();481tool_erase_sep->show();482} else {483tool_erase->hide();484tool_erase_sep->hide();485}486487_update_tool_erase();488blend_space_draw->queue_redraw();489}490491void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {492if (updating) {493return;494}495496if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {497float pos = blend_space->get_blend_point_position(selected_point);498499if (dragging_selected) {500pos += drag_ofs.x;501502if (snap->is_pressed()) {503pos = Math::snapped(pos, blend_space->get_snap());504}505}506507updating = true;508edit_value->set_value(pos);509updating = false;510}511}512513void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {514bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();515tool_erase->set_disabled(!point_valid || read_only);516517if (point_valid) {518Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);519520if (AnimationTreeEditor::get_singleton()->can_edit(an)) {521open_editor->show();522} else {523open_editor->hide();524}525526if (!read_only) {527edit_hb->show();528} else {529edit_hb->hide();530}531} else {532edit_hb->hide();533}534}535536void AnimationNodeBlendSpace1DEditor::_erase_selected() {537if (selected_point != -1) {538updating = true;539540EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();541undo_redo->create_action(TTR("Remove BlendSpace1D Point"));542undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);543undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);544undo_redo->add_do_method(this, "_update_space");545undo_redo->add_undo_method(this, "_update_space");546undo_redo->commit_action();547548// Return selection to host BlendSpace1D node.549EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);550551updating = false;552_update_tool_erase();553554blend_space_draw->queue_redraw();555}556}557558void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {559if (updating) {560return;561}562563updating = true;564EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();565undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));566undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value());567undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));568undo_redo->add_do_method(this, "_update_space");569undo_redo->add_undo_method(this, "_update_space");570undo_redo->add_do_method(this, "_update_edited_point_pos");571undo_redo->add_undo_method(this, "_update_edited_point_pos");572undo_redo->commit_action();573updating = false;574575blend_space_draw->queue_redraw();576}577578void AnimationNodeBlendSpace1DEditor::_open_editor() {579if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {580Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);581ERR_FAIL_COND(an.is_null());582AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));583}584}585586void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {587switch (p_what) {588case NOTIFICATION_THEME_CHANGED: {589error_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));590error_label->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("error_color"), EditorStringName(Editor)));591panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));592tool_blend->set_button_icon(get_editor_theme_icon(SNAME("EditPivot")));593tool_select->set_button_icon(get_editor_theme_icon(SNAME("ToolSelect")));594tool_create->set_button_icon(get_editor_theme_icon(SNAME("EditKey")));595tool_erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));596snap->set_button_icon(get_editor_theme_icon(SNAME("SnapGrid")));597open_editor->set_button_icon(get_editor_theme_icon(SNAME("Edit")));598interpolation->clear();599interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackContinuous")), TTR("Continuous"), 0);600interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackDiscrete")), TTR("Discrete"), 1);601interpolation->add_icon_item(get_editor_theme_icon(SNAME("TrackCapture")), TTR("Capture"), 2);602} break;603604case NOTIFICATION_PROCESS: {605AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();606if (!tree) {607return;608}609610String error;611612error = tree->get_editor_error_message();613614if (error != error_label->get_text()) {615error_label->set_text(error);616if (!error.is_empty()) {617error_panel->show();618} else {619error_panel->hide();620}621}622} break;623624case NOTIFICATION_VISIBILITY_CHANGED: {625set_process(is_visible_in_tree());626} break;627}628}629630void AnimationNodeBlendSpace1DEditor::_bind_methods() {631ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space);632ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase);633634ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);635}636637bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {638Ref<AnimationNodeBlendSpace1D> b1d = p_node;639return b1d.is_valid();640}641642void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {643blend_space = p_node;644read_only = false;645646if (blend_space.is_valid()) {647read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);648649_update_space();650}651652tool_create->set_disabled(read_only);653edit_value->set_editable(!read_only);654label_value->set_editable(!read_only);655min_value->set_editable(!read_only);656max_value->set_editable(!read_only);657sync->set_disabled(read_only);658interpolation->set_disabled(read_only);659}660661AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;662663AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {664singleton = this;665666HBoxContainer *top_hb = memnew(HBoxContainer);667add_child(top_hb);668669Ref<ButtonGroup> bg;670bg.instantiate();671672tool_select = memnew(Button);673tool_select->set_theme_type_variation(SceneStringName(FlatButton));674tool_select->set_toggle_mode(true);675tool_select->set_button_group(bg);676top_hb->add_child(tool_select);677tool_select->set_pressed(true);678tool_select->set_tooltip_text(TTR("Select and move points.\nRMB: Create point at position clicked.\nShift+LMB+Drag: Set the blending position within the space."));679tool_select->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0));680681tool_create = memnew(Button);682tool_create->set_theme_type_variation(SceneStringName(FlatButton));683tool_create->set_toggle_mode(true);684tool_create->set_button_group(bg);685top_hb->add_child(tool_create);686tool_create->set_tooltip_text(TTR("Create points."));687tool_create->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(1));688689tool_blend = memnew(Button);690tool_blend->set_theme_type_variation(SceneStringName(FlatButton));691tool_blend->set_toggle_mode(true);692tool_blend->set_button_group(bg);693top_hb->add_child(tool_blend);694tool_blend->set_tooltip_text(TTR("Set the blending position within the space."));695tool_blend->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(2));696697tool_erase_sep = memnew(VSeparator);698top_hb->add_child(tool_erase_sep);699tool_erase = memnew(Button);700tool_erase->set_theme_type_variation(SceneStringName(FlatButton));701top_hb->add_child(tool_erase);702tool_erase->set_tooltip_text(TTR("Erase points."));703tool_erase->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));704705top_hb->add_child(memnew(VSeparator));706707snap = memnew(Button);708snap->set_theme_type_variation(SceneStringName(FlatButton));709snap->set_toggle_mode(true);710top_hb->add_child(snap);711snap->set_pressed(true);712snap->set_tooltip_text(TTR("Enable snap and show grid."));713snap->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled));714715snap_value = memnew(SpinBox);716top_hb->add_child(snap_value);717snap_value->set_min(0.01);718snap_value->set_step(0.01);719snap_value->set_max(1000);720snap_value->set_accessibility_name(TTRC("Grid Step"));721722top_hb->add_child(memnew(VSeparator));723top_hb->add_child(memnew(Label(TTR("Sync:"))));724sync = memnew(CheckBox);725top_hb->add_child(sync);726sync->connect(SceneStringName(toggled), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));727728top_hb->add_child(memnew(VSeparator));729730top_hb->add_child(memnew(Label(TTR("Blend:"))));731interpolation = memnew(OptionButton);732top_hb->add_child(interpolation);733interpolation->connect(SceneStringName(item_selected), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));734735edit_hb = memnew(HBoxContainer);736top_hb->add_child(edit_hb);737edit_hb->add_child(memnew(VSeparator));738edit_hb->add_child(memnew(Label(TTR("Point"))));739740edit_value = memnew(SpinBox);741edit_hb->add_child(edit_value);742edit_value->set_min(-1000);743edit_value->set_max(1000);744edit_value->set_step(0.01);745edit_value->set_accessibility_name(TTRC("Blend Value"));746edit_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_pos));747748open_editor = memnew(Button);749edit_hb->add_child(open_editor);750open_editor->set_text(TTR("Open Editor"));751open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), CONNECT_DEFERRED);752753edit_hb->hide();754open_editor->hide();755756VBoxContainer *main_vb = memnew(VBoxContainer);757add_child(main_vb);758main_vb->set_v_size_flags(SIZE_EXPAND_FILL);759760panel = memnew(PanelContainer);761panel->set_clip_contents(true);762main_vb->add_child(panel);763panel->set_h_size_flags(SIZE_EXPAND_FILL);764panel->set_v_size_flags(SIZE_EXPAND_FILL);765766blend_space_draw = memnew(Control);767blend_space_draw->connect(SceneStringName(gui_input), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input));768blend_space_draw->connect(SceneStringName(draw), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_draw));769blend_space_draw->set_focus_mode(FOCUS_ALL);770771panel->add_child(blend_space_draw);772773{774HBoxContainer *bottom_hb = memnew(HBoxContainer);775main_vb->add_child(bottom_hb);776bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL);777778min_value = memnew(SpinBox);779min_value->set_min(-10000);780min_value->set_max(0);781min_value->set_step(0.01);782min_value->set_accessibility_name(TTRC("Min"));783784max_value = memnew(SpinBox);785max_value->set_min(0.01);786max_value->set_max(10000);787max_value->set_step(0.01);788max_value->set_accessibility_name(TTRC("Max"));789790label_value = memnew(LineEdit);791label_value->set_expand_to_text_length_enabled(true);792label_value->set_accessibility_name(TTRC("Value"));793794// now add795796bottom_hb->add_child(min_value);797bottom_hb->add_spacer();798bottom_hb->add_child(label_value);799bottom_hb->add_spacer();800bottom_hb->add_child(max_value);801}802803snap_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));804min_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));805max_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));806label_value->connect(SceneStringName(text_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_labels_changed));807808error_panel = memnew(PanelContainer);809add_child(error_panel);810811error_label = memnew(Label);812error_label->set_focus_mode(FOCUS_ACCESSIBILITY);813error_panel->add_child(error_label);814error_panel->hide();815816menu = memnew(PopupMenu);817add_child(menu);818menu->connect(SceneStringName(id_pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type));819820animations_menu = memnew(PopupMenu);821animations_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);822menu->add_child(animations_menu);823animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_animation_type));824825open_file = memnew(EditorFileDialog);826add_child(open_file);827open_file->set_title(TTR("Open Animation Node"));828open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);829open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));830831set_custom_minimum_size(Size2(0, 150 * EDSCALE));832}833834835