1 /*************************************************************************/
2 /*  animation_blend_space_2d_editor.cpp                                  */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 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 
31 #include "animation_blend_space_2d_editor.h"
32 
33 #include "core/io/resource_loader.h"
34 #include "core/math/delaunay.h"
35 #include "core/os/input.h"
36 #include "core/os/keyboard.h"
37 #include "core/project_settings.h"
38 #include "editor/editor_scale.h"
39 #include "scene/animation/animation_blend_tree.h"
40 #include "scene/animation/animation_player.h"
41 #include "scene/gui/menu_button.h"
42 #include "scene/gui/panel.h"
43 #include "scene/main/viewport.h"
44 
can_edit(const Ref<AnimationNode> & p_node)45 bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) {
46 
47 	Ref<AnimationNodeBlendSpace2D> bs2d = p_node;
48 	return bs2d.is_valid();
49 }
50 
_blend_space_changed()51 void AnimationNodeBlendSpace2DEditor::_blend_space_changed() {
52 	blend_space_draw->update();
53 }
54 
edit(const Ref<AnimationNode> & p_node)55 void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
56 
57 	if (blend_space.is_valid()) {
58 		blend_space->disconnect("triangles_updated", this, "_blend_space_changed");
59 	}
60 	blend_space = p_node;
61 
62 	if (!blend_space.is_null()) {
63 		blend_space->connect("triangles_updated", this, "_blend_space_changed");
64 		_update_space();
65 	}
66 }
67 
get_blend_position_path() const68 StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
69 	StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position";
70 	return path;
71 }
72 
_blend_space_gui_input(const Ref<InputEvent> & p_event)73 void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) {
74 
75 	Ref<InputEventKey> k = p_event;
76 	if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && !k->is_echo()) {
77 		if (selected_point != -1 || selected_triangle != -1) {
78 			_erase_selected();
79 			accept_event();
80 		}
81 	}
82 
83 	Ref<InputEventMouseButton> mb = p_event;
84 
85 	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()))) {
86 		menu->clear();
87 		animations_menu->clear();
88 		animations_to_add.clear();
89 		List<StringName> classes;
90 		classes.sort_custom<StringName::AlphCompare>();
91 
92 		ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
93 		menu->add_submenu_item(TTR("Add Animation"), "animations");
94 
95 		AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
96 		ERR_FAIL_COND(!gp);
97 		if (gp && gp->has_node(gp->get_animation_player())) {
98 			AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
99 			if (ap) {
100 				List<StringName> names;
101 				ap->get_animation_list(&names);
102 				for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
103 					animations_menu->add_icon_item(get_icon("Animation", "EditorIcons"), E->get());
104 					animations_to_add.push_back(E->get());
105 				}
106 			}
107 		}
108 
109 		for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
110 
111 			String name = String(E->get()).replace_first("AnimationNode", "");
112 			if (name == "Animation")
113 				continue; // nope
114 			int idx = menu->get_item_count();
115 			menu->add_item(vformat("Add %s", name), idx);
116 			menu->set_item_metadata(idx, E->get());
117 		}
118 
119 		Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
120 		if (clipb.is_valid()) {
121 			menu->add_separator();
122 			menu->add_item(TTR("Paste"), MENU_PASTE);
123 		}
124 		menu->add_separator();
125 		menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
126 
127 		menu->set_global_position(blend_space_draw->get_global_transform().xform(mb->get_position()));
128 		menu->popup();
129 		add_point_pos = (mb->get_position() / blend_space_draw->get_size());
130 		add_point_pos.y = 1.0 - add_point_pos.y;
131 		add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
132 		add_point_pos += blend_space->get_min_space();
133 
134 		if (snap->is_pressed()) {
135 			add_point_pos.x = Math::stepify(add_point_pos.x, blend_space->get_snap().x);
136 			add_point_pos.y = Math::stepify(add_point_pos.y, blend_space->get_snap().y);
137 		}
138 	}
139 
140 	if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
141 
142 		blend_space_draw->update(); //update anyway
143 		//try to see if a point can be selected
144 		selected_point = -1;
145 		selected_triangle = -1;
146 		_update_tool_erase();
147 
148 		for (int i = 0; i < points.size(); i++) {
149 
150 			if (points[i].distance_to(mb->get_position()) < 10 * EDSCALE) {
151 				selected_point = i;
152 				Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
153 				EditorNode::get_singleton()->push_item(node.ptr(), "", true);
154 				dragging_selected_attempt = true;
155 				drag_from = mb->get_position();
156 				_update_tool_erase();
157 				_update_edited_point_pos();
158 				return;
159 			}
160 		}
161 
162 		//then try to see if a triangle can be selected
163 		if (!blend_space->get_auto_triangles()) { //if autotriangles use, disable this
164 			for (int i = 0; i < blend_space->get_triangle_count(); i++) {
165 				Vector<Vector2> triangle;
166 
167 				for (int j = 0; j < 3; j++) {
168 					int idx = blend_space->get_triangle_point(i, j);
169 					ERR_FAIL_INDEX(idx, points.size());
170 					triangle.push_back(points[idx]);
171 				}
172 
173 				if (Geometry::is_point_in_triangle(mb->get_position(), triangle[0], triangle[1], triangle[2])) {
174 					selected_triangle = i;
175 					_update_tool_erase();
176 					return;
177 				}
178 			}
179 		}
180 	}
181 
182 	if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
183 
184 		blend_space_draw->update(); //update anyway
185 		//try to see if a point can be selected
186 		selected_point = -1;
187 
188 		for (int i = 0; i < points.size(); i++) {
189 
190 			if (making_triangle.find(i) != -1)
191 				continue;
192 
193 			if (points[i].distance_to(mb->get_position()) < 10 * EDSCALE) {
194 				making_triangle.push_back(i);
195 				if (making_triangle.size() == 3) {
196 					//add triangle!
197 					if (blend_space->has_triangle(making_triangle[0], making_triangle[1], making_triangle[2])) {
198 						making_triangle.clear();
199 						EditorNode::get_singleton()->show_warning(TTR("Triangle already exists."));
200 						return;
201 					}
202 
203 					updating = true;
204 					undo_redo->create_action(TTR("Add Triangle"));
205 					undo_redo->add_do_method(blend_space.ptr(), "add_triangle", making_triangle[0], making_triangle[1], making_triangle[2]);
206 					undo_redo->add_undo_method(blend_space.ptr(), "remove_triangle", blend_space->get_triangle_count());
207 					undo_redo->add_do_method(this, "_update_space");
208 					undo_redo->add_undo_method(this, "_update_space");
209 					undo_redo->commit_action();
210 					updating = false;
211 					making_triangle.clear();
212 				}
213 				return;
214 			}
215 		}
216 	}
217 
218 	if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
219 		if (dragging_selected) {
220 			//move
221 			Vector2 point = blend_space->get_blend_point_position(selected_point);
222 			point += drag_ofs;
223 			if (snap->is_pressed()) {
224 				point.x = Math::stepify(point.x, blend_space->get_snap().x);
225 				point.y = Math::stepify(point.y, blend_space->get_snap().y);
226 			}
227 
228 			updating = true;
229 			undo_redo->create_action(TTR("Move Node Point"));
230 			undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
231 			undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
232 			undo_redo->add_do_method(this, "_update_space");
233 			undo_redo->add_undo_method(this, "_update_space");
234 			undo_redo->add_do_method(this, "_update_edited_point_pos");
235 			undo_redo->add_undo_method(this, "_update_edited_point_pos");
236 			undo_redo->commit_action();
237 			updating = false;
238 			_update_edited_point_pos();
239 		}
240 		dragging_selected_attempt = false;
241 		dragging_selected = false;
242 		blend_space_draw->update();
243 	}
244 
245 	if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
246 
247 		Vector2 blend_pos = (mb->get_position() / blend_space_draw->get_size());
248 		blend_pos.y = 1.0 - blend_pos.y;
249 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
250 		blend_pos += blend_space->get_min_space();
251 
252 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
253 
254 		blend_space_draw->update();
255 	}
256 
257 	Ref<InputEventMouseMotion> mm = p_event;
258 
259 	if (mm.is_valid() && !blend_space_draw->has_focus()) {
260 		blend_space_draw->grab_focus();
261 		blend_space_draw->update();
262 	}
263 
264 	if (mm.is_valid() && dragging_selected_attempt) {
265 		dragging_selected = true;
266 		drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
267 		blend_space_draw->update();
268 		_update_edited_point_pos();
269 	}
270 
271 	if (mm.is_valid() && tool_triangle->is_pressed() && making_triangle.size()) {
272 		blend_space_draw->update();
273 	}
274 
275 	if (mm.is_valid() && !tool_triangle->is_pressed() && making_triangle.size()) {
276 		making_triangle.clear();
277 		blend_space_draw->update();
278 	}
279 
280 	if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
281 
282 		Vector2 blend_pos = (mm->get_position() / blend_space_draw->get_size());
283 		blend_pos.y = 1.0 - blend_pos.y;
284 		blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
285 		blend_pos += blend_space->get_min_space();
286 
287 		AnimationTreeEditor::get_singleton()->get_tree()->set(get_blend_position_path(), blend_pos);
288 
289 		blend_space_draw->update();
290 	}
291 }
292 
_file_opened(const String & p_file)293 void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
294 
295 	file_loaded = ResourceLoader::load(p_file);
296 	if (file_loaded.is_valid()) {
297 		_add_menu_type(MENU_LOAD_FILE_CONFIRM);
298 	}
299 }
300 
_add_menu_type(int p_index)301 void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
302 
303 	Ref<AnimationRootNode> node;
304 	if (p_index == MENU_LOAD_FILE) {
305 
306 		open_file->clear_filters();
307 		List<String> filters;
308 		ResourceLoader::get_recognized_extensions_for_type("AnimationRootNode", &filters);
309 		for (List<String>::Element *E = filters.front(); E; E = E->next()) {
310 			open_file->add_filter("*." + E->get());
311 		}
312 		open_file->popup_centered_ratio();
313 		return;
314 	} else if (p_index == MENU_LOAD_FILE_CONFIRM) {
315 		node = file_loaded;
316 		file_loaded.unref();
317 	} else if (p_index == MENU_PASTE) {
318 
319 		node = EditorSettings::get_singleton()->get_resource_clipboard();
320 	} else {
321 		String type = menu->get_item_metadata(p_index);
322 
323 		Object *obj = ClassDB::instance(type);
324 		ERR_FAIL_COND(!obj);
325 		AnimationNode *an = Object::cast_to<AnimationNode>(obj);
326 		ERR_FAIL_COND(!an);
327 
328 		node = Ref<AnimationNode>(an);
329 	}
330 
331 	if (!node.is_valid()) {
332 		EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only root nodes are allowed."));
333 		return;
334 	}
335 
336 	updating = true;
337 	undo_redo->create_action(TTR("Add Node Point"));
338 	undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
339 	undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
340 	undo_redo->add_do_method(this, "_update_space");
341 	undo_redo->add_undo_method(this, "_update_space");
342 	undo_redo->commit_action();
343 	updating = false;
344 
345 	blend_space_draw->update();
346 }
347 
_add_animation_type(int p_index)348 void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
349 
350 	Ref<AnimationNodeAnimation> anim;
351 	anim.instance();
352 
353 	anim->set_animation(animations_to_add[p_index]);
354 
355 	updating = true;
356 	undo_redo->create_action(TTR("Add Animation Point"));
357 	undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
358 	undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
359 	undo_redo->add_do_method(this, "_update_space");
360 	undo_redo->add_undo_method(this, "_update_space");
361 	undo_redo->commit_action();
362 	updating = false;
363 
364 	blend_space_draw->update();
365 }
366 
_update_tool_erase()367 void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
368 	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()));
369 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
370 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
371 		if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
372 			open_editor->show();
373 		} else {
374 			open_editor->hide();
375 		}
376 		edit_hb->show();
377 	} else {
378 		edit_hb->hide();
379 	}
380 }
381 
_tool_switch(int p_tool)382 void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) {
383 	making_triangle.clear();
384 
385 	if (p_tool == 2) {
386 		Vector<Vector2> points;
387 		for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
388 			points.push_back(blend_space->get_blend_point_position(i));
389 		}
390 		Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(points);
391 		for (int i = 0; i < tr.size(); i++) {
392 			blend_space->add_triangle(tr[i].points[0], tr[i].points[1], tr[i].points[2]);
393 		}
394 	}
395 
396 	if (p_tool == 0) {
397 		tool_erase->show();
398 		tool_erase_sep->show();
399 	} else {
400 		tool_erase->hide();
401 		tool_erase_sep->hide();
402 	}
403 	_update_tool_erase();
404 	blend_space_draw->update();
405 }
406 
_blend_space_draw()407 void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
408 
409 	Color linecolor = get_color("font_color", "Label");
410 	Color linecolor_soft = linecolor;
411 	linecolor_soft.a *= 0.5;
412 	Ref<Font> font = get_font("font", "Label");
413 	Ref<Texture> icon = get_icon("KeyValue", "EditorIcons");
414 	Ref<Texture> icon_selected = get_icon("KeySelected", "EditorIcons");
415 
416 	Size2 s = blend_space_draw->get_size();
417 
418 	if (blend_space_draw->has_focus()) {
419 		Color color = get_color("accent_color", "Editor");
420 		blend_space_draw->draw_rect(Rect2(Point2(), s), color, false);
421 	}
422 	blend_space_draw->draw_line(Point2(1, 0), Point2(1, s.height - 1), linecolor);
423 	blend_space_draw->draw_line(Point2(1, s.height - 1), Point2(s.width - 1, s.height - 1), linecolor);
424 
425 	blend_space_draw->draw_line(Point2(0, 0), Point2(5 * EDSCALE, 0), linecolor);
426 	if (blend_space->get_min_space().y < 0) {
427 		int y = (blend_space->get_max_space().y / (blend_space->get_max_space().y - blend_space->get_min_space().y)) * s.height;
428 		blend_space_draw->draw_line(Point2(0, y), Point2(5 * EDSCALE, y), linecolor);
429 		blend_space_draw->draw_string(font, Point2(2 * EDSCALE, y - font->get_height() + font->get_ascent()), "0", linecolor);
430 		blend_space_draw->draw_line(Point2(5 * EDSCALE, y), Point2(s.width, y), linecolor_soft);
431 	}
432 
433 	if (blend_space->get_min_space().x < 0) {
434 		int x = (-blend_space->get_min_space().x / (blend_space->get_max_space().x - blend_space->get_min_space().x)) * s.width;
435 		blend_space_draw->draw_line(Point2(x, s.height - 1), Point2(x, s.height - 5 * EDSCALE), linecolor);
436 		blend_space_draw->draw_string(font, Point2(x + 2 * EDSCALE, s.height - 2 * EDSCALE - font->get_height() + font->get_ascent()), "0", linecolor);
437 		blend_space_draw->draw_line(Point2(x, s.height - 5 * EDSCALE), Point2(x, 0), linecolor_soft);
438 	}
439 
440 	if (snap->is_pressed()) {
441 
442 		linecolor_soft.a = linecolor.a * 0.1;
443 
444 		if (blend_space->get_snap().x > 0) {
445 
446 			int prev_idx = 0;
447 			for (int i = 0; i < s.x; i++) {
448 
449 				float v = blend_space->get_min_space().x + i * (blend_space->get_max_space().x - blend_space->get_min_space().x) / s.x;
450 				int idx = int(v / blend_space->get_snap().x);
451 
452 				if (i > 0 && prev_idx != idx) {
453 					blend_space_draw->draw_line(Point2(i, 0), Point2(i, s.height), linecolor_soft);
454 				}
455 
456 				prev_idx = idx;
457 			}
458 		}
459 
460 		if (blend_space->get_snap().y > 0) {
461 
462 			int prev_idx = 0;
463 			for (int i = 0; i < s.y; i++) {
464 
465 				float v = blend_space->get_max_space().y - i * (blend_space->get_max_space().y - blend_space->get_min_space().y) / s.y;
466 				int idx = int(v / blend_space->get_snap().y);
467 
468 				if (i > 0 && prev_idx != idx) {
469 					blend_space_draw->draw_line(Point2(0, i), Point2(s.width, i), linecolor_soft);
470 				}
471 
472 				prev_idx = idx;
473 			}
474 		}
475 	}
476 
477 	//triangles first
478 	for (int i = 0; i < blend_space->get_triangle_count(); i++) {
479 
480 		Vector<Vector2> points;
481 		points.resize(3);
482 
483 		for (int j = 0; j < 3; j++) {
484 			int point_idx = blend_space->get_triangle_point(i, j);
485 			Vector2 point = blend_space->get_blend_point_position(point_idx);
486 			if (dragging_selected && selected_point == point_idx) {
487 				point += drag_ofs;
488 				if (snap->is_pressed()) {
489 					point.x = Math::stepify(point.x, blend_space->get_snap().x);
490 					point.y = Math::stepify(point.y, blend_space->get_snap().y);
491 				}
492 			}
493 			point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
494 			point *= s;
495 			point.y = s.height - point.y;
496 			points.write[j] = point;
497 		}
498 
499 		for (int j = 0; j < 3; j++) {
500 			blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, 1, true);
501 		}
502 
503 		Color color;
504 		if (i == selected_triangle) {
505 			color = get_color("accent_color", "Editor");
506 			color.a *= 0.5;
507 		} else {
508 			color = linecolor;
509 			color.a *= 0.2;
510 		}
511 
512 		Vector<Color> colors;
513 		colors.push_back(color);
514 		colors.push_back(color);
515 		colors.push_back(color);
516 		blend_space_draw->draw_primitive(points, colors, Vector<Vector2>());
517 	}
518 
519 	points.clear();
520 	for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
521 
522 		Vector2 point = blend_space->get_blend_point_position(i);
523 		if (dragging_selected && selected_point == i) {
524 			point += drag_ofs;
525 			if (snap->is_pressed()) {
526 				point.x = Math::stepify(point.x, blend_space->get_snap().x);
527 				point.y = Math::stepify(point.y, blend_space->get_snap().y);
528 			}
529 		}
530 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
531 		point *= s;
532 		point.y = s.height - point.y;
533 
534 		points.push_back(point);
535 		point -= (icon->get_size() / 2);
536 		point = point.floor();
537 
538 		if (i == selected_point) {
539 			blend_space_draw->draw_texture(icon_selected, point);
540 		} else {
541 			blend_space_draw->draw_texture(icon, point);
542 		}
543 	}
544 
545 	if (making_triangle.size()) {
546 		Vector<Vector2> points;
547 		for (int i = 0; i < making_triangle.size(); i++) {
548 			Vector2 point = blend_space->get_blend_point_position(making_triangle[i]);
549 			point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
550 			point *= s;
551 			point.y = s.height - point.y;
552 			points.push_back(point);
553 		}
554 
555 		for (int i = 0; i < points.size() - 1; i++) {
556 			blend_space_draw->draw_line(points[i], points[i + 1], linecolor, 2, true);
557 		}
558 		blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, 2, true);
559 	}
560 
561 	///draw cursor position
562 
563 	{
564 		Color color;
565 		if (tool_blend->is_pressed()) {
566 			color = get_color("accent_color", "Editor");
567 		} else {
568 			color = linecolor;
569 			color.a *= 0.5;
570 		}
571 
572 		Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_tree()->get(get_blend_position_path());
573 		Vector2 point = blend_pos;
574 
575 		point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
576 		point *= s;
577 		point.y = s.height - point.y;
578 
579 		if (blend_space->get_triangle_count()) {
580 			Vector2 closest = blend_space->get_closest_point(blend_pos);
581 			closest = (closest - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
582 			closest *= s;
583 			closest.y = s.height - closest.y;
584 
585 			Color lcol = color;
586 			lcol.a *= 0.4;
587 			blend_space_draw->draw_line(point, closest, lcol, 2);
588 		}
589 
590 		float mind = 5 * EDSCALE;
591 		float maxd = 15 * EDSCALE;
592 		blend_space_draw->draw_line(point + Vector2(mind, 0), point + Vector2(maxd, 0), color, 2);
593 		blend_space_draw->draw_line(point + Vector2(-mind, 0), point + Vector2(-maxd, 0), color, 2);
594 		blend_space_draw->draw_line(point + Vector2(0, mind), point + Vector2(0, maxd), color, 2);
595 		blend_space_draw->draw_line(point + Vector2(0, -mind), point + Vector2(0, -maxd), color, 2);
596 	}
597 }
598 
_snap_toggled()599 void AnimationNodeBlendSpace2DEditor::_snap_toggled() {
600 
601 	blend_space_draw->update();
602 }
603 
_update_space()604 void AnimationNodeBlendSpace2DEditor::_update_space() {
605 
606 	if (updating)
607 		return;
608 
609 	updating = true;
610 
611 	if (blend_space->get_auto_triangles()) {
612 		tool_triangle->hide();
613 	} else {
614 		tool_triangle->show();
615 	}
616 
617 	auto_triangles->set_pressed(blend_space->get_auto_triangles());
618 
619 	interpolation->select(blend_space->get_blend_mode());
620 
621 	max_x_value->set_value(blend_space->get_max_space().x);
622 	max_y_value->set_value(blend_space->get_max_space().y);
623 
624 	min_x_value->set_value(blend_space->get_min_space().x);
625 	min_y_value->set_value(blend_space->get_min_space().y);
626 
627 	label_x->set_text(blend_space->get_x_label());
628 	label_y->set_text(blend_space->get_y_label());
629 
630 	snap_x->set_value(blend_space->get_snap().x);
631 	snap_y->set_value(blend_space->get_snap().y);
632 
633 	blend_space_draw->update();
634 
635 	updating = false;
636 }
637 
_config_changed(double)638 void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
639 	if (updating)
640 		return;
641 
642 	updating = true;
643 	undo_redo->create_action(TTR("Change BlendSpace2D Limits"));
644 	undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value()));
645 	undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
646 	undo_redo->add_do_method(blend_space.ptr(), "set_min_space", Vector2(min_x_value->get_value(), min_y_value->get_value()));
647 	undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
648 	undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value()));
649 	undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
650 	undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
651 	undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
652 	undo_redo->add_do_method(this, "_update_space");
653 	undo_redo->add_undo_method(this, "_update_space");
654 	undo_redo->commit_action();
655 	updating = false;
656 
657 	blend_space_draw->update();
658 }
659 
_labels_changed(String)660 void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
661 	if (updating)
662 		return;
663 
664 	updating = true;
665 	undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS);
666 	undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text());
667 	undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label());
668 	undo_redo->add_do_method(blend_space.ptr(), "set_y_label", label_y->get_text());
669 	undo_redo->add_undo_method(blend_space.ptr(), "set_y_label", blend_space->get_y_label());
670 	undo_redo->add_do_method(this, "_update_space");
671 	undo_redo->add_undo_method(this, "_update_space");
672 	undo_redo->commit_action();
673 	updating = false;
674 }
675 
_erase_selected()676 void AnimationNodeBlendSpace2DEditor::_erase_selected() {
677 
678 	if (selected_point != -1) {
679 
680 		updating = true;
681 		undo_redo->create_action(TTR("Remove BlendSpace2D Point"));
682 		undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
683 		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);
684 
685 		//restore triangles using this point
686 		for (int i = 0; i < blend_space->get_triangle_count(); i++) {
687 			for (int j = 0; j < 3; j++) {
688 				if (blend_space->get_triangle_point(i, j) == selected_point) {
689 					undo_redo->add_undo_method(blend_space.ptr(), "add_triangle", blend_space->get_triangle_point(i, 0), blend_space->get_triangle_point(i, 1), blend_space->get_triangle_point(i, 2), i);
690 					break;
691 				}
692 			}
693 		}
694 
695 		undo_redo->add_do_method(this, "_update_space");
696 		undo_redo->add_undo_method(this, "_update_space");
697 		undo_redo->commit_action();
698 		updating = false;
699 
700 		blend_space_draw->update();
701 	} else if (selected_triangle != -1) {
702 
703 		updating = true;
704 		undo_redo->create_action(TTR("Remove BlendSpace2D Triangle"));
705 		undo_redo->add_do_method(blend_space.ptr(), "remove_triangle", selected_triangle);
706 		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);
707 
708 		undo_redo->add_do_method(this, "_update_space");
709 		undo_redo->add_undo_method(this, "_update_space");
710 		undo_redo->commit_action();
711 		updating = false;
712 
713 		blend_space_draw->update();
714 	}
715 }
716 
_update_edited_point_pos()717 void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() {
718 	if (updating)
719 		return;
720 
721 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
722 		Vector2 pos = blend_space->get_blend_point_position(selected_point);
723 		if (dragging_selected) {
724 			pos += drag_ofs;
725 			if (snap->is_pressed()) {
726 				pos.x = Math::stepify(pos.x, blend_space->get_snap().x);
727 				pos.y = Math::stepify(pos.y, blend_space->get_snap().y);
728 			}
729 		}
730 		updating = true;
731 		edit_x->set_value(pos.x);
732 		edit_y->set_value(pos.y);
733 		updating = false;
734 	}
735 }
736 
_edit_point_pos(double)737 void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
738 	if (updating)
739 		return;
740 	updating = true;
741 	undo_redo->create_action(TTR("Move Node Point"));
742 	undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value()));
743 	undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
744 	undo_redo->add_do_method(this, "_update_space");
745 	undo_redo->add_undo_method(this, "_update_space");
746 	undo_redo->add_do_method(this, "_update_edited_point_pos");
747 	undo_redo->add_undo_method(this, "_update_edited_point_pos");
748 	undo_redo->commit_action();
749 	updating = false;
750 
751 	blend_space_draw->update();
752 }
753 
_notification(int p_what)754 void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
755 
756 	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
757 		error_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
758 		error_label->add_color_override("font_color", get_color("error_color", "Editor"));
759 		panel->add_style_override("panel", get_stylebox("bg", "Tree"));
760 		tool_blend->set_icon(get_icon("EditPivot", "EditorIcons"));
761 		tool_select->set_icon(get_icon("ToolSelect", "EditorIcons"));
762 		tool_create->set_icon(get_icon("EditKey", "EditorIcons"));
763 		tool_triangle->set_icon(get_icon("ToolTriangle", "EditorIcons"));
764 		tool_erase->set_icon(get_icon("Remove", "EditorIcons"));
765 		snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
766 		open_editor->set_icon(get_icon("Edit", "EditorIcons"));
767 		auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons"));
768 		interpolation->clear();
769 		interpolation->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), "", 0);
770 		interpolation->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), "", 1);
771 		interpolation->add_icon_item(get_icon("TrackCapture", "EditorIcons"), "", 2);
772 	}
773 
774 	if (p_what == NOTIFICATION_PROCESS) {
775 
776 		String error;
777 
778 		if (!AnimationTreeEditor::get_singleton()->get_tree()) {
779 			error = TTR("BlendSpace2D does not belong to an AnimationTree node.");
780 		} else if (!AnimationTreeEditor::get_singleton()->get_tree()->is_active()) {
781 			error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
782 		} else if (AnimationTreeEditor::get_singleton()->get_tree()->is_state_invalid()) {
783 			error = AnimationTreeEditor::get_singleton()->get_tree()->get_invalid_state_reason();
784 		} else if (blend_space->get_triangle_count() == 0) {
785 			error = TTR("No triangles exist, so no blending can take place.");
786 		}
787 
788 		if (error != error_label->get_text()) {
789 			error_label->set_text(error);
790 			if (error != String()) {
791 				error_panel->show();
792 			} else {
793 				error_panel->hide();
794 			}
795 		}
796 	}
797 
798 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
799 		set_process(is_visible_in_tree());
800 	}
801 }
802 
_open_editor()803 void AnimationNodeBlendSpace2DEditor::_open_editor() {
804 
805 	if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
806 		Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
807 		ERR_FAIL_COND(an.is_null());
808 		AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
809 	}
810 }
811 
_removed_from_graph()812 void AnimationNodeBlendSpace2DEditor::_removed_from_graph() {
813 	EditorNode::get_singleton()->edit_item(NULL);
814 }
815 
_auto_triangles_toggled()816 void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() {
817 
818 	undo_redo->create_action(TTR("Toggle Auto Triangles"));
819 	undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed());
820 	undo_redo->add_undo_method(blend_space.ptr(), "set_auto_triangles", blend_space->get_auto_triangles());
821 	undo_redo->add_do_method(this, "_update_space");
822 	undo_redo->add_undo_method(this, "_update_space");
823 	undo_redo->commit_action();
824 }
825 
_bind_methods()826 void AnimationNodeBlendSpace2DEditor::_bind_methods() {
827 
828 	ClassDB::bind_method("_blend_space_gui_input", &AnimationNodeBlendSpace2DEditor::_blend_space_gui_input);
829 	ClassDB::bind_method("_blend_space_draw", &AnimationNodeBlendSpace2DEditor::_blend_space_draw);
830 	ClassDB::bind_method("_config_changed", &AnimationNodeBlendSpace2DEditor::_config_changed);
831 	ClassDB::bind_method("_labels_changed", &AnimationNodeBlendSpace2DEditor::_labels_changed);
832 	ClassDB::bind_method("_update_space", &AnimationNodeBlendSpace2DEditor::_update_space);
833 	ClassDB::bind_method("_snap_toggled", &AnimationNodeBlendSpace2DEditor::_snap_toggled);
834 	ClassDB::bind_method("_tool_switch", &AnimationNodeBlendSpace2DEditor::_tool_switch);
835 	ClassDB::bind_method("_erase_selected", &AnimationNodeBlendSpace2DEditor::_erase_selected);
836 	ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace2DEditor::_update_tool_erase);
837 	ClassDB::bind_method("_edit_point_pos", &AnimationNodeBlendSpace2DEditor::_edit_point_pos);
838 
839 	ClassDB::bind_method("_add_menu_type", &AnimationNodeBlendSpace2DEditor::_add_menu_type);
840 	ClassDB::bind_method("_add_animation_type", &AnimationNodeBlendSpace2DEditor::_add_animation_type);
841 
842 	ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos);
843 
844 	ClassDB::bind_method("_open_editor", &AnimationNodeBlendSpace2DEditor::_open_editor);
845 
846 	ClassDB::bind_method("_removed_from_graph", &AnimationNodeBlendSpace2DEditor::_removed_from_graph);
847 
848 	ClassDB::bind_method("_auto_triangles_toggled", &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled);
849 	ClassDB::bind_method("_blend_space_changed", &AnimationNodeBlendSpace2DEditor::_blend_space_changed);
850 
851 	ClassDB::bind_method("_file_opened", &AnimationNodeBlendSpace2DEditor::_file_opened);
852 }
853 
854 AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = NULL;
855 
AnimationNodeBlendSpace2DEditor()856 AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
857 
858 	singleton = this;
859 	updating = false;
860 
861 	HBoxContainer *top_hb = memnew(HBoxContainer);
862 	add_child(top_hb);
863 
864 	Ref<ButtonGroup> bg;
865 	bg.instance();
866 
867 	tool_blend = memnew(ToolButton);
868 	tool_blend->set_toggle_mode(true);
869 	tool_blend->set_button_group(bg);
870 	top_hb->add_child(tool_blend);
871 	tool_blend->set_pressed(true);
872 	tool_blend->set_tooltip(TTR("Set the blending position within the space"));
873 	tool_blend->connect("pressed", this, "_tool_switch", varray(3));
874 
875 	tool_select = memnew(ToolButton);
876 	tool_select->set_toggle_mode(true);
877 	tool_select->set_button_group(bg);
878 	top_hb->add_child(tool_select);
879 	tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
880 	tool_select->connect("pressed", this, "_tool_switch", varray(0));
881 
882 	tool_create = memnew(ToolButton);
883 	tool_create->set_toggle_mode(true);
884 	tool_create->set_button_group(bg);
885 	top_hb->add_child(tool_create);
886 	tool_create->set_tooltip(TTR("Create points."));
887 	tool_create->connect("pressed", this, "_tool_switch", varray(1));
888 
889 	tool_triangle = memnew(ToolButton);
890 	tool_triangle->set_toggle_mode(true);
891 	tool_triangle->set_button_group(bg);
892 	top_hb->add_child(tool_triangle);
893 	tool_triangle->set_tooltip(TTR("Create triangles by connecting points."));
894 	tool_triangle->connect("pressed", this, "_tool_switch", varray(2));
895 
896 	tool_erase_sep = memnew(VSeparator);
897 	top_hb->add_child(tool_erase_sep);
898 	tool_erase = memnew(ToolButton);
899 	top_hb->add_child(tool_erase);
900 	tool_erase->set_tooltip(TTR("Erase points and triangles."));
901 	tool_erase->connect("pressed", this, "_erase_selected");
902 	tool_erase->set_disabled(true);
903 
904 	top_hb->add_child(memnew(VSeparator));
905 
906 	auto_triangles = memnew(ToolButton);
907 	top_hb->add_child(auto_triangles);
908 	auto_triangles->connect("pressed", this, "_auto_triangles_toggled");
909 	auto_triangles->set_toggle_mode(true);
910 	auto_triangles->set_tooltip(TTR("Generate blend triangles automatically (instead of manually)"));
911 
912 	top_hb->add_child(memnew(VSeparator));
913 
914 	snap = memnew(ToolButton);
915 	snap->set_toggle_mode(true);
916 	top_hb->add_child(snap);
917 	snap->set_pressed(true);
918 	snap->set_tooltip(TTR("Enable snap and show grid."));
919 	snap->connect("pressed", this, "_snap_toggled");
920 
921 	snap_x = memnew(SpinBox);
922 	top_hb->add_child(snap_x);
923 	snap_x->set_prefix("x:");
924 	snap_x->set_min(0.01);
925 	snap_x->set_step(0.01);
926 	snap_x->set_max(1000);
927 
928 	snap_y = memnew(SpinBox);
929 	top_hb->add_child(snap_y);
930 	snap_y->set_prefix("y:");
931 	snap_y->set_min(0.01);
932 	snap_y->set_step(0.01);
933 	snap_y->set_max(1000);
934 
935 	top_hb->add_child(memnew(VSeparator));
936 
937 	top_hb->add_child(memnew(Label(TTR("Blend:"))));
938 	interpolation = memnew(OptionButton);
939 	top_hb->add_child(interpolation);
940 	interpolation->connect("item_selected", this, "_config_changed");
941 
942 	edit_hb = memnew(HBoxContainer);
943 	top_hb->add_child(edit_hb);
944 	edit_hb->add_child(memnew(VSeparator));
945 	edit_hb->add_child(memnew(Label(TTR("Point"))));
946 	edit_x = memnew(SpinBox);
947 	edit_hb->add_child(edit_x);
948 	edit_x->set_min(-1000);
949 	edit_x->set_step(0.01);
950 	edit_x->set_max(1000);
951 	edit_x->connect("value_changed", this, "_edit_point_pos");
952 	edit_y = memnew(SpinBox);
953 	edit_hb->add_child(edit_y);
954 	edit_y->set_min(-1000);
955 	edit_y->set_step(0.01);
956 	edit_y->set_max(1000);
957 	edit_y->connect("value_changed", this, "_edit_point_pos");
958 	open_editor = memnew(Button);
959 	edit_hb->add_child(open_editor);
960 	open_editor->set_text(TTR("Open Editor"));
961 	open_editor->connect("pressed", this, "_open_editor", varray(), CONNECT_DEFERRED);
962 	edit_hb->hide();
963 	open_editor->hide();
964 
965 	HBoxContainer *main_hb = memnew(HBoxContainer);
966 	add_child(main_hb);
967 	main_hb->set_v_size_flags(SIZE_EXPAND_FILL);
968 
969 	GridContainer *main_grid = memnew(GridContainer);
970 	main_grid->set_columns(2);
971 	main_hb->add_child(main_grid);
972 	main_grid->set_h_size_flags(SIZE_EXPAND_FILL);
973 	{
974 		VBoxContainer *left_vbox = memnew(VBoxContainer);
975 		main_grid->add_child(left_vbox);
976 		left_vbox->set_v_size_flags(SIZE_EXPAND_FILL);
977 		max_y_value = memnew(SpinBox);
978 		left_vbox->add_child(max_y_value);
979 		left_vbox->add_spacer();
980 		label_y = memnew(LineEdit);
981 		left_vbox->add_child(label_y);
982 		label_y->set_expand_to_text_length(true);
983 		left_vbox->add_spacer();
984 		min_y_value = memnew(SpinBox);
985 		left_vbox->add_child(min_y_value);
986 
987 		max_y_value->set_max(10000);
988 		max_y_value->set_min(0.01);
989 		max_y_value->set_step(0.01);
990 
991 		min_y_value->set_min(-10000);
992 		min_y_value->set_max(0);
993 		min_y_value->set_step(0.01);
994 	}
995 
996 	panel = memnew(PanelContainer);
997 	panel->set_clip_contents(true);
998 	main_grid->add_child(panel);
999 	panel->set_h_size_flags(SIZE_EXPAND_FILL);
1000 
1001 	blend_space_draw = memnew(Control);
1002 	blend_space_draw->connect("gui_input", this, "_blend_space_gui_input");
1003 	blend_space_draw->connect("draw", this, "_blend_space_draw");
1004 	blend_space_draw->set_focus_mode(FOCUS_ALL);
1005 
1006 	panel->add_child(blend_space_draw);
1007 	main_grid->add_child(memnew(Control)); //empty bottom left
1008 
1009 	{
1010 		HBoxContainer *bottom_vbox = memnew(HBoxContainer);
1011 		main_grid->add_child(bottom_vbox);
1012 		bottom_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
1013 		min_x_value = memnew(SpinBox);
1014 		bottom_vbox->add_child(min_x_value);
1015 		bottom_vbox->add_spacer();
1016 		label_x = memnew(LineEdit);
1017 		bottom_vbox->add_child(label_x);
1018 		label_x->set_expand_to_text_length(true);
1019 		bottom_vbox->add_spacer();
1020 		max_x_value = memnew(SpinBox);
1021 		bottom_vbox->add_child(max_x_value);
1022 
1023 		max_x_value->set_max(10000);
1024 		max_x_value->set_min(0.01);
1025 		max_x_value->set_step(0.01);
1026 
1027 		min_x_value->set_min(-10000);
1028 		min_x_value->set_max(0);
1029 		min_x_value->set_step(0.01);
1030 	}
1031 
1032 	snap_x->connect("value_changed", this, "_config_changed");
1033 	snap_y->connect("value_changed", this, "_config_changed");
1034 	max_x_value->connect("value_changed", this, "_config_changed");
1035 	min_x_value->connect("value_changed", this, "_config_changed");
1036 	max_y_value->connect("value_changed", this, "_config_changed");
1037 	min_y_value->connect("value_changed", this, "_config_changed");
1038 	label_x->connect("text_changed", this, "_labels_changed");
1039 	label_y->connect("text_changed", this, "_labels_changed");
1040 
1041 	error_panel = memnew(PanelContainer);
1042 	add_child(error_panel);
1043 	error_label = memnew(Label);
1044 	error_panel->add_child(error_label);
1045 	error_label->set_text("eh");
1046 
1047 	undo_redo = EditorNode::get_undo_redo();
1048 
1049 	set_custom_minimum_size(Size2(0, 300 * EDSCALE));
1050 
1051 	menu = memnew(PopupMenu);
1052 	add_child(menu);
1053 	menu->connect("id_pressed", this, "_add_menu_type");
1054 
1055 	animations_menu = memnew(PopupMenu);
1056 	menu->add_child(animations_menu);
1057 	animations_menu->set_name("animations");
1058 	animations_menu->connect("index_pressed", this, "_add_animation_type");
1059 
1060 	open_file = memnew(EditorFileDialog);
1061 	add_child(open_file);
1062 	open_file->set_title(TTR("Open Animation Node"));
1063 	open_file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
1064 	open_file->connect("file_selected", this, "_file_opened");
1065 	undo_redo = EditorNode::get_undo_redo();
1066 
1067 	selected_point = -1;
1068 	selected_triangle = -1;
1069 
1070 	dragging_selected = false;
1071 	dragging_selected_attempt = false;
1072 }
1073