diff options
Diffstat (limited to 'editor')
35 files changed, 3726 insertions, 204 deletions
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 30983ca149..2f0982e5d9 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -753,7 +753,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { autoload_cache.push_back(info); } - List<Node *> to_add; for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { AutoLoadInfo &info = E->get(); @@ -763,9 +762,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { Ref<Script> scr = info.node->get_script(); info.in_editor = scr.is_valid() && scr->is_tool(); info.node->set_name(info.name); - if (info.in_editor) { - to_add.push_back(info.node); - } } if (info.is_singleton) { @@ -780,10 +776,6 @@ EditorAutoloadSettings::EditorAutoloadSettings() { } } - for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { - get_tree()->get_root()->add_child(E->get()); - } - autoload_changed = "autoload_changed"; updating_autoload = false; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 83f1cd40ba..67e1ca79f3 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -66,9 +66,11 @@ #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" #include "editor/import/resource_importer_wav.h" -#include "editor/plugins/animation_blend_space_editor.h" +#include "editor/plugins/animation_blend_space_1d_editor.h" +#include "editor/plugins/animation_blend_space_2d_editor.h" #include "editor/plugins/animation_blend_tree_editor_plugin.h" #include "editor/plugins/animation_player_editor_plugin.h" +#include "editor/plugins/animation_state_machine_editor.h" #include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/baked_lightmap_editor_plugin.h" @@ -5400,7 +5402,9 @@ EditorNode::EditorNode() { // FIXME: Disabled for Godot 3.0 as made incompatible, it needs to be ported to the new API. //add_editor_plugin(memnew(ShaderGraphEditorPlugin(this))); add_editor_plugin(memnew(AnimationNodeBlendTreeEditorPlugin(this))); - add_editor_plugin(memnew(AnimationNodeBlendSpaceEditorPlugin(this))); + add_editor_plugin(memnew(AnimationNodeBlendSpace1DEditorPlugin(this))); + add_editor_plugin(memnew(AnimationNodeBlendSpace2DEditorPlugin(this))); + add_editor_plugin(memnew(AnimationNodeStateMachineEditorPlugin(this))); add_editor_plugin(memnew(CameraEditorPlugin(this))); add_editor_plugin(memnew(ThemeEditorPlugin(this))); diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp index fcd3dc2f68..d4a97b7095 100644 --- a/editor/editor_profiler.cpp +++ b/editor/editor_profiler.cpp @@ -424,20 +424,25 @@ void EditorProfiler::_update_frame() { void EditorProfiler::_activate_pressed() { if (activate->is_pressed()) { - clear(); activate->set_icon(get_icon("Stop", "EditorIcons")); - activate->set_text(TTR("Stop Profiling")); + activate->set_text(TTR("Stop")); } else { activate->set_icon(get_icon("Play", "EditorIcons")); - activate->set_text(TTR("Start Profiling")); + activate->set_text(TTR("Start")); } emit_signal("enable_profiling", activate->is_pressed()); } +void EditorProfiler::_clear_pressed() { + + clear(); +} + void EditorProfiler::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { activate->set_icon(get_icon("Play", "EditorIcons")); + clear_button->set_icon(get_icon("Clear", "EditorIcons")); } } @@ -599,6 +604,7 @@ void EditorProfiler::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_frame"), &EditorProfiler::_update_frame); ClassDB::bind_method(D_METHOD("_update_plot"), &EditorProfiler::_update_plot); ClassDB::bind_method(D_METHOD("_activate_pressed"), &EditorProfiler::_activate_pressed); + ClassDB::bind_method(D_METHOD("_clear_pressed"), &EditorProfiler::_clear_pressed); ClassDB::bind_method(D_METHOD("_graph_tex_draw"), &EditorProfiler::_graph_tex_draw); ClassDB::bind_method(D_METHOD("_graph_tex_input"), &EditorProfiler::_graph_tex_input); ClassDB::bind_method(D_METHOD("_graph_tex_mouse_exit"), &EditorProfiler::_graph_tex_mouse_exit); @@ -625,10 +631,15 @@ EditorProfiler::EditorProfiler() { add_child(hb); activate = memnew(Button); activate->set_toggle_mode(true); - activate->set_text(TTR("Start Profiling")); + activate->set_text(TTR("Start")); activate->connect("pressed", this, "_activate_pressed"); hb->add_child(activate); + clear_button = memnew(Button); + clear_button->set_text(TTR("Clear")); + clear_button->connect("pressed", this, "_clear_pressed"); + hb->add_child(clear_button); + hb->add_child(memnew(Label(TTR("Measure:")))); display_mode = memnew(OptionButton); diff --git a/editor/editor_profiler.h b/editor/editor_profiler.h index d902a97c5d..cb451475e7 100644 --- a/editor/editor_profiler.h +++ b/editor/editor_profiler.h @@ -100,6 +100,7 @@ public: private: Button *activate; + Button *clear_button; TextureRect *graph; Ref<ImageTexture> graph_texture; PoolVector<uint8_t> graph_image; @@ -133,6 +134,7 @@ private: void _update_frame(); void _activate_pressed(); + void _clear_pressed(); String _get_time_as_text(Metric &m, float p_time, int p_calls); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index ff644ad126..4045d6c3d3 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -313,8 +313,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression _initial_set("interface/editor/quit_confirmation", true); - _initial_set("interface/theme/preset", 0); - hints["interface/theme/preset"] = PropertyInfo(Variant::INT, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Custom,Grey,Godot 2,Arc,Light,Alien,Solarized (Dark),Solarized (Light)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + _initial_set("interface/theme/preset", "Default"); + hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Alien,Arc,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/theme/icon_and_font_color", 0); hints["interface/theme/icon_and_font_color"] = PropertyInfo(Variant::INT, "interface/theme/icon_and_font_color", PROPERTY_HINT_ENUM, "Auto,Dark,Light", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/theme/base_color", Color::html("#323b4f")); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 78aa3da546..98402d8df5 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -254,7 +254,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color base_color = EDITOR_DEF("interface/theme/base_color", Color::html("#323b4f")); float contrast = EDITOR_DEF("interface/theme/contrast", default_contrast); - int preset = EDITOR_DEF("interface/theme/preset", 0); + String preset = EDITOR_DEF("interface/theme/preset", "Default"); + int icon_font_color_setting = EDITOR_DEF("interface/theme/icon_and_font_color", 0); bool highlight_tabs = EDITOR_DEF("interface/theme/highlight_tabs", false); int border_size = EDITOR_DEF("interface/theme/border_size", 1); @@ -266,55 +267,52 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color preset_accent_color; Color preset_base_color; float preset_contrast; - switch (preset) { - case 0: { // Default - preset_accent_color = Color::html("#699ce8"); - preset_base_color = Color::html("#323b4f"); - preset_contrast = default_contrast; - } break; - case 1: { // Custom - accent_color = EDITOR_DEF("interface/theme/accent_color", Color::html("#699ce8")); - base_color = EDITOR_DEF("interface/theme/base_color", Color::html("#323b4f")); - contrast = EDITOR_DEF("interface/theme/contrast", default_contrast); - } break; - case 2: { // Grey - preset_accent_color = Color::html("#b8e4ff"); - preset_base_color = Color::html("#3d3d3d"); - preset_contrast = 0.2; - } break; - case 3: { // Godot 2 - preset_accent_color = Color::html("#86ace2"); - preset_base_color = Color::html("#3C3A44"); - preset_contrast = 0.25; - } break; - case 4: { // Arc - preset_accent_color = Color::html("#5294e2"); - preset_base_color = Color::html("#383c4a"); - preset_contrast = 0.25; - } break; - case 5: { // Light - preset_accent_color = Color::html("#2070ff"); - preset_base_color = Color::html("#ffffff"); - preset_contrast = 0.08; - } break; - case 6: { // Alien - preset_accent_color = Color::html("#1bfe99"); - preset_base_color = Color::html("#2f373f"); - preset_contrast = 0.25; - } break; - case 7: { // Solarized (Dark) - preset_accent_color = Color::html("#268bd2"); - preset_base_color = Color::html("#073642"); - preset_contrast = 0.15; - } break; - case 8: { // Solarized (Light) - preset_accent_color = Color::html("#268bd2"); - preset_base_color = Color::html("#fdf6e3"); - preset_contrast = 0.06; - } break; + + // Please, use alphabet order if you've added new theme here(After "Default" and "Custom") + + if (preset == "Default") { + preset_accent_color = Color::html("#699ce8"); + preset_base_color = Color::html("#323b4f"); + preset_contrast = default_contrast; + } else if (preset == "Custom") { + accent_color = EDITOR_DEF("interface/theme/accent_color", Color::html("#699ce8")); + base_color = EDITOR_DEF("interface/theme/base_color", Color::html("#323b4f")); + contrast = EDITOR_DEF("interface/theme/contrast", default_contrast); + } else if (preset == "Alien") { + preset_accent_color = Color::html("#1bfe99"); + preset_base_color = Color::html("#2f373f"); + preset_contrast = 0.25; + } else if (preset == "Arc") { + preset_accent_color = Color::html("#5294e2"); + preset_base_color = Color::html("#383c4a"); + preset_contrast = 0.25; + } else if (preset == "Godot 2") { + preset_accent_color = Color::html("#86ace2"); + preset_base_color = Color::html("#3C3A44"); + preset_contrast = 0.25; + } else if (preset == "Grey") { + preset_accent_color = Color::html("#b8e4ff"); + preset_base_color = Color::html("#3d3d3d"); + preset_contrast = 0.2; + } else if (preset == "Light") { + preset_accent_color = Color::html("#2070ff"); + preset_base_color = Color::html("#ffffff"); + preset_contrast = 0.08; + } else if (preset == "Solarized (Dark)") { + preset_accent_color = Color::html("#268bd2"); + preset_base_color = Color::html("#073642"); + preset_contrast = 0.15; + } else if (preset == "Solarized (Light)") { + preset_accent_color = Color::html("#268bd2"); + preset_base_color = Color::html("#fdf6e3"); + preset_contrast = 0.06; + } else { // Default + preset_accent_color = Color::html("#699ce8"); + preset_base_color = Color::html("#323b4f"); + preset_contrast = default_contrast; } - if (preset != 1) { + if (preset != "Custom") { accent_color = preset_accent_color; base_color = preset_base_color; contrast = preset_contrast; diff --git a/editor/icons/icon_animation_tree.svg b/editor/icons/icon_animation_tree.svg new file mode 100644 index 0000000000..046506fa37 --- /dev/null +++ b/editor/icons/icon_animation_tree.svg @@ -0,0 +1,5 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1036.4)"> +<path transform="translate(0 1036.4)" d="m1 1v14h1.166v-2h1.834v2h8v-2h2v2h1v-14h-1v2h-2v-2h-8v2h-1.834v-2h-1.166zm4 3h2v1 1h1 3v2h-2v1 1h1 1v2h-1-2a1.0001 1.0001 0 0 1 -1 -1v-1-2h-1a1.0001 1.0001 0 0 1 -1 -1v-1-1-1zm-2.834 1h1.834v2h-1.834v-2zm9.834 0h2v2h-2v-2zm-9.834 4h1.834v2h-1.834v-2zm9.834 0h2v2h-2v-2z" fill="#cea4f1"/> +</g> +</svg> diff --git a/editor/icons/icon_auto_end.svg b/editor/icons/icon_auto_end.svg new file mode 100644 index 0000000000..9e779c69f4 --- /dev/null +++ b/editor/icons/icon_auto_end.svg @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_auto_end.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1273" + inkscape:window-height="766" + id="namedview8" + showgrid="false" + inkscape:zoom="41.7193" + inkscape:cx="12.08616" + inkscape:cy="6.9898672" + inkscape:window-x="539" + inkscape:window-y="208" + inkscape:window-maximized="0" + inkscape:current-layer="svg6" /> + <path + inkscape:connector-curvature="0" + id="path2" + style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + d="m 13.999798,14 c 0.552262,-5.5e-5 0.999945,-0.447738 1,-1 V 3 c -5.5e-5,-0.5522619 -0.447738,-0.9999448 -1,-1 H 5.9997976 C 5.6959349,1.9998247 5.4084731,2.1378063 5.2185476,2.375 l -4,5 c -0.29139692,0.3649711 -0.29139692,0.8830289 0,1.248 l 4,5 c 0.189538,0.237924 0.4770584,0.376652 0.78125,0.37695 h 8.0000004 z m -1,-2 H 6.4802976 l -3.1992,-4 3.1992,-4 H 12.999798 Z M 6.9997976,10 V 6 l -2,2 z" + sodipodi:nodetypes="cccccccccccccccccccccc" /> + <g + aria-label="E" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:40px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:1;stroke:none" + id="text829" + transform="matrix(0.20475474,0,0,0.20475474,4.7903856,12.365563)"> + <path + d="M 15.129502,-36.414393 H 35.422471 V -30.7308 H 22.649034 v 5.429688 h 12.011718 v 5.683594 H 22.649034 v 6.679687 h 13.203125 v 5.6835938 H 15.129502 Z" + style="fill:#e0e0e0;fill-opacity:1" + id="path831" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/editor/icons/icon_play_travel.svg b/editor/icons/icon_play_travel.svg new file mode 100644 index 0000000000..5cd3e07e20 --- /dev/null +++ b/editor/icons/icon_play_travel.svg @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_play_travel.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1446" + inkscape:window-height="646" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="8.2818541" + inkscape:cy="5.7694884" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(0.59321602,0,0,0.59321602,-1.2203136,-611.14809)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <g + transform="matrix(0.59321602,0,0,0.59321602,7.5254716,-610.94451)" + id="g6-3"> + <g + id="g4-6"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2-7" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect842" + width="9.5593224" + height="0.54237264" + x="3.0058463" + y="8.1280737" + ry="0.27118632" /> +</svg> diff --git a/editor/icons/icon_tool_add_node.svg b/editor/icons/icon_tool_add_node.svg new file mode 100644 index 0000000000..a4ff4d08a0 --- /dev/null +++ b/editor/icons/icon_tool_add_node.svg @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_tool_add_node.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1516" + inkscape:window-height="747" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="8" + inkscape:cy="8" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <g + transform="translate(-26.001 -9.8683)" + id="g4"> + <path + style="fill:#e0e0e0;fill-opacity:1" + d="m 27.917081,1047.5557 c -0.422624,0 -0.763672,0.3411 -0.763672,0.7637 v 11.8301 c 0,0.4226 0.341048,0.7637 0.763672,0.7637 h 12.507813 c 0.422624,0 0.761719,-0.3411 0.761719,-0.7637 v -11.8301 c 0,-0.4226 -0.339095,-0.7637 -0.761719,-0.7637 z m 1.898438,1.6954 h 8.642578 c 0.422624,0 0.763672,0.341 0.763672,0.7636 v 8.5078 c 0,0.4227 -0.341048,0.7618 -0.763672,0.7618 h -8.642578 c -0.422625,0 -0.763672,-0.3391 -0.763672,-0.7618 v -8.5078 c 0,-0.4226 0.341047,-0.7636 0.763672,-0.7636 z" + id="rect821" + inkscape:connector-curvature="0" /> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect826" + width="7.7966104" + height="2.3728814" + x="30.20439" + y="1052.9802" + ry="0.76286" /> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke-width:0.88253576" + id="rect828" + width="2.3728814" + height="7.5254235" + x="32.916256" + y="1050.3361" + ry="0.72997814" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_tool_connect.svg b/editor/icons/icon_tool_connect.svg new file mode 100644 index 0000000000..91d5893163 --- /dev/null +++ b/editor/icons/icon_tool_connect.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_tool_connect.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1516" + inkscape:window-height="747" + id="namedview10" + showgrid="false" + inkscape:zoom="3.6875" + inkscape:cx="8.5909556" + inkscape:cy="7.8012075" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(0 -1036.4)" + id="g6"> + <g + transform="translate(-26.001 -9.8683)" + id="g4"> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect849" + width="14.305085" + height="2.1694915" + x="26.766621" + y="1053.1389" + ry="0.76286" /> + <path + style="fill:#e0e0e0;fill-opacity:1;stroke:none;stroke-width:1.16725671px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 30.596131,1046.927 v 14.8861 l 8.228847,-7.5722 z" + id="path853" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_end.svg b/editor/icons/icon_transition_end.svg new file mode 100644 index 0000000000..8a1937670a --- /dev/null +++ b/editor/icons/icon_transition_end.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_end.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="10.204146" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="11.16989" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_end_auto.svg b/editor/icons/icon_transition_end_auto.svg new file mode 100644 index 0000000000..18927bc4ef --- /dev/null +++ b/editor/icons/icon_transition_end_auto.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_automatic.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.56831798" + inkscape:cy="5.1473818" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(-2,-1036.4)" + id="g6" + style="fill:#77ce57;fill-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="11.16989" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_end_auto_big.svg b/editor/icons/icon_transition_end_auto_big.svg new file mode 100644 index 0000000000..aaedafaf04 --- /dev/null +++ b/editor/icons/icon_transition_end_auto_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_automatic_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="0.3064671" + inkscape:cy="14.348448" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4099529,0,0,1.4099529,-4.1975887,-1462.5094)" + id="g6" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-width:1.409953;stroke-opacity:1" + id="rect862" + width="4.3259106" + height="14.194397" + x="14.371336" + y="3.0076122" + ry="1.0755967" /> +</svg> diff --git a/editor/icons/icon_transition_end_big.svg b/editor/icons/icon_transition_end_big.svg new file mode 100644 index 0000000000..46d42e95e3 --- /dev/null +++ b/editor/icons/icon_transition_end_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_end_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="-1.1122019" + inkscape:cy="10.839132" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4203458,0,0,1.4203458,-4.29479,-1473.1325)" + id="g6" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <g + id="g4" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:#424242;stroke-width:1.42026603;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect862" + width="4.3577976" + height="14.299023" + x="14.411009" + y="3.1868868" + ry="1.0835251" /> +</svg> diff --git a/editor/icons/icon_transition_immediate.svg b/editor/icons/icon_transition_immediate.svg new file mode 100644 index 0000000000..ba16a33c91 --- /dev/null +++ b/editor/icons/icon_transition_immediate.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_immediate.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="4.0199579" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_auto.svg b/editor/icons/icon_transition_immediate_auto.svg new file mode 100644 index 0000000000..c127560145 --- /dev/null +++ b/editor/icons/icon_transition_immediate_auto.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_immediate_auto.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="-9.2592678" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="translate(-2,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east_asian:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_auto_big.svg b/editor/icons/icon_transition_immediate_auto_big.svg new file mode 100644 index 0000000000..80d35a36f3 --- /dev/null +++ b/editor/icons/icon_transition_immediate_auto_big.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_immediate_auto_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="11.321237" + inkscape:cy="3.5752171" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="matrix(1.571031,0,0,1.571031,-2.7257681,-1630.6239)" + id="g6" + style="stroke:#404040;stroke-opacity:1"> + <g + id="g4" + style="stroke:#404040;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_immediate_big.svg b/editor/icons/icon_transition_immediate_big.svg new file mode 100644 index 0000000000..108dcdd500 --- /dev/null +++ b/editor/icons/icon_transition_immediate_big.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_immediate_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.19928629" + inkscape:cy="4.534006" + inkscape:window-x="517" + inkscape:window-y="261" + inkscape:window-maximized="0" + inkscape:current-layer="g4" /> + <g + transform="matrix(1.571031,0,0,1.571031,-2.7257681,-1630.6239)" + id="g6" + style="stroke:#404040;stroke-opacity:1"> + <g + id="g4" + style="stroke:#404040;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#404040;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;fill-opacity:1" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/editor/icons/icon_transition_sync.svg b/editor/icons/icon_transition_sync.svg new file mode 100644 index 0000000000..267d806615 --- /dev/null +++ b/editor/icons/icon_transition_sync.svg @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_sync.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="10.204146" + inkscape:cy="5.3391396" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(2.5542471,-1036.4)" + id="g6"> + <g + id="g4"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="1.9655174" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_sync_auto.svg b/editor/icons/icon_transition_sync_auto.svg new file mode 100644 index 0000000000..5ce61e3a6a --- /dev/null +++ b/editor/icons/icon_transition_sync_auto.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_transition_sync_auto.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="20.85965" + inkscape:cx="0.56831798" + inkscape:cy="5.1473818" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="translate(3.0815809,-1036.4)" + id="g6" + style="fill:#77ce57;fill-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1" + id="rect862" + width="3.0681243" + height="10.067283" + x="1.9655174" + y="3.0084109" + ry="0.76286" /> +</svg> diff --git a/editor/icons/icon_transition_sync_auto_big.svg b/editor/icons/icon_transition_sync_auto_big.svg new file mode 100644 index 0000000000..3e84d76398 --- /dev/null +++ b/editor/icons/icon_transition_sync_auto_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_sync_auto_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="0.3064671" + inkscape:cy="14.348448" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4099529,0,0,1.4099529,2.1752927,-1462.5094)" + id="g6" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <g + id="g4" + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#77ce57;fill-opacity:1;fill-rule:evenodd;stroke:#41562e;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#77ce57;fill-opacity:1;stroke:#41562e;stroke-width:1.409953;stroke-opacity:1" + id="rect862" + width="4.3259106" + height="14.194397" + x="1.6255733" + y="3.0076122" + ry="1.0755967" /> +</svg> diff --git a/editor/icons/icon_transition_sync_big.svg b/editor/icons/icon_transition_sync_big.svg new file mode 100644 index 0000000000..e7cf63e0b3 --- /dev/null +++ b/editor/icons/icon_transition_sync_big.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="20" + height="20" + version="1.1" + viewBox="0 0 20 20" + id="svg8" + sodipodi:docname="icon_transition_sync_big.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1403" + inkscape:window-height="782" + id="namedview10" + showgrid="false" + inkscape:zoom="14.75" + inkscape:cx="19.226781" + inkscape:cy="9.27981" + inkscape:window-x="302" + inkscape:window-y="226" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <g + transform="matrix(1.4203458,0,0,1.4203458,1.8747015,-1473.1325)" + id="g6" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <g + id="g4" + style="stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"> + <path + d="m 4.9883,1039.4 c -0.5469,0.01 -0.98717,0.4511 -0.98828,0.998 v 8 c 1.163e-4,0.7986 0.89011,1.275 1.5547,0.8321 l 6,-4 c 0.59362,-0.3959 0.59362,-1.2682 0,-1.6641 l -6,-4 c -0.1678,-0.1111 -0.3652,-0.1689 -0.56641,-0.166 z" + dominant-baseline="auto" + style="color:#000000;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;dominant-baseline:auto;white-space:normal;shape-padding:0;isolation:auto;mix-blend-mode:normal;solid-color:#000000;fill:#e0e0e0;fill-rule:evenodd;stroke:#424242;stroke-width:0.99994373;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto" + id="path2" + inkscape:connector-curvature="0" /> + </g> + </g> + <rect + style="fill:#e0e0e0;fill-opacity:1;stroke:#424242;stroke-width:1.42026603;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect862" + width="4.3577976" + height="14.299023" + x="1.4618562" + y="3.1868868" + ry="1.0835251" /> +</svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 2fb3bf7b1e..a13f741ee7 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1785,8 +1785,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } } - Quat q = xform.basis; - q.normalize(); + Quat q = xform.basis.get_rotation_quat(); Vector3 s = xform.basis.get_scale(); Vector3 l = xform.origin; @@ -1838,8 +1837,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform; - Quat q = xform.basis; - q.normalize(); + Quat q = xform.basis.get_rotation_quat(); Vector3 s = xform.basis.get_scale(); Vector3 l = xform.origin; diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 777f757bb4..eb0bc0f782 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1989,8 +1989,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye int bone = node->joints[i].godot_bone_index; xform = skeleton->get_bone_rest(bone).affine_inverse() * xform; - rot = xform.basis; - rot.normalize(); + rot = xform.basis.get_rotation_quat(); scale = xform.basis.get_scale(); pos = xform.origin; } diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp new file mode 100644 index 0000000000..2e128db883 --- /dev/null +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -0,0 +1,741 @@ +#include "animation_blend_space_1d_editor.h" + +#include "os/keyboard.h" +#include "scene/animation/animation_blend_tree.h" + +void AnimationNodeBlendSpace1DEditorPlugin::edit(Object *p_object) { + anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace1D>(p_object)); +} + +bool AnimationNodeBlendSpace1DEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("AnimationNodeBlendSpace1D"); +} + +void AnimationNodeBlendSpace1DEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + button->show(); + editor->make_bottom_panel_item_visible(anim_tree_editor); + anim_tree_editor->set_process(true); + } else { + if (anim_tree_editor->is_visible_in_tree()) { + editor->hide_bottom_panel(); + } + + button->hide(); + anim_tree_editor->set_process(false); + } +} + +AnimationNodeBlendSpace1DEditorPlugin::AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node) { + editor = p_node; + anim_tree_editor = memnew(AnimationNodeBlendSpace1DEditor); + anim_tree_editor->set_custom_minimum_size(Size2(0, 150 * EDSCALE)); + + button = editor->add_bottom_panel_item(TTR("BlendSpace1D"), anim_tree_editor); + button->hide(); +} + +AnimationNodeBlendSpace1DEditorPlugin::~AnimationNodeBlendSpace1DEditorPlugin() { +} + +void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { + Ref<InputEventKey> k = p_event; + + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (selected_point != -1) { + _erase_selected(); + accept_event(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) { + menu->clear(); + animations_menu->clear(); + animations_to_add.clear(); + + List<StringName> classes; + ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); + classes.sort_custom<StringName::AlphCompare>(); + + menu->add_submenu_item(TTR("Add Animation"), "animations"); + + AnimationTree *gp = blend_space->get_tree(); + ERR_FAIL_COND(!gp); + + if (gp->has_node(gp->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->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_icon("Animation", "Editoricons"), E->get()); + animations_to_add.push_back(E->get()); + } + } + } + + for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { + String name = String(E->get()).replace_first("AnimationNode", ""); + if (name == "Animation") + continue; + + int idx = menu->get_item_count(); + menu->add_item(vformat("Add %s", name)); + menu->set_item_metadata(idx, E->get()); + } + + menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position())); + menu->popup(); + + add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x; + add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); + add_point_pos += blend_space->get_min_space(); + + if (snap->is_pressed()) { + add_point_pos = Math::stepify(add_point_pos, blend_space->get_snap()); + } + } + + if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + blend_space_draw->update(); // why not + + // try to see if a point can be selected + selected_point = -1; + _update_tool_erase(); + + for (int i = 0; i < points.size(); i++) { + + if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) { + selected_point = i; + + Ref<AnimationNode> node = blend_space->get_blend_point_node(i); + EditorNode::get_singleton()->push_item(node.ptr(), "", true); + dragging_selected_attempt = true; + drag_from = mb->get_position(); + _update_tool_erase(); + _update_edited_point_pos(); + return; + } + } + } + + if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) { + if (dragging_selected) { + // move + float point = blend_space->get_blend_point_position(selected_point); + point += drag_ofs.x; + + if (snap->is_pressed()) { + point = Math::stepify(point, blend_space->get_snap()); + } + + updating = true; + undo_redo->create_action("Move Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + _update_edited_point_pos(); + } + + dragging_selected_attempt = false; + dragging_selected = false; + blend_space_draw->update(); + } + + // *set* the blend + if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + float blend_pos = mb->get_position().x / blend_space_draw->get_size().x; + blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); + blend_pos += blend_space->get_min_space(); + + blend_space->set_blend_pos(blend_pos); + blend_space_draw->update(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid() && !blend_space_draw->has_focus()) { + blend_space_draw->grab_focus(); + blend_space_draw->update(); + } + + if (mm.is_valid() && dragging_selected_attempt) { + dragging_selected = true; + drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * ((blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, 0)); + blend_space_draw->update(); + _update_edited_point_pos(); + } + + if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) { + float blend_pos = mm->get_position().x / blend_space_draw->get_size().x; + blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); + blend_pos += blend_space->get_min_space(); + + blend_space->set_blend_pos(blend_pos); + blend_space_draw->update(); + } +} + +void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { + + Color linecolor = get_color("font_color", "Label"); + Color linecolor_soft = linecolor; + linecolor_soft.a *= 0.5; + + Ref<Font> font = get_font("font", "Label"); + Ref<Texture> icon = get_icon("KeyValue", "EditorIcons"); + Ref<Texture> icon_selected = get_icon("KeySelected", "EditorIcons"); + + Size2 s = blend_space_draw->get_size(); + + if (blend_space_draw->has_focus()) { + Color color = get_color("accent_color", "Editor"); + blend_space_draw->draw_rect(Rect2(Point2(), s), color, false); + } + + blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor); + + if (blend_space->get_min_space() < 0) { + float point = 0.0; + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + float x = point; + + blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); + blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height() + font->get_ascent()), "0", linecolor); + blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); + } + + if (snap->is_pressed()) { + + linecolor_soft.a = linecolor.a * 0.1; + + if (blend_space->get_snap() > 0) { + int prev_idx = -1; + + for (int i = 0; i < s.x; i++) { + float v = blend_space->get_min_space() + i * (blend_space->get_max_space() - blend_space->get_min_space()) / s.x; + int idx = int(v / blend_space->get_snap()); + + if (i > 0 && prev_idx != idx) { + blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft); + } + + prev_idx = idx; + } + } + } + + points.clear(); + + for (int i = 0; i < blend_space->get_blend_point_count(); i++) { + float point = blend_space->get_blend_point_position(i); + + if (dragging_selected && selected_point == i) { + point += drag_ofs.x; + if (snap->is_pressed()) { + point = Math::stepify(point, blend_space->get_snap()); + } + } + + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + points.push_back(point); + + Vector2 gui_point = Vector2(point, s.height / 2.0); + + gui_point -= (icon->get_size() / 2.0); + + gui_point = gui_point.floor(); + + if (i == selected_point) { + blend_space_draw->draw_texture(icon_selected, gui_point); + } else { + blend_space_draw->draw_texture(icon, gui_point); + } + } + + // blend position + { + Color color; + if (tool_blend->is_pressed()) { + color = get_color("accent_color", "Editor"); + } else { + color = linecolor; + color.a *= 0.5; + } + + float point = blend_space->get_blend_pos(); + point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); + point *= s.width; + + Vector2 gui_point = Vector2(point, s.height / 2.0); + + float mind = 5 * EDSCALE; + float maxd = 15 * EDSCALE; + blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, 2); + blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, 2); + } +} + +void AnimationNodeBlendSpace1DEditor::_update_space() { + + if (updating) + return; + + updating = true; + + if (blend_space->get_parent().is_valid()) { + goto_parent_hb->show(); + } else { + goto_parent_hb->hide(); + } + + max_value->set_value(blend_space->get_max_space()); + min_value->set_value(blend_space->get_min_space()); + + label_value->set_text(blend_space->get_value_label()); + + snap_value->set_value(blend_space->get_snap()); + + blend_space_draw->update(); + + updating = false; +} + +void AnimationNodeBlendSpace1DEditor::_config_changed(double) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Change BlendSpace1D Limits"); + undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); + undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space()); + undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_labels_changed(String) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Change BlendSpace1D Labels", UndoRedo::MERGE_ENDS); + undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text()); + undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; +} + +void AnimationNodeBlendSpace1DEditor::_snap_toggled() { + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { + String type = menu->get_item_metadata(p_index); + + Object *obj = ClassDB::instance(type); + ERR_FAIL_COND(!obj); + AnimationNode *an = Object::cast_to<AnimationNode>(obj); + ERR_FAIL_COND(!an); + + Ref<AnimationNode> node(an); + + updating = true; + undo_redo->create_action("Add Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos); + undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { + Ref<AnimationNodeAnimation> anim; + anim.instance(); + + anim->set_animation(animations_to_add[p_index]); + + updating = true; + undo_redo->create_action("Add Animation Point"); + undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos); + undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count()); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) { + + if (p_tool == 0) { + tool_erase->show(); + tool_erase_sep->show(); + } else { + tool_erase->hide(); + tool_erase_sep->hide(); + } + + _update_tool_erase(); + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() { + if (updating) + return; + + if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { + float pos = blend_space->get_blend_point_position(selected_point); + + if (dragging_selected) { + pos += drag_ofs.x; + + if (snap->is_pressed()) { + pos = Math::stepify(pos, blend_space->get_snap()); + } + } + + updating = true; + edit_value->set_value(pos); + updating = false; + } +} + +void AnimationNodeBlendSpace1DEditor::_update_tool_erase() { + + bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count(); + tool_erase->set_disabled(!point_valid); + + if (point_valid) { + Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); + + if (EditorNode::get_singleton()->item_has_editor(an.ptr())) { + open_editor->show(); + } else { + open_editor->hide(); + } + + edit_hb->show(); + } else { + edit_hb->hide(); + } +} + +void AnimationNodeBlendSpace1DEditor::_erase_selected() { + if (selected_point != -1) { + updating = true; + + undo_redo->create_action("Remove BlendSpace1D Point"); + undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); + undo_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); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->commit_action(); + + updating = false; + + blend_space_draw->update(); + } +} + +void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) { + if (updating) + return; + + updating = true; + undo_redo->create_action("Move BlendSpace1D Node Point"); + undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value()); + undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point)); + undo_redo->add_do_method(this, "_update_space"); + undo_redo->add_undo_method(this, "_update_space"); + undo_redo->add_do_method(this, "_update_edited_point_pos"); + undo_redo->add_undo_method(this, "_update_edited_point_pos"); + undo_redo->commit_action(); + updating = false; + + blend_space_draw->update(); +} + +void AnimationNodeBlendSpace1DEditor::_open_editor() { + + if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { + Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); + ERR_FAIL_COND(an.is_null()); + EditorNode::get_singleton()->edit_item(an.ptr()); + } +} + +void AnimationNodeBlendSpace1DEditor::_goto_parent() { + EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr()); +} + +void AnimationNodeBlendSpace1DEditor::_removed_from_graph() { + EditorNode::get_singleton()->edit_item(NULL); +} + +void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); + error_label->add_color_override("font_color", get_color("error_color", "Editor")); + panel->add_style_override("panel", get_stylebox("bg", "Tree")); + tool_blend->set_icon(get_icon("EditPivot", "EditorIcons")); + tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_icon("EditKey", "EditorIcons")); + tool_erase->set_icon(get_icon("Remove", "EditorIcons")); + snap->set_icon(get_icon("SnapGrid", "EditorIcons")); + open_editor->set_icon(get_icon("Edit", "EditorIcons")); + goto_parent->set_icon(get_icon("MoveUp", "EditorIcons")); + } + + if (p_what == NOTIFICATION_PROCESS) { + String error; + + if (!blend_space->get_tree()) { + error = TTR("BlendSpace1D does not belong to an AnimationTree node."); + } else if (!blend_space->get_tree()->is_active()) { + error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); + } else if (blend_space->get_tree()->is_state_invalid()) { + error = blend_space->get_tree()->get_invalid_state_reason(); + } + + if (error != error_label->get_text()) { + error_label->set_text(error); + if (error != String()) { + error_panel->show(); + } else { + error_panel->hide(); + } + } + } +} + +void AnimationNodeBlendSpace1DEditor::_bind_methods() { + ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input); + ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace1DEditor::_blend_space_draw); + ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace1DEditor::_config_changed); + ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace1DEditor::_labels_changed); + ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space); + ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace1DEditor::_snap_toggled); + ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace1DEditor::_tool_switch); + ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace1DEditor::_erase_selected); + ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase); + ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace1DEditor::_edit_point_pos); + + ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace1DEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace1DEditor::_add_animation_type); + + ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos); + + ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace1DEditor::_open_editor); + ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace1DEditor::_goto_parent); + + ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace1DEditor::_removed_from_graph); +} + +void AnimationNodeBlendSpace1DEditor::edit(AnimationNodeBlendSpace1D *p_blend_space) { + + if (blend_space.is_valid()) { + blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); + } + + if (p_blend_space) { + blend_space = Ref<AnimationNodeBlendSpace1D>(p_blend_space); + } else { + blend_space.unref(); + } + + if (blend_space.is_null()) { + hide(); + } else { + blend_space->connect("removed_from_graph", this, "_removed_from_graph"); + + _update_space(); + } +} + +AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = NULL; + +AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { + singleton = this; + updating = false; + + HBoxContainer *top_hb = memnew(HBoxContainer); + add_child(top_hb); + + Ref<ButtonGroup> bg; + bg.instance(); + + goto_parent_hb = memnew(HBoxContainer); + top_hb->add_child(goto_parent_hb); + + goto_parent = memnew(ToolButton); + goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED); + goto_parent_hb->add_child(goto_parent); + goto_parent_hb->add_child(memnew(VSeparator)); + goto_parent_hb->hide(); + + tool_blend = memnew(ToolButton); + tool_blend->set_toggle_mode(true); + tool_blend->set_button_group(bg); + top_hb->add_child(tool_blend); + tool_blend->set_pressed(true); + tool_blend->set_tooltip(TTR("Set the blending position within the space")); + tool_blend->connect("pressed", this, "_tool_switch", varray(3)); + + tool_select = memnew(ToolButton); + tool_select->set_toggle_mode(true); + tool_select->set_button_group(bg); + top_hb->add_child(tool_select); + tool_select->set_tooltip(TTR("Select and move points, create points with RMB.")); + tool_select->connect("pressed", this, "_tool_switch", varray(0)); + + tool_create = memnew(ToolButton); + tool_create->set_toggle_mode(true); + tool_create->set_button_group(bg); + top_hb->add_child(tool_create); + tool_create->set_tooltip(TTR("Create points.")); + tool_create->connect("pressed", this, "_tool_switch", varray(1)); + + tool_erase_sep = memnew(VSeparator); + top_hb->add_child(tool_erase_sep); + tool_erase = memnew(ToolButton); + top_hb->add_child(tool_erase); + tool_erase->set_tooltip(TTR("Erase points.")); + tool_erase->connect("pressed", this, "_erase_selected"); + + top_hb->add_child(memnew(VSeparator)); + + snap = memnew(ToolButton); + snap->set_toggle_mode(true); + top_hb->add_child(snap); + snap->set_pressed(true); + snap->connect("pressed", this, "_snap_toggled"); + + snap_value = memnew(SpinBox); + top_hb->add_child(snap_value); + snap_value->set_min(0.01); + snap_value->set_step(0.01); + snap_value->set_max(1000); + + edit_hb = memnew(HBoxContainer); + top_hb->add_child(edit_hb); + edit_hb->add_child(memnew(VSeparator)); + edit_hb->add_child(memnew(Label(TTR("Point")))); + + edit_value = memnew(SpinBox); + edit_hb->add_child(edit_value); + edit_value->set_min(-1000); + edit_value->set_max(1000); + edit_value->set_step(0.01); + edit_value->connect("value_changed", this, "_edit_point_pos"); + + open_editor = memnew(Button); + edit_hb->add_child(open_editor); + open_editor->set_text(TTR("Open Editor")); + open_editor->connect("pressed", this, "_open_editor", varray(), CONNECT_DEFERRED); + + edit_hb->hide(); + open_editor->hide(); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + main_vb->set_v_size_flags(SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_clip_contents(true); + main_vb->add_child(panel); + panel->set_h_size_flags(SIZE_EXPAND_FILL); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + + blend_space_draw = memnew(Control); + blend_space_draw->connect("gui_input", this, "_blend_space_gui_input"); + blend_space_draw->connect("draw", this, "_blend_space_draw"); + blend_space_draw->set_focus_mode(FOCUS_ALL); + + panel->add_child(blend_space_draw); + + { + HBoxContainer *bottom_hb = memnew(HBoxContainer); + main_vb->add_child(bottom_hb); + bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL); + + min_value = memnew(SpinBox); + min_value->set_max(0); + min_value->set_min(-10000); + min_value->set_step(0.01); + + max_value = memnew(SpinBox); + max_value->set_max(10000); + max_value->set_min(0.01); + max_value->set_step(0.01); + + label_value = memnew(LineEdit); + label_value->set_expand_to_text_length(true); + + // now add + + bottom_hb->add_child(min_value); + bottom_hb->add_spacer(); + bottom_hb->add_child(label_value); + bottom_hb->add_spacer(); + bottom_hb->add_child(max_value); + } + + snap_value->connect("value_changed", this, "_config_changed"); + min_value->connect("value_changed", this, "_config_changed"); + max_value->connect("value_changed", this, "_config_changed"); + label_value->connect("text_changed", this, "_labels_changed"); + + error_panel = memnew(PanelContainer); + add_child(error_panel); + + error_label = memnew(Label); + error_panel->add_child(error_label); + error_label->set_text("hmmm"); + + undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("index_pressed", this, "_add_menu_type"); + + animations_menu = memnew(PopupMenu); + menu->add_child(animations_menu); + animations_menu->set_name("animations"); + animations_menu->connect("index_pressed", this, "_add_animation_type"); + + selected_point = -1; + dragging_selected = false; + dragging_selected_attempt = false; + + set_custom_minimum_size(Size2(0, 150 * EDSCALE)); +} diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h new file mode 100644 index 0000000000..52139626e6 --- /dev/null +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -0,0 +1,117 @@ +#ifndef ANIMATION_BLEND_SPACE_1D_EDITOR_H +#define ANIMATION_BLEND_SPACE_1D_EDITOR_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "editor/property_editor.h" +#include "scene/animation/animation_blend_space_1d.h" +#include "scene/gui/button.h" +#include "scene/gui/graph_edit.h" +#include "scene/gui/popup.h" +#include "scene/gui/tree.h" + +class AnimationNodeBlendSpace1DEditor : public VBoxContainer { + + GDCLASS(AnimationNodeBlendSpace1DEditor, VBoxContainer) + + Ref<AnimationNodeBlendSpace1D> blend_space; + + HBoxContainer *goto_parent_hb; + ToolButton *goto_parent; + + PanelContainer *panel; + ToolButton *tool_blend; + ToolButton *tool_select; + ToolButton *tool_create; + VSeparator *tool_erase_sep; + ToolButton *tool_erase; + ToolButton *snap; + SpinBox *snap_value; + + LineEdit *label_value; + SpinBox *max_value; + SpinBox *min_value; + + HBoxContainer *edit_hb; + SpinBox *edit_value; + Button *open_editor; + + int selected_point; + + Control *blend_space_draw; + + PanelContainer *error_panel; + Label *error_label; + + bool updating; + + UndoRedo *undo_redo; + + static AnimationNodeBlendSpace1DEditor *singleton; + + void _blend_space_gui_input(const Ref<InputEvent> &p_event); + void _blend_space_draw(); + + void _update_space(); + + void _config_changed(double); + void _labels_changed(String); + void _snap_toggled(); + + PopupMenu *menu; + PopupMenu *animations_menu; + Vector<String> animations_to_add; + float add_point_pos; + Vector<float> points; + + bool dragging_selected_attempt; + bool dragging_selected; + Vector2 drag_from; + Vector2 drag_ofs; + + void _add_menu_type(int p_index); + void _add_animation_type(int p_index); + + void _tool_switch(int p_tool); + void _update_edited_point_pos(); + void _update_tool_erase(); + void _erase_selected(); + void _edit_point_pos(double); + void _open_editor(); + + void _goto_parent(); + + void _removed_from_graph(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; } + void edit(AnimationNodeBlendSpace1D *p_blend_space); + AnimationNodeBlendSpace1DEditor(); +}; + +class AnimationNodeBlendSpace1DEditorPlugin : public EditorPlugin { + + GDCLASS(AnimationNodeBlendSpace1DEditorPlugin, EditorPlugin) + + AnimationNodeBlendSpace1DEditor *anim_tree_editor; + EditorNode *editor; + Button *button; + +public: + virtual String get_name() const { return "BlendSpace1D"; } + + bool has_main_screen() const { return false; } + + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + AnimationNodeBlendSpace1DEditorPlugin(EditorNode *p_node); + ~AnimationNodeBlendSpace1DEditorPlugin(); +}; + +#endif // ANIMATION_BLEND_SPACE_1D_EDITOR_H diff --git a/editor/plugins/animation_blend_space_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 9118211bf2..8d17062248 100644 --- a/editor/plugins/animation_blend_space_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -1,4 +1,4 @@ -#include "animation_blend_space_editor.h" +#include "animation_blend_space_2d_editor.h" #include "core/io/resource_loader.h" #include "core/project_settings.h" @@ -11,14 +11,14 @@ #include "scene/gui/panel.h" #include "scene/main/viewport.h" -void AnimationNodeBlendSpaceEditor::edit(AnimationNodeBlendSpace *p_blend_space) { +void AnimationNodeBlendSpace2DEditor::edit(AnimationNodeBlendSpace2D *p_blend_space) { if (blend_space.is_valid()) { blend_space->disconnect("removed_from_graph", this, "_removed_from_graph"); } if (p_blend_space) { - blend_space = Ref<AnimationNodeBlendSpace>(p_blend_space); + blend_space = Ref<AnimationNodeBlendSpace2D>(p_blend_space); } else { blend_space.unref(); } @@ -32,7 +32,7 @@ void AnimationNodeBlendSpaceEditor::edit(AnimationNodeBlendSpace *p_blend_space) } } -void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { +void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { @@ -54,7 +54,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationGraphPlayer *gp = blend_space->get_graph_player(); + AnimationTree *gp = blend_space->get_tree(); ERR_FAIL_COND(!gp); if (gp && gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); @@ -203,7 +203,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - blend_space->set_blend_pos(blend_pos); + blend_space->set_blend_position(blend_pos); blend_space_draw->update(); } @@ -237,12 +237,12 @@ void AnimationNodeBlendSpaceEditor::_blend_space_gui_input(const Ref<InputEvent> blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - blend_space->set_blend_pos(blend_pos); + blend_space->set_blend_position(blend_pos); blend_space_draw->update(); } } -void AnimationNodeBlendSpaceEditor::_add_menu_type(int p_index) { +void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { String type = menu->get_item_metadata(p_index); @@ -265,7 +265,7 @@ void AnimationNodeBlendSpaceEditor::_add_menu_type(int p_index) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_add_animation_type(int p_index) { +void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { Ref<AnimationNodeAnimation> anim; anim.instance(); @@ -284,7 +284,7 @@ void AnimationNodeBlendSpaceEditor::_add_animation_type(int p_index) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_update_tool_erase() { +void AnimationNodeBlendSpace2DEditor::_update_tool_erase() { tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())); if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); @@ -299,7 +299,7 @@ void AnimationNodeBlendSpaceEditor::_update_tool_erase() { } } -void AnimationNodeBlendSpaceEditor::_tool_switch(int p_tool) { +void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) { making_triangle.clear(); if (p_tool == 2) { @@ -325,7 +325,7 @@ void AnimationNodeBlendSpaceEditor::_tool_switch(int p_tool) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_blend_space_draw() { +void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { Color linecolor = get_color("font_color", "Label"); Color linecolor_soft = linecolor; @@ -352,7 +352,7 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { } if (blend_space->get_min_space().x < 0) { - int x = (blend_space->get_max_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width; + int x = (-blend_space->get_min_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width; blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor); blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height() + font->get_ascent()), "0", linecolor); blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft); @@ -490,13 +490,13 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { color.a *= 0.5; } - Vector2 point = blend_space->get_blend_pos(); + Vector2 point = blend_space->get_blend_position(); point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); point *= s; point.y = s.height - point.y; if (blend_space->get_triangle_count()) { - Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_pos()); + Vector2 closest = blend_space->get_closest_point(blend_space->get_blend_position()); closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); closest *= s; closest.y = s.height - closest.y; @@ -515,12 +515,12 @@ void AnimationNodeBlendSpaceEditor::_blend_space_draw() { } } -void AnimationNodeBlendSpaceEditor::_snap_toggled() { +void AnimationNodeBlendSpace2DEditor::_snap_toggled() { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_update_space() { +void AnimationNodeBlendSpace2DEditor::_update_space() { if (updating) return; @@ -558,12 +558,12 @@ void AnimationNodeBlendSpaceEditor::_update_space() { updating = false; } -void AnimationNodeBlendSpaceEditor::_config_changed(double) { +void AnimationNodeBlendSpace2DEditor::_config_changed(double) { if (updating) return; updating = true; - undo_redo->create_action("Change BlendSpace Limits"); + undo_redo->create_action("Change BlendSpace2D Limits"); undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value())); undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space()); undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value())); @@ -578,12 +578,12 @@ void AnimationNodeBlendSpaceEditor::_config_changed(double) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_labels_changed(String) { +void AnimationNodeBlendSpace2DEditor::_labels_changed(String) { if (updating) return; updating = true; - undo_redo->create_action("Change BlendSpace Labels", UndoRedo::MERGE_ENDS); + undo_redo->create_action("Change BlendSpace2D Labels", UndoRedo::MERGE_ENDS); undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text()); undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label()); undo_redo->add_do_method(blend_space.ptr(), "set_y_label", label_y->get_text()); @@ -594,12 +594,12 @@ void AnimationNodeBlendSpaceEditor::_labels_changed(String) { updating = false; } -void AnimationNodeBlendSpaceEditor::_erase_selected() { +void AnimationNodeBlendSpace2DEditor::_erase_selected() { if (selected_point != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace Point"); + undo_redo->create_action("Remove BlendSpace2D Point"); undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point); undo_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); @@ -622,7 +622,7 @@ void AnimationNodeBlendSpaceEditor::_erase_selected() { } else if (selected_triangle != -1) { updating = true; - undo_redo->create_action("Remove BlendSpace Triangle"); + undo_redo->create_action("Remove BlendSpace2D Triangle"); undo_redo->add_do_method(blend_space.ptr(), "remove_triangle", selected_triangle); undo_redo->add_undo_method(blend_space.ptr(), "add_triangle", blend_space->get_triangle_point(selected_triangle, 0), blend_space->get_triangle_point(selected_triangle, 1), blend_space->get_triangle_point(selected_triangle, 2), selected_triangle); @@ -635,7 +635,7 @@ void AnimationNodeBlendSpaceEditor::_erase_selected() { } } -void AnimationNodeBlendSpaceEditor::_update_edited_point_pos() { +void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() { if (updating) return; @@ -655,7 +655,7 @@ void AnimationNodeBlendSpaceEditor::_update_edited_point_pos() { } } -void AnimationNodeBlendSpaceEditor::_edit_point_pos(double) { +void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) { if (updating) return; updating = true; @@ -672,7 +672,7 @@ void AnimationNodeBlendSpaceEditor::_edit_point_pos(double) { blend_space_draw->update(); } -void AnimationNodeBlendSpaceEditor::_notification(int p_what) { +void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); @@ -693,12 +693,12 @@ void AnimationNodeBlendSpaceEditor::_notification(int p_what) { String error; - if (!blend_space->get_graph_player()) { - error = TTR("BlendSpace does not belong to an AnimationGraphPlayer node."); - } else if (!blend_space->get_graph_player()->is_active()) { - error = TTR("AnimationGraphPlayer is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (blend_space->get_graph_player()->is_state_invalid()) { - error = blend_space->get_graph_player()->get_invalid_state_reason(); + if (!blend_space->get_tree()) { + error = TTR("BlendSpace2D does not belong to an AnimationTree node."); + } else if (!blend_space->get_tree()->is_active()) { + error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); + } else if (blend_space->get_tree()->is_state_invalid()) { + error = blend_space->get_tree()->get_invalid_state_reason(); } else if (blend_space->get_triangle_count() == 0) { error = TTR("No triangles exist, so no blending can take place."); } @@ -714,7 +714,7 @@ void AnimationNodeBlendSpaceEditor::_notification(int p_what) { } } -void AnimationNodeBlendSpaceEditor::_open_editor() { +void AnimationNodeBlendSpace2DEditor::_open_editor() { if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) { Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point); @@ -723,16 +723,16 @@ void AnimationNodeBlendSpaceEditor::_open_editor() { } } -void AnimationNodeBlendSpaceEditor::_goto_parent() { +void AnimationNodeBlendSpace2DEditor::_goto_parent() { EditorNode::get_singleton()->edit_item(blend_space->get_parent().ptr()); } -void AnimationNodeBlendSpaceEditor::_removed_from_graph() { +void AnimationNodeBlendSpace2DEditor::_removed_from_graph() { EditorNode::get_singleton()->edit_item(NULL); } -void AnimationNodeBlendSpaceEditor::_auto_triangles_toggled() { +void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() { undo_redo->create_action("Toggle Auto Triangles"); undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed()); @@ -742,35 +742,35 @@ void AnimationNodeBlendSpaceEditor::_auto_triangles_toggled() { undo_redo->commit_action(); } -void AnimationNodeBlendSpaceEditor::_bind_methods() { +void AnimationNodeBlendSpace2DEditor::_bind_methods() { - ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpaceEditor::_blend_space_gui_input); - ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpaceEditor::_blend_space_draw); - ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpaceEditor::_config_changed); - ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpaceEditor::_labels_changed); - ClassDB::bind_method("_update_space", &AnimationNodeBlendSpaceEditor::_update_space); - ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpaceEditor::_snap_toggled); - ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpaceEditor::_tool_switch); - ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpaceEditor::_erase_selected); - ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpaceEditor::_update_tool_erase); - ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpaceEditor::_edit_point_pos); + ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace2DEditor::_blend_space_gui_input); + ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace2DEditor::_blend_space_draw); + ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace2DEditor::_config_changed); + ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace2DEditor::_labels_changed); + ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace2DEditor::_update_space); + ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace2DEditor::_snap_toggled); + ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace2DEditor::_tool_switch); + ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace2DEditor::_erase_selected); + ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace2DEditor::_update_tool_erase); + ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace2DEditor::_edit_point_pos); - ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpaceEditor::_add_menu_type); - ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpaceEditor::_add_animation_type); + ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace2DEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace2DEditor::_add_animation_type); - ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpaceEditor::_update_edited_point_pos); + ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos); - ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpaceEditor::_open_editor); - ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpaceEditor::_goto_parent); + ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor); + ClassDB::bind_method("_goto_parent", &AnimationNodeBlendSpace2DEditor::_goto_parent); - ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpaceEditor::_removed_from_graph); + ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph); - ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpaceEditor::_auto_triangles_toggled); + ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled); } -AnimationNodeBlendSpaceEditor *AnimationNodeBlendSpaceEditor::singleton = NULL; +AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL; -AnimationNodeBlendSpaceEditor::AnimationNodeBlendSpaceEditor() { +AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { singleton = this; updating = false; @@ -982,17 +982,17 @@ AnimationNodeBlendSpaceEditor::AnimationNodeBlendSpaceEditor() { dragging_selected_attempt = false; } -void AnimationNodeBlendSpaceEditorPlugin::edit(Object *p_object) { +void AnimationNodeBlendSpace2DEditorPlugin::edit(Object *p_object) { - anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace>(p_object)); + anim_tree_editor->edit(Object::cast_to<AnimationNodeBlendSpace2D>(p_object)); } -bool AnimationNodeBlendSpaceEditorPlugin::handles(Object *p_object) const { +bool AnimationNodeBlendSpace2DEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AnimationNodeBlendSpace"); + return p_object->is_class("AnimationNodeBlendSpace2D"); } -void AnimationNodeBlendSpaceEditorPlugin::make_visible(bool p_visible) { +void AnimationNodeBlendSpace2DEditorPlugin::make_visible(bool p_visible) { if (p_visible) { //editor->hide_animation_player_editors(); @@ -1009,15 +1009,15 @@ void AnimationNodeBlendSpaceEditorPlugin::make_visible(bool p_visible) { } } -AnimationNodeBlendSpaceEditorPlugin::AnimationNodeBlendSpaceEditorPlugin(EditorNode *p_node) { +AnimationNodeBlendSpace2DEditorPlugin::AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node) { editor = p_node; - anim_tree_editor = memnew(AnimationNodeBlendSpaceEditor); + anim_tree_editor = memnew(AnimationNodeBlendSpace2DEditor); anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); - button = editor->add_bottom_panel_item(TTR("BlendSpace"), anim_tree_editor); + button = editor->add_bottom_panel_item(TTR("BlendSpace2D"), anim_tree_editor); button->hide(); } -AnimationNodeBlendSpaceEditorPlugin::~AnimationNodeBlendSpaceEditorPlugin() { +AnimationNodeBlendSpace2DEditorPlugin::~AnimationNodeBlendSpace2DEditorPlugin() { } diff --git a/editor/plugins/animation_blend_space_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 66d2ec6cae..a0e497804e 100644 --- a/editor/plugins/animation_blend_space_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -1,10 +1,10 @@ -#ifndef ANIMATION_BLEND_SPACE_EDITOR_H -#define ANIMATION_BLEND_SPACE_EDITOR_H +#ifndef ANIMATION_BLEND_SPACE_2D_EDITOR_H +#define ANIMATION_BLEND_SPACE_2D_EDITOR_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/property_editor.h" -#include "scene/animation/animation_blend_space.h" +#include "scene/animation/animation_blend_space_2d.h" #include "scene/gui/button.h" #include "scene/gui/graph_edit.h" #include "scene/gui/popup.h" @@ -13,11 +13,11 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class AnimationNodeBlendSpaceEditor : public VBoxContainer { +class AnimationNodeBlendSpace2DEditor : public VBoxContainer { - GDCLASS(AnimationNodeBlendSpaceEditor, VBoxContainer); + GDCLASS(AnimationNodeBlendSpace2DEditor, VBoxContainer); - Ref<AnimationNodeBlendSpace> blend_space; + Ref<AnimationNodeBlendSpace2D> blend_space; HBoxContainer *goto_parent_hb; ToolButton *goto_parent; @@ -59,7 +59,7 @@ class AnimationNodeBlendSpaceEditor : public VBoxContainer { UndoRedo *undo_redo; - static AnimationNodeBlendSpaceEditor *singleton; + static AnimationNodeBlendSpace2DEditor *singleton; void _blend_space_gui_input(const Ref<InputEvent> &p_event); void _blend_space_draw(); @@ -104,27 +104,27 @@ protected: static void _bind_methods(); public: - static AnimationNodeBlendSpaceEditor *get_singleton() { return singleton; } - void edit(AnimationNodeBlendSpace *p_blend_space); - AnimationNodeBlendSpaceEditor(); + static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; } + void edit(AnimationNodeBlendSpace2D *p_blend_space); + AnimationNodeBlendSpace2DEditor(); }; -class AnimationNodeBlendSpaceEditorPlugin : public EditorPlugin { +class AnimationNodeBlendSpace2DEditorPlugin : public EditorPlugin { - GDCLASS(AnimationNodeBlendSpaceEditorPlugin, EditorPlugin); + GDCLASS(AnimationNodeBlendSpace2DEditorPlugin, EditorPlugin); - AnimationNodeBlendSpaceEditor *anim_tree_editor; + AnimationNodeBlendSpace2DEditor *anim_tree_editor; EditorNode *editor; Button *button; public: - virtual String get_name() const { return "BlendSpace"; } + virtual String get_name() const { return "BlendSpace2D"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_object); virtual bool handles(Object *p_object) const; virtual void make_visible(bool p_visible); - AnimationNodeBlendSpaceEditorPlugin(EditorNode *p_node); - ~AnimationNodeBlendSpaceEditorPlugin(); + AnimationNodeBlendSpace2DEditorPlugin(EditorNode *p_node); + ~AnimationNodeBlendSpace2DEditorPlugin(); }; -#endif // ANIMATION_BLEND_SPACE_EDITOR_H +#endif // ANIMATION_BLEND_SPACE_2D_EDITOR_H diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 0875c93a16..7d0e2929bd 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -169,7 +169,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { ProgressBar *pb = memnew(ProgressBar); - AnimationGraphPlayer *player = anim->get_graph_player(); + AnimationTree *player = anim->get_tree(); if (player->has_node(player->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); if (ap) { @@ -417,14 +417,14 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano if (updating || _filter_edit != anode) return false; - NodePath player_path = anode->get_graph_player()->get_animation_player(); + NodePath player_path = anode->get_tree()->get_animation_player(); - if (!anode->get_graph_player()->has_node(player_path)) { + if (!anode->get_tree()->has_node(player_path)) { EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); return false; } - AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_graph_player()->get_node(player_path)); + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(anode->get_tree()->get_node(player_path)); if (!player) { EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); return false; @@ -603,12 +603,12 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { String error; - if (!blend_tree->get_graph_player()) { - error = TTR("BlendTree does not belong to an AnimationGraphPlayer node."); - } else if (!blend_tree->get_graph_player()->is_active()) { - error = TTR("AnimationGraphPlayer is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (blend_tree->get_graph_player()->is_state_invalid()) { - error = blend_tree->get_graph_player()->get_invalid_state_reason(); + if (!blend_tree->get_tree()) { + error = TTR("BlendTree does not belong to an AnimationTree node."); + } else if (!blend_tree->get_tree()->is_active()) { + error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); + } else if (blend_tree->get_tree()->is_state_invalid()) { + error = blend_tree->get_tree()->get_invalid_state_reason(); } if (error != error_label->get_text()) { @@ -624,13 +624,13 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { blend_tree->get_node_connections(&conns); for (List<AnimationNodeBlendTree::NodeConnection>::Element *E = conns.front(); E; E = E->next()) { float activity = 0; - if (blend_tree->get_graph_player() && !blend_tree->get_graph_player()->is_state_invalid()) { + if (blend_tree->get_tree() && !blend_tree->get_tree()->is_state_invalid()) { activity = blend_tree->get_connection_activity(E->get().input_node, E->get().input_index); } graph->set_connection_activity(E->get().output_node, 0, E->get().input_node, E->get().input_index, activity); } - AnimationGraphPlayer *graph_player = blend_tree->get_graph_player(); + AnimationTree *graph_player = blend_tree->get_tree(); AnimationPlayer *player = NULL; if (graph_player->has_node(graph_player->get_animation_player())) { player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); @@ -774,7 +774,9 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale")); add_options.push_back(AddOption("Transition", "AnimationNodeTransition")); add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree")); - add_options.push_back(AddOption("BlendSpace", "AnimationNodeBlendSpace")); + add_options.push_back(AddOption("BlendSpace1D", "AnimationNodeBlendSpace1D")); + add_options.push_back(AddOption("BlendSpace2D", "AnimationNodeBlendSpace2D")); + add_options.push_back(AddOption("StateMachine", "AnimationNodeStateMachine")); _update_options_menu(); error_panel = memnew(PanelContainer); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp new file mode 100644 index 0000000000..04bd5f0cec --- /dev/null +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -0,0 +1,1313 @@ +#include "animation_state_machine_editor.h" + +#include "core/io/resource_loader.h" +#include "core/project_settings.h" +#include "math/delaunay.h" +#include "os/input.h" +#include "os/keyboard.h" +#include "scene/animation/animation_blend_tree.h" +#include "scene/animation/animation_player.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/panel.h" +#include "scene/main/viewport.h" + +void AnimationNodeStateMachineEditor::edit(AnimationNodeStateMachine *p_state_machine) { + + if (state_machine.is_valid()) { + state_machine->disconnect("removed_from_graph", this, "_removed_from_graph"); + } + + if (p_state_machine) { + state_machine = Ref<AnimationNodeStateMachine>(p_state_machine); + } else { + state_machine.unref(); + } + + if (state_machine.is_null()) { + hide(); + } else { + state_machine->connect("removed_from_graph", this, "_removed_from_graph"); + + selected_transition_from = StringName(); + selected_transition_to = StringName(); + selected_node = StringName(); + _update_mode(); + _update_graph(); + } +} + +void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventKey> k = p_event; + if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) { + if (selected_node != StringName() || selected_transition_to != StringName() || selected_transition_from != StringName()) { + _erase_selected(); + accept_event(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + + //Add new node + if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) { + 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"); + + AnimationTree *gp = state_machine->get_tree(); + ERR_FAIL_COND(!gp); + if (gp && gp->has_node(gp->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->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_icon("Animation", "EditorIcons"), E->get()); + animations_to_add.push_back(E->get()); + } + } + } + + for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { + + String name = String(E->get()).replace_first("AnimationNode", ""); + if (name == "Animation") + continue; // nope + int idx = menu->get_item_count(); + menu->add_item(vformat("Add %s", name)); + menu->set_item_metadata(idx, E->get()); + } + + menu->set_global_position(state_machine_draw->get_global_transform().xform(mb->get_position())); + menu->popup(); + add_node_pos = mb->get_position() / EDSCALE + state_machine->get_graph_offset(); + } + + // select node or push a field inside + if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + selected_transition_from = StringName(); + selected_transition_to = StringName(); + selected_node = StringName(); + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + + if (node_rects[i].play.has_point(mb->get_position())) { //edit name + if (play_mode->get_selected() == 1 || !state_machine->is_playing()) { + //start + state_machine->start(node_rects[i].node_name); + } else { + //travel + if (!state_machine->travel(node_rects[i].node_name)) { + + state_machine->start(node_rects[i].node_name); + //removing this due to usability.. + //error_time = 5; + //error_text = vformat(TTR("No path found from '%s' to '%s'."), state_machine->get_current_node(), node_rects[i].node_name); + } + } + state_machine_draw->update(); + return; + } + + if (node_rects[i].name.has_point(mb->get_position())) { //edit name + + Ref<StyleBox> line_sb = get_stylebox("normal", "LineEdit"); + + Rect2 edit_rect = node_rects[i].name; + edit_rect.position -= line_sb->get_offset(); + edit_rect.size += line_sb->get_minimum_size(); + + name_edit->set_global_position(state_machine_draw->get_global_transform().xform(edit_rect.position)); + name_edit->set_size(edit_rect.size); + name_edit->set_text(node_rects[i].node_name); + name_edit->show_modal(); + name_edit->grab_focus(); + name_edit->select_all(); + + prev_name = node_rects[i].node_name; + return; + } + + if (node_rects[i].edit.has_point(mb->get_position())) { //edit name + call_deferred("_open_editor", node_rects[i].node_name); + return; + } + + if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected + selected_node = node_rects[i].node_name; + + Ref<AnimationNode> anode = state_machine->get_node(selected_node); + EditorNode::get_singleton()->push_item(anode.ptr(), "", true); + state_machine_draw->update(); + dragging_selected_attempt = true; + dragging_selected = false; + drag_from = mb->get_position(); + snap_x = StringName(); + snap_y = StringName(); + _update_mode(); + return; + } + } + + //test the lines now + int closest = -1; + float closest_d = 1e20; + for (int i = 0; i < transition_lines.size(); i++) { + + Vector2 s[2] = { + transition_lines[i].from, + transition_lines[i].to + }; + Vector2 cpoint = Geometry::get_closest_point_to_segment_2d(mb->get_position(), s); + float d = cpoint.distance_to(mb->get_position()); + if (d > transition_lines[i].width) { + continue; + } + + if (d < closest_d) { + closest = i; + closest_d = d; + } + } + + if (closest >= 0) { + selected_transition_from = transition_lines[closest].from_node; + selected_transition_to = transition_lines[closest].to_node; + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest); + EditorNode::get_singleton()->push_item(tr.ptr(), "", true); + } + + state_machine_draw->update(); + _update_mode(); + } + + //end moving node + if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + + if (dragging_selected) { + + Ref<AnimationNode> an = state_machine->get_node(selected_node); + updating = true; + undo_redo->create_action("Move Node"); + undo_redo->add_do_method(an.ptr(), "set_position", an->get_position() + drag_ofs / EDSCALE); + undo_redo->add_undo_method(an.ptr(), "set_position", an->get_position()); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + } + snap_x = StringName(); + snap_y = StringName(); + + dragging_selected_attempt = false; + dragging_selected = false; + state_machine_draw->update(); + } + + //connect nodes + if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected + connecting = true; + connecting_from = node_rects[i].node_name; + connecting_to = mb->get_position(); + connecting_to_node = StringName(); + return; + } + } + } + + //end connecting nodes + if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + + if (connecting_to_node != StringName()) { + + if (state_machine->has_transition(connecting_from, connecting_to_node)) { + EditorNode::get_singleton()->show_warning("Transition exists!"); + + } else { + + Ref<AnimationNodeStateMachineTransition> tr; + tr.instance(); + tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); + + updating = true; + undo_redo->create_action("Add Transition"); + undo_redo->add_do_method(state_machine.ptr(), "add_transition", connecting_from, connecting_to_node, tr); + undo_redo->add_undo_method(state_machine.ptr(), "remove_transition", connecting_from, connecting_to_node); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + selected_transition_from = connecting_from; + selected_transition_to = connecting_to_node; + + EditorNode::get_singleton()->push_item(tr.ptr(), "", true); + _update_mode(); + } + } + connecting_to_node = StringName(); + connecting = false; + state_machine_draw->update(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + //pan window + if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) { + + h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); + v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); + } + + //move mouse while connecting + if (mm.is_valid() && connecting) { + + connecting_to = mm->get_position(); + connecting_to_node = StringName(); + state_machine_draw->update(); + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + if (node_rects[i].node_name != connecting_from && node_rects[i].node.has_point(connecting_to)) { //select node since nothing else was selected + connecting_to_node = node_rects[i].node_name; + return; + } + } + } + + //move mouse while moving a node + if (mm.is_valid() && dragging_selected_attempt) { + + dragging_selected = true; + drag_ofs = mm->get_position() - drag_from; + snap_x = StringName(); + snap_y = StringName(); + { + //snap + Vector2 cpos = state_machine->get_node(selected_node)->get_position() + drag_ofs / EDSCALE; + List<StringName> nodes; + state_machine->get_node_list(&nodes); + + float best_d_x = 1e20; + float best_d_y = 1e20; + + for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { + if (E->get() == selected_node) + continue; + Vector2 npos = state_machine->get_node(E->get())->get_position(); + + float d_x = ABS(npos.x - cpos.x); + if (d_x < MIN(5, best_d_x)) { + drag_ofs.x -= cpos.x - npos.x; + best_d_x = d_x; + snap_x = E->get(); + } + + float d_y = ABS(npos.y - cpos.y); + if (d_y < MIN(5, best_d_y)) { + drag_ofs.y -= cpos.y - npos.y; + best_d_y = d_y; + snap_y = E->get(); + } + } + } + + state_machine_draw->update(); + } + + //put ibeam (text cursor) over names to make it clearer that they are editable + if (mm.is_valid()) { + + state_machine_draw->grab_focus(); + + bool over_text_now = false; + String new_over_node = StringName(); + int new_over_node_what = -1; + if (tool_select->is_pressed()) { + + for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order + + if (node_rects[i].name.has_point(mm->get_position())) { + over_text_now = true; + break; + } + + if (node_rects[i].node.has_point(mm->get_position())) { + new_over_node = node_rects[i].node_name; + if (node_rects[i].play.has_point(mm->get_position())) { + new_over_node_what = 0; + } + if (node_rects[i].edit.has_point(mm->get_position())) { + new_over_node_what = 1; + } + } + } + } + + 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; + state_machine_draw->update(); + } + + if (over_text != over_text_now) { + + if (over_text_now) { + state_machine_draw->set_default_cursor_shape(CURSOR_IBEAM); + } else { + state_machine_draw->set_default_cursor_shape(CURSOR_ARROW); + } + + over_text = over_text_now; + } + } +} + +void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { + + String type = menu->get_item_metadata(p_index); + + Object *obj = ClassDB::instance(type); + ERR_FAIL_COND(!obj); + AnimationNode *an = Object::cast_to<AnimationNode>(obj); + ERR_FAIL_COND(!an); + + Ref<AnimationNode> node(an); + node->set_position(add_node_pos); + + String base_name = type.replace_first("AnimationNode", ""); + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + name = base_name + " " + itos(base); + } + + updating = true; + undo_redo->create_action("Add Node"); + undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node); + undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { + + Ref<AnimationNodeAnimation> anim; + anim.instance(); + + anim->set_animation(animations_to_add[p_index]); + + String base_name = animations_to_add[p_index]; + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + name = base_name + " " + itos(base); + } + + anim->set_position(add_node_pos); + + updating = true; + undo_redo->create_action("Add Node"); + undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim); + undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); +} + +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, bool p_auto_advance) { + + Color linecolor = get_color("font_color", "Label"); + Color icon_color(1, 1, 1); + Color accent = get_color("accent_color", "Editor"); + + if (!p_enabled) { + linecolor.a *= 0.2; + icon_color.a *= 0.2; + accent.a *= 0.6; + } + + Ref<Texture> icons[6] = { + get_icon("TransitionImmediateBig", "EditorIcons"), + get_icon("TransitionSyncBig", "EditorIcons"), + get_icon("TransitionEndBig", "EditorIcons"), + get_icon("TransitionImmediateAutoBig", "EditorIcons"), + get_icon("TransitionSyncAutoBig", "EditorIcons"), + get_icon("TransitionEndAutoBig", "EditorIcons") + }; + + if (p_selected) { + state_machine_draw->draw_line(p_from, p_to, accent, 6, true); + } + + if (p_travel) { + linecolor = accent; + linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v()); + } + state_machine_draw->draw_line(p_from, p_to, linecolor, 2, true); + + Ref<Texture> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; + + Transform2D xf; + xf.elements[0] = (p_to - p_from).normalized(); + xf.elements[1] = xf.elements[0].tangent(); + xf.elements[2] = (p_from + p_to) * 0.5 - xf.elements[1] * icon->get_height() * 0.5 - xf.elements[0] * icon->get_height() * 0.5; + + state_machine_draw->draw_set_transform_matrix(xf); + state_machine_draw->draw_texture(icon, Vector2(), icon_color); + state_machine_draw->draw_set_transform_matrix(Transform2D()); +} + +void AnimationNodeStateMachineEditor::_clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { + + if (r_to == r_from) + return; + + //this could be optimized... + Vector2 n = (r_to - r_from).normalized(); + while (p_rect.has_point(r_from)) { + r_from += n; + } +} + +void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect) { + + if (r_to == r_from) + return; + + //this could be optimized... + Vector2 n = (r_to - r_from).normalized(); + while (p_rect.has_point(r_to)) { + r_to -= n; + } +} + +void AnimationNodeStateMachineEditor::_state_machine_draw() { + + Ref<StyleBox> style = get_stylebox("frame", "GraphNode"); + Ref<StyleBox> style_selected = get_stylebox("selectedframe", "GraphNode"); + + Ref<Font> font = get_font("title_font", "GraphNode"); + Color font_color = get_color("title_color", "GraphNode"); + Ref<Texture> play = get_icon("Play", "EditorIcons"); + Ref<Texture> auto_play = get_icon("AutoPlay", "EditorIcons"); + Ref<Texture> edit = get_icon("Edit", "EditorIcons"); + Color accent = get_color("accent_color", "Editor"); + Color linecolor = get_color("font_color", "Label"); + linecolor.a *= 0.3; + Ref<StyleBox> playing_overlay = get_stylebox("position", "GraphNode"); + + bool playing = state_machine->is_playing(); + StringName current = state_machine->get_current_node(); + StringName blend_from = state_machine->get_blend_from_node(); + Vector<StringName> travel_path = state_machine->get_travel_path(); + + if (state_machine_draw->has_focus()) { + state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false); + } + int sep = 3 * EDSCALE; + + List<StringName> nodes; + state_machine->get_node_list(&nodes); + + node_rects.clear(); + Rect2 scroll_range(Point2(), state_machine_draw->get_size()); + + //snap lines + if (dragging_selected) { + + Vector2 from = (state_machine->get_node(selected_node)->get_position() * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE; + if (snap_x != StringName()) { + Vector2 to = (state_machine->get_node(snap_x)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; + state_machine_draw->draw_line(from, to, linecolor, 2); + } + if (snap_y != StringName()) { + Vector2 to = (state_machine->get_node(snap_y)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; + state_machine_draw->draw_line(from, to, linecolor, 2); + } + } + + //pre pass nodes so we know the rectangles + for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { + + Ref<AnimationNode> anode = state_machine->get_node(E->get()); + String name = E->get(); + bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr()); + Ref<StyleBox> sb = E->get() == selected_node ? style_selected : style; + + Size2 s = sb->get_minimum_size(); + int strsize = font->get_string_size(name).width; + s.width += strsize; + s.height += MAX(font->get_height(), play->get_height()); + s.width += sep + play->get_width(); + if (needs_editor) { + s.width += sep + edit->get_width(); + } + + Vector2 offset; + offset += anode->get_position() * EDSCALE; + if (selected_node == E->get() && dragging_selected) { + offset += drag_ofs; + } + offset -= s / 2; + offset = offset.floor(); + + //prepre rect + + NodeRect nr; + nr.node = Rect2(offset, s); + nr.node_name = E->get(); + + scroll_range = scroll_range.merge(nr.node); //merge with range + + //now scroll it to draw + nr.node.position -= state_machine->get_graph_offset() * EDSCALE; + + node_rects.push_back(nr); + } + + transition_lines.clear(); + + //draw conecting line for potential new transition + if (connecting) { + Vector2 from = (state_machine->get_node(connecting_from)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; + Vector2 to; + if (connecting_to_node != StringName()) { + to = (state_machine->get_node(connecting_to_node)->get_position() * EDSCALE) - state_machine->get_graph_offset() * EDSCALE; + } else { + to = connecting_to; + } + + for (int i = 0; i < node_rects.size(); i++) { + if (node_rects[i].node_name == connecting_from) { + _clip_src_line_to_rect(from, to, node_rects[i].node); + } + if (node_rects[i].node_name == connecting_to_node) { + _clip_dst_line_to_rect(from, to, node_rects[i].node); + } + } + + _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected()), true, false, false, false); + } + + Ref<Texture> tr_reference_icon = get_icon("TransitionImmediateBig", "EditorIcons"); + float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8); + + //draw transition lines + for (int i = 0; i < state_machine->get_transition_count(); i++) { + + TransitionLine tl; + tl.from_node = state_machine->get_transition_from(i); + Vector2 ofs_from = (dragging_selected && tl.from_node == selected_node) ? drag_ofs : Vector2(); + tl.from = (state_machine->get_node(tl.from_node)->get_position() * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE; + + tl.to_node = state_machine->get_transition_to(i); + Vector2 ofs_to = (dragging_selected && tl.to_node == selected_node) ? drag_ofs : Vector2(); + tl.to = (state_machine->get_node(tl.to_node)->get_position() * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE; + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i); + tl.disabled = tr->is_disabled(); + tl.auto_advance = tr->has_auto_advance(); + tl.mode = tr->get_switch_mode(); + tl.width = tr_bidi_offset; + + if (state_machine->has_transition(tl.to_node, tl.from_node)) { //offset if same exists + Vector2 offset = -(tl.from - tl.to).normalized().tangent() * tr_bidi_offset; + tl.from += offset; + tl.to += offset; + } + + for (int i = 0; i < node_rects.size(); i++) { + if (node_rects[i].node_name == tl.from_node) { + _clip_src_line_to_rect(tl.from, tl.to, node_rects[i].node); + } + if (node_rects[i].node_name == tl.to_node) { + _clip_dst_line_to_rect(tl.from, tl.to, node_rects[i].node); + } + } + + bool selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node; + + bool travel = false; + + if (blend_from == tl.from_node && current == tl.to_node) { + travel = true; + } + + if (travel_path.size()) { + + if (current == tl.from_node && travel_path[0] == tl.to_node) { + travel = true; + } else { + for (int j = 0; j < travel_path.size() - 1; j++) { + if (travel_path[j] == tl.from_node && travel_path[j + 1] == tl.to_node) { + travel = true; + break; + } + } + } + } + _connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, selected, travel, tl.auto_advance); + + transition_lines.push_back(tl); + } + + //draw actual nodes + for (int i = 0; i < node_rects.size(); i++) { + + String name = node_rects[i].node_name; + Ref<AnimationNode> anode = state_machine->get_node(name); + bool needs_editor = EditorNode::get_singleton()->item_has_editor(anode.ptr()); + Ref<StyleBox> sb = name == selected_node ? style_selected : style; + int strsize = font->get_string_size(name).width; + + NodeRect &nr = node_rects[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); + + if (playing && (blend_from == name || current == name || travel_path.find(name) != -1)) { + state_machine_draw->draw_style_box(playing_overlay, nr.node); + } + + bool onstart = state_machine->get_start_node() == name; + if (onstart) { + state_machine_draw->draw_string(font, offset + Vector2(0, -font->get_height() - 3 * EDSCALE + font->get_ascent()), TTR("Start"), font_color); + } + + if (state_machine->get_end_node() == name) { + + int endofs = nr.node.size.x - font->get_string_size(TTR("End")).x; + state_machine_draw->draw_string(font, offset + Vector2(endofs, -font->get_height() - 3 * EDSCALE + font->get_ascent()), TTR("End"), font_color); + } + + offset.x += sb->get_offset().x; + + nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor(); + nr.play.size = play->get_size(); + + Ref<Texture> play_tex = onstart ? auto_play : play; + + if (over_node == name && over_node_what == 0) { + state_machine_draw->draw_texture(play_tex, nr.play.position, accent); + } else { + state_machine_draw->draw_texture(play_tex, nr.play.position); + } + offset.x += sep + play->get_width(); + + nr.name.position = offset + Vector2(0, (h - font->get_height()) / 2).floor(); + nr.name.size = Vector2(strsize, font->get_height()); + + state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent()), name, font_color); + offset.x += strsize + sep; + + if (needs_editor) { + nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor(); + nr.edit.size = edit->get_size(); + + if (over_node == name && over_node_what == 1) { + state_machine_draw->draw_texture(edit, nr.edit.position, accent); + } else { + state_machine_draw->draw_texture(edit, nr.edit.position); + } + offset.x += sep + edit->get_width(); + } + } + + scroll_range = scroll_range.grow(200 * EDSCALE); + + //adjust scrollbars + updating = true; + h_scroll->set_min(scroll_range.position.x); + h_scroll->set_max(scroll_range.position.x + scroll_range.size.x); + h_scroll->set_page(state_machine_draw->get_size().x); + h_scroll->set_value(state_machine->get_graph_offset().x); + + v_scroll->set_min(scroll_range.position.y); + v_scroll->set_max(scroll_range.position.y + scroll_range.size.y); + v_scroll->set_page(state_machine_draw->get_size().y); + v_scroll->set_value(state_machine->get_graph_offset().y); + updating = false; + + state_machine_play_pos->update(); +} + +void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { + + if (!state_machine->is_playing()) + return; + + int idx = -1; + for (int i = 0; node_rects.size(); i++) { + if (node_rects[i].node_name == state_machine->get_current_node()) { + idx = i; + break; + } + } + + if (idx == -1) + return; + + NodeRect &nr = node_rects[idx]; + + Vector2 from; + from.x = nr.play.position.x; + from.y = (nr.play.position.y + nr.play.size.y + nr.node.position.y + nr.node.size.y) * 0.5; + + Vector2 to; + if (nr.edit.size.x) { + to.x = nr.edit.position.x + nr.edit.size.x; + } else { + to.x = nr.name.position.x + nr.name.size.x; + } + to.y = from.y; + + float len = MAX(0.0001, state_machine->get_current_length()); + + float pos = CLAMP(state_machine->get_current_play_pos(), 0, len); + float c = pos / len; + Color fg = get_color("font_color", "Label"); + Color bg = fg; + bg.a *= 0.3; + + state_machine_play_pos->draw_line(from, to, bg, 2); + + to = from.linear_interpolate(to, c); + + state_machine_play_pos->draw_line(from, to, fg, 2); +} + +void AnimationNodeStateMachineEditor::_update_graph() { + + if (updating) + return; + + updating = true; + + if (state_machine->get_parent().is_valid()) { + goto_parent_hbox->show(); + } else { + goto_parent_hbox->hide(); + } + + state_machine_draw->update(); + + updating = false; +} + +void AnimationNodeStateMachineEditor::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + error_panel->add_style_override("panel", get_stylebox("bg", "Tree")); + error_label->add_color_override("font_color", get_color("error_color", "Editor")); + panel->add_style_override("panel", get_stylebox("bg", "Tree")); + goto_parent->set_icon(get_icon("MoveUp", "EditorIcons")); + + tool_select->set_icon(get_icon("ToolSelect", "EditorIcons")); + tool_create->set_icon(get_icon("ToolAddNode", "EditorIcons")); + tool_connect->set_icon(get_icon("ToolConnect", "EditorIcons")); + + transition_mode->clear(); + transition_mode->add_icon_item(get_icon("TransitionImmediate", "EditorIcons"), TTR("Immediate")); + transition_mode->add_icon_item(get_icon("TransitionSync", "EditorIcons"), TTR("Sync")); + transition_mode->add_icon_item(get_icon("TransitionEnd", "EditorIcons"), TTR("At End")); + + //force filter on those, so they deform better + get_icon("TransitionImmediateBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionEndBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionSyncBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionImmediateAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionEndAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + get_icon("TransitionSyncAutoBig", "EditorIcons")->set_flags(Texture::FLAG_FILTER); + + tool_erase->set_icon(get_icon("Remove", "EditorIcons")); + tool_autoplay->set_icon(get_icon("AutoPlay", "EditorIcons")); + tool_end->set_icon(get_icon("AutoEnd", "EditorIcons")); + + play_mode->clear(); + play_mode->add_icon_item(get_icon("PlayTravel", "EditorIcons"), TTR("Travel")); + play_mode->add_icon_item(get_icon("Play", "EditorIcons"), TTR("Immediate")); + } + + if (p_what == NOTIFICATION_PROCESS) { + + String error; + + if (error_time > 0) { + error = error_text; + error_time -= get_process_delta_time(); + } else if (!state_machine->get_tree()) { + error = TTR("StateMachine does not belong to an AnimationTree node."); + } else if (!state_machine->get_tree()->is_active()) { + error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); + } else if (state_machine->get_tree()->is_state_invalid()) { + error = state_machine->get_tree()->get_invalid_state_reason(); + } else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) { + if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) { + error = TTR("Start and end nodes are needed for a sub-transition."); + } + } + + if (error != error_label->get_text()) { + error_label->set_text(error); + if (error != String()) { + error_panel->show(); + } else { + error_panel->hide(); + } + } + + for (int i = 0; i < transition_lines.size(); i++) { + int tidx = -1; + for (int j = 0; j < state_machine->get_transition_count(); j++) { + if (transition_lines[i].from_node == state_machine->get_transition_from(j) && transition_lines[i].to_node == state_machine->get_transition_to(j)) { + tidx = j; + break; + } + } + + if (tidx == -1) { //missing transition, should redraw + state_machine_draw->update(); + break; + } + + if (transition_lines[i].disabled != state_machine->get_transition(tidx)->is_disabled()) { + state_machine_draw->update(); + break; + } + + if (transition_lines[i].auto_advance != state_machine->get_transition(tidx)->has_auto_advance()) { + state_machine_draw->update(); + break; + } + + if (transition_lines[i].mode != state_machine->get_transition(tidx)->get_switch_mode()) { + state_machine_draw->update(); + break; + } + } + + bool same_travel_path = true; + Vector<StringName> tp = state_machine->get_travel_path(); + + { + + if (last_travel_path.size() != tp.size()) { + same_travel_path = false; + } else { + for (int i = 0; i < last_travel_path.size(); i++) { + if (last_travel_path[i] != tp[i]) { + same_travel_path = false; + break; + } + } + } + } + + //update if travel state changed + if (!same_travel_path || last_active != state_machine->is_playing() || last_current_node != state_machine->get_current_node() || last_blend_from_node != state_machine->get_blend_from_node()) { + + state_machine_draw->update(); + last_travel_path = tp; + last_current_node = state_machine->get_current_node(); + last_active = state_machine->is_playing(); + last_blend_from_node = state_machine->get_blend_from_node(); + state_machine_play_pos->update(); + } + + if (last_play_pos != state_machine->get_current_play_pos()) { + + last_play_pos = state_machine->get_current_play_pos(); + state_machine_play_pos->update(); + } + } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + over_node = StringName(); + } +} + +void AnimationNodeStateMachineEditor::_open_editor(const String &p_name) { + Ref<AnimationNode> an = state_machine->get_node(p_name); + ERR_FAIL_COND(!an.is_valid()); + EditorNode::get_singleton()->edit_item(an.ptr()); +} + +void AnimationNodeStateMachineEditor::_goto_parent() { + + EditorNode::get_singleton()->edit_item(state_machine->get_parent().ptr()); +} + +void AnimationNodeStateMachineEditor::_removed_from_graph() { + EditorNode::get_singleton()->edit_item(NULL); +} + +void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) { + + String new_name = p_text; + + ERR_FAIL_COND(new_name == "" || new_name.find(".") != -1 || new_name.find("/") != -1) + + ERR_FAIL_COND(new_name == prev_name); + + String base_name = new_name; + int base = 1; + String name = base_name; + while (state_machine->has_node(name)) { + base++; + name = base_name + " " + itos(base); + } + + updating = true; + undo_redo->create_action("Node Renamed"); + undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name); + undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + + state_machine_draw->update(); + + name_edit->hide(); +} + +void AnimationNodeStateMachineEditor::_scroll_changed(double) { + if (updating) + return; + + state_machine->set_graph_offset(Vector2(h_scroll->get_value(), v_scroll->get_value())); + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_erase_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + updating = true; + undo_redo->create_action("Node Removed"); + undo_redo->add_do_method(state_machine.ptr(), "remove_node", selected_node); + undo_redo->add_undo_method(state_machine.ptr(), "add_node", selected_node, state_machine->get_node(selected_node)); + for (int i = 0; i < state_machine->get_transition_count(); i++) { + String from = state_machine->get_transition_from(i); + String to = state_machine->get_transition_to(i); + if (from == selected_node || to == selected_node) { + undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(i)); + } + } + if (String(state_machine->get_start_node()) == selected_node) { + undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", selected_node); + } + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + selected_node = StringName(); + } + + if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) { + + Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to)); + updating = true; + undo_redo->create_action("Transition Removed"); + undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to); + undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + selected_transition_from = StringName(); + selected_transition_to = StringName(); + } + + state_machine_draw->update(); +} + +void AnimationNodeStateMachineEditor::_autoplay_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + + StringName new_start_node; + if (state_machine->get_start_node() == selected_node) { //toggle it + new_start_node = StringName(); + } else { + new_start_node = selected_node; + } + + updating = true; + undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->add_do_method(state_machine.ptr(), "set_start_node", new_start_node); + undo_redo->add_undo_method(state_machine.ptr(), "set_start_node", state_machine->get_start_node()); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + state_machine_draw->update(); + } +} + +void AnimationNodeStateMachineEditor::_end_selected() { + + if (selected_node != StringName() && state_machine->has_node(selected_node)) { + + StringName new_end_node; + if (state_machine->get_end_node() == selected_node) { //toggle it + new_end_node = StringName(); + } else { + new_end_node = selected_node; + } + + updating = true; + undo_redo->create_action("Set Start Node (Autoplay)"); + undo_redo->add_do_method(state_machine.ptr(), "set_end_node", new_end_node); + undo_redo->add_undo_method(state_machine.ptr(), "set_end_node", state_machine->get_end_node()); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + updating = false; + state_machine_draw->update(); + } +} +void AnimationNodeStateMachineEditor::_update_mode() { + + if (tool_select->is_pressed()) { + tool_erase_hb->show(); + tool_erase->set_disabled(selected_node == StringName() && selected_transition_from == StringName() && selected_transition_to == StringName()); + tool_autoplay->set_disabled(selected_node == StringName()); + tool_end->set_disabled(selected_node == StringName()); + } else { + tool_erase_hb->hide(); + } +} + +void AnimationNodeStateMachineEditor::_bind_methods() { + + ClassDB::bind_method("_state_machine_gui_input", &AnimationNodeStateMachineEditor::_state_machine_gui_input); + ClassDB::bind_method("_state_machine_draw", &AnimationNodeStateMachineEditor::_state_machine_draw); + ClassDB::bind_method("_state_machine_pos_draw", &AnimationNodeStateMachineEditor::_state_machine_pos_draw); + ClassDB::bind_method("_update_graph", &AnimationNodeStateMachineEditor::_update_graph); + + ClassDB::bind_method("_add_menu_type", &AnimationNodeStateMachineEditor::_add_menu_type); + ClassDB::bind_method("_add_animation_type", &AnimationNodeStateMachineEditor::_add_animation_type); + + ClassDB::bind_method("_name_edited", &AnimationNodeStateMachineEditor::_name_edited); + + ClassDB::bind_method("_goto_parent", &AnimationNodeStateMachineEditor::_goto_parent); + ClassDB::bind_method("_removed_from_graph", &AnimationNodeStateMachineEditor::_removed_from_graph); + + ClassDB::bind_method("_open_editor", &AnimationNodeStateMachineEditor::_open_editor); + ClassDB::bind_method("_scroll_changed", &AnimationNodeStateMachineEditor::_scroll_changed); + + ClassDB::bind_method("_erase_selected", &AnimationNodeStateMachineEditor::_erase_selected); + ClassDB::bind_method("_autoplay_selected", &AnimationNodeStateMachineEditor::_autoplay_selected); + ClassDB::bind_method("_end_selected", &AnimationNodeStateMachineEditor::_end_selected); + ClassDB::bind_method("_update_mode", &AnimationNodeStateMachineEditor::_update_mode); +} + +AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = NULL; + +AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { + + singleton = this; + updating = false; + + HBoxContainer *top_hb = memnew(HBoxContainer); + add_child(top_hb); + + goto_parent_hbox = memnew(HBoxContainer); + goto_parent = memnew(ToolButton); + goto_parent->connect("pressed", this, "_goto_parent", varray(), CONNECT_DEFERRED); + goto_parent_hbox->add_child(goto_parent); + goto_parent_hbox->add_child(memnew(VSeparator)); + top_hb->add_child(goto_parent_hbox); + + Ref<ButtonGroup> bg; + bg.instance(); + + tool_select = memnew(ToolButton); + top_hb->add_child(tool_select); + tool_select->set_toggle_mode(true); + tool_select->set_button_group(bg); + tool_select->set_pressed(true); + tool_select->set_tooltip(TTR("Select and move nodes.\nRMB to add new nodes.\nShift+LMB to create connections.")); + tool_select->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_create = memnew(ToolButton); + top_hb->add_child(tool_create); + tool_create->set_toggle_mode(true); + tool_create->set_button_group(bg); + tool_create->set_tooltip(TTR("Create new nodes.")); + tool_create->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_connect = memnew(ToolButton); + top_hb->add_child(tool_connect); + tool_connect->set_toggle_mode(true); + tool_connect->set_button_group(bg); + tool_connect->set_tooltip(TTR("Connect nodes.")); + tool_connect->connect("pressed", this, "_update_mode", varray(), CONNECT_DEFERRED); + + tool_erase_hb = memnew(HBoxContainer); + top_hb->add_child(tool_erase_hb); + tool_erase_hb->add_child(memnew(VSeparator)); + tool_erase = memnew(ToolButton); + tool_erase->set_tooltip(TTR("Remove selected node or transition")); + tool_erase_hb->add_child(tool_erase); + tool_erase->connect("pressed", this, "_erase_selected"); + tool_erase->set_disabled(true); + + tool_erase_hb->add_child(memnew(VSeparator)); + + tool_autoplay = memnew(ToolButton); + tool_autoplay->set_tooltip(TTR("Toggle autoplay this animation on start, restart or seek to zero.")); + tool_erase_hb->add_child(tool_autoplay); + tool_autoplay->connect("pressed", this, "_autoplay_selected"); + tool_autoplay->set_disabled(true); + + tool_end = memnew(ToolButton); + tool_end->set_tooltip(TTR("Set the end animation. This is useful for sub-transitions.")); + tool_erase_hb->add_child(tool_end); + tool_end->connect("pressed", this, "_end_selected"); + tool_end->set_disabled(true); + + top_hb->add_child(memnew(VSeparator)); + top_hb->add_child(memnew(Label(TTR("Transition: ")))); + transition_mode = memnew(OptionButton); + top_hb->add_child(transition_mode); + + top_hb->add_spacer(); + + top_hb->add_child(memnew(Label("Play Mode:"))); + play_mode = memnew(OptionButton); + top_hb->add_child(play_mode); + + GridContainer *main_grid = memnew(GridContainer); + main_grid->set_columns(2); + add_child(main_grid); + main_grid->set_v_size_flags(SIZE_EXPAND_FILL); + + panel = memnew(PanelContainer); + panel->set_clip_contents(true); + main_grid->add_child(panel); + panel->set_h_size_flags(SIZE_EXPAND_FILL); + + state_machine_draw = memnew(Control); + state_machine_draw->connect("gui_input", this, "_state_machine_gui_input"); + state_machine_draw->connect("draw", this, "_state_machine_draw"); + state_machine_draw->set_focus_mode(FOCUS_ALL); + + state_machine_play_pos = memnew(Control); + state_machine_draw->add_child(state_machine_play_pos); + state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent + state_machine_play_pos->set_anchors_and_margins_preset(PRESET_WIDE); + state_machine_play_pos->connect("draw", this, "_state_machine_pos_draw"); + + panel->add_child(state_machine_draw); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + + v_scroll = memnew(VScrollBar); + main_grid->add_child(v_scroll); + v_scroll->connect("value_changed", this, "_scroll_changed"); + + h_scroll = memnew(HScrollBar); + main_grid->add_child(h_scroll); + h_scroll->connect("value_changed", this, "_scroll_changed"); + + main_grid->add_child(memnew(Control)); //empty bottom right + + error_panel = memnew(PanelContainer); + add_child(error_panel); + error_label = memnew(Label); + error_panel->add_child(error_label); + error_label->set_text("eh"); + + undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + set_custom_minimum_size(Size2(0, 300 * EDSCALE)); + + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("index_pressed", this, "_add_menu_type"); + + animations_menu = memnew(PopupMenu); + menu->add_child(animations_menu); + animations_menu->set_name("animations"); + animations_menu->connect("index_pressed", this, "_add_animation_type"); + + name_edit = memnew(LineEdit); + state_machine_draw->add_child(name_edit); + name_edit->hide(); + name_edit->connect("text_entered", this, "_name_edited"); + name_edit->set_as_toplevel(true); + + over_text = false; + + over_node_what = -1; + dragging_selected_attempt = false; + connecting = false; + + last_active = false; + + error_time = 0; +} + +void AnimationNodeStateMachineEditorPlugin::edit(Object *p_object) { + + anim_tree_editor->edit(Object::cast_to<AnimationNodeStateMachine>(p_object)); +} + +bool AnimationNodeStateMachineEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("AnimationNodeStateMachine"); +} + +void AnimationNodeStateMachineEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) { + //editor->hide_animation_player_editors(); + //editor->animation_panel_make_visible(true); + button->show(); + editor->make_bottom_panel_item_visible(anim_tree_editor); + anim_tree_editor->set_process(true); + } else { + + if (anim_tree_editor->is_visible_in_tree()) + editor->hide_bottom_panel(); + button->hide(); + anim_tree_editor->set_process(false); + } +} + +AnimationNodeStateMachineEditorPlugin::AnimationNodeStateMachineEditorPlugin(EditorNode *p_node) { + + editor = p_node; + anim_tree_editor = memnew(AnimationNodeStateMachineEditor); + anim_tree_editor->set_custom_minimum_size(Size2(0, 300)); + + button = editor->add_bottom_panel_item(TTR("StateMachine"), anim_tree_editor); + button->hide(); +} + +AnimationNodeStateMachineEditorPlugin::~AnimationNodeStateMachineEditorPlugin() { +} diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h new file mode 100644 index 0000000000..efd3de7415 --- /dev/null +++ b/editor/plugins/animation_state_machine_editor.h @@ -0,0 +1,167 @@ +#ifndef ANIMATION_STATE_MACHINE_EDITOR_H +#define ANIMATION_STATE_MACHINE_EDITOR_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "editor/property_editor.h" +#include "scene/animation/animation_node_state_machine.h" +#include "scene/gui/button.h" +#include "scene/gui/graph_edit.h" +#include "scene/gui/popup.h" +#include "scene/gui/tree.h" + +class AnimationNodeStateMachineEditor : public VBoxContainer { + + GDCLASS(AnimationNodeStateMachineEditor, VBoxContainer); + + Ref<AnimationNodeStateMachine> state_machine; + + ToolButton *tool_select; + ToolButton *tool_create; + ToolButton *tool_connect; + LineEdit *name_edit; + + HBoxContainer *tool_erase_hb; + ToolButton *tool_erase; + ToolButton *tool_autoplay; + ToolButton *tool_end; + + OptionButton *transition_mode; + OptionButton *play_mode; + + HBoxContainer *goto_parent_hbox; + ToolButton *goto_parent; + + PanelContainer *panel; + + StringName selected_node; + + HScrollBar *h_scroll; + VScrollBar *v_scroll; + + Control *state_machine_draw; + Control *state_machine_play_pos; + + PanelContainer *error_panel; + Label *error_label; + + bool updating; + + UndoRedo *undo_redo; + + static AnimationNodeStateMachineEditor *singleton; + + void _state_machine_gui_input(const Ref<InputEvent> &p_event); + void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, bool p_auto_advance); + void _state_machine_draw(); + void _state_machine_pos_draw(); + + void _update_graph(); + + PopupMenu *menu; + PopupMenu *animations_menu; + Vector<String> animations_to_add; + + Vector2 add_node_pos; + + bool dragging_selected_attempt; + bool dragging_selected; + Vector2 drag_from; + Vector2 drag_ofs; + StringName snap_x; + StringName snap_y; + + bool connecting; + StringName connecting_from; + Vector2 connecting_to; + StringName connecting_to_node; + + void _add_menu_type(int p_index); + void _add_animation_type(int p_index); + + void _goto_parent(); + + void _removed_from_graph(); + + struct NodeRect { + StringName node_name; + Rect2 node; + Rect2 play; + Rect2 name; + Rect2 edit; + }; + + Vector<NodeRect> node_rects; + + struct TransitionLine { + StringName from_node; + StringName to_node; + Vector2 from; + Vector2 to; + AnimationNodeStateMachineTransition::SwitchMode mode; + bool disabled; + bool auto_advance; + float width; + }; + + Vector<TransitionLine> transition_lines; + + StringName selected_transition_from; + StringName selected_transition_to; + + bool over_text; + StringName over_node; + int over_node_what; + + String prev_name; + void _name_edited(const String &p_text); + void _open_editor(const String &p_name); + void _scroll_changed(double); + + void _clip_src_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect); + void _clip_dst_line_to_rect(Vector2 &r_from, Vector2 &r_to, const Rect2 &p_rect); + + void _erase_selected(); + void _update_mode(); + void _autoplay_selected(); + void _end_selected(); + + bool last_active; + StringName last_blend_from_node; + StringName last_current_node; + Vector<StringName> last_travel_path; + float last_play_pos; + + float error_time; + String error_text; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + static AnimationNodeStateMachineEditor *get_singleton() { return singleton; } + void edit(AnimationNodeStateMachine *p_state_machine); + AnimationNodeStateMachineEditor(); +}; + +class AnimationNodeStateMachineEditorPlugin : public EditorPlugin { + + GDCLASS(AnimationNodeStateMachineEditorPlugin, EditorPlugin); + + AnimationNodeStateMachineEditor *anim_tree_editor; + EditorNode *editor; + Button *button; + +public: + virtual String get_name() const { return "StateMachine"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + AnimationNodeStateMachineEditorPlugin(EditorNode *p_node); + ~AnimationNodeStateMachineEditorPlugin(); +}; + +#endif // ANIMATION_STATE_MACHINE_EDITOR_H diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 83072534b8..9724017787 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -804,12 +804,12 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { void ScriptEditor::_file_dialog_action(String p_file) { switch (file_dialog_option) { - case FILE_SAVE_THEME_AS: { + case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { editor->show_warning(TTR("Error while saving theme"), TTR("Error saving")); } } break; - case FILE_IMPORT_THEME: { + case THEME_IMPORT: { if (!EditorSettings::get_singleton()->import_text_editor_theme(p_file)) { editor->show_warning(TTR("Error importing theme"), TTR("Error importing")); } @@ -859,33 +859,6 @@ void ScriptEditor::_menu_option(int p_option) { save_all_scripts(); } break; - case FILE_IMPORT_THEME: { - file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); - file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - file_dialog_option = FILE_IMPORT_THEME; - file_dialog->clear_filters(); - file_dialog->add_filter("*.tet"); - file_dialog->popup_centered_ratio(); - file_dialog->set_title(TTR("Import Theme")); - } break; - case FILE_RELOAD_THEME: { - EditorSettings::get_singleton()->load_text_editor_theme(); - } break; - case FILE_SAVE_THEME: { - if (!EditorSettings::get_singleton()->save_text_editor_theme()) { - editor->show_warning(TTR("Error while saving theme"), TTR("Error saving")); - } - } break; - case FILE_SAVE_THEME_AS: { - file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); - file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); - file_dialog_option = FILE_SAVE_THEME_AS; - file_dialog->clear_filters(); - file_dialog->add_filter("*.tet"); - file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); - file_dialog->popup_centered_ratio(); - file_dialog->set_title(TTR("Save Theme As...")); - } break; case SEARCH_HELP: { help_search_dialog->popup(); @@ -1143,6 +1116,38 @@ void ScriptEditor::_menu_option(int p_option) { } } +void ScriptEditor::_theme_option(int p_option) { + switch (p_option) { + case THEME_IMPORT: { + file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = THEME_IMPORT; + file_dialog->clear_filters(); + file_dialog->add_filter("*.tet"); + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Import Theme")); + } break; + case THEME_RELOAD: { + EditorSettings::get_singleton()->load_text_editor_theme(); + } break; + case THEME_SAVE: { + if (!EditorSettings::get_singleton()->save_text_editor_theme()) { + editor->show_warning(TTR("Error while saving theme"), TTR("Error saving")); + } + } break; + case THEME_SAVE_AS: { + file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = THEME_SAVE_AS; + file_dialog->clear_filters(); + file_dialog->add_filter("*.tet"); + file_dialog->set_current_path(EditorSettings::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))); + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Save Theme As...")); + } break; + } +} + void ScriptEditor::_tab_changed(int p_which) { ensure_select_current(); @@ -2591,6 +2596,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs); ClassDB::bind_method("_close_other_tabs", &ScriptEditor::_close_other_tabs); ClassDB::bind_method("_open_recent_script", &ScriptEditor::_open_recent_script); + ClassDB::bind_method("_theme_option", &ScriptEditor::_theme_option); ClassDB::bind_method("_editor_play", &ScriptEditor::_editor_play); ClassDB::bind_method("_editor_pause", &ScriptEditor::_editor_pause); ClassDB::bind_method("_editor_stop", &ScriptEditor::_editor_stop); @@ -2763,10 +2769,18 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KEY_MASK_ALT | KEY_RIGHT), WINDOW_NEXT); file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme")), FILE_IMPORT_THEME); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), FILE_RELOAD_THEME); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), FILE_SAVE_THEME); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_theme_as", TTR("Save Theme As")), FILE_SAVE_THEME_AS); + + file_menu->get_popup()->add_submenu_item(TTR("Theme"), "Theme", FILE_THEME); + + theme_submenu = memnew(PopupMenu); + theme_submenu->set_name("Theme"); + file_menu->get_popup()->add_child(theme_submenu); + theme_submenu->connect("id_pressed", this, "_theme_option"); + theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme")), THEME_IMPORT); + theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD); + theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), THEME_SAVE); + theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme_as", TTR("Save Theme As")), THEME_SAVE_AS); + file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 769612bdb6..67f506fdda 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -134,10 +134,7 @@ class ScriptEditor : public PanelContainer { FILE_SAVE, FILE_SAVE_AS, FILE_SAVE_ALL, - FILE_IMPORT_THEME, - FILE_RELOAD_THEME, - FILE_SAVE_THEME, - FILE_SAVE_THEME_AS, + FILE_THEME, FILE_RUN, FILE_CLOSE, CLOSE_DOCS, @@ -168,6 +165,13 @@ class ScriptEditor : public PanelContainer { WINDOW_SELECT_BASE = 100 }; + enum { + THEME_IMPORT, + THEME_RELOAD, + THEME_SAVE, + THEME_SAVE_AS + }; + enum ScriptSortBy { SORT_BY_NAME, SORT_BY_PATH, @@ -190,6 +194,7 @@ class ScriptEditor : public PanelContainer { uint64_t idle; PopupMenu *recent_scripts; + PopupMenu *theme_submenu; Button *help_search; Button *site_search; @@ -251,6 +256,7 @@ class ScriptEditor : public PanelContainer { void _tab_changed(int p_which); void _menu_option(int p_option); + void _theme_option(int p_option); Tree *disk_changed_list; ConfirmationDialog *disk_changed; diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index eb9ab93228..ae88b3a035 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -61,7 +61,7 @@ void EditorSettingsDialog::_settings_property_edited(const String &p_name) { if (full_name == "text_editor/theme/color_theme") { property_editor->get_property_editor()->update_tree(); } else if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") { - EditorSettings::get_singleton()->set_manually("interface/theme/preset", 1); // set preset to Custom + EditorSettings::get_singleton()->set_manually("interface/theme/preset", "Custom"); // set preset to Custom } else if (full_name.begins_with("text_editor/highlighting")) { EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom"); } |