1 /*************************************************************************/
2 /* animation_tree_editor_plugin.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 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_tree_editor_plugin.h"
31
32 #include "core/globals.h"
33 #include "core/io/resource_loader.h"
34 #include "os/input.h"
35 #include "os/keyboard.h"
36 #include "scene/gui/menu_button.h"
37 #include "scene/gui/panel.h"
38 #include "scene/main/viewport.h"
39
edit(AnimationTreePlayer * p_anim_tree)40 void AnimationTreeEditor::edit(AnimationTreePlayer *p_anim_tree) {
41
42 anim_tree = p_anim_tree;
43
44 if (!anim_tree) {
45 hide();
46 } else {
47 order.clear();
48 p_anim_tree->get_node_list(&order);
49 /*
50 for(List<StringName>::Element* E=order.front();E;E=E->next()) {
51
52 if (E->get() >= (int)last_id)
53 last_id=E->get()+1;
54 }*/
55 play_button->set_pressed(p_anim_tree->is_active());
56 //read the orders
57 }
58 }
59
_get_maximum_size()60 Size2 AnimationTreeEditor::_get_maximum_size() {
61
62 Size2 max;
63
64 for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
65
66 Point2 pos = anim_tree->node_get_pos(E->get());
67
68 if (click_type == CLICK_NODE && click_node == E->get()) {
69
70 pos += click_motion - click_pos;
71 }
72 pos += get_node_size(E->get());
73 if (pos.x > max.x)
74 max.x = pos.x;
75 if (pos.y > max.y)
76 max.y = pos.y;
77 }
78
79 return max;
80 }
81
82 const char *AnimationTreeEditor::_node_type_names[] = { "Output", "Animation", "OneShot", "Mix", "Blend2", "Blend3", "Blend4", "TimeScale", "TimeSeek", "Transition" };
83
get_node_size(const StringName & p_node) const84 Size2 AnimationTreeEditor::get_node_size(const StringName &p_node) const {
85
86 AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
87
88 Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
89 Ref<Font> font = get_font("font", "PopupMenu");
90
91 Size2 size = style->get_minimum_size();
92
93 int count = 2; // title and name
94 int inputs = anim_tree->node_get_input_count(p_node);
95 count += inputs ? inputs : 1;
96 String name = p_node;
97
98 float name_w = font->get_string_size(name).width;
99 float type_w = font->get_string_size(String(_node_type_names[type])).width;
100 float max_w = MAX(name_w, type_w);
101
102 switch (type) {
103 case AnimationTreePlayer::NODE_TIMESEEK:
104 case AnimationTreePlayer::NODE_OUTPUT: {
105 } break;
106 case AnimationTreePlayer::NODE_ANIMATION:
107 case AnimationTreePlayer::NODE_ONESHOT:
108 case AnimationTreePlayer::NODE_MIX:
109 case AnimationTreePlayer::NODE_BLEND2:
110 case AnimationTreePlayer::NODE_BLEND3:
111 case AnimationTreePlayer::NODE_BLEND4:
112 case AnimationTreePlayer::NODE_TIMESCALE:
113 case AnimationTreePlayer::NODE_TRANSITION: {
114
115 size.height += font->get_height();
116 } break;
117 case AnimationTreePlayer::NODE_MAX: {
118 }
119 }
120
121 size.x += max_w + 20;
122 size.y += count * (font->get_height() + get_constant("vseparation", "PopupMenu"));
123
124 return size;
125 }
126
_edit_dialog_changede(String)127 void AnimationTreeEditor::_edit_dialog_changede(String) {
128
129 edit_dialog->hide();
130 }
131
_edit_dialog_changeds(String s)132 void AnimationTreeEditor::_edit_dialog_changeds(String s) {
133
134 _edit_dialog_changed();
135 }
136
_edit_dialog_changedf(float)137 void AnimationTreeEditor::_edit_dialog_changedf(float) {
138
139 _edit_dialog_changed();
140 }
141
_edit_dialog_changed()142 void AnimationTreeEditor::_edit_dialog_changed() {
143
144 if (updating_edit)
145 return;
146
147 if (renaming_edit) {
148
149 if (anim_tree->node_rename(edited_node, edit_line[0]->get_text()) == OK) {
150 for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
151
152 if (E->get() == edited_node)
153 E->get() = edit_line[0]->get_text();
154 }
155 edited_node = edit_line[0]->get_text();
156 }
157 update();
158 return;
159 }
160
161 AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
162
163 switch (type) {
164
165 case AnimationTreePlayer::NODE_TIMESCALE:
166 anim_tree->timescale_node_set_scale(edited_node, edit_line[0]->get_text().to_double());
167 break;
168 case AnimationTreePlayer::NODE_ONESHOT:
169 anim_tree->oneshot_node_set_fadein_time(edited_node, edit_line[0]->get_text().to_double());
170 anim_tree->oneshot_node_set_fadeout_time(edited_node, edit_line[1]->get_text().to_double());
171 anim_tree->oneshot_node_set_autorestart_delay(edited_node, edit_line[2]->get_text().to_double());
172 anim_tree->oneshot_node_set_autorestart_random_delay(edited_node, edit_line[3]->get_text().to_double());
173 anim_tree->oneshot_node_set_autorestart(edited_node, edit_check->is_pressed());
174 anim_tree->oneshot_node_set_mix_mode(edited_node, edit_option->get_selected());
175
176 break;
177
178 case AnimationTreePlayer::NODE_MIX:
179
180 anim_tree->mix_node_set_amount(edited_node, edit_scroll[0]->get_val());
181 break;
182 case AnimationTreePlayer::NODE_BLEND2:
183 anim_tree->blend2_node_set_amount(edited_node, edit_scroll[0]->get_val());
184
185 break;
186
187 case AnimationTreePlayer::NODE_BLEND3:
188 anim_tree->blend3_node_set_amount(edited_node, edit_scroll[0]->get_val());
189
190 break;
191 case AnimationTreePlayer::NODE_BLEND4:
192
193 anim_tree->blend4_node_set_amount(edited_node, Point2(edit_scroll[0]->get_val(), edit_scroll[1]->get_val()));
194
195 break;
196
197 case AnimationTreePlayer::NODE_TRANSITION: {
198 anim_tree->transition_node_set_xfade_time(edited_node, edit_line[0]->get_text().to_double());
199 if (anim_tree->transition_node_get_current(edited_node) != edit_option->get_selected())
200 anim_tree->transition_node_set_current(edited_node, edit_option->get_selected());
201 } break;
202 default: {}
203 }
204 }
205
_edit_dialog_animation_changed()206 void AnimationTreeEditor::_edit_dialog_animation_changed() {
207
208 Ref<Animation> anim = property_editor->get_variant().operator RefPtr();
209 anim_tree->animation_node_set_animation(edited_node, anim);
210 update();
211 }
212
_edit_dialog_edit_animation()213 void AnimationTreeEditor::_edit_dialog_edit_animation() {
214
215 if (get_tree()->is_editor_hint()) {
216 get_tree()->get_root()->get_child(0)->call("_resource_selected", property_editor->get_variant().operator RefPtr());
217 };
218 };
219
_edit_oneshot_start()220 void AnimationTreeEditor::_edit_oneshot_start() {
221
222 anim_tree->oneshot_node_start(edited_node);
223 }
224
_play_toggled()225 void AnimationTreeEditor::_play_toggled() {
226
227 anim_tree->set_active(play_button->is_pressed());
228 }
229
_master_anim_menu_item(int p_item)230 void AnimationTreeEditor::_master_anim_menu_item(int p_item) {
231
232 if (p_item == 0)
233 _edit_filters();
234 else {
235
236 String str = master_anim_popup->get_item_text(p_item);
237 anim_tree->animation_node_set_master_animation(edited_node, str);
238 }
239 update();
240 }
241
_popup_edit_dialog()242 void AnimationTreeEditor::_popup_edit_dialog() {
243
244 updating_edit = true;
245
246 for (int i = 0; i < 2; i++)
247 edit_scroll[i]->hide();
248
249 for (int i = 0; i < 4; i++) {
250
251 edit_line[i]->hide();
252 edit_label[i]->hide();
253 }
254
255 edit_option->hide();
256 edit_button->hide();
257 filter_button->hide();
258 edit_check->hide();
259
260 Point2 pos = anim_tree->node_get_pos(edited_node) - Point2(h_scroll->get_val(), v_scroll->get_val());
261 Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
262 Size2 size = get_node_size(edited_node);
263 Point2 popup_pos(pos.x + style->get_margin(MARGIN_LEFT), pos.y + size.y - style->get_margin(MARGIN_BOTTOM));
264 popup_pos += get_global_pos();
265
266 if (renaming_edit) {
267
268 edit_label[0]->set_text(TTR("New name:"));
269 edit_label[0]->set_pos(Point2(5, 5));
270 edit_label[0]->show();
271 edit_line[0]->set_begin(Point2(15, 25));
272 edit_line[0]->set_text(edited_node);
273 edit_line[0]->show();
274 edit_dialog->set_size(Size2(150, 50));
275
276 } else {
277
278 AnimationTreePlayer::NodeType type = anim_tree->node_get_type(edited_node);
279
280 switch (type) {
281
282 case AnimationTreePlayer::NODE_ANIMATION:
283
284 if (anim_tree->get_master_player() != NodePath() && anim_tree->has_node(anim_tree->get_master_player()) && anim_tree->get_node(anim_tree->get_master_player())->cast_to<AnimationPlayer>()) {
285
286 AnimationPlayer *ap = anim_tree->get_node(anim_tree->get_master_player())->cast_to<AnimationPlayer>();
287 master_anim_popup->clear();
288 master_anim_popup->add_item("Edit Filters");
289 master_anim_popup->add_separator();
290 List<StringName> sn;
291 ap->get_animation_list(&sn);
292 sn.sort_custom<StringName::AlphCompare>();
293 for (List<StringName>::Element *E = sn.front(); E; E = E->next()) {
294 master_anim_popup->add_item(E->get());
295 }
296
297 master_anim_popup->set_pos(popup_pos);
298 master_anim_popup->popup();
299 } else {
300 property_editor->edit(this, "", Variant::OBJECT, anim_tree->animation_node_get_animation(edited_node), PROPERTY_HINT_RESOURCE_TYPE, "Animation");
301 property_editor->set_pos(popup_pos);
302 property_editor->popup();
303 updating_edit = false;
304 }
305 return;
306 case AnimationTreePlayer::NODE_TIMESCALE:
307 edit_label[0]->set_text(TTR("Scale:"));
308 edit_label[0]->set_pos(Point2(5, 5));
309 edit_label[0]->show();
310 edit_line[0]->set_begin(Point2(15, 25));
311 edit_line[0]->set_text(rtos(anim_tree->timescale_node_get_scale(edited_node)));
312 edit_line[0]->show();
313 edit_dialog->set_size(Size2(150, 50));
314 break;
315 case AnimationTreePlayer::NODE_ONESHOT:
316 edit_label[0]->set_text(TTR("Fade In (s):"));
317 edit_label[0]->set_pos(Point2(5, 5));
318 edit_label[0]->show();
319 edit_line[0]->set_begin(Point2(15, 25));
320 edit_line[0]->set_text(rtos(anim_tree->oneshot_node_get_fadein_time(edited_node)));
321 edit_line[0]->show();
322 edit_label[1]->set_text(TTR("Fade Out (s):"));
323 edit_label[1]->set_pos(Point2(5, 55));
324 edit_label[1]->show();
325 edit_line[1]->set_begin(Point2(15, 75));
326 edit_line[1]->set_text(rtos(anim_tree->oneshot_node_get_fadeout_time(edited_node)));
327 edit_line[1]->show();
328
329 edit_option->clear();
330 edit_option->add_item(TTR("Blend"), 0);
331 edit_option->add_item(TTR("Mix"), 1);
332 edit_option->set_begin(Point2(15, 105));
333
334 edit_option->select(anim_tree->oneshot_node_get_mix_mode(edited_node));
335 edit_option->show();
336
337 edit_check->set_text(TTR("Auto Restart:"));
338 edit_check->set_begin(Point2(15, 125));
339 edit_check->set_pressed(anim_tree->oneshot_node_has_autorestart(edited_node));
340 edit_check->show();
341
342 edit_label[2]->set_text(TTR("Restart (s):"));
343 edit_label[2]->set_pos(Point2(5, 145));
344 edit_label[2]->show();
345 edit_line[2]->set_begin(Point2(15, 165));
346 edit_line[2]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_delay(edited_node)));
347 edit_line[2]->show();
348 edit_label[3]->set_text(TTR("Random Restart (s):"));
349 edit_label[3]->set_pos(Point2(5, 195));
350 edit_label[3]->show();
351 edit_line[3]->set_begin(Point2(15, 215));
352 edit_line[3]->set_text(rtos(anim_tree->oneshot_node_get_autorestart_random_delay(edited_node)));
353 edit_line[3]->show();
354
355 filter_button->set_begin(Point2(10, 245));
356 filter_button->show();
357
358 edit_button->set_begin(Point2(10, 268));
359 edit_button->set_text(TTR("Start!"));
360
361 edit_button->show();
362
363 edit_dialog->set_size(Size2(180, 293));
364
365 break;
366
367 case AnimationTreePlayer::NODE_MIX:
368
369 edit_label[0]->set_text(TTR("Amount:"));
370 edit_label[0]->set_pos(Point2(5, 5));
371 edit_label[0]->show();
372 edit_scroll[0]->set_min(0);
373 edit_scroll[0]->set_max(1);
374 edit_scroll[0]->set_step(0.01);
375 edit_scroll[0]->set_val(anim_tree->mix_node_get_amount(edited_node));
376 edit_scroll[0]->set_begin(Point2(15, 25));
377 edit_scroll[0]->show();
378 edit_dialog->set_size(Size2(150, 50));
379
380 break;
381 case AnimationTreePlayer::NODE_BLEND2:
382 edit_label[0]->set_text(TTR("Blend:"));
383 edit_label[0]->set_pos(Point2(5, 5));
384 edit_label[0]->show();
385 edit_scroll[0]->set_min(0);
386 edit_scroll[0]->set_max(1);
387 edit_scroll[0]->set_step(0.01);
388 edit_scroll[0]->set_val(anim_tree->blend2_node_get_amount(edited_node));
389 edit_scroll[0]->set_begin(Point2(15, 25));
390 edit_scroll[0]->show();
391 filter_button->set_begin(Point2(10, 47));
392 filter_button->show();
393 edit_dialog->set_size(Size2(150, 74));
394
395 break;
396
397 case AnimationTreePlayer::NODE_BLEND3:
398 edit_label[0]->set_text(TTR("Blend:"));
399 edit_label[0]->set_pos(Point2(5, 5));
400 edit_label[0]->show();
401 edit_scroll[0]->set_min(-1);
402 edit_scroll[0]->set_max(1);
403 edit_scroll[0]->set_step(0.01);
404 edit_scroll[0]->set_val(anim_tree->blend3_node_get_amount(edited_node));
405 edit_scroll[0]->set_begin(Point2(15, 25));
406 edit_scroll[0]->show();
407 edit_dialog->set_size(Size2(150, 50));
408
409 break;
410 case AnimationTreePlayer::NODE_BLEND4:
411
412 edit_label[0]->set_text(TTR("Blend 0:"));
413 edit_label[0]->set_pos(Point2(5, 5));
414 edit_label[0]->show();
415 edit_scroll[0]->set_min(0);
416 edit_scroll[0]->set_max(1);
417 edit_scroll[0]->set_step(0.01);
418 edit_scroll[0]->set_val(anim_tree->blend4_node_get_amount(edited_node).x);
419 edit_scroll[0]->set_begin(Point2(15, 25));
420 edit_scroll[0]->show();
421 edit_label[1]->set_text(TTR("Blend 1:"));
422 edit_label[1]->set_pos(Point2(5, 55));
423 edit_label[1]->show();
424 edit_scroll[1]->set_min(0);
425 edit_scroll[1]->set_max(1);
426 edit_scroll[1]->set_step(0.01);
427 edit_scroll[1]->set_val(anim_tree->blend4_node_get_amount(edited_node).y);
428 edit_scroll[1]->set_begin(Point2(15, 75));
429 edit_scroll[1]->show();
430 edit_dialog->set_size(Size2(150, 100));
431
432 break;
433
434 case AnimationTreePlayer::NODE_TRANSITION: {
435
436 edit_label[0]->set_text(TTR("X-Fade Time (s):"));
437 edit_label[0]->set_pos(Point2(5, 5));
438 edit_label[0]->show();
439 edit_line[0]->set_begin(Point2(15, 25));
440 edit_line[0]->set_text(rtos(anim_tree->transition_node_get_xfade_time(edited_node)));
441 edit_line[0]->show();
442
443 edit_label[1]->set_text(TTR("Current:"));
444 edit_label[1]->set_pos(Point2(5, 55));
445 edit_label[1]->show();
446 edit_option->set_begin(Point2(15, 75));
447
448 edit_option->clear();
449
450 for (int i = 0; i < anim_tree->transition_node_get_input_count(edited_node); i++) {
451 edit_option->add_item(itos(i), i);
452 }
453
454 edit_option->select(anim_tree->transition_node_get_current(edited_node));
455 edit_option->show();
456 edit_dialog->set_size(Size2(150, 100));
457
458 } break;
459 default: {}
460 }
461 }
462
463 edit_dialog->set_pos(popup_pos);
464 edit_dialog->popup();
465
466 updating_edit = false;
467 }
468
_draw_node(const StringName & p_node)469 void AnimationTreeEditor::_draw_node(const StringName &p_node) {
470
471 RID ci = get_canvas_item();
472 AnimationTreePlayer::NodeType type = anim_tree->node_get_type(p_node);
473
474 Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
475 Ref<Font> font = get_font("font", "PopupMenu");
476 Color font_color = get_color("font_color", "PopupMenu");
477 Color font_color_title = get_color("font_color_hover", "PopupMenu");
478 font_color_title.a *= 0.8;
479 Ref<Texture> slot_icon = get_icon("NodeRealSlot", "EditorIcons");
480
481 Size2 size = get_node_size(p_node);
482 Point2 pos = anim_tree->node_get_pos(p_node);
483 if (click_type == CLICK_NODE && click_node == p_node) {
484
485 pos += click_motion - click_pos;
486 if (pos.x < 5)
487 pos.x = 5;
488 if (pos.y < 5)
489 pos.y = 5;
490 }
491
492 pos -= Point2(h_scroll->get_val(), v_scroll->get_val());
493
494 style->draw(ci, Rect2(pos, size));
495
496 float w = size.width - style->get_minimum_size().width;
497 float h = font->get_height() + get_constant("vseparation", "PopupMenu");
498
499 Point2 ofs = style->get_offset() + pos;
500 Point2 ascofs(0, font->get_ascent());
501
502 Color bx = font_color_title;
503 bx.a *= 0.1;
504 draw_rect(Rect2(ofs, Size2(size.width - style->get_minimum_size().width, font->get_height())), bx);
505 font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, String(_node_type_names[type]), font_color_title);
506
507 ofs.y += h;
508 font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, p_node, font_color);
509 ofs.y += h;
510
511 int count = 2; // title and name
512 int inputs = anim_tree->node_get_input_count(p_node);
513 count += inputs ? inputs : 1;
514
515 float icon_h_ofs = Math::floor((font->get_height() - slot_icon->get_height()) / 2.0) + 1;
516
517 if (type != AnimationTreePlayer::NODE_OUTPUT)
518 slot_icon->draw(ci, ofs + Point2(w, icon_h_ofs)); //output
519
520 if (inputs) {
521 for (int i = 0; i < inputs; i++) {
522
523 slot_icon->draw(ci, ofs + Point2(-slot_icon->get_width(), icon_h_ofs));
524 String text;
525 switch (type) {
526
527 case AnimationTreePlayer::NODE_TIMESCALE:
528 case AnimationTreePlayer::NODE_TIMESEEK: text = "in"; break;
529 case AnimationTreePlayer::NODE_OUTPUT: text = "out"; break;
530 case AnimationTreePlayer::NODE_ANIMATION: break;
531 case AnimationTreePlayer::NODE_ONESHOT: text = (i == 0 ? "in" : "add"); break;
532 case AnimationTreePlayer::NODE_BLEND2:
533 case AnimationTreePlayer::NODE_MIX: text = (i == 0 ? "a" : "b"); break;
534 case AnimationTreePlayer::NODE_BLEND3:
535 switch (i) {
536 case 0: text = "b-"; break;
537 case 1: text = "a"; break;
538 case 2: text = "b+"; break;
539 }
540 break;
541
542 case AnimationTreePlayer::NODE_BLEND4:
543 switch (i) {
544 case 0: text = "a0"; break;
545 case 1: text = "b0"; break;
546 case 2: text = "a1"; break;
547 case 3: text = "b1"; break;
548 }
549 break;
550
551 case AnimationTreePlayer::NODE_TRANSITION:
552 text = itos(i);
553 if (anim_tree->transition_node_has_input_auto_advance(p_node, i))
554 text += "->";
555
556 break;
557 default: {}
558 }
559 font->draw(ci, ofs + ascofs + Point2(3, 0), text, font_color);
560
561 ofs.y += h;
562 }
563 } else {
564 ofs.y += h;
565 }
566
567 Ref<StyleBox> pg_bg = get_stylebox("bg", "ProgressBar");
568 Ref<StyleBox> pg_fill = get_stylebox("fill", "ProgressBar");
569 Rect2 pg_rect(ofs, Size2(w, h));
570
571 bool editable = true;
572 switch (type) {
573 case AnimationTreePlayer::NODE_ANIMATION: {
574
575 Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
576 String text;
577 if (anim_tree->animation_node_get_master_animation(p_node) != "")
578 text = anim_tree->animation_node_get_master_animation(p_node);
579 else if (anim.is_null())
580 text = "load..";
581 else
582 text = anim->get_name();
583
584 font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, text, font_color_title);
585
586 } break;
587 case AnimationTreePlayer::NODE_ONESHOT:
588 case AnimationTreePlayer::NODE_MIX:
589 case AnimationTreePlayer::NODE_BLEND2:
590 case AnimationTreePlayer::NODE_BLEND3:
591 case AnimationTreePlayer::NODE_BLEND4:
592 case AnimationTreePlayer::NODE_TIMESCALE:
593 case AnimationTreePlayer::NODE_TRANSITION: {
594
595 font->draw_halign(ci, ofs + ascofs, HALIGN_CENTER, w, "edit..", font_color_title);
596 } break;
597 default: editable = false;
598 }
599
600 if (editable) {
601
602 Ref<Texture> arrow = get_icon("arrow", "Tree");
603 Point2 arrow_ofs(w - arrow->get_width(), Math::floor((h - arrow->get_height()) / 2));
604 arrow->draw(ci, ofs + arrow_ofs);
605 }
606 }
607
608 #if 0
609 void AnimationTreeEditor::_node_param_changed() {
610
611 // anim_tree->node_set_param( click_node,property_editor->get_variant() );
612 // update();
613 // _write_anim_tree_graph();
614 }
615 #endif
616
_locate_click(const Point2 & p_click,StringName * p_node_id,int * p_slot_index) const617 AnimationTreeEditor::ClickType AnimationTreeEditor::_locate_click(const Point2 &p_click, StringName *p_node_id, int *p_slot_index) const {
618
619 Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
620 Ref<Font> font = get_font("font", "PopupMenu");
621
622 float h = (font->get_height() + get_constant("vseparation", "PopupMenu"));
623
624 for (const List<StringName>::Element *E = order.back(); E; E = E->prev()) {
625
626 StringName node = E->get();
627
628 AnimationTreePlayer::NodeType type = anim_tree->node_get_type(node);
629
630 Point2 pos = anim_tree->node_get_pos(node);
631 Size2 size = get_node_size(node);
632
633 pos -= Point2(h_scroll->get_val(), v_scroll->get_val());
634
635 if (!Rect2(pos, size).has_point(p_click))
636 continue;
637
638 if (p_node_id)
639 *p_node_id = node;
640
641 pos = p_click - pos;
642
643 float y = pos.y - style->get_offset().height;
644
645 if (y < 2 * h)
646 return CLICK_NODE;
647 y -= 2 * h;
648
649 int inputs = anim_tree->node_get_input_count(node);
650 int count = MAX(inputs, 1);
651
652 if (inputs == 0 || (pos.x > size.width / 2 && type != AnimationTreePlayer::NODE_OUTPUT)) {
653
654 if (y < count * h) {
655
656 if (p_slot_index)
657 *p_slot_index = 0;
658 return CLICK_OUTPUT_SLOT;
659 }
660 }
661
662 for (int i = 0; i < count; i++) {
663
664 if (y < h) {
665 if (p_slot_index)
666 *p_slot_index = i;
667 return CLICK_INPUT_SLOT;
668 }
669 y -= h;
670 }
671
672 bool has_parameters = type != AnimationTreePlayer::NODE_OUTPUT && type != AnimationTreePlayer::NODE_TIMESEEK;
673 return has_parameters ? CLICK_PARAMETER : CLICK_NODE;
674 }
675
676 return CLICK_NONE;
677 }
678
_get_slot_pos(const StringName & p_node,bool p_input,int p_slot)679 Point2 AnimationTreeEditor::_get_slot_pos(const StringName &p_node, bool p_input, int p_slot) {
680
681 Ref<StyleBox> style = get_stylebox("panel", "PopupMenu");
682 Ref<Font> font = get_font("font", "PopupMenu");
683 Ref<Texture> slot_icon = get_icon("NodeRealSlot", "EditorIcons");
684
685 Size2 size = get_node_size(p_node);
686 Point2 pos = anim_tree->node_get_pos(p_node);
687
688 if (click_type == CLICK_NODE && click_node == p_node) {
689
690 pos += click_motion - click_pos;
691 if (pos.x < 5)
692 pos.x = 5;
693 if (pos.y < 5)
694 pos.y = 5;
695 }
696
697 pos -= Point2(h_scroll->get_val(), v_scroll->get_val());
698
699 float w = size.width - style->get_minimum_size().width;
700 float h = font->get_height() + get_constant("vseparation", "PopupMenu");
701
702 pos += style->get_offset();
703
704 pos.y += h * 2;
705
706 pos.y += h * p_slot;
707
708 pos += Point2(-slot_icon->get_width() / 2.0, h / 2.0).floor();
709
710 if (!p_input) {
711 pos.x += w + slot_icon->get_width();
712 }
713
714 return pos;
715 }
716
717 #if 0
718 void AnimationTreeEditor::_node_edit_property(const StringName& p_node) {
719
720 Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
721 Size2 size = get_node_size(p_node);
722 Point2 pos = Point2( anim_tree->node_get_pos_x(p_node), anim_tree->node_get_pos_y(p_node) )-offset;
723
724 VisualServer::AnimationTreeNodeType type=anim_tree->node_get_type(p_node);
725
726 PropertyInfo ph = VisualServer::get_singleton()->anim_tree_node_get_type_info(type);
727 if (ph.type==Variant::NIL)
728 return;
729 if (ph.type==Variant::_RID)
730 ph.type=Variant::RESOURCE;
731
732 property_editor->edit(NULL,ph.name,ph.type,anim_tree->node_get_param(p_node),ph.hint,ph.hint_string);
733
734 Point2 popup_pos=Point2( pos.x+(size.width-property_editor->get_size().width)/2.0,pos.y+(size.y-style->get_margin(MARGIN_BOTTOM))).floor();
735 popup_pos+=get_global_pos();
736 property_editor->set_pos(popup_pos);
737
738 property_editor->popup();
739
740 }
741 #endif
742
_input_event(InputEvent p_event)743 void AnimationTreeEditor::_input_event(InputEvent p_event) {
744
745 switch (p_event.type) {
746
747 case InputEvent::MOUSE_BUTTON: {
748
749 if (p_event.mouse_button.pressed) {
750
751 if (p_event.mouse_button.button_index == 1) {
752 click_pos = Point2(p_event.mouse_button.x, p_event.mouse_button.y);
753 click_motion = click_pos;
754 click_type = _locate_click(click_pos, &click_node, &click_slot);
755 if (click_type != CLICK_NONE) {
756
757 order.erase(click_node);
758 order.push_back(click_node);
759 update();
760 }
761
762 switch (click_type) {
763 case CLICK_INPUT_SLOT: {
764 click_pos = _get_slot_pos(click_node, true, click_slot);
765 } break;
766 case CLICK_OUTPUT_SLOT: {
767 click_pos = _get_slot_pos(click_node, false, click_slot);
768 } break;
769 case CLICK_PARAMETER: {
770
771 edited_node = click_node;
772 renaming_edit = false;
773 _popup_edit_dialog();
774 //open editor
775 // _node_edit_property(click_node);
776 } break;
777 default: {}
778 }
779 }
780 if (p_event.mouse_button.button_index == 2) {
781
782 if (click_type != CLICK_NONE) {
783 click_type = CLICK_NONE;
784 update();
785 } else {
786 // try to disconnect/remove
787
788 Point2 rclick_pos = Point2(p_event.mouse_button.x, p_event.mouse_button.y);
789 rclick_type = _locate_click(rclick_pos, &rclick_node, &rclick_slot);
790 if (rclick_type == CLICK_INPUT_SLOT || rclick_type == CLICK_OUTPUT_SLOT) {
791
792 node_popup->clear();
793 node_popup->add_item(TTR("Disconnect"), NODE_DISCONNECT);
794 if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION) {
795 node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
796 if (rclick_type == CLICK_INPUT_SLOT) {
797 if (anim_tree->transition_node_has_input_auto_advance(rclick_node, rclick_slot))
798 node_popup->add_item(TTR("Clear Auto-Advance"), NODE_CLEAR_AUTOADVANCE);
799 else
800 node_popup->add_item(TTR("Set Auto-Advance"), NODE_SET_AUTOADVANCE);
801 node_popup->add_item(TTR("Delete Input"), NODE_DELETE_INPUT);
802 }
803 }
804
805 node_popup->set_pos(rclick_pos + get_global_pos());
806 node_popup->popup();
807 }
808
809 if (rclick_type == CLICK_NODE) {
810 node_popup->clear();
811 node_popup->add_item(TTR("Rename"), NODE_RENAME);
812 node_popup->add_item(TTR("Remove"), NODE_ERASE);
813 if (anim_tree->node_get_type(rclick_node) == AnimationTreePlayer::NODE_TRANSITION)
814 node_popup->add_item(TTR("Add Input"), NODE_ADD_INPUT);
815 node_popup->set_pos(rclick_pos + get_global_pos());
816 node_popup->popup();
817 }
818 }
819 }
820 } else {
821
822 if (p_event.mouse_button.button_index == 1 && click_type != CLICK_NONE) {
823
824 switch (click_type) {
825 case CLICK_INPUT_SLOT:
826 case CLICK_OUTPUT_SLOT: {
827
828 Point2 dst_click_pos = Point2(p_event.mouse_button.x, p_event.mouse_button.y);
829 StringName id;
830 int slot;
831 ClickType dst_click_type = _locate_click(dst_click_pos, &id, &slot);
832
833 if (dst_click_type == CLICK_INPUT_SLOT && click_type == CLICK_OUTPUT_SLOT) {
834
835 anim_tree->connect(click_node, id, slot);
836 }
837 if (click_type == CLICK_INPUT_SLOT && dst_click_type == CLICK_OUTPUT_SLOT) {
838
839 anim_tree->connect(id, click_node, click_slot);
840 }
841
842 } break;
843 case CLICK_NODE: {
844 Point2 new_pos = anim_tree->node_get_pos(click_node) + (click_motion - click_pos);
845 if (new_pos.x < 5)
846 new_pos.x = 5;
847 if (new_pos.y < 5)
848 new_pos.y = 5;
849 anim_tree->node_set_pos(click_node, new_pos);
850
851 } break;
852 default: {}
853 }
854
855 click_type = CLICK_NONE;
856 update();
857 }
858 }
859 }
860
861 case InputEvent::MOUSE_MOTION: {
862
863 if (p_event.mouse_motion.button_mask & 1 && click_type != CLICK_NONE) {
864
865 click_motion = Point2(p_event.mouse_button.x, p_event.mouse_button.y);
866 update();
867 }
868 if ((p_event.mouse_motion.button_mask & 4 || Input::get_singleton()->is_key_pressed(KEY_SPACE))) {
869
870 h_scroll->set_val(h_scroll->get_val() - p_event.mouse_motion.relative_x);
871 v_scroll->set_val(v_scroll->get_val() - p_event.mouse_motion.relative_y);
872 update();
873 }
874
875 } break;
876 }
877 }
878
_draw_cos_line(const Vector2 & p_from,const Vector2 & p_to,const Color & p_color)879 void AnimationTreeEditor::_draw_cos_line(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color) {
880
881 static const int steps = 20;
882
883 Rect2 r;
884 r.pos = p_from;
885 r.expand_to(p_to);
886 Vector2 sign = Vector2((p_from.x < p_to.x) ? 1 : -1, (p_from.y < p_to.y) ? 1 : -1);
887 bool flip = sign.x * sign.y < 0;
888
889 Vector2 prev;
890 for (int i = 0; i <= steps; i++) {
891
892 float d = i / float(steps);
893 float c = -Math::cos(d * Math_PI) * 0.5 + 0.5;
894 if (flip)
895 c = 1.0 - c;
896 Vector2 p = r.pos + Vector2(d * r.size.width, c * r.size.height);
897
898 if (i > 0) {
899
900 draw_line(prev, p, p_color, 2);
901 }
902
903 prev = p;
904 }
905 }
906
_notification(int p_what)907 void AnimationTreeEditor::_notification(int p_what) {
908
909 switch (p_what) {
910
911 case NOTIFICATION_ENTER_TREE: {
912
913 play_button->set_icon(get_icon("Play", "EditorIcons"));
914 add_menu->set_icon(get_icon("Add", "EditorIcons"));
915 } break;
916 case NOTIFICATION_DRAW: {
917
918 _update_scrollbars();
919 //VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1));
920 get_stylebox("bg", "Tree")->draw(get_canvas_item(), Rect2(Point2(), get_size()));
921 VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
922
923 for (List<StringName>::Element *E = order.front(); E; E = E->next()) {
924
925 _draw_node(E->get());
926 }
927
928 if (click_type == CLICK_INPUT_SLOT || click_type == CLICK_OUTPUT_SLOT) {
929
930 _draw_cos_line(click_pos, click_motion, Color(0.5, 1, 0.5, 0.8));
931 }
932
933 List<AnimationTreePlayer::Connection> connections;
934 anim_tree->get_connection_list(&connections);
935
936 for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
937
938 const AnimationTreePlayer::Connection &c = E->get();
939 Point2 source = _get_slot_pos(c.src_node, false, 0);
940 Point2 dest = _get_slot_pos(c.dst_node, true, c.dst_input);
941 Color col = Color(1, 1, 0.5, 0.8);
942 /*
943 if (click_type==CLICK_NODE && click_node==c.src_node) {
944
945 source+=click_motion-click_pos;
946 }
947
948 if (click_type==CLICK_NODE && click_node==c.dst_node) {
949
950 dest+=click_motion-click_pos;
951 }*/
952
953 _draw_cos_line(source, dest, col);
954 }
955
956 switch (anim_tree->get_last_error()) {
957
958 case AnimationTreePlayer::CONNECT_OK: {
959
960 Ref<Font> f = get_font("font", "Label");
961 f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is valid."), Color(0, 1, 0.6, 0.8));
962 } break;
963 default: {
964
965 Ref<Font> f = get_font("font", "Label");
966 f->draw(get_canvas_item(), Point2(5, 25 + f->get_ascent()), TTR("Animation tree is invalid."), Color(1, 0.6, 0.0, 0.8));
967 } break;
968 }
969
970 } break;
971 }
972 }
973
_update_scrollbars()974 void AnimationTreeEditor::_update_scrollbars() {
975
976 Size2 size = get_size();
977 Size2 hmin = h_scroll->get_combined_minimum_size();
978 Size2 vmin = v_scroll->get_combined_minimum_size();
979
980 v_scroll->set_begin(Point2(size.width - vmin.width, 0));
981 v_scroll->set_end(Point2(size.width, size.height));
982
983 h_scroll->set_begin(Point2(0, size.height - hmin.height));
984 h_scroll->set_end(Point2(size.width - vmin.width, size.height));
985
986 Size2 min = _get_maximum_size();
987
988 if (min.height < size.height - hmin.height) {
989
990 v_scroll->hide();
991 offset.y = 0;
992 } else {
993
994 v_scroll->show();
995 v_scroll->set_max(min.height);
996 v_scroll->set_page(size.height - hmin.height);
997 offset.y = v_scroll->get_val();
998 }
999
1000 if (min.width < size.width - vmin.width) {
1001
1002 h_scroll->hide();
1003 offset.x = 0;
1004 } else {
1005
1006 h_scroll->show();
1007 h_scroll->set_max(min.width);
1008 h_scroll->set_page(size.width - vmin.width);
1009 offset.x = h_scroll->get_val();
1010 }
1011 }
1012
_scroll_moved(float)1013 void AnimationTreeEditor::_scroll_moved(float) {
1014
1015 offset.x = h_scroll->get_val();
1016 offset.y = v_scroll->get_val();
1017 update();
1018 }
1019
_node_menu_item(int p_item)1020 void AnimationTreeEditor::_node_menu_item(int p_item) {
1021
1022 switch (p_item) {
1023
1024 case NODE_DISCONNECT: {
1025
1026 if (rclick_type == CLICK_INPUT_SLOT) {
1027
1028 anim_tree->disconnect(rclick_node, rclick_slot);
1029 update();
1030 }
1031
1032 if (rclick_type == CLICK_OUTPUT_SLOT) {
1033
1034 List<AnimationTreePlayer::Connection> connections;
1035 anim_tree->get_connection_list(&connections);
1036
1037 for (List<AnimationTreePlayer::Connection>::Element *E = connections.front(); E; E = E->next()) {
1038
1039 const AnimationTreePlayer::Connection &c = E->get();
1040 if (c.dst_node == rclick_node) {
1041
1042 anim_tree->disconnect(c.dst_node, c.dst_input);
1043 }
1044 }
1045 update();
1046 }
1047
1048 } break;
1049 case NODE_RENAME: {
1050
1051 renaming_edit = true;
1052 edited_node = rclick_node;
1053 _popup_edit_dialog();
1054
1055 } break;
1056 case NODE_ADD_INPUT: {
1057
1058 anim_tree->transition_node_set_input_count(rclick_node, anim_tree->transition_node_get_input_count(rclick_node) + 1);
1059 update();
1060 } break;
1061 case NODE_DELETE_INPUT: {
1062
1063 anim_tree->transition_node_delete_input(rclick_node, rclick_slot);
1064 update();
1065 } break;
1066 case NODE_SET_AUTOADVANCE: {
1067
1068 anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, true);
1069 update();
1070
1071 } break;
1072 case NODE_CLEAR_AUTOADVANCE: {
1073
1074 anim_tree->transition_node_set_input_auto_advance(rclick_node, rclick_slot, false);
1075 update();
1076
1077 } break;
1078
1079 case NODE_ERASE: {
1080
1081 if (rclick_node == "out")
1082 break;
1083 order.erase(rclick_node);
1084 anim_tree->remove_node(rclick_node);
1085 update();
1086 } break;
1087 }
1088 }
1089
_add_node(int p_item)1090 StringName AnimationTreeEditor::_add_node(int p_item) {
1091
1092 static const char *bname[] = {
1093 "out",
1094 "anim",
1095 "oneshot",
1096 "mix",
1097 "blend2",
1098 "blend3",
1099 "blend4",
1100 "scale",
1101 "seek",
1102 "transition"
1103 };
1104
1105 String name;
1106 int idx = 1;
1107
1108 while (true) {
1109
1110 name = bname[p_item];
1111 if (idx > 1)
1112 name += " " + itos(idx);
1113 if (anim_tree->node_exists(name))
1114 idx++;
1115 else
1116 break;
1117 }
1118
1119 anim_tree->add_node((AnimationTreePlayer::NodeType)p_item, name);
1120 anim_tree->node_set_pos(name, Point2(last_x, last_y));
1121 order.push_back(name);
1122 last_x += 10;
1123 last_y += 10;
1124 last_x = last_x % (int)get_size().width;
1125 last_y = last_y % (int)get_size().height;
1126 update();
1127
1128 return name;
1129 };
1130
_file_dialog_selected(String p_path)1131 void AnimationTreeEditor::_file_dialog_selected(String p_path) {
1132
1133 switch (file_op) {
1134
1135 case MENU_IMPORT_ANIMATIONS: {
1136 Vector<String> files = file_dialog->get_selected_files();
1137
1138 for (int i = 0; i < files.size(); i++) {
1139
1140 StringName node = _add_node(AnimationTreePlayer::NODE_ANIMATION);
1141
1142 RES anim = ResourceLoader::load(files[i]);
1143 anim_tree->animation_node_set_animation(node, anim);
1144 //anim_tree->node_set_name(node, files[i].get_file());
1145 };
1146 } break;
1147
1148 default:
1149 break;
1150 };
1151 };
1152
_add_menu_item(int p_item)1153 void AnimationTreeEditor::_add_menu_item(int p_item) {
1154
1155 if (p_item == MENU_GRAPH_CLEAR) {
1156
1157 //clear
1158 } else if (p_item == MENU_IMPORT_ANIMATIONS) {
1159
1160 file_op = MENU_IMPORT_ANIMATIONS;
1161 file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
1162 file_dialog->popup_centered_ratio();
1163
1164 } else {
1165
1166 _add_node(p_item);
1167 }
1168 }
1169
get_minimum_size() const1170 Size2 AnimationTreeEditor::get_minimum_size() const {
1171
1172 return Size2(10, 200);
1173 }
1174
_find_paths_for_filter(const StringName & p_node,Set<String> & paths)1175 void AnimationTreeEditor::_find_paths_for_filter(const StringName &p_node, Set<String> &paths) {
1176
1177 ERR_FAIL_COND(!anim_tree->node_exists(p_node));
1178
1179 for (int i = 0; i < anim_tree->node_get_input_count(p_node); i++) {
1180
1181 StringName port = anim_tree->node_get_input_source(p_node, i);
1182 if (port == StringName())
1183 continue;
1184 _find_paths_for_filter(port, paths);
1185 }
1186
1187 if (anim_tree->node_get_type(p_node) == AnimationTreePlayer::NODE_ANIMATION) {
1188
1189 Ref<Animation> anim = anim_tree->animation_node_get_animation(p_node);
1190 if (anim.is_valid()) {
1191
1192 for (int i = 0; i < anim->get_track_count(); i++) {
1193 paths.insert(anim->track_get_path(i));
1194 }
1195 }
1196 }
1197 }
1198
_filter_edited()1199 void AnimationTreeEditor::_filter_edited() {
1200
1201 TreeItem *ed = filter->get_edited();
1202 if (!ed)
1203 return;
1204
1205 if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
1206 anim_tree->oneshot_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
1207 } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
1208 anim_tree->blend2_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
1209 } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
1210 anim_tree->animation_node_set_filter_path(edited_node, ed->get_metadata(0), ed->is_checked(0));
1211 }
1212 }
1213
_edit_filters()1214 void AnimationTreeEditor::_edit_filters() {
1215
1216 filter_dialog->popup_centered_ratio();
1217 filter->clear();
1218
1219 Set<String> npb;
1220 _find_paths_for_filter(edited_node, npb);
1221
1222 TreeItem *root = filter->create_item();
1223 filter->set_hide_root(true);
1224 Map<String, TreeItem *> pm;
1225
1226 Node *base = anim_tree->get_node(anim_tree->get_base_path());
1227
1228 for (Set<String>::Element *E = npb.front(); E; E = E->next()) {
1229
1230 TreeItem *parent = root;
1231 String descr = E->get();
1232 if (base) {
1233 NodePath np = E->get();
1234
1235 if (np.get_property() != StringName()) {
1236 Node *n = base->get_node(np);
1237 Skeleton *s = n->cast_to<Skeleton>();
1238 if (s) {
1239
1240 String skelbase = E->get().substr(0, E->get().find(":"));
1241
1242 int bidx = s->find_bone(np.get_property());
1243
1244 if (bidx != -1) {
1245 int bparent = s->get_bone_parent(bidx);
1246 //
1247 if (bparent != -1) {
1248
1249 String bpn = skelbase + ":" + s->get_bone_name(bparent);
1250 if (pm.has(bpn)) {
1251 parent = pm[bpn];
1252 descr = np.get_property();
1253 }
1254 } else {
1255
1256 if (pm.has(skelbase)) {
1257 parent = pm[skelbase];
1258 }
1259 }
1260 }
1261 }
1262 }
1263 }
1264
1265 TreeItem *it = filter->create_item(parent);
1266 it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
1267 it->set_text(0, descr);
1268 it->set_metadata(0, NodePath(E->get()));
1269 it->set_editable(0, true);
1270 if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ONESHOT) {
1271 it->set_checked(0, anim_tree->oneshot_node_is_path_filtered(edited_node, E->get()));
1272 } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_BLEND2) {
1273 it->set_checked(0, anim_tree->blend2_node_is_path_filtered(edited_node, E->get()));
1274 } else if (anim_tree->node_get_type(edited_node) == AnimationTreePlayer::NODE_ANIMATION) {
1275 it->set_checked(0, anim_tree->animation_node_is_path_filtered(edited_node, E->get()));
1276 }
1277 pm[E->get()] = it;
1278 }
1279 }
1280
_bind_methods()1281 void AnimationTreeEditor::_bind_methods() {
1282
1283 ObjectTypeDB::bind_method("_add_menu_item", &AnimationTreeEditor::_add_menu_item);
1284 ObjectTypeDB::bind_method("_node_menu_item", &AnimationTreeEditor::_node_menu_item);
1285 ObjectTypeDB::bind_method("_input_event", &AnimationTreeEditor::_input_event);
1286 // ObjectTypeDB::bind_method( "_node_param_changed", &AnimationTreeEditor::_node_param_changed );
1287 ObjectTypeDB::bind_method("_scroll_moved", &AnimationTreeEditor::_scroll_moved);
1288 ObjectTypeDB::bind_method("_edit_dialog_changeds", &AnimationTreeEditor::_edit_dialog_changeds);
1289 ObjectTypeDB::bind_method("_edit_dialog_changede", &AnimationTreeEditor::_edit_dialog_changede);
1290 ObjectTypeDB::bind_method("_edit_dialog_changedf", &AnimationTreeEditor::_edit_dialog_changedf);
1291 ObjectTypeDB::bind_method("_edit_dialog_changed", &AnimationTreeEditor::_edit_dialog_changed);
1292 ObjectTypeDB::bind_method("_edit_dialog_animation_changed", &AnimationTreeEditor::_edit_dialog_animation_changed);
1293 ObjectTypeDB::bind_method("_edit_dialog_edit_animation", &AnimationTreeEditor::_edit_dialog_edit_animation);
1294 ObjectTypeDB::bind_method("_play_toggled", &AnimationTreeEditor::_play_toggled);
1295 ObjectTypeDB::bind_method("_edit_oneshot_start", &AnimationTreeEditor::_edit_oneshot_start);
1296 ObjectTypeDB::bind_method("_file_dialog_selected", &AnimationTreeEditor::_file_dialog_selected);
1297 ObjectTypeDB::bind_method("_master_anim_menu_item", &AnimationTreeEditor::_master_anim_menu_item);
1298 ObjectTypeDB::bind_method("_edit_filters", &AnimationTreeEditor::_edit_filters);
1299 ObjectTypeDB::bind_method("_filter_edited", &AnimationTreeEditor::_filter_edited);
1300 }
1301
AnimationTreeEditor()1302 AnimationTreeEditor::AnimationTreeEditor() {
1303
1304 set_focus_mode(FOCUS_ALL);
1305
1306 PopupMenu *p;
1307 List<PropertyInfo> defaults;
1308
1309 add_menu = memnew(MenuButton);
1310 //add_menu->set_
1311 add_menu->set_pos(Point2(0, 0));
1312 add_menu->set_size(Point2(25, 15));
1313 add_child(add_menu);
1314
1315 p = add_menu->get_popup();
1316 p->add_item(TTR("Animation Node"), AnimationTreePlayer::NODE_ANIMATION);
1317 p->add_item(TTR("OneShot Node"), AnimationTreePlayer::NODE_ONESHOT);
1318 p->add_item(TTR("Mix Node"), AnimationTreePlayer::NODE_MIX);
1319 p->add_item(TTR("Blend2 Node"), AnimationTreePlayer::NODE_BLEND2);
1320 p->add_item(TTR("Blend3 Node"), AnimationTreePlayer::NODE_BLEND3);
1321 p->add_item(TTR("Blend4 Node"), AnimationTreePlayer::NODE_BLEND4);
1322 p->add_item(TTR("TimeScale Node"), AnimationTreePlayer::NODE_TIMESCALE);
1323 p->add_item(TTR("TimeSeek Node"), AnimationTreePlayer::NODE_TIMESEEK);
1324 p->add_item(TTR("Transition Node"), AnimationTreePlayer::NODE_TRANSITION);
1325 p->add_separator();
1326 p->add_item(TTR("Import Animations.."), MENU_IMPORT_ANIMATIONS); // wtf
1327 p->add_separator();
1328 p->add_item(TTR("Clear"), MENU_GRAPH_CLEAR);
1329
1330 p->connect("item_pressed", this, "_add_menu_item");
1331
1332 play_button = memnew(Button);
1333 play_button->set_pos(Point2(25, 0));
1334 play_button->set_size(Point2(25, 15));
1335 add_child(play_button);
1336 play_button->set_toggle_mode(true);
1337 play_button->connect("pressed", this, "_play_toggled");
1338
1339 last_x = 50;
1340 last_y = 50;
1341
1342 property_editor = memnew(CustomPropertyEditor);
1343 add_child(property_editor);
1344 property_editor->connect("variant_changed", this, "_edit_dialog_animation_changed");
1345 property_editor->connect("resource_edit_request", this, "_edit_dialog_edit_animation");
1346
1347 h_scroll = memnew(HScrollBar);
1348 v_scroll = memnew(VScrollBar);
1349
1350 add_child(h_scroll);
1351 add_child(v_scroll);
1352
1353 h_scroll->connect("value_changed", this, "_scroll_moved");
1354 v_scroll->connect("value_changed", this, "_scroll_moved");
1355
1356 node_popup = memnew(PopupMenu);
1357 add_child(node_popup);
1358 node_popup->set_as_toplevel(true);
1359
1360 master_anim_popup = memnew(PopupMenu);
1361 add_child(master_anim_popup);
1362 master_anim_popup->connect("item_pressed", this, "_master_anim_menu_item");
1363
1364 node_popup->connect("item_pressed", this, "_node_menu_item");
1365
1366 updating_edit = false;
1367
1368 edit_dialog = memnew(PopupPanel);
1369 // edit_dialog->get_ok()->hide();
1370 // edit_dialog->get_cancel()->hide();
1371 add_child(edit_dialog);
1372
1373 edit_option = memnew(OptionButton);
1374 edit_option->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1375 edit_option->set_margin(MARGIN_RIGHT, 10);
1376 edit_dialog->add_child(edit_option);
1377 edit_option->connect("item_selected", this, "_edit_dialog_changedf");
1378 edit_option->hide();
1379
1380 for (int i = 0; i < 2; i++) {
1381 edit_scroll[i] = memnew(HSlider);
1382 edit_scroll[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1383 edit_scroll[i]->set_margin(MARGIN_RIGHT, 10);
1384 edit_dialog->add_child(edit_scroll[i]);
1385 edit_scroll[i]->hide();
1386 edit_scroll[i]->connect("value_changed", this, "_edit_dialog_changedf");
1387 }
1388 for (int i = 0; i < 4; i++) {
1389 edit_line[i] = memnew(LineEdit);
1390 edit_line[i]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1391 edit_line[i]->set_margin(MARGIN_RIGHT, 10);
1392 edit_dialog->add_child(edit_line[i]);
1393 edit_line[i]->hide();
1394 edit_line[i]->connect("text_changed", this, "_edit_dialog_changeds");
1395 edit_line[i]->connect("text_entered", this, "_edit_dialog_changede");
1396 edit_label[i] = memnew(Label);
1397 edit_dialog->add_child(edit_label[i]);
1398 edit_label[i]->hide();
1399 }
1400
1401 edit_button = memnew(Button);
1402 edit_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1403 edit_button->set_margin(MARGIN_RIGHT, 10);
1404 edit_dialog->add_child(edit_button);
1405 edit_button->hide();
1406 edit_button->connect("pressed", this, "_edit_oneshot_start");
1407
1408 edit_check = memnew(CheckButton);
1409 edit_check->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1410 edit_check->set_margin(MARGIN_RIGHT, 10);
1411 edit_dialog->add_child(edit_check);
1412 edit_check->hide();
1413 edit_check->connect("pressed", this, "_edit_dialog_changed");
1414
1415 file_dialog = memnew(EditorFileDialog);
1416 file_dialog->set_enable_multiple_selection(true);
1417 file_dialog->set_current_dir(Globals::get_singleton()->get_resource_path());
1418 add_child(file_dialog);
1419 file_dialog->connect("file_selected", this, "_file_dialog_selected");
1420
1421 filter_dialog = memnew(AcceptDialog);
1422 filter_dialog->set_title(TTR("Edit Node Filters"));
1423 add_child(filter_dialog);
1424
1425 filter = memnew(Tree);
1426 filter_dialog->add_child(filter);
1427 filter_dialog->set_child_rect(filter);
1428 filter->connect("item_edited", this, "_filter_edited");
1429
1430 filter_button = memnew(Button);
1431 filter_button->set_anchor(MARGIN_RIGHT, ANCHOR_END);
1432 filter_button->set_margin(MARGIN_RIGHT, 10);
1433 edit_dialog->add_child(filter_button);
1434 filter_button->hide();
1435 filter_button->set_text(TTR("Filters.."));
1436 filter_button->connect("pressed", this, "_edit_filters");
1437 }
1438
edit(Object * p_object)1439 void AnimationTreeEditorPlugin::edit(Object *p_object) {
1440
1441 anim_tree_editor->edit(p_object->cast_to<AnimationTreePlayer>());
1442 }
1443
handles(Object * p_object) const1444 bool AnimationTreeEditorPlugin::handles(Object *p_object) const {
1445
1446 return p_object->is_type("AnimationTreePlayer");
1447 }
1448
make_visible(bool p_visible)1449 void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
1450
1451 if (p_visible) {
1452 // editor->hide_animation_player_editors();
1453 // editor->animation_panel_make_visible(true);
1454 button->show();
1455 editor->make_bottom_panel_item_visible(anim_tree_editor);
1456 anim_tree_editor->set_fixed_process(true);
1457 } else {
1458
1459 if (anim_tree_editor->is_visible())
1460 editor->hide_bottom_panel();
1461 button->hide();
1462 anim_tree_editor->set_fixed_process(false);
1463 }
1464 }
1465
AnimationTreeEditorPlugin(EditorNode * p_node)1466 AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) {
1467
1468 editor = p_node;
1469 anim_tree_editor = memnew(AnimationTreeEditor);
1470 anim_tree_editor->set_custom_minimum_size(Size2(0, 300));
1471
1472 button = editor->add_bottom_panel_item("AnimationTree", anim_tree_editor);
1473 button->hide();
1474 }
1475
~AnimationTreeEditorPlugin()1476 AnimationTreeEditorPlugin::~AnimationTreeEditorPlugin() {
1477 }
1478