2
0

animation_blend_space_1d_editor.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*************************************************************************/
  2. /* animation_blend_space_1d_editor.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "animation_blend_space_1d_editor.h"
  31. #include "core/os/keyboard.h"
  32. #include "editor/editor_file_dialog.h"
  33. #include "editor/editor_node.h"
  34. #include "editor/editor_scale.h"
  35. #include "scene/animation/animation_blend_tree.h"
  36. StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
  37. StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position";
  38. return path;
  39. }
  40. void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
  41. Ref<InputEventKey> k = p_event;
  42. if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
  43. if (selected_point != -1) {
  44. _erase_selected();
  45. accept_event();
  46. }
  47. }
  48. Ref<InputEventMouseButton> mb = p_event;
  49. if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
  50. menu->clear();
  51. animations_menu->clear();
  52. animations_to_add.clear();
  53. List<StringName> classes;
  54. ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
  55. classes.sort_custom<StringName::AlphCompare>();
  56. menu->add_submenu_item(TTR("Add Animation"), "animations");
  57. AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
  58. ERR_FAIL_COND(!gp);
  59. if (gp->has_node(gp->get_animation_player())) {
  60. AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
  61. if (ap) {
  62. List<StringName> names;
  63. ap->get_animation_list(&names);
  64. for (const StringName &E : names) {
  65. animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
  66. animations_to_add.push_back(E);
  67. }
  68. }
  69. }
  70. for (const StringName &E : classes) {
  71. String name = String(E).replace_first("AnimationNode", "");
  72. if (name == "Animation") {
  73. continue;
  74. }
  75. int idx = menu->get_item_count();
  76. menu->add_item(vformat(TTR("Add %s"), name), idx);
  77. menu->set_item_metadata(idx, E);
  78. }
  79. Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
  80. if (clipb.is_valid()) {
  81. menu->add_separator();
  82. menu->add_item(TTR("Paste"), MENU_PASTE);
  83. }
  84. menu->add_separator();
  85. menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
  86. menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
  87. menu->reset_size();
  88. menu->popup();
  89. add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
  90. add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
  91. add_point_pos += blend_space->get_min_space();
  92. if (snap->is_pressed()) {
  93. add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
  94. }
  95. }
  96. if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  97. blend_space_draw->update(); // why not
  98. // try to see if a point can be selected
  99. selected_point = -1;
  100. _update_tool_erase();
  101. for (int i = 0; i < points.size(); i++) {
  102. if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) {
  103. selected_point = i;
  104. Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
  105. EditorNode::get_singleton()->push_item(node.ptr(), "", true);
  106. dragging_selected_attempt = true;
  107. drag_from = mb->get_position();
  108. _update_tool_erase();
  109. _update_edited_point_pos();
  110. return;
  111. }
  112. }
  113. }
  114. if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
  115. if (dragging_selected) {
  116. // move
  117. float point = blend_space->get_blend_point_position(selected_point);
  118. point += drag_ofs.x;
  119. if (snap->is_pressed()) {
  120. point = Math::snapped(point, blend_space->get_snap());
  121. }
  122. updating = true;
  123. undo_redo->create_action(TTR("Move Node Point"));
  124. undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
  125. undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
  126. undo_redo->add_do_method(this, "_update_space");
  127. undo_redo->add_undo_method(this, "_update_space");
  128. undo_redo->add_do_method(this, "_update_edited_point_pos");
  129. undo_redo->add_undo_method(this, "_update_edited_point_pos");
  130. undo_redo->commit_action();
  131. updating = false;
  132. _update_edited_point_pos();
  133. }
  134. dragging_selected_attempt = false;
  135. dragging_selected = false;
  136. blend_space_draw->update();
  137. }
  138. // *set* the blend
  139. if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  140. float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
  141. blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
  142. blend_pos += blend_space->get_min_space();
  143. AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
  144. blend_space_draw->update();
  145. }
  146. Ref<InputEventMouseMotion> mm = p_event;
  147. if (mm.is_valid() && !blend_space_draw->has_focus()) {
  148. blend_space_draw->grab_focus();
  149. blend_space_draw->update();
  150. }
  151. if (mm.is_valid() && dragging_selected_attempt) {
  152. dragging_selected = true;
  153. 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));
  154. blend_space_draw->update();
  155. _update_edited_point_pos();
  156. }
  157. if (mm.is_valid() && tool_blend->is_pressed() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
  158. float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
  159. blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
  160. blend_pos += blend_space->get_min_space();
  161. AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
  162. blend_space_draw->update();
  163. }
  164. }
  165. void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
  166. Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
  167. Color linecolor_soft = linecolor;
  168. linecolor_soft.a *= 0.5;
  169. Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
  170. int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
  171. Ref<Texture2D> icon = get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons"));
  172. Ref<Texture2D> icon_selected = get_theme_icon(SNAME("KeySelected"), SNAME("EditorIcons"));
  173. Size2 s = blend_space_draw->get_size();
  174. if (blend_space_draw->has_focus()) {
  175. Color color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  176. blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
  177. }
  178. blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor);
  179. if (blend_space->get_min_space() < 0) {
  180. float point = 0.0;
  181. point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
  182. point *= s.width;
  183. float x = point;
  184. blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor);
  185. blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height(font_size) + font->get_ascent(font_size)), "0", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, linecolor);
  186. blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft);
  187. }
  188. if (snap->is_pressed()) {
  189. linecolor_soft.a = linecolor.a * 0.1;
  190. if (blend_space->get_snap() > 0) {
  191. int prev_idx = -1;
  192. for (int i = 0; i < s.x; i++) {
  193. float v = blend_space->get_min_space() + i * (blend_space->get_max_space() - blend_space->get_min_space()) / s.x;
  194. int idx = int(v / blend_space->get_snap());
  195. if (i > 0 && prev_idx != idx) {
  196. blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft);
  197. }
  198. prev_idx = idx;
  199. }
  200. }
  201. }
  202. points.clear();
  203. for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
  204. float point = blend_space->get_blend_point_position(i);
  205. if (dragging_selected && selected_point == i) {
  206. point += drag_ofs.x;
  207. if (snap->is_pressed()) {
  208. point = Math::snapped(point, blend_space->get_snap());
  209. }
  210. }
  211. point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
  212. point *= s.width;
  213. points.push_back(point);
  214. Vector2 gui_point = Vector2(point, s.height / 2.0);
  215. gui_point -= (icon->get_size() / 2.0);
  216. gui_point = gui_point.floor();
  217. if (i == selected_point) {
  218. blend_space_draw->draw_texture(icon_selected, gui_point);
  219. } else {
  220. blend_space_draw->draw_texture(icon, gui_point);
  221. }
  222. }
  223. // blend position
  224. {
  225. Color color;
  226. if (tool_blend->is_pressed()) {
  227. color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  228. } else {
  229. color = linecolor;
  230. color.a *= 0.5;
  231. }
  232. float point = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
  233. point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
  234. point *= s.width;
  235. Vector2 gui_point = Vector2(point, s.height / 2.0);
  236. float mind = 5 * EDSCALE;
  237. float maxd = 15 * EDSCALE;
  238. blend_space_draw->draw_line(gui_point + Vector2(mind, 0), gui_point + Vector2(maxd, 0), color, 2);
  239. blend_space_draw->draw_line(gui_point + Vector2(-mind, 0), gui_point + Vector2(-maxd, 0), color, 2);
  240. blend_space_draw->draw_line(gui_point + Vector2(0, mind), gui_point + Vector2(0, maxd), color, 2);
  241. blend_space_draw->draw_line(gui_point + Vector2(0, -mind), gui_point + Vector2(0, -maxd), color, 2);
  242. }
  243. }
  244. void AnimationNodeBlendSpace1DEditor::_update_space() {
  245. if (updating) {
  246. return;
  247. }
  248. updating = true;
  249. max_value->set_value(blend_space->get_max_space());
  250. min_value->set_value(blend_space->get_min_space());
  251. label_value->set_text(blend_space->get_value_label());
  252. snap_value->set_value(blend_space->get_snap());
  253. blend_space_draw->update();
  254. updating = false;
  255. }
  256. void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
  257. if (updating) {
  258. return;
  259. }
  260. updating = true;
  261. undo_redo->create_action(TTR("Change BlendSpace1D Limits"));
  262. undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
  263. undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
  264. undo_redo->add_do_method(blend_space.ptr(), "set_min_space", min_value->get_value());
  265. undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
  266. undo_redo->add_do_method(blend_space.ptr(), "set_snap", snap_value->get_value());
  267. undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
  268. undo_redo->add_do_method(this, "_update_space");
  269. undo_redo->add_undo_method(this, "_update_space");
  270. undo_redo->commit_action();
  271. updating = false;
  272. blend_space_draw->update();
  273. }
  274. void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
  275. if (updating) {
  276. return;
  277. }
  278. updating = true;
  279. undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS);
  280. undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text());
  281. undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label());
  282. undo_redo->add_do_method(this, "_update_space");
  283. undo_redo->add_undo_method(this, "_update_space");
  284. undo_redo->commit_action();
  285. updating = false;
  286. }
  287. void AnimationNodeBlendSpace1DEditor::_snap_toggled() {
  288. blend_space_draw->update();
  289. }
  290. void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
  291. file_loaded = ResourceLoader::load(p_file);
  292. if (file_loaded.is_valid()) {
  293. _add_menu_type(MENU_LOAD_FILE_CONFIRM);
  294. }
  295. }
  296. void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
  297. Ref<AnimationRootNode> node;
  298. if (p_index == MENU_LOAD_FILE) {
  299. open_file->clear_filters();
  300. List<String> filters;
  301. ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
  302. for (const String &E : filters) {
  303. open_file->add_filter("*." + E);
  304. }
  305. open_file->popup_file_dialog();
  306. return;
  307. } else if (p_index == MENU_LOAD_FILE_CONFIRM) {
  308. node = file_loaded;
  309. file_loaded.unref();
  310. } else if (p_index == MENU_PASTE) {
  311. node = EditorSettings::get_singleton()->get_resource_clipboard();
  312. } else {
  313. String type = menu->get_item_metadata(p_index);
  314. Object *obj = ClassDB::instantiate(type);
  315. ERR_FAIL_COND(!obj);
  316. AnimationNode *an = Object::cast_to<AnimationNode>(obj);
  317. ERR_FAIL_COND(!an);
  318. node = Ref<AnimationNode>(an);
  319. }
  320. if (!node.is_valid()) {
  321. EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
  322. return;
  323. }
  324. updating = true;
  325. undo_redo->create_action(TTR("Add Node Point"));
  326. undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
  327. undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
  328. undo_redo->add_do_method(this, "_update_space");
  329. undo_redo->add_undo_method(this, "_update_space");
  330. undo_redo->commit_action();
  331. updating = false;
  332. blend_space_draw->update();
  333. }
  334. void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
  335. Ref<AnimationNodeAnimation> anim;
  336. anim.instantiate();
  337. anim->set_animation(animations_to_add[p_index]);
  338. updating = true;
  339. undo_redo->create_action(TTR("Add Animation Point"));
  340. undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
  341. undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
  342. undo_redo->add_do_method(this, "_update_space");
  343. undo_redo->add_undo_method(this, "_update_space");
  344. undo_redo->commit_action();
  345. updating = false;
  346. blend_space_draw->update();
  347. }
  348. void AnimationNodeBlendSpace1DEditor::_tool_switch(int p_tool) {
  349. if (p_tool == 0) {
  350. tool_erase->show();
  351. tool_erase_sep->show();
  352. } else {
  353. tool_erase->hide();
  354. tool_erase_sep->hide();
  355. }
  356. _update_tool_erase();
  357. blend_space_draw->update();
  358. }
  359. void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
  360. if (updating) {
  361. return;
  362. }
  363. if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
  364. float pos = blend_space->get_blend_point_position(selected_point);
  365. if (dragging_selected) {
  366. pos += drag_ofs.x;
  367. if (snap->is_pressed()) {
  368. pos = Math::snapped(pos, blend_space->get_snap());
  369. }
  370. }
  371. updating = true;
  372. edit_value->set_value(pos);
  373. updating = false;
  374. }
  375. }
  376. void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
  377. bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
  378. tool_erase->set_disabled(!point_valid);
  379. if (point_valid) {
  380. Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
  381. if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
  382. open_editor->show();
  383. } else {
  384. open_editor->hide();
  385. }
  386. edit_hb->show();
  387. } else {
  388. edit_hb->hide();
  389. }
  390. }
  391. void AnimationNodeBlendSpace1DEditor::_erase_selected() {
  392. if (selected_point != -1) {
  393. updating = true;
  394. undo_redo->create_action(TTR("Remove BlendSpace1D Point"));
  395. undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
  396. 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);
  397. undo_redo->add_do_method(this, "_update_space");
  398. undo_redo->add_undo_method(this, "_update_space");
  399. undo_redo->commit_action();
  400. updating = false;
  401. blend_space_draw->update();
  402. }
  403. }
  404. void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
  405. if (updating) {
  406. return;
  407. }
  408. updating = true;
  409. undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));
  410. undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value());
  411. undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
  412. undo_redo->add_do_method(this, "_update_space");
  413. undo_redo->add_undo_method(this, "_update_space");
  414. undo_redo->add_do_method(this, "_update_edited_point_pos");
  415. undo_redo->add_undo_method(this, "_update_edited_point_pos");
  416. undo_redo->commit_action();
  417. updating = false;
  418. blend_space_draw->update();
  419. }
  420. void AnimationNodeBlendSpace1DEditor::_open_editor() {
  421. if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
  422. Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
  423. ERR_FAIL_COND(an.is_null());
  424. AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
  425. }
  426. }
  427. void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
  428. switch (p_what) {
  429. case NOTIFICATION_ENTER_TREE:
  430. case NOTIFICATION_THEME_CHANGED: {
  431. error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
  432. error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
  433. panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
  434. tool_blend->set_icon(get_theme_icon(SNAME("EditPivot"), SNAME("EditorIcons")));
  435. tool_select->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
  436. tool_create->set_icon(get_theme_icon(SNAME("EditKey"), SNAME("EditorIcons")));
  437. tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
  438. snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
  439. open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
  440. } break;
  441. case NOTIFICATION_PROCESS: {
  442. String error;
  443. if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
  444. error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
  445. } else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
  446. error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
  447. }
  448. if (error != error_label->get_text()) {
  449. error_label->set_text(error);
  450. if (!error.is_empty()) {
  451. error_panel->show();
  452. } else {
  453. error_panel->hide();
  454. }
  455. }
  456. } break;
  457. case NOTIFICATION_VISIBILITY_CHANGED: {
  458. set_process(is_visible_in_tree());
  459. } break;
  460. }
  461. }
  462. void AnimationNodeBlendSpace1DEditor::_bind_methods() {
  463. ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace1DEditor::_update_space);
  464. ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase);
  465. ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);
  466. }
  467. bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {
  468. Ref<AnimationNodeBlendSpace1D> b1d = p_node;
  469. return b1d.is_valid();
  470. }
  471. void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
  472. blend_space = p_node;
  473. if (!blend_space.is_null()) {
  474. _update_space();
  475. }
  476. }
  477. AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
  478. AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
  479. singleton = this;
  480. HBoxContainer *top_hb = memnew(HBoxContainer);
  481. add_child(top_hb);
  482. Ref<ButtonGroup> bg;
  483. bg.instantiate();
  484. tool_blend = memnew(Button);
  485. tool_blend->set_flat(true);
  486. tool_blend->set_toggle_mode(true);
  487. tool_blend->set_button_group(bg);
  488. top_hb->add_child(tool_blend);
  489. tool_blend->set_pressed(true);
  490. tool_blend->set_tooltip(TTR("Set the blending position within the space"));
  491. tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(3));
  492. tool_select = memnew(Button);
  493. tool_select->set_flat(true);
  494. tool_select->set_toggle_mode(true);
  495. tool_select->set_button_group(bg);
  496. top_hb->add_child(tool_select);
  497. tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
  498. tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(0));
  499. tool_create = memnew(Button);
  500. tool_create->set_flat(true);
  501. tool_create->set_toggle_mode(true);
  502. tool_create->set_button_group(bg);
  503. top_hb->add_child(tool_create);
  504. tool_create->set_tooltip(TTR("Create points."));
  505. tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch), varray(1));
  506. tool_erase_sep = memnew(VSeparator);
  507. top_hb->add_child(tool_erase_sep);
  508. tool_erase = memnew(Button);
  509. tool_erase->set_flat(true);
  510. top_hb->add_child(tool_erase);
  511. tool_erase->set_tooltip(TTR("Erase points."));
  512. tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));
  513. top_hb->add_child(memnew(VSeparator));
  514. snap = memnew(Button);
  515. snap->set_flat(true);
  516. snap->set_toggle_mode(true);
  517. top_hb->add_child(snap);
  518. snap->set_pressed(true);
  519. snap->set_tooltip(TTR("Enable snap and show grid."));
  520. snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled));
  521. snap_value = memnew(SpinBox);
  522. top_hb->add_child(snap_value);
  523. snap_value->set_min(0.01);
  524. snap_value->set_step(0.01);
  525. snap_value->set_max(1000);
  526. edit_hb = memnew(HBoxContainer);
  527. top_hb->add_child(edit_hb);
  528. edit_hb->add_child(memnew(VSeparator));
  529. edit_hb->add_child(memnew(Label(TTR("Point"))));
  530. edit_value = memnew(SpinBox);
  531. edit_hb->add_child(edit_value);
  532. edit_value->set_min(-1000);
  533. edit_value->set_max(1000);
  534. edit_value->set_step(0.01);
  535. edit_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_pos));
  536. open_editor = memnew(Button);
  537. edit_hb->add_child(open_editor);
  538. open_editor->set_text(TTR("Open Editor"));
  539. open_editor->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), varray(), CONNECT_DEFERRED);
  540. edit_hb->hide();
  541. open_editor->hide();
  542. VBoxContainer *main_vb = memnew(VBoxContainer);
  543. add_child(main_vb);
  544. main_vb->set_v_size_flags(SIZE_EXPAND_FILL);
  545. panel = memnew(PanelContainer);
  546. panel->set_clip_contents(true);
  547. main_vb->add_child(panel);
  548. panel->set_h_size_flags(SIZE_EXPAND_FILL);
  549. panel->set_v_size_flags(SIZE_EXPAND_FILL);
  550. blend_space_draw = memnew(Control);
  551. blend_space_draw->connect("gui_input", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_gui_input));
  552. blend_space_draw->connect("draw", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_blend_space_draw));
  553. blend_space_draw->set_focus_mode(FOCUS_ALL);
  554. panel->add_child(blend_space_draw);
  555. {
  556. HBoxContainer *bottom_hb = memnew(HBoxContainer);
  557. main_vb->add_child(bottom_hb);
  558. bottom_hb->set_h_size_flags(SIZE_EXPAND_FILL);
  559. min_value = memnew(SpinBox);
  560. min_value->set_min(-10000);
  561. min_value->set_max(0);
  562. min_value->set_step(0.01);
  563. max_value = memnew(SpinBox);
  564. max_value->set_min(0.01);
  565. max_value->set_max(10000);
  566. max_value->set_step(0.01);
  567. label_value = memnew(LineEdit);
  568. label_value->set_expand_to_text_length_enabled(true);
  569. // now add
  570. bottom_hb->add_child(min_value);
  571. bottom_hb->add_spacer();
  572. bottom_hb->add_child(label_value);
  573. bottom_hb->add_spacer();
  574. bottom_hb->add_child(max_value);
  575. }
  576. snap_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
  577. min_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
  578. max_value->connect("value_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
  579. label_value->connect("text_changed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_labels_changed));
  580. error_panel = memnew(PanelContainer);
  581. add_child(error_panel);
  582. error_label = memnew(Label);
  583. error_panel->add_child(error_label);
  584. error_label->set_text("hmmm");
  585. undo_redo = EditorNode::get_undo_redo();
  586. menu = memnew(PopupMenu);
  587. add_child(menu);
  588. menu->connect("id_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_menu_type));
  589. animations_menu = memnew(PopupMenu);
  590. menu->add_child(animations_menu);
  591. animations_menu->set_name("animations");
  592. animations_menu->connect("index_pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_add_animation_type));
  593. open_file = memnew(EditorFileDialog);
  594. add_child(open_file);
  595. open_file->set_title(TTR("Open Animation Node"));
  596. open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
  597. open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));
  598. undo_redo = EditorNode::get_undo_redo();
  599. set_custom_minimum_size(Size2(0, 150 * EDSCALE));
  600. }