1 /*************************************************************************/
2 /*  animation_editor.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_editor.h"
31 #include "editor/plugins/animation_player_editor_plugin.h"
32 #include "editor_node.h"
33 #include "editor_settings.h"
34 #include "io/resource_saver.h"
35 #include "os/keyboard.h"
36 #include "os/os.h"
37 #include "pair.h"
38 #include "scene/gui/separator.h"
39 #include "scene/main/viewport.h"
40 /* Missing to fix:
41 
42   *Set
43   *Find better source for hint for edited value keys
44   * + button on track to add a key
45   * when clicked for first time, erase selection of not selected at first
46   * automatically create discrete/continuous tracks!!
47   *when create track do undo/redo
48 */
49 
50 class AnimationCurveEdit : public Control {
51 	OBJ_TYPE(AnimationCurveEdit, Control);
52 
53 public:
54 	enum Mode {
55 		MODE_DISABLED,
56 		MODE_SINGLE,
57 		MODE_MULTIPLE
58 	};
59 
60 private:
61 	Set<float> multiples;
62 	float transition;
63 	Mode mode;
64 
_notification(int p_what)65 	void _notification(int p_what) {
66 
67 		if (p_what == NOTIFICATION_DRAW) {
68 
69 			RID ci = get_canvas_item();
70 
71 			Size2 s = get_size();
72 			Rect2 r(Point2(), s);
73 
74 			//r=r.grow(3);
75 			Ref<StyleBox> sb = get_stylebox("normal", "LineEdit");
76 			sb->draw(ci, r);
77 			r.size -= sb->get_minimum_size();
78 			r.pos += sb->get_offset();
79 			//VisualServer::get_singleton()->canvas_item_add
80 
81 			Ref<Font> f = get_font("font", "Label");
82 			r = r.grow(-2);
83 			Color color = get_color("font_color", "Label");
84 
85 			int points = 48;
86 			if (mode == MODE_MULTIPLE) {
87 
88 				Color mcolor = color;
89 				mcolor.a *= 0.3;
90 
91 				Set<float>::Element *E = multiples.front();
92 				for (int j = 0; j < 16; j++) {
93 
94 					if (!E)
95 						break;
96 
97 					float prev = 1.0;
98 					float exp = E->get();
99 					bool flip = false; //hint_text=="attenuation";
100 
101 					for (int i = 1; i <= points; i++) {
102 
103 						float ifl = i / float(points);
104 						float iflp = (i - 1) / float(points);
105 
106 						float h = 1.0 - Math::ease(ifl, exp);
107 
108 						if (flip) {
109 							ifl = 1.0 - ifl;
110 							iflp = 1.0 - iflp;
111 						}
112 
113 						VisualServer::get_singleton()->canvas_item_add_line(ci, r.pos + Point2(iflp * r.size.width, prev * r.size.height), r.pos + Point2(ifl * r.size.width, h * r.size.height), mcolor);
114 						prev = h;
115 					}
116 
117 					E = E->next();
118 				}
119 			}
120 
121 			float exp = transition;
122 			if (mode != MODE_DISABLED) {
123 
124 				float prev = 1.0;
125 
126 				bool flip = false; //hint_text=="attenuation";
127 
128 				for (int i = 1; i <= points; i++) {
129 
130 					float ifl = i / float(points);
131 					float iflp = (i - 1) / float(points);
132 
133 					float h = 1.0 - Math::ease(ifl, exp);
134 
135 					if (flip) {
136 						ifl = 1.0 - ifl;
137 						iflp = 1.0 - iflp;
138 					}
139 
140 					VisualServer::get_singleton()->canvas_item_add_line(ci, r.pos + Point2(iflp * r.size.width, prev * r.size.height), r.pos + Point2(ifl * r.size.width, h * r.size.height), color);
141 					prev = h;
142 				}
143 			}
144 
145 			String txt = String::num(exp, 2);
146 			if (mode == MODE_DISABLED) {
147 				txt = TTR("Disabled");
148 			} else if (mode == MODE_MULTIPLE) {
149 				txt += " - " + TTR("All Selection");
150 			}
151 
152 			f->draw(ci, Point2(10, 10 + f->get_ascent()), txt, color);
153 		}
154 	}
155 
_input_event(const InputEvent & p_ev)156 	void _input_event(const InputEvent &p_ev) {
157 		if (p_ev.type == InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask & BUTTON_MASK_LEFT) {
158 
159 			if (mode == MODE_DISABLED)
160 				return;
161 
162 			float rel = p_ev.mouse_motion.relative_x;
163 			if (rel == 0)
164 				return;
165 
166 			bool flip = false;
167 
168 			if (flip)
169 				rel = -rel;
170 
171 			float val = transition;
172 			if (val == 0)
173 				return;
174 			bool sg = val < 0;
175 			val = Math::absf(val);
176 
177 			val = Math::log(val) / Math::log(2);
178 			//logspace
179 			val += rel * 0.05;
180 			//
181 
182 			val = Math::pow(2, val);
183 			if (sg)
184 				val = -val;
185 
186 			transition = val;
187 			update();
188 			//emit_signal("variant_changed");
189 			emit_signal("transition_changed", transition);
190 		}
191 	}
192 
193 public:
_bind_methods()194 	static void _bind_methods() {
195 
196 		//	ObjectTypeDB::bind_method("_update_obj",&AnimationKeyEdit::_update_obj);
197 		ObjectTypeDB::bind_method("_input_event", &AnimationCurveEdit::_input_event);
198 		ADD_SIGNAL(MethodInfo("transition_changed"));
199 	}
200 
set_mode(Mode p_mode)201 	void set_mode(Mode p_mode) {
202 
203 		mode = p_mode;
204 		update();
205 	}
206 
clear_multiples()207 	void clear_multiples() {
208 		multiples.clear();
209 		update();
210 	}
set_multiple(float p_transition)211 	void set_multiple(float p_transition) {
212 
213 		multiples.insert(p_transition);
214 	}
215 
set_transition(float p_transition)216 	void set_transition(float p_transition) {
217 		transition = p_transition;
218 		update();
219 	}
220 
get_transition() const221 	float get_transition() const {
222 		return transition;
223 	}
224 
force_transition(float p_value)225 	void force_transition(float p_value) {
226 		if (mode == MODE_DISABLED)
227 			return;
228 		transition = p_value;
229 		emit_signal("transition_changed", p_value);
230 		update();
231 	}
232 
AnimationCurveEdit()233 	AnimationCurveEdit() {
234 
235 		transition = 1.0;
236 		set_default_cursor_shape(CURSOR_HSPLIT);
237 		mode = MODE_DISABLED;
238 	}
239 };
240 
241 class AnimationKeyEdit : public Object {
242 
243 	OBJ_TYPE(AnimationKeyEdit, Object);
244 
245 public:
246 	bool setting;
247 	bool hidden;
248 
_bind_methods()249 	static void _bind_methods() {
250 
251 		ObjectTypeDB::bind_method("_update_obj", &AnimationKeyEdit::_update_obj);
252 		ObjectTypeDB::bind_method("_key_ofs_changed", &AnimationKeyEdit::_key_ofs_changed);
253 	}
254 
255 	//PopupDialog *ke_dialog;
256 
_fix_node_path(Variant & value)257 	void _fix_node_path(Variant &value) {
258 
259 		NodePath np = value;
260 
261 		if (np == NodePath())
262 			return;
263 
264 		Node *root = EditorNode::get_singleton()->get_tree()->get_root();
265 
266 		Node *np_node = root->get_node(np);
267 		ERR_FAIL_COND(!np_node);
268 
269 		Node *edited_node = root->get_node(base);
270 		ERR_FAIL_COND(!edited_node);
271 
272 		value = edited_node->get_path_to(np_node);
273 	}
274 
_update_obj(const Ref<Animation> & p_anim)275 	void _update_obj(const Ref<Animation> &p_anim) {
276 		if (setting)
277 			return;
278 		if (hidden)
279 			return;
280 		if (!(animation == p_anim))
281 			return;
282 		notify_change();
283 	}
284 
_key_ofs_changed(const Ref<Animation> & p_anim,float from,float to)285 	void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
286 		if (hidden)
287 			return;
288 		if (!(animation == p_anim))
289 			return;
290 		if (from != key_ofs)
291 			return;
292 		key_ofs = to;
293 		if (setting)
294 			return;
295 		notify_change();
296 	}
297 
_set(const StringName & p_name,const Variant & p_value)298 	bool _set(const StringName &p_name, const Variant &p_value) {
299 
300 		int key = animation->track_find_key(track, key_ofs, true);
301 		ERR_FAIL_COND_V(key == -1, false);
302 
303 		String name = p_name;
304 		if (name == "time") {
305 
306 			float new_time = p_value;
307 			if (new_time == key_ofs)
308 				return true;
309 
310 			int existing = animation->track_find_key(track, new_time, true);
311 
312 			setting = true;
313 			undo_redo->create_action(TTR("Move Add Key"), UndoRedo::MERGE_ENDS);
314 
315 			Variant val = animation->track_get_key_value(track, key);
316 			float trans = animation->track_get_key_transition(track, key);
317 
318 			undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
319 			undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
320 			undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
321 			undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", track, new_time);
322 			undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
323 			undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
324 
325 			if (existing != -1) {
326 				Variant v = animation->track_get_key_value(track, existing);
327 				float trans = animation->track_get_key_transition(track, existing);
328 				undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
329 			}
330 
331 			undo_redo->commit_action();
332 			setting = false;
333 
334 			return true;
335 		} else if (name == "easing") {
336 
337 			float val = p_value;
338 			float prev_val = animation->track_get_key_transition(track, key);
339 			setting = true;
340 			undo_redo->create_action(TTR("Anim Change Transition"), UndoRedo::MERGE_ENDS);
341 			undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
342 			undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
343 			undo_redo->add_do_method(this, "_update_obj", animation);
344 			undo_redo->add_undo_method(this, "_update_obj", animation);
345 			undo_redo->commit_action();
346 			setting = false;
347 			return true;
348 		}
349 
350 		switch (animation->track_get_type(track)) {
351 
352 			case Animation::TYPE_TRANSFORM: {
353 
354 				Dictionary d_old = animation->track_get_key_value(track, key);
355 				Dictionary d_new = d_old;
356 				d_new[p_name] = p_value;
357 				setting = true;
358 				undo_redo->create_action(TTR("Anim Change Transform"));
359 				undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
360 				undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
361 				undo_redo->add_do_method(this, "_update_obj", animation);
362 				undo_redo->add_undo_method(this, "_update_obj", animation);
363 				undo_redo->commit_action();
364 				setting = false;
365 				return true;
366 
367 			} break;
368 			case Animation::TYPE_VALUE: {
369 
370 				if (name == "value") {
371 
372 					Variant value = p_value;
373 
374 					if (value.get_type() == Variant::NODE_PATH) {
375 
376 						_fix_node_path(value);
377 					}
378 
379 					setting = true;
380 					undo_redo->create_action(TTR("Anim Change Value"), UndoRedo::MERGE_ENDS);
381 					Variant prev = animation->track_get_key_value(track, key);
382 					undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
383 					undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
384 					undo_redo->add_do_method(this, "_update_obj", animation);
385 					undo_redo->add_undo_method(this, "_update_obj", animation);
386 					undo_redo->commit_action();
387 					setting = false;
388 					return true;
389 				}
390 
391 			} break;
392 			case Animation::TYPE_METHOD: {
393 
394 				Dictionary d_old = animation->track_get_key_value(track, key);
395 				Dictionary d_new = d_old;
396 
397 				bool change_notify_deserved = false;
398 				bool mergeable = false;
399 
400 				if (name == "name") {
401 
402 					d_new["method"] = p_value;
403 				}
404 
405 				if (name == "arg_count") {
406 
407 					Vector<Variant> args = d_old["args"];
408 					args.resize(p_value);
409 					d_new["args"] = args;
410 					change_notify_deserved = true;
411 				}
412 
413 				if (name.begins_with("args/")) {
414 
415 					Vector<Variant> args = d_old["args"];
416 					int idx = name.get_slice("/", 1).to_int();
417 					ERR_FAIL_INDEX_V(idx, args.size(), false);
418 
419 					String what = name.get_slice("/", 2);
420 					if (what == "type") {
421 						Variant::Type t = Variant::Type(int(p_value));
422 
423 						if (t != args[idx].get_type()) {
424 							Variant::CallError err;
425 							if (Variant::can_convert(args[idx].get_type(), t)) {
426 								Variant old = args[idx];
427 								Variant *ptrs[1] = { &old };
428 								args[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err);
429 							} else {
430 
431 								args[idx] = Variant::construct(t, NULL, 0, err);
432 							}
433 							change_notify_deserved = true;
434 							d_new["args"] = args;
435 						}
436 					}
437 					if (what == "value") {
438 
439 						Variant value = p_value;
440 						if (value.get_type() == Variant::NODE_PATH) {
441 
442 							_fix_node_path(value);
443 						}
444 
445 						args[idx] = value;
446 						d_new["args"] = args;
447 						mergeable = true;
448 					}
449 				}
450 
451 				if (mergeable)
452 					undo_redo->create_action(TTR("Anim Change Call"), UndoRedo::MERGE_ENDS);
453 				else
454 					undo_redo->create_action(TTR("Anim Change Call"));
455 
456 				Variant prev = animation->track_get_key_value(track, key);
457 				setting = true;
458 				undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
459 				undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
460 				undo_redo->add_do_method(this, "_update_obj", animation);
461 				undo_redo->add_undo_method(this, "_update_obj", animation);
462 				undo_redo->commit_action();
463 				setting = false;
464 				if (change_notify_deserved)
465 					notify_change();
466 				return true;
467 			} break;
468 		}
469 
470 		return false;
471 	}
472 
_get(const StringName & p_name,Variant & r_ret) const473 	bool _get(const StringName &p_name, Variant &r_ret) const {
474 
475 		int key = animation->track_find_key(track, key_ofs, true);
476 		ERR_FAIL_COND_V(key == -1, false);
477 
478 		String name = p_name;
479 		if (name == "time") {
480 			r_ret = key_ofs;
481 			return true;
482 		} else if (name == "easing") {
483 			r_ret = animation->track_get_key_transition(track, key);
484 			return true;
485 		}
486 
487 		switch (animation->track_get_type(track)) {
488 
489 			case Animation::TYPE_TRANSFORM: {
490 
491 				Dictionary d = animation->track_get_key_value(track, key);
492 				ERR_FAIL_COND_V(!d.has(name), false);
493 				r_ret = d[p_name];
494 				return true;
495 
496 			} break;
497 			case Animation::TYPE_VALUE: {
498 
499 				if (name == "value") {
500 					r_ret = animation->track_get_key_value(track, key);
501 					return true;
502 				}
503 
504 			} break;
505 			case Animation::TYPE_METHOD: {
506 
507 				Dictionary d = animation->track_get_key_value(track, key);
508 
509 				if (name == "name") {
510 
511 					ERR_FAIL_COND_V(!d.has("method"), false);
512 					r_ret = d["method"];
513 					return true;
514 				}
515 
516 				ERR_FAIL_COND_V(!d.has("args"), false);
517 
518 				Vector<Variant> args = d["args"];
519 
520 				if (name == "arg_count") {
521 
522 					r_ret = args.size();
523 					return true;
524 				}
525 
526 				if (name.begins_with("args/")) {
527 
528 					int idx = name.get_slice("/", 1).to_int();
529 					ERR_FAIL_INDEX_V(idx, args.size(), false);
530 
531 					String what = name.get_slice("/", 2);
532 					if (what == "type") {
533 						r_ret = args[idx].get_type();
534 						return true;
535 					}
536 					if (what == "value") {
537 						r_ret = args[idx];
538 						return true;
539 					}
540 				}
541 
542 			} break;
543 		}
544 
545 		return false;
546 	}
_get_property_list(List<PropertyInfo> * p_list) const547 	void _get_property_list(List<PropertyInfo> *p_list) const {
548 
549 		if (animation.is_null())
550 			return;
551 
552 		ERR_FAIL_INDEX(track, animation->get_track_count());
553 		int key = animation->track_find_key(track, key_ofs, true);
554 		ERR_FAIL_COND(key == -1);
555 
556 		p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
557 
558 		switch (animation->track_get_type(track)) {
559 
560 			case Animation::TYPE_TRANSFORM: {
561 
562 				p_list->push_back(PropertyInfo(Variant::VECTOR3, "loc"));
563 				p_list->push_back(PropertyInfo(Variant::QUAT, "rot"));
564 				p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
565 
566 			} break;
567 			case Animation::TYPE_VALUE: {
568 
569 				Variant v = animation->track_get_key_value(track, key);
570 
571 				if (hint.type != Variant::NIL) {
572 
573 					PropertyInfo pi = hint;
574 					pi.name = "value";
575 					p_list->push_back(pi);
576 				} else {
577 
578 					PropertyHint hint = PROPERTY_HINT_NONE;
579 					String hint_string;
580 
581 					if (v.get_type() == Variant::OBJECT) {
582 						//could actually check the object property if exists..? yes i will!
583 						Ref<Resource> res = v;
584 						if (res.is_valid()) {
585 
586 							hint = PROPERTY_HINT_RESOURCE_TYPE;
587 							hint_string = res->get_type();
588 						}
589 					}
590 
591 					if (v.get_type() != Variant::NIL)
592 						p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string));
593 				}
594 
595 			} break;
596 			case Animation::TYPE_METHOD: {
597 
598 				p_list->push_back(PropertyInfo(Variant::STRING, "name"));
599 				p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,5,1"));
600 
601 				Dictionary d = animation->track_get_key_value(track, key);
602 				ERR_FAIL_COND(!d.has("args"));
603 				Vector<Variant> args = d["args"];
604 				String vtypes;
605 				for (int i = 0; i < Variant::VARIANT_MAX; i++) {
606 
607 					if (i > 0)
608 						vtypes += ",";
609 					vtypes += Variant::get_type_name(Variant::Type(i));
610 				}
611 
612 				for (int i = 0; i < args.size(); i++) {
613 
614 					p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes));
615 					if (args[i].get_type() != Variant::NIL)
616 						p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value"));
617 				}
618 
619 			} break;
620 		}
621 
622 		//if (animation->track_get_type(track)!=Animation::TYPE_METHOD)
623 		//	p_list->push_back( PropertyInfo( Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
624 	}
625 
626 	UndoRedo *undo_redo;
627 	Ref<Animation> animation;
628 	int track;
629 	float key_ofs;
630 
631 	PropertyInfo hint;
632 	NodePath base;
633 
notify_change()634 	void notify_change() {
635 
636 		_change_notify();
637 	}
638 
AnimationKeyEdit()639 	AnimationKeyEdit() {
640 		hidden = true;
641 		key_ofs = 0;
642 		track = -1;
643 		setting = false;
644 	}
645 };
646 
_menu_add_track(int p_type)647 void AnimationKeyEditor::_menu_add_track(int p_type) {
648 
649 	ERR_FAIL_COND(!animation.is_valid());
650 
651 	switch (p_type) {
652 
653 		case ADD_TRACK_MENU_ADD_CALL_TRACK: {
654 			if (root) {
655 				call_select->popup_centered_ratio();
656 				break;
657 			}
658 		} break;
659 		case ADD_TRACK_MENU_ADD_VALUE_TRACK:
660 		case ADD_TRACK_MENU_ADD_TRANSFORM_TRACK: {
661 
662 			undo_redo->create_action(TTR("Anim Add Track"));
663 			undo_redo->add_do_method(animation.ptr(), "add_track", p_type);
664 			undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), ".");
665 			undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
666 			undo_redo->commit_action();
667 
668 		} break;
669 	}
670 }
671 
_anim_duplicate_keys(bool transpose)672 void AnimationKeyEditor::_anim_duplicate_keys(bool transpose) {
673 	//duplicait!
674 	if (selection.size() && animation.is_valid() && selected_track >= 0 && selected_track < animation->get_track_count()) {
675 
676 		int top_track = 0x7FFFFFFF;
677 		float top_time = 1e10;
678 		for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
679 
680 			const SelectedKey &sk = E->key();
681 
682 			float t = animation->track_get_key_time(sk.track, sk.key);
683 			if (t < top_time)
684 				top_time = t;
685 			if (sk.track < top_track)
686 				top_track = sk.track;
687 		}
688 		ERR_FAIL_COND(top_track == 0x7FFFFFFF || top_time == 1e10);
689 
690 		//
691 
692 		int start_track = transpose ? selected_track : top_track;
693 
694 		undo_redo->create_action(TTR("Anim Duplicate Keys"));
695 
696 		List<Pair<int, float> > new_selection_values;
697 
698 		for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
699 
700 			const SelectedKey &sk = E->key();
701 
702 			float t = animation->track_get_key_time(sk.track, sk.key);
703 
704 			float dst_time = t + (timeline_pos - top_time);
705 			int dst_track = sk.track + (start_track - top_track);
706 
707 			if (dst_track < 0 || dst_track >= animation->get_track_count())
708 				continue;
709 
710 			if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track))
711 				continue;
712 
713 			int existing_idx = animation->track_find_key(dst_track, dst_time, true);
714 
715 			undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
716 			undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", dst_track, dst_time);
717 
718 			Pair<int, float> p;
719 			p.first = dst_track;
720 			p.second = dst_time;
721 			new_selection_values.push_back(p);
722 
723 			if (existing_idx != -1) {
724 
725 				undo_redo->add_undo_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(dst_track, existing_idx), animation->track_get_key_transition(dst_track, existing_idx));
726 			}
727 		}
728 
729 		undo_redo->commit_action();
730 
731 		//reselect duplicated
732 
733 		Map<SelectedKey, KeyInfo> new_selection;
734 		for (List<Pair<int, float> >::Element *E = new_selection_values.front(); E; E = E->next()) {
735 
736 			int track = E->get().first;
737 			float time = E->get().second;
738 
739 			int existing_idx = animation->track_find_key(track, time, true);
740 
741 			if (existing_idx == -1)
742 				continue;
743 			SelectedKey sk2;
744 			sk2.track = track;
745 			sk2.key = existing_idx;
746 
747 			KeyInfo ki;
748 			ki.pos = time;
749 
750 			new_selection[sk2] = ki;
751 		}
752 
753 		selection = new_selection;
754 		track_editor->update();
755 		_edit_if_single_selection();
756 	}
757 }
758 
_menu_track(int p_type)759 void AnimationKeyEditor::_menu_track(int p_type) {
760 
761 	ERR_FAIL_COND(!animation.is_valid());
762 
763 	last_menu_track_opt = p_type;
764 	switch (p_type) {
765 
766 		case TRACK_MENU_SCALE:
767 		case TRACK_MENU_SCALE_PIVOT: {
768 
769 			scale_dialog->popup_centered(Size2(200, 100));
770 		} break;
771 		case TRACK_MENU_MOVE_UP: {
772 
773 			int idx = selected_track;
774 			if (idx > 0 && idx < animation->get_track_count()) {
775 				undo_redo->create_action(TTR("Move Anim Track Up"));
776 				undo_redo->add_do_method(animation.ptr(), "track_move_down", idx);
777 				undo_redo->add_undo_method(animation.ptr(), "track_move_up", idx - 1);
778 				undo_redo->commit_action();
779 				selected_track = idx - 1;
780 			}
781 
782 		} break;
783 		case TRACK_MENU_MOVE_DOWN: {
784 
785 			int idx = selected_track;
786 			if (idx >= 0 && idx < animation->get_track_count() - 1) {
787 				undo_redo->create_action(TTR("Move Anim Track Down"));
788 				undo_redo->add_do_method(animation.ptr(), "track_move_up", idx);
789 				undo_redo->add_undo_method(animation.ptr(), "track_move_down", idx + 1);
790 				undo_redo->commit_action();
791 				selected_track = idx + 1;
792 			}
793 
794 		} break;
795 		case TRACK_MENU_REMOVE: {
796 
797 			int idx = selected_track;
798 			if (idx >= 0 && idx < animation->get_track_count()) {
799 				undo_redo->create_action(TTR("Remove Anim Track"));
800 				undo_redo->add_do_method(animation.ptr(), "remove_track", idx);
801 				undo_redo->add_undo_method(animation.ptr(), "add_track", animation->track_get_type(idx), idx);
802 				undo_redo->add_undo_method(animation.ptr(), "track_set_path", idx, animation->track_get_path(idx));
803 				//todo interpolation
804 				for (int i = 0; i < animation->track_get_key_count(idx); i++) {
805 
806 					Variant v = animation->track_get_key_value(idx, i);
807 					float time = animation->track_get_key_time(idx, i);
808 					float trans = animation->track_get_key_transition(idx, i);
809 
810 					undo_redo->add_undo_method(animation.ptr(), "track_insert_key", idx, time, v);
811 					undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", idx, i, trans);
812 				}
813 
814 				undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", idx, animation->track_get_interpolation_type(idx));
815 				if (animation->track_get_type(idx) == Animation::TYPE_VALUE) {
816 					undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", idx, animation->value_track_get_update_mode(idx));
817 				}
818 
819 				undo_redo->commit_action();
820 			}
821 
822 		} break;
823 		case TRACK_MENU_DUPLICATE:
824 		case TRACK_MENU_DUPLICATE_TRANSPOSE: {
825 
826 			_anim_duplicate_keys(p_type == TRACK_MENU_DUPLICATE_TRANSPOSE);
827 		} break;
828 		case TRACK_MENU_SET_ALL_TRANS_LINEAR:
829 		case TRACK_MENU_SET_ALL_TRANS_CONSTANT:
830 		case TRACK_MENU_SET_ALL_TRANS_OUT:
831 		case TRACK_MENU_SET_ALL_TRANS_IN:
832 		case TRACK_MENU_SET_ALL_TRANS_INOUT:
833 		case TRACK_MENU_SET_ALL_TRANS_OUTIN: {
834 
835 			if (!selection.size() || !animation.is_valid())
836 				break;
837 
838 			float t = 0;
839 			switch (p_type) {
840 				case TRACK_MENU_SET_ALL_TRANS_LINEAR: t = 1.0; break;
841 				case TRACK_MENU_SET_ALL_TRANS_CONSTANT: t = 0.0; break;
842 				case TRACK_MENU_SET_ALL_TRANS_OUT: t = 0.5; break;
843 				case TRACK_MENU_SET_ALL_TRANS_IN: t = 2.0; break;
844 				case TRACK_MENU_SET_ALL_TRANS_INOUT: t = -0.5; break;
845 				case TRACK_MENU_SET_ALL_TRANS_OUTIN: t = -2.0; break;
846 			}
847 
848 			undo_redo->create_action(TTR("Set Transitions to:") + " " + rtos(t));
849 
850 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
851 
852 				const SelectedKey &sk = E->key();
853 
854 				undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", sk.track, sk.key, t);
855 				undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", sk.track, sk.key, animation->track_get_key_transition(sk.track, sk.key));
856 			}
857 
858 			undo_redo->commit_action();
859 
860 		} break;
861 		case TRACK_MENU_NEXT_STEP: {
862 
863 			if (animation.is_null())
864 				break;
865 			float step = animation->get_step();
866 			if (step == 0)
867 				step = 1;
868 
869 			float pos = timeline_pos;
870 
871 			pos = Math::stepify(pos + step, step);
872 			if (pos > animation->get_length())
873 				pos = animation->get_length();
874 			timeline_pos = pos;
875 			track_pos->update();
876 			emit_signal("timeline_changed", pos, true);
877 
878 		} break;
879 		case TRACK_MENU_PREV_STEP: {
880 			if (animation.is_null())
881 				break;
882 			float step = animation->get_step();
883 			if (step == 0)
884 				step = 1;
885 
886 			float pos = timeline_pos;
887 			pos = Math::stepify(pos - step, step);
888 			if (pos < 0)
889 				pos = 0;
890 			timeline_pos = pos;
891 			track_pos->update();
892 			emit_signal("timeline_changed", pos, true);
893 
894 		} break;
895 
896 		case TRACK_MENU_OPTIMIZE: {
897 
898 			optimize_dialog->popup_centered(Size2(250, 180));
899 		} break;
900 		case TRACK_MENU_CLEAN_UP: {
901 
902 			cleanup_dialog->popup_centered_minsize(Size2(300, 0));
903 		} break;
904 		case TRACK_MENU_CLEAN_UP_CONFIRM: {
905 
906 			if (cleanup_all->is_pressed()) {
907 				List<StringName> names;
908 				AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names);
909 				for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
910 					_cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E->get()));
911 				}
912 			} else {
913 				_cleanup_animation(animation);
914 			}
915 		} break;
916 		case CURVE_SET_LINEAR: {
917 			curve_edit->force_transition(1.0);
918 
919 		} break;
920 		case CURVE_SET_IN: {
921 
922 			curve_edit->force_transition(4.0);
923 
924 		} break;
925 		case CURVE_SET_OUT: {
926 
927 			curve_edit->force_transition(0.25);
928 		} break;
929 		case CURVE_SET_INOUT: {
930 			curve_edit->force_transition(-4);
931 
932 		} break;
933 		case CURVE_SET_OUTIN: {
934 
935 			curve_edit->force_transition(-0.25);
936 		} break;
937 		case CURVE_SET_CONSTANT: {
938 
939 			curve_edit->force_transition(0);
940 		} break;
941 	}
942 }
943 
_cleanup_animation(Ref<Animation> p_animation)944 void AnimationKeyEditor::_cleanup_animation(Ref<Animation> p_animation) {
945 
946 	for (int i = 0; i < p_animation->get_track_count(); i++) {
947 
948 		bool prop_exists = false;
949 		Variant::Type valid_type = Variant::NIL;
950 		Object *obj = NULL;
951 
952 		RES res;
953 		Node *node = root->get_node_and_resource(p_animation->track_get_path(i), res);
954 
955 		if (res.is_valid()) {
956 			obj = res.ptr();
957 		} else if (node) {
958 			obj = node;
959 		}
960 
961 		if (obj && p_animation->track_get_type(i) == Animation::TYPE_VALUE) {
962 			valid_type = obj->get_static_property_type(p_animation->track_get_path(i).get_property(), &prop_exists);
963 		}
964 
965 		if (!obj && cleanup_tracks->is_pressed()) {
966 
967 			p_animation->remove_track(i);
968 			i--;
969 			continue;
970 		}
971 
972 		if (!prop_exists || p_animation->track_get_type(i) != Animation::TYPE_VALUE || cleanup_keys->is_pressed() == false)
973 			continue;
974 
975 		for (int j = 0; j < p_animation->track_get_key_count(i); j++) {
976 
977 			Variant v = p_animation->track_get_key_value(i, j);
978 
979 			if (!Variant::can_convert(v.get_type(), valid_type)) {
980 				p_animation->track_remove_key(i, j);
981 				j--;
982 			}
983 		}
984 
985 		if (p_animation->track_get_key_count(i) == 0 && cleanup_tracks->is_pressed()) {
986 			p_animation->remove_track(i);
987 			i--;
988 		}
989 	}
990 
991 	undo_redo->clear_history();
992 	_update_paths();
993 }
994 
_animation_optimize()995 void AnimationKeyEditor::_animation_optimize() {
996 
997 	animation->optimize(optimize_linear_error->get_val(), optimize_angular_error->get_val(), optimize_max_angle->get_val());
998 	track_editor->update();
999 	undo_redo->clear_history();
1000 }
1001 
_get_zoom_scale() const1002 float AnimationKeyEditor::_get_zoom_scale() const {
1003 
1004 	float zv = zoom->get_val();
1005 	if (zv < 1) {
1006 		zv = 1.0 - zv;
1007 		return Math::pow(1.0 + zv, 8.0) * 100;
1008 	} else {
1009 		return 1.0 / Math::pow(zv, 8.0) * 100;
1010 	}
1011 }
1012 
_track_pos_draw()1013 void AnimationKeyEditor::_track_pos_draw() {
1014 
1015 	if (!animation.is_valid()) {
1016 		return;
1017 	}
1018 
1019 	Ref<StyleBox> style = get_stylebox("normal", "TextEdit");
1020 	Size2 size = track_editor->get_size() - style->get_minimum_size();
1021 	Size2 ofs = style->get_offset();
1022 
1023 	int settings_limit = size.width - right_data_size_cache;
1024 	int name_limit = settings_limit * name_column_ratio;
1025 
1026 	float keys_from = h_scroll->get_val();
1027 	float zoom_scale = _get_zoom_scale();
1028 	float keys_to = keys_from + (settings_limit - name_limit) / zoom_scale;
1029 
1030 	//will move to separate control! (for speedup)
1031 	if (timeline_pos >= keys_from && timeline_pos < keys_to) {
1032 		//draw position
1033 		int pixel = (timeline_pos - h_scroll->get_val()) * zoom_scale;
1034 		pixel += name_limit;
1035 		track_pos->draw_line(ofs + Point2(pixel, 0), ofs + Point2(pixel, size.height), Color(1, 0.3, 0.3, 0.8));
1036 	}
1037 }
1038 
_track_editor_draw()1039 void AnimationKeyEditor::_track_editor_draw() {
1040 
1041 	VisualServer::get_singleton()->canvas_item_set_clip(track_editor->get_canvas_item(), true);
1042 
1043 	if (animation.is_valid() && animation->get_track_count()) {
1044 		if (selected_track < 0)
1045 			selected_track = 0;
1046 		else if (selected_track >= animation->get_track_count())
1047 			selected_track = animation->get_track_count() - 1;
1048 	}
1049 
1050 	track_pos->update();
1051 	Control *te = track_editor;
1052 	Ref<StyleBox> style = get_stylebox("normal", "TextEdit");
1053 	te->draw_style_box(style, Rect2(Point2(), track_editor->get_size()));
1054 
1055 	if (te->has_focus()) {
1056 		te->draw_style_box(get_stylebox("bg_focus", "Tree"), Rect2(Point2(), track_editor->get_size()));
1057 	}
1058 
1059 	if (!animation.is_valid()) {
1060 		v_scroll->hide();
1061 		h_scroll->hide();
1062 		menu_add_track->set_disabled(true);
1063 		menu_track->set_disabled(true);
1064 		edit_button->set_disabled(true);
1065 		key_editor_tab->hide();
1066 		move_up_button->set_disabled(true);
1067 		move_down_button->set_disabled(true);
1068 		remove_button->set_disabled(true);
1069 
1070 		return;
1071 	}
1072 
1073 	menu_add_track->set_disabled(false);
1074 	menu_track->set_disabled(false);
1075 	edit_button->set_disabled(false);
1076 	move_up_button->set_disabled(false);
1077 	move_down_button->set_disabled(false);
1078 	remove_button->set_disabled(false);
1079 	if (edit_button->is_pressed())
1080 		key_editor_tab->show();
1081 
1082 	te_drawing = true;
1083 
1084 	Size2 size = te->get_size() - style->get_minimum_size();
1085 	Size2 ofs = style->get_offset();
1086 
1087 	Ref<Font> font = te->get_font("font", "Tree");
1088 	int sep = get_constant("vseparation", "Tree");
1089 	int hsep = get_constant("hseparation", "Tree");
1090 	Color color = get_color("font_color", "Tree");
1091 	Color sepcolor = get_color("guide_color", "Tree");
1092 	Color timecolor = get_color("prop_subsection", "Editor");
1093 	timecolor = Color::html("ff4a414f");
1094 	Color hover_color = Color(1, 1, 1, 0.05);
1095 	Color select_color = Color(1, 1, 1, 0.1);
1096 	Color invalid_path_color = Color(1, 0.6, 0.4, 0.5);
1097 	Color track_select_color = Color::html("ffbd8e8e");
1098 
1099 	Ref<Texture> remove_icon = get_icon("Remove", "EditorIcons");
1100 	Ref<Texture> move_up_icon = get_icon("MoveUp", "EditorIcons");
1101 	Ref<Texture> move_down_icon = get_icon("MoveDown", "EditorIcons");
1102 	Ref<Texture> remove_icon_hl = get_icon("RemoveHl", "EditorIcons");
1103 	Ref<Texture> move_up_icon_hl = get_icon("MoveUpHl", "EditorIcons");
1104 	Ref<Texture> move_down_icon_hl = get_icon("MoveDownHl", "EditorIcons");
1105 	Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons");
1106 	Ref<Texture> add_key_icon_hl = get_icon("TrackAddKeyHl", "EditorIcons");
1107 	Ref<Texture> down_icon = get_icon("select_arrow", "Tree");
1108 	Ref<Texture> interp_icon[3] = {
1109 		get_icon("InterpRaw", "EditorIcons"),
1110 		get_icon("InterpLinear", "EditorIcons"),
1111 		get_icon("InterpCubic", "EditorIcons")
1112 	};
1113 	Ref<Texture> cont_icon[3] = {
1114 		get_icon("TrackContinuous", "EditorIcons"),
1115 		get_icon("TrackDiscrete", "EditorIcons"),
1116 		get_icon("TrackTrigger", "EditorIcons")
1117 	};
1118 	Ref<Texture> type_icon[3] = {
1119 		get_icon("KeyValue", "EditorIcons"),
1120 		get_icon("KeyXform", "EditorIcons"),
1121 		get_icon("KeyCall", "EditorIcons")
1122 	};
1123 
1124 	Ref<Texture> invalid_icon = get_icon("KeyInvalid", "EditorIcons");
1125 	Ref<Texture> invalid_icon_hover = get_icon("KeyInvalidHover", "EditorIcons");
1126 
1127 	Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons");
1128 
1129 	Ref<Texture> type_hover = get_icon("KeyHover", "EditorIcons");
1130 	Ref<Texture> type_selected = get_icon("KeySelected", "EditorIcons");
1131 
1132 	int right_separator_ofs = down_icon->get_width() * 2 + add_key_icon->get_width() + interp_icon[0]->get_width() + cont_icon[0]->get_width() + hsep * 7;
1133 
1134 	int h = font->get_height() + sep;
1135 
1136 	int fit = (size.height / h) - 1;
1137 	int total = animation->get_track_count();
1138 	if (total < fit) {
1139 		v_scroll->hide();
1140 		v_scroll->set_max(total);
1141 		v_scroll->set_page(fit);
1142 	} else {
1143 		v_scroll->show();
1144 		v_scroll->set_max(total);
1145 		v_scroll->set_page(fit);
1146 	}
1147 
1148 	int settings_limit = size.width - right_separator_ofs;
1149 	int name_limit = settings_limit * name_column_ratio;
1150 
1151 	te->draw_line(ofs + Point2(name_limit, 0), ofs + Point2(name_limit, size.height), color);
1152 	te->draw_line(ofs + Point2(settings_limit, 0), ofs + Point2(settings_limit, size.height), color);
1153 	te->draw_texture(hsize_icon, ofs + Point2(name_limit - hsize_icon->get_width() - hsep, (h - hsize_icon->get_height()) / 2));
1154 
1155 	te->draw_line(ofs + Point2(0, h), ofs + Point2(size.width, h), color);
1156 	// draw time
1157 
1158 	float keys_from;
1159 	float keys_to;
1160 	float zoom_scale;
1161 
1162 	{
1163 
1164 		int zoomw = settings_limit - name_limit;
1165 
1166 		float scale = _get_zoom_scale();
1167 		zoom_scale = scale;
1168 
1169 		float l = animation->get_length();
1170 		if (l <= 0)
1171 			l = 0.001; //avoid crashor
1172 
1173 		int end_px = (l - h_scroll->get_val()) * scale;
1174 		int begin_px = -h_scroll->get_val() * scale;
1175 		Color notimecol;
1176 		notimecol.r = timecolor.gray();
1177 		notimecol.g = notimecol.r;
1178 		notimecol.b = notimecol.r;
1179 		notimecol.a = timecolor.a;
1180 
1181 		{
1182 
1183 			te->draw_rect(Rect2(ofs + Point2(name_limit, 0), Point2(zoomw - 1, h)), notimecol);
1184 
1185 			if (begin_px < zoomw && end_px > 0) {
1186 
1187 				if (begin_px < 0)
1188 					begin_px = 0;
1189 				if (end_px > zoomw)
1190 					end_px = zoomw;
1191 
1192 				te->draw_rect(Rect2(ofs + Point2(name_limit + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor);
1193 			}
1194 		}
1195 
1196 		keys_from = h_scroll->get_val();
1197 		keys_to = keys_from + zoomw / scale;
1198 
1199 		{
1200 			float time_min = 0;
1201 			float time_max = animation->get_length();
1202 			for (int i = 0; i < animation->get_track_count(); i++) {
1203 
1204 				if (animation->track_get_key_count(i) > 0) {
1205 
1206 					float beg = animation->track_get_key_time(i, 0);
1207 					if (beg < time_min)
1208 						time_min = beg;
1209 					float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1);
1210 					if (end > time_max)
1211 						time_max = end;
1212 				}
1213 			}
1214 
1215 			float extra = (zoomw / scale) * 0.5;
1216 
1217 			if (time_min < -0.001)
1218 				time_min -= extra;
1219 			time_max += extra;
1220 			h_scroll->set_min(time_min);
1221 			h_scroll->set_max(time_max);
1222 
1223 			if (zoomw / scale < (time_max - time_min)) {
1224 				h_scroll->show();
1225 
1226 			} else {
1227 
1228 				h_scroll->hide();
1229 			}
1230 		}
1231 
1232 		h_scroll->set_page(zoomw / scale);
1233 
1234 		Color color_time_sec = color;
1235 		Color color_time_dec = color;
1236 		color_time_dec.a *= 0.5;
1237 #define SC_ADJ 100
1238 		int min = 30;
1239 		int dec = 1;
1240 		int step = 1;
1241 		int decimals = 2;
1242 		bool step_found = false;
1243 
1244 		while (!step_found) {
1245 
1246 			static const int _multp[3] = { 1, 2, 5 };
1247 			for (int i = 0; i < 3; i++) {
1248 
1249 				step = (_multp[i] * dec);
1250 				if (step * scale / SC_ADJ > min) {
1251 					step_found = true;
1252 					break;
1253 				}
1254 			}
1255 			if (step_found)
1256 				break;
1257 			dec *= 10;
1258 			decimals--;
1259 			if (decimals < 0)
1260 				decimals = 0;
1261 		}
1262 
1263 		for (int i = 0; i < zoomw; i++) {
1264 
1265 			float pos = h_scroll->get_val() + double(i) / scale;
1266 			float prev = h_scroll->get_val() + (double(i) - 1.0) / scale;
1267 
1268 			int sc = int(Math::floor(pos * SC_ADJ));
1269 			int prev_sc = int(Math::floor(prev * SC_ADJ));
1270 			bool sub = (sc % SC_ADJ);
1271 
1272 			if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
1273 
1274 				int scd = sc < 0 ? prev_sc : sc;
1275 				te->draw_line(ofs + Point2(name_limit + i, 0), ofs + Point2(name_limit + i, h), color);
1276 				te->draw_string(font, ofs + Point2(name_limit + i + 3, (h - font->get_height()) / 2 + font->get_ascent()).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), sub ? color_time_dec : color_time_sec, zoomw - i);
1277 			}
1278 		}
1279 	}
1280 
1281 	color.a *= 0.5;
1282 
1283 	for (int i = 0; i < fit; i++) {
1284 
1285 		//this code sucks, i always forget how it works
1286 
1287 		int idx = v_scroll->get_val() + i;
1288 		if (idx >= animation->get_track_count())
1289 			break;
1290 		int y = h + i * h + sep;
1291 
1292 		bool prop_exists = false;
1293 		Variant::Type valid_type = Variant::NIL;
1294 		Object *obj = NULL;
1295 
1296 		RES res;
1297 		Node *node = root ? root->get_node_and_resource(animation->track_get_path(idx), res) : (Node *)NULL;
1298 
1299 		if (res.is_valid()) {
1300 			obj = res.ptr();
1301 		} else if (node) {
1302 			obj = node;
1303 		}
1304 
1305 		if (obj && animation->track_get_type(idx) == Animation::TYPE_VALUE) {
1306 			valid_type = obj->get_static_property_type(animation->track_get_path(idx).get_property(), &prop_exists);
1307 		}
1308 
1309 		if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx == mouse_over.track) {
1310 			Color sepc = hover_color;
1311 			te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width, h - 1)), sepc);
1312 		}
1313 
1314 		if (selected_track == idx) {
1315 			Color tc = select_color;
1316 			//tc.a*=0.7;
1317 			te->draw_rect(Rect2(ofs + Point2(0, y), Size2(size.width - 1, h - 1)), tc);
1318 		}
1319 
1320 		te->draw_texture(type_icon[animation->track_get_type(idx)], ofs + Point2(0, y + (h - type_icon[0]->get_height()) / 2).floor());
1321 		NodePath np = animation->track_get_path(idx);
1322 		Node *n = root ? root->get_node(np) : (Node *)NULL;
1323 		Color ncol = color;
1324 		if (n && editor_selection->is_selected(n))
1325 			ncol = track_select_color;
1326 		te->draw_string(font, Point2(ofs + Point2(type_icon[0]->get_width() + sep, y + font->get_ascent() + (sep / 2))).floor(), np, ncol, name_limit - (type_icon[0]->get_width() + sep) - 5);
1327 
1328 		if (!obj)
1329 			te->draw_line(ofs + Point2(0, y + h / 2), ofs + Point2(name_limit, y + h / 2), invalid_path_color);
1330 
1331 		te->draw_line(ofs + Point2(0, y + h), ofs + Point2(size.width, y + h), sepcolor);
1332 
1333 		Point2 icon_ofs = ofs + Point2(size.width, y + (h - remove_icon->get_height()) / 2).floor();
1334 		icon_ofs.y += 4;
1335 
1336 		/*		icon_ofs.x-=remove_icon->get_width();
1337 
1338 		te->draw_texture((mouse_over.over==MouseOver::OVER_REMOVE && mouse_over.track==idx)?remove_icon_hl:remove_icon,icon_ofs);
1339 		icon_ofs.x-=hsep;
1340 		icon_ofs.x-=move_down_icon->get_width();
1341 		te->draw_texture((mouse_over.over==MouseOver::OVER_DOWN && mouse_over.track==idx)?move_down_icon_hl:move_down_icon,icon_ofs);
1342 		icon_ofs.x-=hsep;
1343 		icon_ofs.x-=move_up_icon->get_width();
1344 		te->draw_texture((mouse_over.over==MouseOver::OVER_UP && mouse_over.track==idx)?move_up_icon_hl:move_up_icon,icon_ofs);
1345 		icon_ofs.x-=hsep;
1346 		te->draw_line(Point2(icon_ofs.x,ofs.y+y),Point2(icon_ofs.x,ofs.y+y+h),sepcolor);
1347 
1348 		icon_ofs.x-=hsep;
1349 		*/
1350 		icon_ofs.x -= down_icon->get_width();
1351 		te->draw_texture(down_icon, icon_ofs);
1352 
1353 		int interp_type = animation->track_get_interpolation_type(idx);
1354 		ERR_CONTINUE(interp_type < 0 || interp_type >= 3);
1355 		icon_ofs.x -= hsep;
1356 		icon_ofs.x -= interp_icon[interp_type]->get_width();
1357 		te->draw_texture(interp_icon[interp_type], icon_ofs);
1358 
1359 		icon_ofs.x -= hsep;
1360 		te->draw_line(Point2(icon_ofs.x, ofs.y + y), Point2(icon_ofs.x, ofs.y + y + h), sepcolor);
1361 
1362 		if (animation->track_get_type(idx) == Animation::TYPE_VALUE) {
1363 
1364 			int umode = animation->value_track_get_update_mode(idx);
1365 
1366 			icon_ofs.x -= hsep;
1367 			icon_ofs.x -= down_icon->get_width();
1368 			te->draw_texture(down_icon, icon_ofs);
1369 
1370 			icon_ofs.x -= hsep;
1371 			icon_ofs.x -= cont_icon[umode]->get_width();
1372 			te->draw_texture(cont_icon[umode], icon_ofs);
1373 		} else {
1374 
1375 			icon_ofs.x -= hsep * 2 + cont_icon[0]->get_width() + down_icon->get_width();
1376 		}
1377 
1378 		icon_ofs.x -= hsep;
1379 		te->draw_line(Point2(icon_ofs.x, ofs.y + y), Point2(icon_ofs.x, ofs.y + y + h), sepcolor);
1380 
1381 		icon_ofs.x -= hsep;
1382 		icon_ofs.x -= add_key_icon->get_width();
1383 		te->draw_texture((mouse_over.over == MouseOver::OVER_ADD_KEY && mouse_over.track == idx) ? add_key_icon_hl : add_key_icon, icon_ofs);
1384 
1385 		//draw the keys;
1386 		int tt = animation->track_get_type(idx);
1387 		float key_vofs = Math::floor((h - type_icon[tt]->get_height()) / 2);
1388 		float key_hofs = -Math::floor(type_icon[tt]->get_height() / 2);
1389 
1390 		int kc = animation->track_get_key_count(idx);
1391 		bool first = true;
1392 
1393 		for (int i = 0; i < kc; i++) {
1394 
1395 			float time = animation->track_get_key_time(idx, i);
1396 			if (time < keys_from)
1397 				continue;
1398 			if (time > keys_to) {
1399 
1400 				if (first && i > 0 && animation->track_get_key_value(idx, i) == animation->track_get_key_value(idx, i - 1)) {
1401 					//draw whole line
1402 					te->draw_line(ofs + Vector2(name_limit, y + h / 2), ofs + Point2(settings_limit, y + h / 2), color);
1403 				}
1404 
1405 				break;
1406 			}
1407 
1408 			float x = key_hofs + name_limit + (time - keys_from) * zoom_scale;
1409 
1410 			Ref<Texture> tex = type_icon[tt];
1411 
1412 			SelectedKey sk;
1413 			sk.key = i;
1414 			sk.track = idx;
1415 			if (selection.has(sk)) {
1416 
1417 				if (click.click == ClickOver::CLICK_MOVE_KEYS)
1418 					continue;
1419 				tex = type_selected;
1420 			}
1421 
1422 			if (mouse_over.over == MouseOver::OVER_KEY && mouse_over.track == idx && mouse_over.over_key == i)
1423 				tex = type_hover;
1424 
1425 			Variant value = animation->track_get_key_value(idx, i);
1426 			if (first && i > 0 && value == animation->track_get_key_value(idx, i - 1)) {
1427 
1428 				te->draw_line(ofs + Vector2(name_limit, y + h / 2), ofs + Point2(x, y + h / 2), color);
1429 			}
1430 
1431 			if (i < kc - 1 && value == animation->track_get_key_value(idx, i + 1)) {
1432 				float x_n = key_hofs + name_limit + (animation->track_get_key_time(idx, i + 1) - keys_from) * zoom_scale;
1433 
1434 				x_n = MIN(x_n, settings_limit);
1435 				te->draw_line(ofs + Point2(x_n, y + h / 2), ofs + Point2(x, y + h / 2), color);
1436 			}
1437 
1438 			if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) {
1439 				te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor());
1440 			}
1441 
1442 			if (prop_exists && !Variant::can_convert(value.get_type(), valid_type)) {
1443 				if (tex == type_hover)
1444 					te->draw_texture(invalid_icon_hover, ofs + Point2(x, y + key_vofs).floor());
1445 				else
1446 					te->draw_texture(invalid_icon, ofs + Point2(x, y + key_vofs).floor());
1447 			} else {
1448 
1449 				te->draw_texture(tex, ofs + Point2(x, y + key_vofs).floor());
1450 			}
1451 
1452 			first = false;
1453 		}
1454 	}
1455 
1456 	switch (click.click) {
1457 		case ClickOver::CLICK_SELECT_KEYS: {
1458 
1459 			te->draw_rect(Rect2(click.at, click.to - click.at), Color(0.7, 0.7, 1.0, 0.5));
1460 
1461 		} break;
1462 		case ClickOver::CLICK_MOVE_KEYS: {
1463 
1464 			float from_t = 1e20;
1465 
1466 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
1467 				float t = animation->track_get_key_time(E->key().track, E->key().key);
1468 				if (t < from_t)
1469 					from_t = t;
1470 			}
1471 
1472 			float motion = from_t + (click.to.x - click.at.x) / zoom_scale;
1473 			if (step->get_val())
1474 				motion = Math::stepify(motion, step->get_val());
1475 
1476 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
1477 
1478 				int idx = E->key().track;
1479 				int i = idx - v_scroll->get_val();
1480 				if (i < 0 || i >= fit)
1481 					continue;
1482 				int y = h + i * h + sep;
1483 
1484 				float key_vofs = Math::floor((h - type_selected->get_height()) / 2);
1485 				float key_hofs = -Math::floor(type_selected->get_height() / 2);
1486 
1487 				float time = animation->track_get_key_time(idx, E->key().key);
1488 				float diff = time - from_t;
1489 
1490 				float t = motion + diff;
1491 
1492 				float x = (t - keys_from) * zoom_scale;
1493 				//x+=click.to.x - click.at.x;
1494 				if (x < 0 || x >= (settings_limit - name_limit))
1495 					continue;
1496 
1497 				x += name_limit;
1498 
1499 				te->draw_texture(type_selected, ofs + Point2(x + key_hofs, y + key_vofs).floor());
1500 			}
1501 		} break;
1502 		default: {};
1503 	}
1504 
1505 	te_drawing = false;
1506 }
1507 
_track_name_changed(const String & p_name)1508 void AnimationKeyEditor::_track_name_changed(const String &p_name) {
1509 
1510 	ERR_FAIL_COND(!animation.is_valid());
1511 	undo_redo->create_action(TTR("Anim Track Rename"));
1512 	undo_redo->add_do_method(animation.ptr(), "track_set_path", track_name_editing, p_name);
1513 	undo_redo->add_undo_method(animation.ptr(), "track_set_path", track_name_editing, animation->track_get_path(track_name_editing));
1514 	undo_redo->commit_action();
1515 	track_name->hide();
1516 }
1517 
_track_menu_selected(int p_idx)1518 void AnimationKeyEditor::_track_menu_selected(int p_idx) {
1519 
1520 	ERR_FAIL_COND(!animation.is_valid());
1521 
1522 	if (interp_editing != -1) {
1523 
1524 		ERR_FAIL_INDEX(interp_editing, animation->get_track_count());
1525 		undo_redo->create_action(TTR("Anim Track Change Interpolation"));
1526 		undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", interp_editing, p_idx);
1527 		undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", interp_editing, animation->track_get_interpolation_type(interp_editing));
1528 		undo_redo->commit_action();
1529 	} else if (cont_editing != -1) {
1530 
1531 		ERR_FAIL_INDEX(cont_editing, animation->get_track_count());
1532 
1533 		undo_redo->create_action(TTR("Anim Track Change Value Mode"));
1534 		undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", cont_editing, p_idx);
1535 		undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", cont_editing, animation->value_track_get_update_mode(cont_editing));
1536 		undo_redo->commit_action();
1537 	} else {
1538 		switch (p_idx) {
1539 
1540 			case RIGHT_MENU_DUPLICATE:
1541 				_anim_duplicate_keys();
1542 				break;
1543 			case RIGHT_MENU_DUPLICATE_TRANSPOSE:
1544 				_anim_duplicate_keys(true);
1545 				break;
1546 			case RIGHT_MENU_REMOVE:
1547 				_anim_delete_keys();
1548 				break;
1549 		}
1550 	}
1551 }
1552 
1553 struct _AnimMoveRestore {
1554 
1555 	int track;
1556 	float time;
1557 	Variant key;
1558 	float transition;
1559 };
1560 
_clear_selection_for_anim(const Ref<Animation> & p_anim)1561 void AnimationKeyEditor::_clear_selection_for_anim(const Ref<Animation> &p_anim) {
1562 
1563 	if (!(animation == p_anim))
1564 		return;
1565 	//selection.clear();
1566 	_clear_selection();
1567 }
1568 
_select_at_anim(const Ref<Animation> & p_anim,int p_track,float p_pos)1569 void AnimationKeyEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos) {
1570 
1571 	if (!(animation == p_anim))
1572 		return;
1573 
1574 	int idx = animation->track_find_key(p_track, p_pos, true);
1575 	ERR_FAIL_COND(idx < 0);
1576 
1577 	SelectedKey sk;
1578 	sk.track = p_track;
1579 	sk.key = idx;
1580 	KeyInfo ki;
1581 	ki.pos = p_pos;
1582 
1583 	selection.insert(sk, ki);
1584 }
1585 
_find_hint_for_track(int p_idx,NodePath & r_base_path)1586 PropertyInfo AnimationKeyEditor::_find_hint_for_track(int p_idx, NodePath &r_base_path) {
1587 
1588 	r_base_path = NodePath();
1589 	ERR_FAIL_COND_V(!animation.is_valid(), PropertyInfo());
1590 	ERR_FAIL_INDEX_V(p_idx, animation->get_track_count(), PropertyInfo());
1591 
1592 	if (!root)
1593 		return PropertyInfo();
1594 
1595 	NodePath path = animation->track_get_path(p_idx);
1596 
1597 	if (!root->has_node_and_resource(path))
1598 		return PropertyInfo();
1599 
1600 	RES res;
1601 	Node *node = root->get_node_and_resource(path, res);
1602 
1603 	if (node) {
1604 		r_base_path = node->get_path();
1605 	}
1606 
1607 	String property = path.get_property();
1608 	if (property == "")
1609 		return PropertyInfo();
1610 
1611 	List<PropertyInfo> pinfo;
1612 	if (res.is_valid())
1613 		res->get_property_list(&pinfo);
1614 	else
1615 		node->get_property_list(&pinfo);
1616 
1617 	for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
1618 
1619 		if (E->get().name == property)
1620 			return E->get();
1621 	}
1622 
1623 	return PropertyInfo();
1624 }
1625 
_curve_transition_changed(float p_what)1626 void AnimationKeyEditor::_curve_transition_changed(float p_what) {
1627 
1628 	if (selection.size() == 0)
1629 		return;
1630 	if (selection.size() == 1)
1631 		undo_redo->create_action(TTR("Edit Node Curve"), UndoRedo::MERGE_ENDS);
1632 	else
1633 		undo_redo->create_action(TTR("Edit Selection Curve"), UndoRedo::MERGE_ENDS);
1634 
1635 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
1636 
1637 		int track = E->key().track;
1638 		int key = E->key().key;
1639 		float prev_val = animation->track_get_key_transition(track, key);
1640 		undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, p_what);
1641 		undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
1642 	}
1643 
1644 	undo_redo->commit_action();
1645 }
1646 
_toggle_edit_curves()1647 void AnimationKeyEditor::_toggle_edit_curves() {
1648 
1649 	if (edit_button->is_pressed())
1650 		key_editor_tab->show();
1651 	else
1652 		key_editor_tab->hide();
1653 }
1654 
_edit_if_single_selection()1655 bool AnimationKeyEditor::_edit_if_single_selection() {
1656 
1657 	if (selection.size() != 1) {
1658 
1659 		if (selection.size() == 0) {
1660 			curve_edit->set_mode(AnimationCurveEdit::MODE_DISABLED);
1661 			//print_line("disable");
1662 		} else {
1663 
1664 			curve_edit->set_mode(AnimationCurveEdit::MODE_MULTIPLE);
1665 			curve_edit->set_transition(1.0);
1666 			curve_edit->clear_multiples();
1667 			//add all
1668 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
1669 
1670 				curve_edit->set_multiple(animation->track_get_key_transition(E->key().track, E->key().key));
1671 			}
1672 			//print_line("multiple");
1673 		}
1674 		return false;
1675 	}
1676 	curve_edit->set_mode(AnimationCurveEdit::MODE_SINGLE);
1677 	//print_line("regular");
1678 
1679 	int idx = selection.front()->key().track;
1680 	int key = selection.front()->key().key;
1681 	{
1682 
1683 		key_edit->animation = animation;
1684 		key_edit->track = idx;
1685 		key_edit->key_ofs = animation->track_get_key_time(idx, key);
1686 		key_edit->hint = _find_hint_for_track(idx, key_edit->base);
1687 		key_edit->notify_change();
1688 
1689 		curve_edit->set_transition(animation->track_get_key_transition(idx, key));
1690 
1691 		/*key_edit_dialog->set_size( Size2( 200,200) );
1692 		key_edit_dialog->set_pos(  track_editor->get_global_pos() + ofs + mpos +Point2(-100,20));
1693 		key_edit_dialog->popup();*/
1694 	}
1695 
1696 	return true;
1697 }
1698 
_anim_delete_keys()1699 void AnimationKeyEditor::_anim_delete_keys() {
1700 	if (selection.size()) {
1701 		undo_redo->create_action(TTR("Anim Delete Keys"));
1702 
1703 		for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
1704 
1705 			undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
1706 			undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
1707 		}
1708 		undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
1709 		undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
1710 		undo_redo->commit_action();
1711 		//selection.clear();
1712 		accept_event();
1713 		_edit_if_single_selection();
1714 	}
1715 }
1716 
_track_editor_input_event(const InputEvent & p_input)1717 void AnimationKeyEditor::_track_editor_input_event(const InputEvent &p_input) {
1718 
1719 	Control *te = track_editor;
1720 	Ref<StyleBox> style = get_stylebox("normal", "TextEdit");
1721 
1722 	if (!animation.is_valid()) {
1723 		return;
1724 	}
1725 
1726 	Size2 size = te->get_size() - style->get_minimum_size();
1727 	Size2 ofs = style->get_offset();
1728 
1729 	Ref<Font> font = te->get_font("font", "Tree");
1730 	int sep = get_constant("vseparation", "Tree");
1731 	int hsep = get_constant("hseparation", "Tree");
1732 	Ref<Texture> remove_icon = get_icon("Remove", "EditorIcons");
1733 	Ref<Texture> move_up_icon = get_icon("MoveUp", "EditorIcons");
1734 	Ref<Texture> move_down_icon = get_icon("MoveDown", "EditorIcons");
1735 	Ref<Texture> down_icon = get_icon("select_arrow", "Tree");
1736 	Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons");
1737 	Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons");
1738 
1739 	Ref<Texture> interp_icon[3] = {
1740 		get_icon("InterpRaw", "EditorIcons"),
1741 		get_icon("InterpLinear", "EditorIcons"),
1742 		get_icon("InterpCubic", "EditorIcons")
1743 	};
1744 	Ref<Texture> cont_icon[3] = {
1745 		get_icon("TrackContinuous", "EditorIcons"),
1746 		get_icon("TrackDiscrete", "EditorIcons"),
1747 		get_icon("TrackTrigger", "EditorIcons")
1748 	};
1749 	Ref<Texture> type_icon[3] = {
1750 		get_icon("KeyValue", "EditorIcons"),
1751 		get_icon("KeyXform", "EditorIcons"),
1752 		get_icon("KeyCall", "EditorIcons")
1753 	};
1754 	int right_separator_ofs = down_icon->get_width() * 2 + add_key_icon->get_width() + interp_icon[0]->get_width() + cont_icon[0]->get_width() + hsep * 7;
1755 
1756 	int h = font->get_height() + sep;
1757 
1758 	int fit = (size.height / h) - 1;
1759 	int total = animation->get_track_count();
1760 	if (total < fit) {
1761 		v_scroll->hide();
1762 	} else {
1763 		v_scroll->show();
1764 		v_scroll->set_max(total);
1765 		v_scroll->set_page(fit);
1766 	}
1767 
1768 	int settings_limit = size.width - right_separator_ofs;
1769 	int name_limit = settings_limit * name_column_ratio;
1770 
1771 	switch (p_input.type) {
1772 
1773 		case InputEvent::KEY: {
1774 
1775 			if (p_input.key.scancode == KEY_D && p_input.key.pressed && p_input.key.mod.command) {
1776 
1777 				if (p_input.key.mod.shift)
1778 					_menu_track(TRACK_MENU_DUPLICATE_TRANSPOSE);
1779 				else
1780 					_menu_track(TRACK_MENU_DUPLICATE);
1781 
1782 				accept_event();
1783 
1784 			} else if (p_input.key.scancode == KEY_DELETE && p_input.key.pressed && click.click == ClickOver::CLICK_NONE) {
1785 
1786 				_anim_delete_keys();
1787 			} else if (animation.is_valid() && animation->get_track_count() > 0) {
1788 
1789 				if (p_input.is_pressed() && (p_input.is_action("ui_up") || p_input.is_action("ui_page_up"))) {
1790 
1791 					if (p_input.is_action("ui_up"))
1792 						selected_track--;
1793 					if (v_scroll->is_visible() && p_input.is_action("ui_page_up"))
1794 						selected_track--;
1795 
1796 					if (selected_track < 0)
1797 						selected_track = 0;
1798 
1799 					if (v_scroll->is_visible()) {
1800 						if (v_scroll->get_val() > selected_track)
1801 							v_scroll->set_val(selected_track);
1802 					}
1803 
1804 					track_editor->update();
1805 					accept_event();
1806 				}
1807 
1808 				if (p_input.is_pressed() && (p_input.is_action("ui_down") || p_input.is_action("ui_page_down"))) {
1809 
1810 					if (p_input.is_action("ui_down"))
1811 						selected_track++;
1812 					else if (v_scroll->is_visible() && p_input.is_action("ui_page_down"))
1813 						selected_track += v_scroll->get_page();
1814 
1815 					if (selected_track >= animation->get_track_count())
1816 						selected_track = animation->get_track_count() - 1;
1817 
1818 					if (v_scroll->is_visible() && v_scroll->get_page() + v_scroll->get_val() < selected_track + 1) {
1819 						v_scroll->set_val(selected_track - v_scroll->get_page() + 1);
1820 					}
1821 
1822 					track_editor->update();
1823 					accept_event();
1824 				}
1825 			}
1826 
1827 		} break;
1828 		case InputEvent::MOUSE_BUTTON: {
1829 
1830 			const InputEventMouseButton &mb = p_input.mouse_button;
1831 
1832 			if (mb.button_index == BUTTON_WHEEL_UP && mb.pressed) {
1833 
1834 				if (mb.mod.command) {
1835 					zoom->set_val(zoom->get_val() + zoom->get_step());
1836 				} else {
1837 					v_scroll->set_val(v_scroll->get_val() - v_scroll->get_page() * mb.factor / 8);
1838 				}
1839 			}
1840 
1841 			if (mb.button_index == BUTTON_WHEEL_DOWN && mb.pressed) {
1842 
1843 				if (mb.mod.command) {
1844 					zoom->set_val(zoom->get_val() - zoom->get_step());
1845 				} else {
1846 					v_scroll->set_val(v_scroll->get_val() + v_scroll->get_page() * mb.factor / 8);
1847 				}
1848 			}
1849 
1850 			if (mb.button_index == BUTTON_WHEEL_RIGHT && mb.pressed) {
1851 				h_scroll->set_val(h_scroll->get_val() - h_scroll->get_page() * mb.factor / 8);
1852 			}
1853 
1854 			if (mb.button_index == BUTTON_WHEEL_LEFT && mb.pressed) {
1855 
1856 				v_scroll->set_val(v_scroll->get_val() + v_scroll->get_page() * mb.factor / 8);
1857 			}
1858 
1859 			if (mb.button_index == BUTTON_RIGHT && mb.pressed) {
1860 
1861 				Point2 mpos = Point2(mb.x, mb.y) - ofs;
1862 
1863 				if (selection.size() == 0) {
1864 					// Auto-select on right-click if nothing is selected
1865 					// Note: This code is pretty much duplicated from the left click code,
1866 					// both codes could be moved into a function to avoid the duplicated code.
1867 					Point2 mpos = Point2(mb.x, mb.y) - ofs;
1868 
1869 					if (mpos.y < h) {
1870 						return;
1871 					}
1872 
1873 					mpos.y -= h;
1874 
1875 					int idx = mpos.y / h;
1876 					idx += v_scroll->get_val();
1877 					if (idx < 0 || idx >= animation->get_track_count())
1878 						break;
1879 
1880 					if (mpos.x < name_limit) {
1881 					} else if (mpos.x < settings_limit) {
1882 						float pos = mpos.x - name_limit;
1883 						pos /= _get_zoom_scale();
1884 						pos += h_scroll->get_val();
1885 						float w_time = (type_icon[0]->get_width() / _get_zoom_scale()) / 2.0;
1886 
1887 						int kidx = animation->track_find_key(idx, pos);
1888 						int kidx_n = kidx + 1;
1889 						int key = -1;
1890 
1891 						if (kidx >= 0 && kidx < animation->track_get_key_count(idx)) {
1892 
1893 							float kpos = animation->track_get_key_time(idx, kidx);
1894 							if (ABS(pos - kpos) <= w_time) {
1895 
1896 								key = kidx;
1897 							}
1898 						}
1899 
1900 						if (key == -1 && kidx_n >= 0 && kidx_n < animation->track_get_key_count(idx)) {
1901 
1902 							float kpos = animation->track_get_key_time(idx, kidx_n);
1903 							if (ABS(pos - kpos) <= w_time) {
1904 
1905 								key = kidx_n;
1906 							}
1907 						}
1908 
1909 						if (key == -1) {
1910 
1911 							click.click = ClickOver::CLICK_SELECT_KEYS;
1912 							click.at = Point2(mb.x, mb.y);
1913 							click.to = click.at;
1914 							click.shift = mb.mod.shift;
1915 							selected_track = idx;
1916 							track_editor->update();
1917 							//drag select region
1918 							return;
1919 						}
1920 
1921 						SelectedKey sk;
1922 						sk.track = idx;
1923 						sk.key = key;
1924 						KeyInfo ki;
1925 						ki.pos = animation->track_get_key_time(idx, key);
1926 						click.shift = mb.mod.shift;
1927 						click.selk = sk;
1928 
1929 						if (!mb.mod.shift && !selection.has(sk))
1930 							_clear_selection();
1931 
1932 						selection.insert(sk, ki);
1933 
1934 						click.click = ClickOver::CLICK_MOVE_KEYS;
1935 						click.at = Point2(mb.x, mb.y);
1936 						click.to = click.at;
1937 						update();
1938 						selected_track = idx;
1939 						track_editor->update();
1940 
1941 						if (_edit_if_single_selection() && mb.mod.command) {
1942 							edit_button->set_pressed(true);
1943 							key_editor_tab->show();
1944 						}
1945 					}
1946 				}
1947 
1948 				if (selection.size()) {
1949 					// User has right clicked and we have a selection, show a popup menu with options
1950 					track_menu->clear();
1951 					track_menu->set_size(Point2(1, 1));
1952 					track_menu->add_item(TTR("Duplicate Selection"), RIGHT_MENU_DUPLICATE);
1953 					track_menu->add_item(TTR("Duplicate Transposed"), RIGHT_MENU_DUPLICATE_TRANSPOSE);
1954 					track_menu->add_item(TTR("Remove Selection"), RIGHT_MENU_REMOVE);
1955 
1956 					track_menu->set_pos(te->get_global_pos() + mpos);
1957 
1958 					interp_editing = -1;
1959 					cont_editing = -1;
1960 
1961 					track_menu->popup();
1962 				}
1963 			}
1964 
1965 			if (mb.button_index == BUTTON_LEFT && !(mb.button_mask & ~BUTTON_MASK_LEFT)) {
1966 
1967 				if (mb.pressed) {
1968 
1969 					Point2 mpos = Point2(mb.x, mb.y) - ofs;
1970 
1971 					if (mpos.y < h) {
1972 
1973 						if (mpos.x < name_limit && mpos.x > (name_limit - hsep - hsize_icon->get_width())) {
1974 
1975 							click.click = ClickOver::CLICK_RESIZE_NAMES;
1976 							click.at = Point2(mb.x, mb.y);
1977 							click.to = click.at;
1978 							click.at.y = name_limit;
1979 						}
1980 
1981 						if (mpos.x >= name_limit && mpos.x < settings_limit) {
1982 							//seek
1983 							//int zoomw = settings_limit-name_limit;
1984 							float scale = _get_zoom_scale();
1985 							float pos = h_scroll->get_val() + (mpos.x - name_limit) / scale;
1986 							if (animation->get_step())
1987 								pos = Math::stepify(pos, animation->get_step());
1988 
1989 							if (pos < 0)
1990 								pos = 0;
1991 							if (pos >= animation->get_length())
1992 								pos = animation->get_length();
1993 							timeline_pos = pos;
1994 							click.click = ClickOver::CLICK_DRAG_TIMELINE;
1995 							click.at = Point2(mb.x, mb.y);
1996 							click.to = click.at;
1997 							emit_signal("timeline_changed", pos, false);
1998 						}
1999 
2000 						return;
2001 					}
2002 
2003 					mpos.y -= h;
2004 
2005 					int idx = mpos.y / h;
2006 					idx += v_scroll->get_val();
2007 					if (idx < 0)
2008 						break;
2009 
2010 					if (idx >= animation->get_track_count()) {
2011 
2012 						if (mpos.x >= name_limit && mpos.x < settings_limit) {
2013 
2014 							click.click = ClickOver::CLICK_SELECT_KEYS;
2015 							click.at = Point2(mb.x, mb.y);
2016 							click.to = click.at;
2017 							//drag select region
2018 						}
2019 
2020 						break;
2021 					}
2022 
2023 					if (mpos.x < name_limit) {
2024 						//name column
2025 
2026 						// area
2027 						if (idx != selected_track) {
2028 
2029 							selected_track = idx;
2030 							track_editor->update();
2031 							break;
2032 						}
2033 
2034 						Rect2 area(ofs.x, ofs.y + ((int(mpos.y) / h) + 1) * h, name_limit, h);
2035 						track_name->set_text(animation->track_get_path(idx));
2036 						track_name->set_pos(te->get_global_pos() + area.pos);
2037 						track_name->set_size(area.size);
2038 						track_name->show_modal();
2039 						track_name->grab_focus();
2040 						track_name->select_all();
2041 						track_name_editing = idx;
2042 
2043 					} else if (mpos.x < settings_limit) {
2044 
2045 						float pos = mpos.x - name_limit;
2046 						pos /= _get_zoom_scale();
2047 						pos += h_scroll->get_val();
2048 						float w_time = (type_icon[0]->get_width() / _get_zoom_scale()) / 2.0;
2049 
2050 						int kidx = animation->track_find_key(idx, pos);
2051 						int kidx_n = kidx + 1;
2052 						int key = -1;
2053 
2054 						if (kidx >= 0 && kidx < animation->track_get_key_count(idx)) {
2055 
2056 							float kpos = animation->track_get_key_time(idx, kidx);
2057 							if (ABS(pos - kpos) <= w_time) {
2058 
2059 								key = kidx;
2060 							}
2061 						}
2062 
2063 						if (key == -1 && kidx_n >= 0 && kidx_n < animation->track_get_key_count(idx)) {
2064 
2065 							float kpos = animation->track_get_key_time(idx, kidx_n);
2066 							if (ABS(pos - kpos) <= w_time) {
2067 
2068 								key = kidx_n;
2069 							}
2070 						}
2071 
2072 						if (key == -1) {
2073 
2074 							click.click = ClickOver::CLICK_SELECT_KEYS;
2075 							click.at = Point2(mb.x, mb.y);
2076 							click.to = click.at;
2077 							click.shift = mb.mod.shift;
2078 							selected_track = idx;
2079 							track_editor->update();
2080 							//drag select region
2081 							return;
2082 						}
2083 
2084 						SelectedKey sk;
2085 						sk.track = idx;
2086 						sk.key = key;
2087 						KeyInfo ki;
2088 						ki.pos = animation->track_get_key_time(idx, key);
2089 						click.shift = mb.mod.shift;
2090 						click.selk = sk;
2091 
2092 						if (!mb.mod.shift && !selection.has(sk))
2093 							_clear_selection();
2094 
2095 						selection.insert(sk, ki);
2096 
2097 						click.click = ClickOver::CLICK_MOVE_KEYS;
2098 						click.at = Point2(mb.x, mb.y);
2099 						click.to = click.at;
2100 						update();
2101 						selected_track = idx;
2102 						track_editor->update();
2103 
2104 						if (_edit_if_single_selection() && mb.mod.command) {
2105 							edit_button->set_pressed(true);
2106 							key_editor_tab->show();
2107 						}
2108 					} else {
2109 						//button column
2110 						int ofsx = size.width - mpos.x;
2111 						if (ofsx < 0)
2112 							break;
2113 						/*
2114 						if (ofsx < remove_icon->get_width()) {
2115 
2116 							undo_redo->create_action("Remove Anim Track");
2117 							undo_redo->add_do_method(animation.ptr(),"remove_track",idx);
2118 							undo_redo->add_undo_method(animation.ptr(),"add_track",animation->track_get_type(idx),idx);
2119 							undo_redo->add_undo_method(animation.ptr(),"track_set_path",idx,animation->track_get_path(idx));
2120 							//todo interpolation
2121 							for(int i=0;i<animation->track_get_key_count(idx);i++) {
2122 
2123 								Variant v = animation->track_get_key_value(idx,i);
2124 								float time =  animation->track_get_key_time(idx,i);
2125 								float trans =  animation->track_get_key_transition(idx,i);
2126 
2127 								undo_redo->add_undo_method(animation.ptr(),"track_insert_key",idx,time,v);
2128 								undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",idx,i,trans);
2129 
2130 							}
2131 
2132 							undo_redo->add_undo_method(animation.ptr(),"track_set_interpolation_type",idx,animation->track_get_interpolation_type(idx));
2133 							if (animation->track_get_type(idx)==Animation::TYPE_VALUE) {
2134 								undo_redo->add_undo_method(animation.ptr(),"value_track_set_continuous",idx,animation->value_track_is_continuous(idx));
2135 
2136 							}
2137 
2138 							undo_redo->commit_action();
2139 
2140 
2141 							return;
2142 						}
2143 
2144 						ofsx-=hsep+remove_icon->get_width();
2145 
2146 						if (ofsx < move_down_icon->get_width()) {
2147 
2148 							if (idx < animation->get_track_count() -1) {
2149 								undo_redo->create_action("Move Anim Track Down");
2150 								undo_redo->add_do_method(animation.ptr(),"track_move_up",idx);
2151 								undo_redo->add_undo_method(animation.ptr(),"track_move_down",idx+1);
2152 								undo_redo->commit_action();
2153 							}
2154 							return;
2155 						}
2156 
2157 						ofsx-=hsep+move_down_icon->get_width();
2158 
2159 						if (ofsx < move_up_icon->get_width()) {
2160 
2161 							if (idx >0) {
2162 								undo_redo->create_action("Move Anim Track Up");
2163 								undo_redo->add_do_method(animation.ptr(),"track_move_down",idx);
2164 								undo_redo->add_undo_method(animation.ptr(),"track_move_up",idx-1);
2165 								undo_redo->commit_action();
2166 							}
2167 							return;
2168 						}
2169 
2170 
2171 						ofsx-=hsep*3+move_up_icon->get_width();
2172 						*/
2173 
2174 						if (ofsx < down_icon->get_width() + interp_icon[0]->get_width() + hsep * 2) {
2175 
2176 							track_menu->clear();
2177 							track_menu->set_size(Point2(1, 1));
2178 							static const char *interp_name[3] = { "Nearest", "Linear", "Cubic" };
2179 							for (int i = 0; i < 3; i++) {
2180 								track_menu->add_icon_item(interp_icon[i], interp_name[i]);
2181 							}
2182 
2183 							int lofs = remove_icon->get_width() + move_up_icon->get_width() + move_down_icon->get_width() + down_icon->get_width() * 2 + hsep * 7; //interp_icon[0]->get_width() + cont_icon[0]->get_width() ;
2184 							int popup_y = ofs.y + ((int(mpos.y) / h) + 2) * h;
2185 							int popup_x = ofs.x + size.width - lofs;
2186 
2187 							track_menu->set_pos(te->get_global_pos() + Point2(popup_x, popup_y));
2188 
2189 							interp_editing = idx;
2190 							cont_editing = -1;
2191 
2192 							track_menu->popup();
2193 
2194 							return;
2195 						}
2196 
2197 						ofsx -= hsep * 2 + interp_icon[0]->get_width() + down_icon->get_width();
2198 
2199 						if (ofsx < down_icon->get_width() + cont_icon[0]->get_width()) {
2200 
2201 							track_menu->clear();
2202 							track_menu->set_size(Point2(1, 1));
2203 							String cont_name[3] = { TTR("Continuous"), TTR("Discrete"), TTR("Trigger") };
2204 							for (int i = 0; i < 3; i++) {
2205 								track_menu->add_icon_item(cont_icon[i], cont_name[i]);
2206 							}
2207 
2208 							int lofs = settings_limit;
2209 							int popup_y = ofs.y + ((int(mpos.y) / h) + 2) * h;
2210 							int popup_x = ofs.x + lofs;
2211 
2212 							track_menu->set_pos(te->get_global_pos() + Point2(popup_x, popup_y));
2213 
2214 							interp_editing = -1;
2215 							cont_editing = idx;
2216 
2217 							track_menu->popup();
2218 
2219 							return;
2220 						}
2221 
2222 						ofsx -= hsep * 3 + cont_icon[0]->get_width() + down_icon->get_width();
2223 
2224 						if (ofsx < add_key_icon->get_width()) {
2225 
2226 							Animation::TrackType tt = animation->track_get_type(idx);
2227 
2228 							float pos = timeline_pos;
2229 							int existing = animation->track_find_key(idx, pos, true);
2230 
2231 							Variant newval;
2232 
2233 							if (tt == Animation::TYPE_TRANSFORM) {
2234 								Dictionary d;
2235 								d["loc"] = Vector3();
2236 								d["rot"] = Quat();
2237 								d["scale"] = Vector3();
2238 								newval = d;
2239 
2240 							} else if (tt == Animation::TYPE_METHOD) {
2241 
2242 								Dictionary d;
2243 								d["method"] = "";
2244 								d["args"] = Vector<Variant>();
2245 
2246 								newval = d;
2247 							} else if (tt == Animation::TYPE_VALUE) {
2248 
2249 								NodePath np;
2250 								PropertyInfo inf = _find_hint_for_track(idx, np);
2251 								if (inf.type != Variant::NIL) {
2252 
2253 									Variant::CallError err;
2254 									newval = Variant::construct(inf.type, NULL, 0, err);
2255 								}
2256 
2257 								if (newval.get_type() == Variant::NIL) {
2258 									//popup a new type
2259 									cvi_track = idx;
2260 									cvi_pos = pos;
2261 
2262 									type_menu->set_pos(get_global_pos() + mpos + ofs);
2263 									type_menu->popup();
2264 									return;
2265 								}
2266 							}
2267 
2268 							undo_redo->create_action(TTR("Anim Add Key"));
2269 
2270 							undo_redo->add_do_method(animation.ptr(), "track_insert_key", idx, pos, newval, 1);
2271 							undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", idx, pos);
2272 
2273 							if (existing != -1) {
2274 								Variant v = animation->track_get_key_value(idx, existing);
2275 								float trans = animation->track_get_key_transition(idx, existing);
2276 								undo_redo->add_undo_method(animation.ptr(), "track_insert_key", idx, pos, v, trans);
2277 							}
2278 
2279 							undo_redo->commit_action();
2280 
2281 							return;
2282 						}
2283 					}
2284 
2285 				} else {
2286 
2287 					switch (click.click) {
2288 						case ClickOver::CLICK_SELECT_KEYS: {
2289 
2290 							float zoom_scale = _get_zoom_scale();
2291 							float keys_from = h_scroll->get_val();
2292 							float keys_to = keys_from + (settings_limit - name_limit) / zoom_scale;
2293 
2294 							float from_time = keys_from + (click.at.x - (name_limit + ofs.x)) / zoom_scale;
2295 							float to_time = keys_from + (click.to.x - (name_limit + ofs.x)) / zoom_scale;
2296 
2297 							if (to_time < from_time)
2298 								SWAP(from_time, to_time);
2299 
2300 							if (from_time > keys_to || to_time < keys_from)
2301 								break;
2302 
2303 							if (from_time < keys_from)
2304 								from_time = keys_from;
2305 
2306 							if (to_time >= keys_to)
2307 								to_time = keys_to;
2308 
2309 							int from_track = int(click.at.y - ofs.y - h - sep) / h + v_scroll->get_val();
2310 							int to_track = int(click.to.y - ofs.y - h - sep) / h + v_scroll->get_val();
2311 							int from_mod = int(click.at.y - ofs.y - sep) % h;
2312 							int to_mod = int(click.to.y - ofs.y - sep) % h;
2313 
2314 							if (to_track < from_track) {
2315 
2316 								SWAP(from_track, to_track);
2317 								SWAP(from_mod, to_mod);
2318 							}
2319 
2320 							if ((from_mod > (h / 2)) && ((click.at.y - ofs.y) >= (h + sep))) {
2321 								from_track++;
2322 							}
2323 
2324 							if (to_mod < h / 2) {
2325 								to_track--;
2326 							}
2327 
2328 							if (from_track > to_track) {
2329 								if (!click.shift)
2330 									_clear_selection();
2331 								_edit_if_single_selection();
2332 								break;
2333 							}
2334 
2335 							int tracks_from = v_scroll->get_val();
2336 							int tracks_to = v_scroll->get_val() + fit - 1;
2337 							if (tracks_to >= animation->get_track_count())
2338 								tracks_to = animation->get_track_count() - 1;
2339 
2340 							tracks_from = 0;
2341 							tracks_to = animation->get_track_count() - 1;
2342 							if (to_track > tracks_to)
2343 								to_track = tracks_to;
2344 							if (from_track < tracks_from)
2345 								from_track = tracks_from;
2346 
2347 							if (from_track > tracks_to || to_track < tracks_from) {
2348 								if (!click.shift)
2349 									_clear_selection();
2350 								_edit_if_single_selection();
2351 								break;
2352 							}
2353 
2354 							if (!click.shift)
2355 								_clear_selection();
2356 
2357 							int higher_track = 0x7FFFFFFF;
2358 							for (int i = from_track; i <= to_track; i++) {
2359 
2360 								int kc = animation->track_get_key_count(i);
2361 								for (int j = 0; j < kc; j++) {
2362 
2363 									float t = animation->track_get_key_time(i, j);
2364 									if (t < from_time)
2365 										continue;
2366 									if (t > to_time)
2367 										break;
2368 
2369 									if (i < higher_track)
2370 										higher_track = i;
2371 
2372 									SelectedKey sk;
2373 									sk.track = i;
2374 									sk.key = j;
2375 									KeyInfo ki;
2376 									ki.pos = t;
2377 									selection[sk] = ki;
2378 								}
2379 							}
2380 
2381 							if (higher_track != 0x7FFFFFFF) {
2382 								selected_track = higher_track;
2383 								track_editor->update();
2384 							}
2385 
2386 							_edit_if_single_selection();
2387 
2388 						} break;
2389 						case ClickOver::CLICK_MOVE_KEYS: {
2390 
2391 							if (selection.empty())
2392 								break;
2393 							if (click.at == click.to) {
2394 
2395 								if (!click.shift) {
2396 
2397 									KeyInfo ki = selection[click.selk];
2398 									_clear_selection();
2399 									selection[click.selk] = ki;
2400 									_edit_if_single_selection();
2401 								}
2402 
2403 								break;
2404 							}
2405 
2406 							float from_t = 1e20;
2407 
2408 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
2409 								float t = animation->track_get_key_time(E->key().track, E->key().key);
2410 								if (t < from_t)
2411 									from_t = t;
2412 							}
2413 
2414 							float motion = from_t + (click.to.x - click.at.x) / _get_zoom_scale();
2415 							if (step->get_val())
2416 								motion = Math::stepify(motion, step->get_val());
2417 
2418 							undo_redo->create_action(TTR("Anim Move Keys"));
2419 
2420 							List<_AnimMoveRestore> to_restore;
2421 
2422 							// 1-remove the keys
2423 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2424 
2425 								undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
2426 							}
2427 							// 2- remove overlapped keys
2428 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2429 
2430 								float newtime = E->get().pos - from_t + motion;
2431 								int idx = animation->track_find_key(E->key().track, newtime, true);
2432 								if (idx == -1)
2433 									continue;
2434 								SelectedKey sk;
2435 								sk.key = idx;
2436 								sk.track = E->key().track;
2437 								if (selection.has(sk))
2438 									continue; //already in selection, don't save
2439 
2440 								undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_pos", E->key().track, newtime);
2441 								_AnimMoveRestore amr;
2442 
2443 								amr.key = animation->track_get_key_value(E->key().track, idx);
2444 								amr.track = E->key().track;
2445 								amr.time = newtime;
2446 								amr.transition = animation->track_get_key_transition(E->key().track, idx);
2447 
2448 								to_restore.push_back(amr);
2449 							}
2450 
2451 							// 3-move the keys (re insert them)
2452 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2453 
2454 								float newpos = E->get().pos - from_t + motion;
2455 								//if (newpos<0)
2456 								//	continue; //no add at the begining
2457 								undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
2458 							}
2459 
2460 							// 4-(undo) remove inserted keys
2461 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2462 
2463 								float newpos = E->get().pos + -from_t + motion;
2464 								//if (newpos<0)
2465 								//	continue; //no remove what no inserted
2466 								undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", E->key().track, newpos);
2467 							}
2468 
2469 							// 5-(undo) reinsert keys
2470 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2471 
2472 								undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
2473 							}
2474 
2475 							// 6-(undo) reinsert overlapped keys
2476 							for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
2477 
2478 								_AnimMoveRestore &amr = E->get();
2479 								undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
2480 							}
2481 
2482 							// 6-(undo) reinsert overlapped keys
2483 							for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
2484 
2485 								_AnimMoveRestore &amr = E->get();
2486 								undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
2487 							}
2488 
2489 							undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
2490 							undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
2491 
2492 							// 7-reselect
2493 
2494 							for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
2495 
2496 								float oldpos = E->get().pos;
2497 								float newpos = oldpos - from_t + motion;
2498 								//if (newpos>=0)
2499 								undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
2500 								undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
2501 							}
2502 
2503 							undo_redo->commit_action();
2504 							_edit_if_single_selection();
2505 
2506 						} break;
2507 						default: {}
2508 					}
2509 
2510 					//button released
2511 					click.click = ClickOver::CLICK_NONE;
2512 					track_editor->update();
2513 				}
2514 			}
2515 
2516 		} break;
2517 
2518 		case InputEvent::MOUSE_MOTION: {
2519 
2520 			const InputEventMouseMotion &mb = p_input.mouse_motion;
2521 
2522 			mouse_over.over = MouseOver::OVER_NONE;
2523 			mouse_over.track = -1;
2524 			te->update();
2525 			track_editor->set_tooltip("");
2526 
2527 			if (!track_editor->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
2528 				track_editor->call_deferred("grab_focus");
2529 
2530 			if (click.click != ClickOver::CLICK_NONE) {
2531 
2532 				switch (click.click) {
2533 					case ClickOver::CLICK_RESIZE_NAMES: {
2534 
2535 						float base = click.at.y;
2536 						float clickp = click.at.x - ofs.x;
2537 						float dif = base - clickp;
2538 
2539 						float target = mb.x + dif - ofs.x;
2540 
2541 						float ratio = target / settings_limit;
2542 
2543 						if (ratio > 0.9)
2544 							ratio = 0.9;
2545 						else if (ratio < 0.2)
2546 							ratio = 0.2;
2547 
2548 						name_column_ratio = ratio;
2549 
2550 					} break;
2551 					case ClickOver::CLICK_DRAG_TIMELINE: {
2552 
2553 						Point2 mpos = Point2(mb.x, mb.y) - ofs;
2554 						/*
2555 						if (mpos.x<name_limit)
2556 							mpos.x=name_limit;
2557 						if (mpos.x>settings_limit)
2558 							mpos.x=settings_limit;
2559 							*/
2560 
2561 						//int zoomw = settings_limit-name_limit;
2562 						float scale = _get_zoom_scale();
2563 						float pos = h_scroll->get_val() + (mpos.x - name_limit) / scale;
2564 						if (animation->get_step()) {
2565 							pos = Math::stepify(pos, animation->get_step());
2566 						}
2567 						if (pos < 0)
2568 							pos = 0;
2569 						if (pos >= animation->get_length())
2570 							pos = animation->get_length();
2571 
2572 						if (pos < h_scroll->get_val()) {
2573 							h_scroll->set_val(pos);
2574 						} else if (pos > h_scroll->get_val() + (settings_limit - name_limit) / scale) {
2575 							h_scroll->set_val(pos - (settings_limit - name_limit) / scale);
2576 						}
2577 
2578 						timeline_pos = pos;
2579 						emit_signal("timeline_changed", pos, true);
2580 
2581 					} break;
2582 					case ClickOver::CLICK_SELECT_KEYS: {
2583 
2584 						click.to = Point2(mb.x, mb.y);
2585 						if (click.to.y < h && click.at.y > h && mb.relative_y < 0) {
2586 
2587 							float prev = v_scroll->get_val();
2588 							v_scroll->set_val(v_scroll->get_val() - 1);
2589 							if (prev != v_scroll->get_val())
2590 								click.at.y += h;
2591 						}
2592 						if (click.to.y > size.height && click.at.y < size.height && mb.relative_y > 0) {
2593 
2594 							float prev = v_scroll->get_val();
2595 							v_scroll->set_val(v_scroll->get_val() + 1);
2596 							if (prev != v_scroll->get_val())
2597 								click.at.y -= h;
2598 						}
2599 
2600 					} break;
2601 					case ClickOver::CLICK_MOVE_KEYS: {
2602 
2603 						click.to = Point2(mb.x, mb.y);
2604 					} break;
2605 					default: {}
2606 				}
2607 
2608 				return;
2609 			} else if (mb.button_mask & BUTTON_MASK_MIDDLE) {
2610 
2611 				int rel = mb.relative_x;
2612 				float relf = rel / _get_zoom_scale();
2613 				h_scroll->set_val(h_scroll->get_val() - relf);
2614 			}
2615 
2616 			if (mb.button_mask == 0) {
2617 
2618 				Point2 mpos = Point2(mb.x, mb.y) - ofs;
2619 
2620 				if (mpos.y < h) {
2621 #if 0
2622 					//seek
2623 					//int zoomw = settings_limit-name_limit;
2624 					float scale = _get_zoom_scale();
2625 					float pos = h_scroll->get_val() + (mpos.y-name_limit) / scale;
2626 					if (pos<0 )
2627 						pos=0;
2628 					if (pos>=animation->get_length())
2629 						pos=animation->get_length();
2630 					timeline->set_val(pos);
2631 #endif
2632 					return;
2633 				}
2634 
2635 				mpos.y -= h;
2636 
2637 				int idx = mpos.y / h;
2638 				idx += v_scroll->get_val();
2639 				if (idx < 0 || idx >= animation->get_track_count())
2640 					break;
2641 
2642 				mouse_over.track = idx;
2643 
2644 				if (mpos.x < name_limit) {
2645 					//name column
2646 
2647 					mouse_over.over = MouseOver::OVER_NAME;
2648 
2649 				} else if (mpos.x < settings_limit) {
2650 
2651 					float pos = mpos.x - name_limit;
2652 					pos /= _get_zoom_scale();
2653 					pos += h_scroll->get_val();
2654 					float w_time = (type_icon[0]->get_width() / _get_zoom_scale()) / 2.0;
2655 
2656 					int kidx = animation->track_find_key(idx, pos);
2657 					int kidx_n = kidx + 1;
2658 
2659 					bool found = false;
2660 
2661 					if (kidx >= 0 && kidx < animation->track_get_key_count(idx)) {
2662 
2663 						float kpos = animation->track_get_key_time(idx, kidx);
2664 						if (ABS(pos - kpos) <= w_time) {
2665 
2666 							mouse_over.over = MouseOver::OVER_KEY;
2667 							mouse_over.track = idx;
2668 							mouse_over.over_key = kidx;
2669 							found = true;
2670 						}
2671 					}
2672 
2673 					if (!found && kidx_n >= 0 && kidx_n < animation->track_get_key_count(idx)) {
2674 
2675 						float kpos = animation->track_get_key_time(idx, kidx_n);
2676 						if (ABS(pos - kpos) <= w_time) {
2677 
2678 							mouse_over.over = MouseOver::OVER_KEY;
2679 							mouse_over.track = idx;
2680 							mouse_over.over_key = kidx_n;
2681 							found = true;
2682 						}
2683 					}
2684 
2685 					if (found) {
2686 
2687 						String text;
2688 						text = "time: " + rtos(animation->track_get_key_time(idx, mouse_over.over_key)) + "\n";
2689 
2690 						switch (animation->track_get_type(idx)) {
2691 
2692 							case Animation::TYPE_TRANSFORM: {
2693 
2694 								Dictionary d = animation->track_get_key_value(idx, mouse_over.over_key);
2695 								if (d.has("loc"))
2696 									text += "loc: " + String(d["loc"]) + "\n";
2697 								if (d.has("rot"))
2698 									text += "rot: " + String(d["rot"]) + "\n";
2699 								if (d.has("scale"))
2700 									text += "scale: " + String(d["scale"]) + "\n";
2701 							} break;
2702 							case Animation::TYPE_VALUE: {
2703 
2704 								Variant v = animation->track_get_key_value(idx, mouse_over.over_key);
2705 								//text+="value: "+String(v)+"\n";
2706 
2707 								bool prop_exists = false;
2708 								Variant::Type valid_type = Variant::NIL;
2709 								Object *obj = NULL;
2710 
2711 								RES res;
2712 								Node *node = root->get_node_and_resource(animation->track_get_path(idx), res);
2713 
2714 								if (res.is_valid()) {
2715 									obj = res.ptr();
2716 								} else if (node) {
2717 									obj = node;
2718 								}
2719 
2720 								if (obj) {
2721 									valid_type = obj->get_static_property_type(animation->track_get_path(idx).get_property(), &prop_exists);
2722 								}
2723 
2724 								text += "type: " + Variant::get_type_name(v.get_type()) + "\n";
2725 								if (prop_exists && !Variant::can_convert(v.get_type(), valid_type)) {
2726 									text += "value: " + String(v) + "  (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n";
2727 								} else {
2728 									text += "value: " + String(v) + "\n";
2729 								}
2730 
2731 							} break;
2732 							case Animation::TYPE_METHOD: {
2733 
2734 								Dictionary d = animation->track_get_key_value(idx, mouse_over.over_key);
2735 								if (d.has("method"))
2736 									text += String(d["method"]);
2737 								text += "(";
2738 								Vector<Variant> args;
2739 								if (d.has("args"))
2740 									args = d["args"];
2741 								for (int i = 0; i < args.size(); i++) {
2742 
2743 									if (i > 0)
2744 										text += ", ";
2745 									text += String(args[i]);
2746 								}
2747 								text += ")\n";
2748 
2749 							} break;
2750 						}
2751 						text += "easing: " + rtos(animation->track_get_key_transition(idx, mouse_over.over_key));
2752 
2753 						track_editor->set_tooltip(text);
2754 						return;
2755 					}
2756 
2757 				} else {
2758 					//button column
2759 					int ofsx = size.width - mpos.x;
2760 					if (ofsx < 0)
2761 						break;
2762 					/*
2763 					if (ofsx < remove_icon->get_width()) {
2764 
2765 						mouse_over.over=MouseOver::OVER_REMOVE;
2766 
2767 						return;
2768 					}
2769 
2770 					ofsx-=hsep+remove_icon->get_width();
2771 
2772 					if (ofsx < move_down_icon->get_width()) {
2773 
2774 						mouse_over.over=MouseOver::OVER_DOWN;
2775 						return;
2776 					}
2777 
2778 					ofsx-=hsep+move_down_icon->get_width();
2779 
2780 					if (ofsx < move_up_icon->get_width()) {
2781 
2782 						mouse_over.over=MouseOver::OVER_UP;
2783 						return;
2784 					}
2785 
2786 					ofsx-=hsep*3+move_up_icon->get_width();
2787 
2788 	*/
2789 
2790 					if (ofsx < down_icon->get_width() + interp_icon[0]->get_width() + hsep * 2) {
2791 
2792 						mouse_over.over = MouseOver::OVER_INTERP;
2793 						return;
2794 					}
2795 
2796 					ofsx -= hsep * 2 + interp_icon[0]->get_width() + down_icon->get_width();
2797 
2798 					if (ofsx < down_icon->get_width() + cont_icon[0]->get_width() + hsep * 3) {
2799 
2800 						mouse_over.over = MouseOver::OVER_VALUE;
2801 						return;
2802 					}
2803 
2804 					ofsx -= hsep * 3 + cont_icon[0]->get_width() + down_icon->get_width();
2805 
2806 					if (ofsx < add_key_icon->get_width()) {
2807 
2808 						mouse_over.over = MouseOver::OVER_ADD_KEY;
2809 						return;
2810 					}
2811 				}
2812 			}
2813 
2814 		} break;
2815 	}
2816 }
2817 
_notification(int p_what)2818 void AnimationKeyEditor::_notification(int p_what) {
2819 
2820 	switch (p_what) {
2821 		case NOTIFICATION_VISIBILITY_CHANGED: {
2822 
2823 			EditorNode::get_singleton()->update_keying();
2824 			emit_signal("keying_changed");
2825 		} break;
2826 
2827 		case NOTIFICATION_ENTER_TREE: {
2828 
2829 			key_editor->edit(key_edit);
2830 
2831 			zoomicon->set_texture(get_icon("Zoom", "EditorIcons"));
2832 
2833 			menu_add_track->set_icon(get_icon("AddTrack", "EditorIcons"));
2834 			menu_add_track->get_popup()->add_icon_item(get_icon("KeyValue", "EditorIcons"), "Add Normal Track", ADD_TRACK_MENU_ADD_VALUE_TRACK);
2835 			menu_add_track->get_popup()->add_icon_item(get_icon("KeyXform", "EditorIcons"), "Add Transform Track", ADD_TRACK_MENU_ADD_TRANSFORM_TRACK);
2836 			menu_add_track->get_popup()->add_icon_item(get_icon("KeyCall", "EditorIcons"), "Add Call Func Track", ADD_TRACK_MENU_ADD_CALL_TRACK);
2837 
2838 			menu_track->set_icon(get_icon("Tools", "EditorIcons"));
2839 			menu_track->get_popup()->add_item(TTR("Scale Selection"), TRACK_MENU_SCALE);
2840 			menu_track->get_popup()->add_item(TTR("Scale From Cursor"), TRACK_MENU_SCALE_PIVOT);
2841 			menu_track->get_popup()->add_separator();
2842 			menu_track->get_popup()->add_item(TTR("Duplicate Selection"), TRACK_MENU_DUPLICATE);
2843 			menu_track->get_popup()->add_item(TTR("Duplicate Transposed"), TRACK_MENU_DUPLICATE_TRANSPOSE);
2844 			menu_track->get_popup()->add_separator();
2845 			menu_track->get_popup()->add_item(TTR("Goto Next Step"), TRACK_MENU_NEXT_STEP, KEY_MASK_CMD | KEY_RIGHT);
2846 			menu_track->get_popup()->add_item(TTR("Goto Prev Step"), TRACK_MENU_PREV_STEP, KEY_MASK_CMD | KEY_LEFT);
2847 			menu_track->get_popup()->add_separator();
2848 			PopupMenu *tpp = memnew(PopupMenu);
2849 			tpp->add_item(TTR("Linear"), TRACK_MENU_SET_ALL_TRANS_LINEAR);
2850 			tpp->add_item(TTR("Constant"), TRACK_MENU_SET_ALL_TRANS_CONSTANT);
2851 			tpp->add_item(TTR("In"), TRACK_MENU_SET_ALL_TRANS_IN);
2852 			tpp->add_item(TTR("Out"), TRACK_MENU_SET_ALL_TRANS_OUT);
2853 			tpp->add_item(TTR("In-Out"), TRACK_MENU_SET_ALL_TRANS_INOUT);
2854 			tpp->add_item(TTR("Out-In"), TRACK_MENU_SET_ALL_TRANS_OUTIN);
2855 			tpp->set_name(TTR("Transitions"));
2856 			tpp->connect("item_pressed", this, "_menu_track");
2857 			optimize_dialog->connect("confirmed", this, "_animation_optimize");
2858 
2859 			menu_track->get_popup()->add_child(tpp);
2860 			//menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
2861 			//menu_track->get_popup()->add_separator();
2862 			menu_track->get_popup()->add_item(TTR("Optimize Animation"), TRACK_MENU_OPTIMIZE);
2863 			menu_track->get_popup()->add_item(TTR("Clean-Up Animation"), TRACK_MENU_CLEAN_UP);
2864 
2865 			curve_linear->set_icon(get_icon("CurveLinear", "EditorIcons"));
2866 			curve_in->set_icon(get_icon("CurveIn", "EditorIcons"));
2867 			curve_out->set_icon(get_icon("CurveOut", "EditorIcons"));
2868 			curve_inout->set_icon(get_icon("CurveInOut", "EditorIcons"));
2869 			curve_outin->set_icon(get_icon("CurveOutIn", "EditorIcons"));
2870 			curve_constant->set_icon(get_icon("CurveConstant", "EditorIcons"));
2871 
2872 			curve_linear->connect("pressed", this, "_menu_track", varray(CURVE_SET_LINEAR));
2873 			curve_in->connect("pressed", this, "_menu_track", varray(CURVE_SET_IN));
2874 			curve_out->connect("pressed", this, "_menu_track", varray(CURVE_SET_OUT));
2875 			curve_inout->connect("pressed", this, "_menu_track", varray(CURVE_SET_INOUT));
2876 			curve_outin->connect("pressed", this, "_menu_track", varray(CURVE_SET_OUTIN));
2877 			curve_constant->connect("pressed", this, "_menu_track", varray(CURVE_SET_CONSTANT));
2878 
2879 			move_up_button->set_icon(get_icon("MoveUp", "EditorIcons"));
2880 			move_down_button->set_icon(get_icon("MoveDown", "EditorIcons"));
2881 			remove_button->set_icon(get_icon("Remove", "EditorIcons"));
2882 			edit_button->set_icon(get_icon("EditKey", "EditorIcons"));
2883 			edit_button->connect("pressed", this, "_toggle_edit_curves");
2884 
2885 			loop->set_icon(get_icon("Loop", "EditorIcons"));
2886 			curve_edit->connect("transition_changed", this, "_curve_transition_changed");
2887 
2888 			//edit_button->add_color_override("font_color",get_color("font_color","Tree"));
2889 			//edit_button->add_color_override("font_color_hover",get_color("font_color","Tree"));
2890 
2891 			{
2892 
2893 				right_data_size_cache = 0;
2894 				int hsep = get_constant("hseparation", "Tree");
2895 				Ref<Texture> remove_icon = get_icon("Remove", "EditorIcons");
2896 				Ref<Texture> move_up_icon = get_icon("MoveUp", "EditorIcons");
2897 				Ref<Texture> move_down_icon = get_icon("MoveDown", "EditorIcons");
2898 				Ref<Texture> down_icon = get_icon("select_arrow", "Tree");
2899 				Ref<Texture> add_key_icon = get_icon("TrackAddKey", "EditorIcons");
2900 				Ref<Texture> interp_icon[3] = {
2901 					get_icon("InterpRaw", "EditorIcons"),
2902 					get_icon("InterpLinear", "EditorIcons"),
2903 					get_icon("InterpCubic", "EditorIcons")
2904 				};
2905 				Ref<Texture> cont_icon[3] = {
2906 					get_icon("TrackContinuous", "EditorIcons"),
2907 					get_icon("TrackDiscrete", "EditorIcons"),
2908 					get_icon("TrackTrigger", "EditorIcons")
2909 				};
2910 
2911 				//right_data_size_cache = remove_icon->get_width() + move_up_icon->get_width() + move_down_icon->get_width() + down_icon->get_width() *2 + interp_icon[0]->get_width() + cont_icon[0]->get_width() + add_key_icon->get_width() + hsep*11;
2912 				right_data_size_cache = down_icon->get_width() * 2 + add_key_icon->get_width() + interp_icon[0]->get_width() + cont_icon[0]->get_width() + hsep * 7;
2913 			}
2914 			call_select->connect("selected", this, "_add_call_track");
2915 			//				rename_anim->set_icon( get_icon("Rename","EditorIcons") );
2916 			/*
2917 				edit_anim->set_icon( get_icon("Edit","EditorIcons") );
2918 				blend_anim->set_icon( get_icon("Blend","EditorIcons") );
2919 				play->set_icon( get_icon("Play","EditorIcons") );
2920 				stop->set_icon( get_icon("Stop","EditorIcons") );
2921 				pause->set_icon( get_icon("Pause","EditorIcons") );
2922 */
2923 			//			menu->set_icon(get_icon("Animation","EditorIcons"));
2924 			//			play->set_icon(get_icon("AnimationPlay","EditorIcons"));
2925 			//menu->set_icon(get_icon("Animation","EditorIcons"));
2926 			_update_menu();
2927 
2928 		} break;
2929 	}
2930 }
2931 
_scroll_changed(double)2932 void AnimationKeyEditor::_scroll_changed(double) {
2933 
2934 	if (te_drawing)
2935 		return;
2936 
2937 	track_editor->update();
2938 }
2939 
_update_paths()2940 void AnimationKeyEditor::_update_paths() {
2941 
2942 	if (animation.is_valid()) {
2943 		//timeline->set_max(animation->get_length());
2944 		//timeline->set_step(0.01);
2945 		track_editor->update();
2946 		length->set_val(animation->get_length());
2947 		step->set_val(animation->get_step());
2948 	}
2949 }
2950 
_root_removed()2951 void AnimationKeyEditor::_root_removed() {
2952 
2953 	root = NULL;
2954 }
2955 
_update_menu()2956 void AnimationKeyEditor::_update_menu() {
2957 
2958 	updating = true;
2959 
2960 	if (animation.is_valid()) {
2961 
2962 		length->set_val(animation->get_length());
2963 		loop->set_pressed(animation->has_loop());
2964 		step->set_val(animation->get_step());
2965 	}
2966 
2967 	track_editor->update();
2968 	updating = false;
2969 }
_clear_selection()2970 void AnimationKeyEditor::_clear_selection() {
2971 
2972 	selection.clear();
2973 	key_edit->animation = Ref<Animation>();
2974 	key_edit->track = 0;
2975 	key_edit->key_ofs = 0;
2976 	key_edit->hint = PropertyInfo();
2977 	key_edit->base = NodePath();
2978 	key_edit->notify_change();
2979 }
2980 
set_animation(const Ref<Animation> & p_anim)2981 void AnimationKeyEditor::set_animation(const Ref<Animation> &p_anim) {
2982 
2983 	if (animation.is_valid())
2984 		animation->disconnect("changed", this, "_update_paths");
2985 	animation = p_anim;
2986 	if (animation.is_valid())
2987 		animation->connect("changed", this, "_update_paths");
2988 
2989 	timeline_pos = 0;
2990 	_clear_selection();
2991 	_update_paths();
2992 
2993 	_update_menu();
2994 	selected_track = -1;
2995 	_edit_if_single_selection();
2996 
2997 	EditorNode::get_singleton()->update_keying();
2998 }
2999 
set_root(Node * p_root)3000 void AnimationKeyEditor::set_root(Node *p_root) {
3001 
3002 	if (root)
3003 		root->disconnect("exit_tree", this, "_root_removed");
3004 
3005 	root = p_root;
3006 
3007 	if (root)
3008 		root->connect("exit_tree", this, "_root_removed", make_binds(), CONNECT_ONESHOT);
3009 }
3010 
get_root() const3011 Node *AnimationKeyEditor::get_root() const {
3012 
3013 	return root;
3014 }
3015 
update_keying()3016 void AnimationKeyEditor::update_keying() {
3017 
3018 	bool keying_enabled = is_visible() && animation.is_valid();
3019 
3020 	if (keying_enabled == keying)
3021 		return;
3022 
3023 	keying = keying_enabled;
3024 	_update_menu();
3025 	emit_signal("keying_changed");
3026 }
3027 
has_keying() const3028 bool AnimationKeyEditor::has_keying() const {
3029 
3030 	return keying;
3031 }
3032 
_query_insert(const InsertData & p_id)3033 void AnimationKeyEditor::_query_insert(const InsertData &p_id) {
3034 
3035 	if (insert_frame != OS::get_singleton()->get_frames_drawn()) {
3036 		//clear insert list for the frame if frame changed
3037 		if (insert_confirm->is_visible())
3038 			return; //do nothing
3039 		insert_data.clear();
3040 		insert_query = false;
3041 	}
3042 	insert_frame = OS::get_singleton()->get_frames_drawn();
3043 
3044 	for (List<InsertData>::Element *E = insert_data.front(); E; E = E->next()) {
3045 		//prevent insertion of multiple tracks
3046 		if (E->get().path == p_id.path)
3047 			return; //already inserted a track for this on this frame
3048 	}
3049 
3050 	insert_data.push_back(p_id);
3051 
3052 	if (p_id.track_idx == -1) {
3053 		if (bool(EDITOR_DEF("animation/confirm_insert_track", true))) {
3054 			//potential new key, does not exist
3055 			if (insert_data.size() == 1)
3056 				insert_confirm->set_text(vformat(TTR("Create NEW track for %s and insert key?"), p_id.query));
3057 			else
3058 				insert_confirm->set_text(vformat(TTR("Create %d NEW tracks and insert keys?"), insert_data.size()));
3059 
3060 			insert_confirm->get_ok()->set_text(TTR("Create"));
3061 			insert_confirm->popup_centered_minsize();
3062 			insert_query = true;
3063 		} else {
3064 			call_deferred("_insert_delay");
3065 			insert_queue = true;
3066 		}
3067 
3068 	} else {
3069 		if (!insert_query && !insert_queue) {
3070 			call_deferred("_insert_delay");
3071 			insert_queue = true;
3072 		}
3073 	}
3074 }
3075 
insert_transform_key(Spatial * p_node,const String & p_sub,const Transform & p_xform)3076 void AnimationKeyEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform) {
3077 
3078 	if (!keying)
3079 		return;
3080 	if (!animation.is_valid())
3081 		return;
3082 
3083 	ERR_FAIL_COND(!root);
3084 	//let's build a node path
3085 	String path = root->get_path_to(p_node);
3086 	if (p_sub != "")
3087 		path += ":" + p_sub;
3088 
3089 	NodePath np = path;
3090 
3091 	int track_idx = -1;
3092 
3093 	for (int i = 0; i < animation->get_track_count(); i++) {
3094 
3095 		if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM)
3096 			continue;
3097 		if (animation->track_get_path(i) != np)
3098 			continue;
3099 
3100 		track_idx = i;
3101 		break;
3102 	}
3103 
3104 	InsertData id;
3105 	Dictionary val;
3106 
3107 	id.path = np;
3108 	id.track_idx = track_idx;
3109 	id.value = p_xform;
3110 	id.type = Animation::TYPE_TRANSFORM;
3111 	id.query = "node '" + p_node->get_name() + "'";
3112 	id.advance = false;
3113 
3114 	//dialog insert
3115 
3116 	_query_insert(id);
3117 }
3118 
insert_node_value_key(Node * p_node,const String & p_property,const Variant & p_value,bool p_only_if_exists)3119 void AnimationKeyEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) {
3120 
3121 	ERR_FAIL_COND(!root);
3122 	//let's build a node path
3123 
3124 	Node *node = p_node;
3125 
3126 	String path = root->get_path_to(node);
3127 
3128 	for (int i = 1; i < history->get_path_size(); i++) {
3129 
3130 		String prop = history->get_path_property(i);
3131 		ERR_FAIL_COND(prop == "");
3132 		path += ":" + prop;
3133 	}
3134 
3135 	path += ":" + p_property;
3136 
3137 	NodePath np = path;
3138 
3139 	//locate track
3140 
3141 	int track_idx = -1;
3142 
3143 	for (int i = 0; i < animation->get_track_count(); i++) {
3144 
3145 		if (animation->track_get_type(i) != Animation::TYPE_VALUE)
3146 			continue;
3147 		if (animation->track_get_path(i) != np)
3148 			continue;
3149 
3150 		track_idx = i;
3151 		break;
3152 	}
3153 
3154 	if (p_only_if_exists && track_idx == -1)
3155 		return;
3156 	InsertData id;
3157 	id.path = np;
3158 	id.track_idx = track_idx;
3159 	id.value = p_value;
3160 	id.type = Animation::TYPE_VALUE;
3161 	id.query = "property '" + p_property + "'";
3162 	id.advance = false;
3163 	//dialog insert
3164 	_query_insert(id);
3165 }
3166 
insert_value_key(const String & p_property,const Variant & p_value,bool p_advance)3167 void AnimationKeyEditor::insert_value_key(const String &p_property, const Variant &p_value, bool p_advance) {
3168 
3169 	ERR_FAIL_COND(!root);
3170 	//let's build a node path
3171 	ERR_FAIL_COND(history->get_path_size() == 0);
3172 	Object *obj = ObjectDB::get_instance(history->get_path_object(0));
3173 	ERR_FAIL_COND(!obj || !obj->cast_to<Node>());
3174 
3175 	Node *node = obj->cast_to<Node>();
3176 
3177 	String path = root->get_path_to(node);
3178 
3179 	for (int i = 1; i < history->get_path_size(); i++) {
3180 
3181 		String prop = history->get_path_property(i);
3182 		ERR_FAIL_COND(prop == "");
3183 		path += ":" + prop;
3184 	}
3185 
3186 	path += ":" + p_property;
3187 
3188 	NodePath np = path;
3189 
3190 	//locate track
3191 
3192 	int track_idx = -1;
3193 
3194 	for (int i = 0; i < animation->get_track_count(); i++) {
3195 
3196 		if (animation->track_get_type(i) != Animation::TYPE_VALUE)
3197 			continue;
3198 		if (animation->track_get_path(i) != np)
3199 			continue;
3200 
3201 		track_idx = i;
3202 		break;
3203 	}
3204 
3205 	InsertData id;
3206 	id.path = np;
3207 	id.track_idx = track_idx;
3208 	id.value = p_value;
3209 	id.type = Animation::TYPE_VALUE;
3210 	id.query = "property '" + p_property + "'";
3211 	id.advance = p_advance;
3212 	//dialog insert
3213 	_query_insert(id);
3214 }
3215 
_confirm_insert_list()3216 void AnimationKeyEditor::_confirm_insert_list() {
3217 
3218 	undo_redo->create_action(TTR("Anim Create & Insert"));
3219 
3220 	int last_track = animation->get_track_count();
3221 	while (insert_data.size()) {
3222 
3223 		last_track = _confirm_insert(insert_data.front()->get(), last_track);
3224 		insert_data.pop_front();
3225 	}
3226 
3227 	undo_redo->commit_action();
3228 }
3229 
_confirm_insert(InsertData p_id,int p_last_track)3230 int AnimationKeyEditor::_confirm_insert(InsertData p_id, int p_last_track) {
3231 
3232 	if (p_last_track == -1)
3233 		p_last_track = animation->get_track_count();
3234 
3235 	bool created = false;
3236 	if (p_id.track_idx < 0) {
3237 
3238 		created = true;
3239 		undo_redo->create_action(TTR("Anim Insert Track & Key"));
3240 		Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
3241 
3242 		if (p_id.type == Animation::TYPE_VALUE) {
3243 			//wants a new tack
3244 
3245 			{
3246 				//shitty hack
3247 				NodePath np;
3248 				animation->add_track(p_id.type);
3249 				animation->track_set_path(animation->get_track_count() - 1, p_id.path);
3250 				PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
3251 				animation->remove_track(animation->get_track_count() - 1); //hack
3252 
3253 				if (h.type == Variant::REAL ||
3254 						h.type == Variant::VECTOR2 ||
3255 						h.type == Variant::RECT2 ||
3256 						h.type == Variant::VECTOR3 ||
3257 						h.type == Variant::_AABB ||
3258 						h.type == Variant::QUAT ||
3259 						h.type == Variant::COLOR ||
3260 						h.type == Variant::TRANSFORM) {
3261 
3262 					update_mode = Animation::UPDATE_CONTINUOUS;
3263 				}
3264 
3265 				if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
3266 					update_mode = Animation::UPDATE_TRIGGER;
3267 				}
3268 			}
3269 		}
3270 
3271 		p_id.track_idx = p_last_track;
3272 
3273 		undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type);
3274 		undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path);
3275 		if (p_id.type == Animation::TYPE_VALUE)
3276 			undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", p_id.track_idx, update_mode);
3277 
3278 	} else {
3279 		undo_redo->create_action(TTR("Anim Insert Key"));
3280 	}
3281 
3282 	float time = timeline_pos;
3283 	Variant value;
3284 
3285 	switch (p_id.type) {
3286 
3287 		case Animation::TYPE_VALUE: {
3288 
3289 			value = p_id.value;
3290 
3291 		} break;
3292 		case Animation::TYPE_TRANSFORM: {
3293 
3294 			Transform tr = p_id.value;
3295 			Dictionary d;
3296 			d["loc"] = tr.origin;
3297 			d["scale"] = tr.basis.get_scale();
3298 			d["rot"] = Quat(tr.basis); //.orthonormalized();
3299 			value = d;
3300 		} break;
3301 		default: {}
3302 	}
3303 
3304 	undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, value);
3305 
3306 	if (created) {
3307 
3308 		//just remove the track
3309 		undo_redo->add_undo_method(animation.ptr(), "remove_track", p_last_track);
3310 		p_last_track++;
3311 	} else {
3312 
3313 		undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", p_id.track_idx, time);
3314 		int existing = animation->track_find_key(p_id.track_idx, time, true);
3315 		if (existing != -1) {
3316 			Variant v = animation->track_get_key_value(p_id.track_idx, existing);
3317 			float trans = animation->track_get_key_transition(p_id.track_idx, existing);
3318 			undo_redo->add_undo_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, v, trans);
3319 		}
3320 	}
3321 
3322 	undo_redo->add_do_method(this, "update");
3323 	undo_redo->add_undo_method(this, "update");
3324 	undo_redo->add_do_method(track_editor, "update");
3325 	undo_redo->add_undo_method(track_editor, "update");
3326 	undo_redo->add_do_method(track_pos, "update");
3327 	undo_redo->add_undo_method(track_pos, "update");
3328 
3329 	undo_redo->commit_action();
3330 
3331 	return p_last_track;
3332 }
3333 
get_current_animation() const3334 Ref<Animation> AnimationKeyEditor::get_current_animation() const {
3335 
3336 	return animation;
3337 }
3338 
_animation_len_changed(float p_len)3339 void AnimationKeyEditor::_animation_len_changed(float p_len) {
3340 
3341 	if (updating)
3342 		return;
3343 
3344 	if (!animation.is_null()) {
3345 
3346 		undo_redo->create_action(TTR("Change Anim Len"));
3347 		undo_redo->add_do_method(animation.ptr(), "set_length", p_len);
3348 		undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
3349 		undo_redo->add_do_method(this, "_animation_len_update");
3350 		undo_redo->add_undo_method(this, "_animation_len_update");
3351 		undo_redo->commit_action();
3352 	}
3353 }
3354 
_animation_len_update()3355 void AnimationKeyEditor::_animation_len_update() {
3356 
3357 	if (!animation.is_null())
3358 		emit_signal(alc, animation->get_length());
3359 }
3360 
_animation_changed()3361 void AnimationKeyEditor::_animation_changed() {
3362 	if (updating)
3363 		return;
3364 	_update_menu();
3365 }
3366 
_animation_loop_changed()3367 void AnimationKeyEditor::_animation_loop_changed() {
3368 
3369 	if (updating)
3370 		return;
3371 
3372 	if (!animation.is_null()) {
3373 
3374 		undo_redo->create_action(TTR("Change Anim Loop"));
3375 		undo_redo->add_do_method(animation.ptr(), "set_loop", loop->is_pressed());
3376 		undo_redo->add_undo_method(animation.ptr(), "set_loop", !loop->is_pressed());
3377 		undo_redo->commit_action();
3378 	}
3379 }
3380 
_create_value_item(int p_type)3381 void AnimationKeyEditor::_create_value_item(int p_type) {
3382 
3383 	undo_redo->create_action(TTR("Anim Create Typed Value Key"));
3384 
3385 	Variant::CallError ce;
3386 	Variant v = Variant::construct(Variant::Type(p_type), NULL, 0, ce);
3387 	undo_redo->add_do_method(animation.ptr(), "track_insert_key", cvi_track, cvi_pos, v);
3388 	undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", cvi_track, cvi_pos);
3389 
3390 	int existing = animation->track_find_key(cvi_track, cvi_pos, true);
3391 
3392 	if (existing != -1) {
3393 		Variant v = animation->track_get_key_value(cvi_track, existing);
3394 		float trans = animation->track_get_key_transition(cvi_track, existing);
3395 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", cvi_track, cvi_pos, v, trans);
3396 	}
3397 
3398 	undo_redo->commit_action();
3399 }
3400 
set_anim_pos(float p_pos)3401 void AnimationKeyEditor::set_anim_pos(float p_pos) {
3402 
3403 	if (animation.is_null())
3404 		return;
3405 	timeline_pos = p_pos;
3406 	update();
3407 	track_pos->update();
3408 	track_editor->update();
3409 }
3410 
_pane_drag(const Point2 & p_delta)3411 void AnimationKeyEditor::_pane_drag(const Point2 &p_delta) {
3412 
3413 	Size2 ecs = ec->get_custom_minimum_size();
3414 	ecs.y -= p_delta.y;
3415 	if (ecs.y < 100)
3416 		ecs.y = 100;
3417 	ec->set_custom_minimum_size(ecs);
3418 }
3419 
_insert_delay()3420 void AnimationKeyEditor::_insert_delay() {
3421 
3422 	if (insert_query) {
3423 		//discard since it's entered into query mode
3424 		insert_queue = false;
3425 		return;
3426 	}
3427 
3428 	undo_redo->create_action(TTR("Anim Insert"));
3429 
3430 	int last_track = animation->get_track_count();
3431 	bool advance = false;
3432 	while (insert_data.size()) {
3433 
3434 		if (insert_data.front()->get().advance)
3435 			advance = true;
3436 		last_track = _confirm_insert(insert_data.front()->get(), last_track);
3437 		insert_data.pop_front();
3438 	}
3439 
3440 	undo_redo->commit_action();
3441 
3442 	if (advance) {
3443 		float step = animation->get_step();
3444 		if (step == 0)
3445 			step = 1;
3446 
3447 		float pos = timeline_pos;
3448 
3449 		pos = Math::stepify(pos + step, step);
3450 		if (pos > animation->get_length())
3451 			pos = animation->get_length();
3452 		timeline_pos = pos;
3453 		track_pos->update();
3454 		emit_signal("timeline_changed", pos, true);
3455 	}
3456 	insert_queue = false;
3457 }
3458 
_step_changed(float p_len)3459 void AnimationKeyEditor::_step_changed(float p_len) {
3460 
3461 	updating = true;
3462 	if (!animation.is_null()) {
3463 		animation->set_step(p_len);
3464 		emit_signal("animation_step_changed", animation->get_step());
3465 	}
3466 	updating = false;
3467 }
3468 
_scale()3469 void AnimationKeyEditor::_scale() {
3470 
3471 	if (selection.empty())
3472 		return;
3473 
3474 	float from_t = 1e20;
3475 	float to_t = -1e20;
3476 	float len = -1e20;
3477 	float pivot = 0;
3478 
3479 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
3480 		float t = animation->track_get_key_time(E->key().track, E->key().key);
3481 		if (t < from_t)
3482 			from_t = t;
3483 		if (t > to_t)
3484 			to_t = t;
3485 	}
3486 
3487 	len = to_t - from_t;
3488 	if (last_menu_track_opt == TRACK_MENU_SCALE_PIVOT) {
3489 		pivot = timeline_pos;
3490 
3491 	} else {
3492 
3493 		pivot = from_t;
3494 	}
3495 
3496 	float s = scale->get_val();
3497 	if (s == 0) {
3498 		ERR_PRINT("Can't scale to 0");
3499 	}
3500 
3501 	undo_redo->create_action(TTR("Anim Scale Keys"));
3502 
3503 	List<_AnimMoveRestore> to_restore;
3504 
3505 	// 1-remove the keys
3506 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3507 
3508 		undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
3509 	}
3510 	// 2- remove overlapped keys
3511 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3512 
3513 		float newtime = (E->get().pos - from_t) * s + from_t;
3514 		int idx = animation->track_find_key(E->key().track, newtime, true);
3515 		if (idx == -1)
3516 			continue;
3517 		SelectedKey sk;
3518 		sk.key = idx;
3519 		sk.track = E->key().track;
3520 		if (selection.has(sk))
3521 			continue; //already in selection, don't save
3522 
3523 		undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_pos", E->key().track, newtime);
3524 		_AnimMoveRestore amr;
3525 
3526 		amr.key = animation->track_get_key_value(E->key().track, idx);
3527 		amr.track = E->key().track;
3528 		amr.time = newtime;
3529 		amr.transition = animation->track_get_key_transition(E->key().track, idx);
3530 
3531 		to_restore.push_back(amr);
3532 	}
3533 
3534 #define _NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t
3535 	// 3-move the keys (re insert them)
3536 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3537 
3538 		float newpos = _NEW_POS(E->get().pos);
3539 		undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
3540 	}
3541 
3542 	// 4-(undo) remove inserted keys
3543 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3544 
3545 		float newpos = _NEW_POS(E->get().pos);
3546 		undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_pos", E->key().track, newpos);
3547 	}
3548 
3549 	// 5-(undo) reinsert keys
3550 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3551 
3552 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
3553 	}
3554 
3555 	// 6-(undo) reinsert overlapped keys
3556 	for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
3557 
3558 		_AnimMoveRestore &amr = E->get();
3559 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
3560 	}
3561 
3562 	// 6-(undo) reinsert overlapped keys
3563 	for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
3564 
3565 		_AnimMoveRestore &amr = E->get();
3566 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
3567 	}
3568 
3569 	undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
3570 	undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
3571 
3572 	// 7-reselect
3573 
3574 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
3575 
3576 		float oldpos = E->get().pos;
3577 		float newpos = _NEW_POS(oldpos);
3578 		if (newpos >= 0)
3579 			undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
3580 		undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
3581 	}
3582 #undef _NEW_POS
3583 	undo_redo->commit_action();
3584 }
3585 
_add_call_track(const NodePath & p_base)3586 void AnimationKeyEditor::_add_call_track(const NodePath &p_base) {
3587 
3588 	Node *base = EditorNode::get_singleton()->get_edited_scene();
3589 	if (!base)
3590 		return;
3591 	Node *from = base->get_node(p_base);
3592 	if (!from || !root)
3593 		return;
3594 
3595 	NodePath path = root->get_path_to(from);
3596 
3597 	//print_line("root: "+String(root->get_path()));
3598 	//print_line("path: "+String(path));
3599 
3600 	undo_redo->create_action(TTR("Anim Add Call Track"));
3601 	undo_redo->add_do_method(animation.ptr(), "add_track", Animation::TYPE_METHOD);
3602 	undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path);
3603 	undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
3604 	undo_redo->commit_action();
3605 }
3606 
cleanup()3607 void AnimationKeyEditor::cleanup() {
3608 
3609 	set_animation(Ref<Animation>());
3610 }
3611 
_bind_methods()3612 void AnimationKeyEditor::_bind_methods() {
3613 
3614 	ObjectTypeDB::bind_method(_MD("_root_removed"), &AnimationKeyEditor::_root_removed);
3615 	ObjectTypeDB::bind_method(_MD("_scale"), &AnimationKeyEditor::_scale);
3616 	ObjectTypeDB::bind_method(_MD("set_root"), &AnimationKeyEditor::set_root);
3617 
3618 	//	ObjectTypeDB::bind_method(_MD("_confirm_insert"),&AnimationKeyEditor::_confirm_insert);
3619 	ObjectTypeDB::bind_method(_MD("_confirm_insert_list"), &AnimationKeyEditor::_confirm_insert_list);
3620 
3621 	ObjectTypeDB::bind_method(_MD("_update_paths"), &AnimationKeyEditor::_update_paths);
3622 	ObjectTypeDB::bind_method(_MD("_track_editor_draw"), &AnimationKeyEditor::_track_editor_draw);
3623 
3624 	ObjectTypeDB::bind_method(_MD("_animation_changed"), &AnimationKeyEditor::_animation_changed);
3625 	ObjectTypeDB::bind_method(_MD("_scroll_changed"), &AnimationKeyEditor::_scroll_changed);
3626 	ObjectTypeDB::bind_method(_MD("_track_editor_input_event"), &AnimationKeyEditor::_track_editor_input_event);
3627 	ObjectTypeDB::bind_method(_MD("_track_name_changed"), &AnimationKeyEditor::_track_name_changed);
3628 	ObjectTypeDB::bind_method(_MD("_track_menu_selected"), &AnimationKeyEditor::_track_menu_selected);
3629 	ObjectTypeDB::bind_method(_MD("_menu_add_track"), &AnimationKeyEditor::_menu_add_track);
3630 	ObjectTypeDB::bind_method(_MD("_menu_track"), &AnimationKeyEditor::_menu_track);
3631 	ObjectTypeDB::bind_method(_MD("_clear_selection_for_anim"), &AnimationKeyEditor::_clear_selection_for_anim);
3632 	ObjectTypeDB::bind_method(_MD("_select_at_anim"), &AnimationKeyEditor::_select_at_anim);
3633 	ObjectTypeDB::bind_method(_MD("_track_pos_draw"), &AnimationKeyEditor::_track_pos_draw);
3634 	ObjectTypeDB::bind_method(_MD("_insert_delay"), &AnimationKeyEditor::_insert_delay);
3635 	ObjectTypeDB::bind_method(_MD("_step_changed"), &AnimationKeyEditor::_step_changed);
3636 
3637 	ObjectTypeDB::bind_method(_MD("_animation_loop_changed"), &AnimationKeyEditor::_animation_loop_changed);
3638 	ObjectTypeDB::bind_method(_MD("_animation_len_changed"), &AnimationKeyEditor::_animation_len_changed);
3639 	ObjectTypeDB::bind_method(_MD("_create_value_item"), &AnimationKeyEditor::_create_value_item);
3640 	ObjectTypeDB::bind_method(_MD("_pane_drag"), &AnimationKeyEditor::_pane_drag);
3641 
3642 	ObjectTypeDB::bind_method(_MD("_animation_len_update"), &AnimationKeyEditor::_animation_len_update);
3643 
3644 	ObjectTypeDB::bind_method(_MD("set_animation"), &AnimationKeyEditor::set_animation);
3645 	ObjectTypeDB::bind_method(_MD("_animation_optimize"), &AnimationKeyEditor::_animation_optimize);
3646 	ObjectTypeDB::bind_method(_MD("_curve_transition_changed"), &AnimationKeyEditor::_curve_transition_changed);
3647 	ObjectTypeDB::bind_method(_MD("_toggle_edit_curves"), &AnimationKeyEditor::_toggle_edit_curves);
3648 	ObjectTypeDB::bind_method(_MD("_add_call_track"), &AnimationKeyEditor::_add_call_track);
3649 
3650 	ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "res"), PropertyInfo(Variant::STRING, "prop")));
3651 	ADD_SIGNAL(MethodInfo("keying_changed"));
3652 	ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "pos"), PropertyInfo(Variant::BOOL, "drag")));
3653 	ADD_SIGNAL(MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL, "len")));
3654 	ADD_SIGNAL(MethodInfo("animation_step_changed", PropertyInfo(Variant::REAL, "step")));
3655 	ADD_SIGNAL(MethodInfo("key_edited", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "key")));
3656 }
3657 
AnimationKeyEditor()3658 AnimationKeyEditor::AnimationKeyEditor() {
3659 
3660 	alc = "animation_len_changed";
3661 	editor_selection = EditorNode::get_singleton()->get_editor_selection();
3662 
3663 	selected_track = -1;
3664 	updating = false;
3665 	te_drawing = false;
3666 	undo_redo = EditorNode::get_singleton()->get_undo_redo();
3667 	history = EditorNode::get_singleton()->get_editor_history();
3668 
3669 	ec = memnew(Control);
3670 	ec->set_custom_minimum_size(Size2(0, 150));
3671 	add_child(ec);
3672 	ec->set_v_size_flags(SIZE_EXPAND_FILL);
3673 
3674 	h_scroll = memnew(HScrollBar);
3675 	h_scroll->connect("value_changed", this, "_scroll_changed");
3676 	add_child(h_scroll);
3677 	h_scroll->set_val(0);
3678 
3679 	HBoxContainer *hb = memnew(HBoxContainer);
3680 	add_child(hb);
3681 
3682 	root = NULL;
3683 	//menu = memnew( MenuButton );
3684 	//menu->set_flat(true);
3685 	//menu->set_pos(Point2());
3686 	//add_child(menu);
3687 
3688 	zoomicon = memnew(TextureFrame);
3689 	hb->add_child(zoomicon);
3690 	zoomicon->set_tooltip(TTR("Animation zoom."));
3691 
3692 	zoom = memnew(HSlider);
3693 	//hb->add_child(zoom);
3694 	zoom->set_step(0.01);
3695 	zoom->set_min(0.0);
3696 	zoom->set_max(2.0);
3697 	zoom->set_val(1.0);
3698 	zoom->set_h_size_flags(SIZE_EXPAND_FILL);
3699 	zoom->set_stretch_ratio(2);
3700 	hb->add_child(zoom);
3701 	zoom->connect("value_changed", this, "_scroll_changed");
3702 	zoom->set_tooltip(TTR("Animation zoom."));
3703 
3704 	hb->add_child(memnew(VSeparator));
3705 
3706 	Label *l = memnew(Label);
3707 	l->set_text(TTR("Length (s):"));
3708 	hb->add_child(l);
3709 
3710 	length = memnew(SpinBox);
3711 	length->set_min(0.01);
3712 	length->set_max(10000);
3713 	length->set_step(0.01);
3714 	length->set_h_size_flags(SIZE_EXPAND_FILL);
3715 	length->set_stretch_ratio(1);
3716 	length->set_tooltip(TTR("Animation length (in seconds)."));
3717 
3718 	hb->add_child(length);
3719 	length->connect("value_changed", this, "_animation_len_changed");
3720 
3721 	l = memnew(Label);
3722 	l->set_text(TTR("Step (s):"));
3723 	hb->add_child(l);
3724 
3725 	step = memnew(SpinBox);
3726 	step->set_min(0.00);
3727 	step->set_max(128);
3728 	step->set_step(0.01);
3729 	step->set_val(0.0);
3730 	step->set_h_size_flags(SIZE_EXPAND_FILL);
3731 	step->set_stretch_ratio(1);
3732 	step->set_tooltip(TTR("Cursor step snap (in seconds)."));
3733 
3734 	hb->add_child(step);
3735 	step->connect("value_changed", this, "_step_changed");
3736 
3737 	loop = memnew(ToolButton);
3738 	loop->set_toggle_mode(true);
3739 	loop->connect("pressed", this, "_animation_loop_changed");
3740 	hb->add_child(loop);
3741 	loop->set_tooltip(TTR("Enable/Disable looping in animation."));
3742 
3743 	hb->add_child(memnew(VSeparator));
3744 
3745 	menu_add_track = memnew(MenuButton);
3746 	hb->add_child(menu_add_track);
3747 	menu_add_track->get_popup()->connect("item_pressed", this, "_menu_add_track");
3748 	menu_add_track->set_tooltip(TTR("Add new tracks."));
3749 
3750 	move_up_button = memnew(ToolButton);
3751 	hb->add_child(move_up_button);
3752 	move_up_button->connect("pressed", this, "_menu_track", make_binds(TRACK_MENU_MOVE_UP));
3753 	move_up_button->set_focus_mode(FOCUS_NONE);
3754 	move_up_button->set_disabled(true);
3755 	move_up_button->set_tooltip(TTR("Move current track up."));
3756 
3757 	move_down_button = memnew(ToolButton);
3758 	hb->add_child(move_down_button);
3759 	move_down_button->connect("pressed", this, "_menu_track", make_binds(TRACK_MENU_MOVE_DOWN));
3760 	move_down_button->set_focus_mode(FOCUS_NONE);
3761 	move_down_button->set_disabled(true);
3762 	move_down_button->set_tooltip(TTR("Move current track down."));
3763 
3764 	remove_button = memnew(ToolButton);
3765 	hb->add_child(remove_button);
3766 	remove_button->connect("pressed", this, "_menu_track", make_binds(TRACK_MENU_REMOVE));
3767 	remove_button->set_focus_mode(FOCUS_NONE);
3768 	remove_button->set_disabled(true);
3769 	remove_button->set_tooltip(TTR("Remove selected track."));
3770 
3771 	hb->add_child(memnew(VSeparator));
3772 
3773 	menu_track = memnew(MenuButton);
3774 	hb->add_child(menu_track);
3775 	menu_track->get_popup()->connect("item_pressed", this, "_menu_track");
3776 	menu_track->set_tooltip(TTR("Track tools"));
3777 
3778 	edit_button = memnew(ToolButton);
3779 	edit_button->set_toggle_mode(true);
3780 	edit_button->set_focus_mode(FOCUS_NONE);
3781 	edit_button->set_disabled(true);
3782 
3783 	hb->add_child(edit_button);
3784 	edit_button->set_tooltip(TTR("Enable editing of individual keys by clicking them."));
3785 
3786 	optimize_dialog = memnew(ConfirmationDialog);
3787 	add_child(optimize_dialog);
3788 	optimize_dialog->set_title(TTR("Anim. Optimizer"));
3789 	VBoxContainer *optimize_vb = memnew(VBoxContainer);
3790 	optimize_dialog->add_child(optimize_vb);
3791 	optimize_dialog->set_child_rect(optimize_vb);
3792 	optimize_linear_error = memnew(SpinBox);
3793 	optimize_linear_error->set_max(1.0);
3794 	optimize_linear_error->set_min(0.001);
3795 	optimize_linear_error->set_step(0.001);
3796 	optimize_linear_error->set_val(0.05);
3797 	optimize_vb->add_margin_child(TTR("Max. Linear Error:"), optimize_linear_error);
3798 	optimize_angular_error = memnew(SpinBox);
3799 	optimize_angular_error->set_max(1.0);
3800 	optimize_angular_error->set_min(0.001);
3801 	optimize_angular_error->set_step(0.001);
3802 	optimize_angular_error->set_val(0.01);
3803 
3804 	optimize_vb->add_margin_child(TTR("Max. Angular Error:"), optimize_angular_error);
3805 	optimize_max_angle = memnew(SpinBox);
3806 	optimize_vb->add_margin_child(TTR("Max Optimizable Angle:"), optimize_max_angle);
3807 	optimize_max_angle->set_max(360.0);
3808 	optimize_max_angle->set_min(0.0);
3809 	optimize_max_angle->set_step(0.1);
3810 	optimize_max_angle->set_val(22);
3811 
3812 	optimize_dialog->get_ok()->set_text(TTR("Optimize"));
3813 
3814 	/*keying = memnew( Button );
3815 	keying->set_toggle_mode(true);
3816 	//keying->set_text("Keys");
3817 	keying->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,60);
3818 	keying->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,10);
3819 	keying->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_BEGIN,55);
3820 	keying->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,10);
3821 	//add_child(keying);
3822 	keying->connect("pressed",this,"_keying_toggled");
3823 	*/
3824 
3825 	/*	l = memnew( Label );
3826 	l->set_text("Base: ");
3827 	l->set_pos(Point2(0,3));
3828 //	dr_panel->add_child(l);*/
3829 
3830 	//	menu->get_popup()->connect("item_pressed",this,"_menu_callback");
3831 
3832 	hb = memnew(HBoxContainer);
3833 	hb->set_area_as_parent_rect();
3834 	ec->add_child(hb);
3835 	hb->set_v_size_flags(SIZE_EXPAND_FILL);
3836 
3837 	track_editor = memnew(Control);
3838 	track_editor->connect("draw", this, "_track_editor_draw");
3839 	hb->add_child(track_editor);
3840 	track_editor->connect("input_event", this, "_track_editor_input_event");
3841 	track_editor->set_focus_mode(Control::FOCUS_ALL);
3842 	track_editor->set_h_size_flags(SIZE_EXPAND_FILL);
3843 
3844 	track_pos = memnew(Control);
3845 	track_pos->set_area_as_parent_rect();
3846 	track_pos->set_ignore_mouse(true);
3847 	track_editor->add_child(track_pos);
3848 	track_pos->connect("draw", this, "_track_pos_draw");
3849 
3850 	select_anim_warning = memnew(Label);
3851 	track_editor->add_child(select_anim_warning);
3852 	select_anim_warning->set_area_as_parent_rect();
3853 	select_anim_warning->set_text(TTR("Select an AnimationPlayer from the Scene Tree to edit animations."));
3854 	select_anim_warning->set_autowrap(true);
3855 	select_anim_warning->set_align(Label::ALIGN_CENTER);
3856 	select_anim_warning->set_valign(Label::VALIGN_CENTER);
3857 
3858 	v_scroll = memnew(VScrollBar);
3859 	hb->add_child(v_scroll);
3860 	v_scroll->connect("value_changed", this, "_scroll_changed");
3861 	v_scroll->set_val(0);
3862 
3863 	key_editor_tab = memnew(TabContainer);
3864 	hb->add_child(key_editor_tab);
3865 	key_editor_tab->set_custom_minimum_size(Size2(200, 0));
3866 
3867 	key_editor = memnew(PropertyEditor);
3868 	key_editor->set_area_as_parent_rect();
3869 	key_editor->hide_top_label();
3870 	key_editor->set_name(TTR("Key"));
3871 	key_editor_tab->add_child(key_editor);
3872 
3873 	key_edit = memnew(AnimationKeyEdit);
3874 	key_edit->undo_redo = undo_redo;
3875 	//key_edit->ke_dialog=key_edit_dialog;
3876 
3877 	type_menu = memnew(PopupMenu);
3878 	add_child(type_menu);
3879 	for (int i = 0; i < Variant::VARIANT_MAX; i++)
3880 		type_menu->add_item(Variant::get_type_name(Variant::Type(i)), i);
3881 	type_menu->connect("item_pressed", this, "_create_value_item");
3882 
3883 	VBoxContainer *curve_vb = memnew(VBoxContainer);
3884 	curve_vb->set_name(TTR("Transition"));
3885 	HBoxContainer *curve_hb = memnew(HBoxContainer);
3886 	curve_vb->add_child(curve_hb);
3887 
3888 	curve_linear = memnew(ToolButton);
3889 	curve_linear->set_focus_mode(FOCUS_NONE);
3890 	curve_hb->add_child(curve_linear);
3891 	curve_in = memnew(ToolButton);
3892 	curve_in->set_focus_mode(FOCUS_NONE);
3893 	curve_hb->add_child(curve_in);
3894 	curve_out = memnew(ToolButton);
3895 	curve_out->set_focus_mode(FOCUS_NONE);
3896 	curve_hb->add_child(curve_out);
3897 	curve_inout = memnew(ToolButton);
3898 	curve_inout->set_focus_mode(FOCUS_NONE);
3899 	curve_hb->add_child(curve_inout);
3900 	curve_outin = memnew(ToolButton);
3901 	curve_outin->set_focus_mode(FOCUS_NONE);
3902 	curve_hb->add_child(curve_outin);
3903 	curve_constant = memnew(ToolButton);
3904 	curve_constant->set_focus_mode(FOCUS_NONE);
3905 	curve_hb->add_child(curve_constant);
3906 
3907 	curve_edit = memnew(AnimationCurveEdit);
3908 	curve_vb->add_child(curve_edit);
3909 	curve_edit->set_v_size_flags(SIZE_EXPAND_FILL);
3910 	key_editor_tab->add_child(curve_vb);
3911 
3912 	track_name = memnew(LineEdit);
3913 	track_name->set_as_toplevel(true);
3914 	track_name->hide();
3915 	add_child(track_name);
3916 	track_name->connect("text_entered", this, "_track_name_changed");
3917 	track_menu = memnew(PopupMenu);
3918 	add_child(track_menu);
3919 	track_menu->connect("item_pressed", this, "_track_menu_selected");
3920 
3921 	key_editor_tab->hide();
3922 
3923 	last_idx = 1;
3924 
3925 	_update_menu();
3926 
3927 	insert_confirm = memnew(ConfirmationDialog);
3928 	add_child(insert_confirm);
3929 	insert_confirm->connect("confirmed", this, "_confirm_insert_list");
3930 
3931 	click.click = ClickOver::CLICK_NONE;
3932 
3933 	name_column_ratio = 0.3;
3934 	timeline_pos = 0;
3935 
3936 	keying = false;
3937 	insert_frame = 0;
3938 	insert_query = false;
3939 	insert_queue = false;
3940 
3941 	editor_selection->connect("selection_changed", track_editor, "update");
3942 
3943 	scale_dialog = memnew(ConfirmationDialog);
3944 	VBoxContainer *vbc = memnew(VBoxContainer);
3945 	scale_dialog->add_child(vbc);
3946 	scale_dialog->set_child_rect(vbc);
3947 	scale = memnew(SpinBox);
3948 	scale->set_min(-99999);
3949 	scale->set_max(99999);
3950 	scale->set_step(0.001);
3951 	vbc->add_margin_child(TTR("Scale Ratio:"), scale);
3952 	scale_dialog->connect("confirmed", this, "_scale");
3953 	add_child(scale_dialog);
3954 
3955 	call_select = memnew(SceneTreeDialog);
3956 	add_child(call_select);
3957 	call_select->set_title(TTR("Call Functions in Which Node?"));
3958 
3959 	cleanup_dialog = memnew(ConfirmationDialog);
3960 	add_child(cleanup_dialog);
3961 	VBoxContainer *cleanup_vb = memnew(VBoxContainer);
3962 	cleanup_dialog->add_child(cleanup_vb);
3963 	cleanup_dialog->set_child_rect(cleanup_vb);
3964 	cleanup_keys = memnew(CheckButton);
3965 	cleanup_keys->set_text(TTR("Remove invalid keys"));
3966 	cleanup_keys->set_pressed(true);
3967 	cleanup_vb->add_child(cleanup_keys);
3968 
3969 	cleanup_tracks = memnew(CheckButton);
3970 	cleanup_tracks->set_text(TTR("Remove unresolved and empty tracks"));
3971 	cleanup_tracks->set_pressed(true);
3972 	cleanup_vb->add_child(cleanup_tracks);
3973 
3974 	cleanup_all = memnew(CheckButton);
3975 	cleanup_all->set_text(TTR("Clean-up all animations"));
3976 	cleanup_vb->add_child(cleanup_all);
3977 
3978 	cleanup_dialog->set_title(TTR("Clean-Up Animation(s) (NO UNDO!)"));
3979 	cleanup_dialog->get_ok()->set_text(TTR("Clean-Up"));
3980 
3981 	cleanup_dialog->connect("confirmed", this, "_menu_track", varray(TRACK_MENU_CLEAN_UP_CONFIRM));
3982 
3983 	add_constant_override("separation", get_constant("separation", "VBoxContainer"));
3984 }
3985 
~AnimationKeyEditor()3986 AnimationKeyEditor::~AnimationKeyEditor() {
3987 
3988 	memdelete(key_edit);
3989 }
3990