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