1 /*************************************************************************/
2 /*  property_editor.cpp                                                  */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "property_editor.h"
32 
33 #include "core/class_db.h"
34 #include "core/io/image_loader.h"
35 #include "core/io/marshalls.h"
36 #include "core/io/resource_loader.h"
37 #include "core/math/expression.h"
38 #include "core/os/input.h"
39 #include "core/os/keyboard.h"
40 #include "core/pair.h"
41 #include "core/print_string.h"
42 #include "core/project_settings.h"
43 #include "editor/array_property_edit.h"
44 #include "editor/create_dialog.h"
45 #include "editor/dictionary_property_edit.h"
46 #include "editor/editor_export.h"
47 #include "editor/editor_file_system.h"
48 #include "editor/editor_help.h"
49 #include "editor/editor_node.h"
50 #include "editor/editor_scale.h"
51 #include "editor/editor_settings.h"
52 #include "editor/filesystem_dock.h"
53 #include "editor/multi_node_edit.h"
54 #include "editor/property_selector.h"
55 #include "scene/gui/label.h"
56 #include "scene/main/viewport.h"
57 #include "scene/resources/font.h"
58 #include "scene/resources/packed_scene.h"
59 #include "scene/scene_string_names.h"
60 
_bind_methods()61 void EditorResourceConversionPlugin::_bind_methods() {
62 
63 	MethodInfo mi;
64 	mi.name = "_convert";
65 	mi.return_val.type = Variant::OBJECT;
66 	mi.return_val.class_name = "Resource";
67 	mi.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE;
68 	mi.return_val.hint_string = "Resource";
69 	mi.arguments.push_back(mi.return_val);
70 	mi.arguments[0].name = "resource";
71 
72 	BIND_VMETHOD(mi)
73 
74 	mi.name = "_handles";
75 	mi.return_val = PropertyInfo(Variant::BOOL, "");
76 
77 	BIND_VMETHOD(MethodInfo(Variant::STRING, "_converts_to"));
78 }
79 
converts_to() const80 String EditorResourceConversionPlugin::converts_to() const {
81 
82 	if (get_script_instance())
83 		return get_script_instance()->call("_converts_to");
84 
85 	return "";
86 }
87 
handles(const Ref<Resource> & p_resource) const88 bool EditorResourceConversionPlugin::handles(const Ref<Resource> &p_resource) const {
89 
90 	if (get_script_instance())
91 		return get_script_instance()->call("_handles", p_resource);
92 
93 	return false;
94 }
95 
convert(const Ref<Resource> & p_resource) const96 Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_resource) const {
97 
98 	if (get_script_instance())
99 		return get_script_instance()->call("_convert", p_resource);
100 
101 	return Ref<Resource>();
102 }
103 
_notification(int p_what)104 void CustomPropertyEditor::_notification(int p_what) {
105 
106 	if (p_what == NOTIFICATION_DRAW) {
107 
108 		RID ci = get_canvas_item();
109 		get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size()));
110 	}
111 	if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
112 		hide();
113 	}
114 }
115 
_menu_option(int p_which)116 void CustomPropertyEditor::_menu_option(int p_which) {
117 
118 	switch (type) {
119 
120 		case Variant::INT: {
121 
122 			if (hint == PROPERTY_HINT_FLAGS) {
123 
124 				int val = v;
125 
126 				if (val & (1 << p_which)) {
127 
128 					val &= ~(1 << p_which);
129 				} else {
130 					val |= (1 << p_which);
131 				}
132 
133 				v = val;
134 				emit_signal("variant_changed");
135 			} else if (hint == PROPERTY_HINT_ENUM) {
136 
137 				v = menu->get_item_metadata(p_which);
138 				emit_signal("variant_changed");
139 			}
140 		} break;
141 		case Variant::STRING: {
142 
143 			if (hint == PROPERTY_HINT_ENUM) {
144 
145 				v = hint_text.get_slice(",", p_which);
146 				emit_signal("variant_changed");
147 			}
148 		} break;
149 		case Variant::OBJECT: {
150 
151 			switch (p_which) {
152 				case OBJ_MENU_LOAD: {
153 
154 					file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
155 					String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
156 
157 					List<String> extensions;
158 					for (int i = 0; i < type.get_slice_count(","); i++) {
159 
160 						ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",", i), &extensions);
161 					}
162 
163 					Set<String> valid_extensions;
164 					for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
165 						valid_extensions.insert(E->get());
166 					}
167 
168 					file->clear_filters();
169 					for (Set<String>::Element *E = valid_extensions.front(); E; E = E->next()) {
170 
171 						file->add_filter("*." + E->get() + " ; " + E->get().to_upper());
172 					}
173 
174 					file->popup_centered_ratio();
175 				} break;
176 
177 				case OBJ_MENU_EDIT: {
178 
179 					RefPtr RefPtr = v;
180 
181 					if (!RefPtr.is_null()) {
182 
183 						emit_signal("resource_edit_request");
184 						hide();
185 					}
186 				} break;
187 				case OBJ_MENU_CLEAR: {
188 
189 					v = Variant();
190 					emit_signal("variant_changed");
191 					hide();
192 				} break;
193 
194 				case OBJ_MENU_MAKE_UNIQUE: {
195 
196 					RefPtr RefPtr = v;
197 					Ref<Resource> res_orig = RefPtr;
198 					if (res_orig.is_null())
199 						return;
200 
201 					List<PropertyInfo> property_list;
202 					res_orig->get_property_list(&property_list);
203 					List<Pair<String, Variant> > propvalues;
204 
205 					for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
206 
207 						Pair<String, Variant> p;
208 						PropertyInfo &pi = E->get();
209 						if (pi.usage & PROPERTY_USAGE_STORAGE) {
210 
211 							p.first = pi.name;
212 							p.second = res_orig->get(pi.name);
213 						}
214 
215 						propvalues.push_back(p);
216 					}
217 
218 					String orig_type = res_orig->get_class();
219 
220 					Object *inst = ClassDB::instance(orig_type);
221 
222 					Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst));
223 
224 					ERR_FAIL_COND(res.is_null());
225 
226 					for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) {
227 
228 						Pair<String, Variant> &p = E->get();
229 						res->set(p.first, p.second);
230 					}
231 
232 					v = res.get_ref_ptr();
233 					emit_signal("variant_changed");
234 					hide();
235 				} break;
236 
237 				case OBJ_MENU_COPY: {
238 
239 					EditorSettings::get_singleton()->set_resource_clipboard(v);
240 
241 				} break;
242 				case OBJ_MENU_PASTE: {
243 
244 					v = EditorSettings::get_singleton()->get_resource_clipboard();
245 					emit_signal("variant_changed");
246 
247 				} break;
248 				case OBJ_MENU_NEW_SCRIPT: {
249 
250 					if (Object::cast_to<Node>(owner))
251 						EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(owner), false);
252 
253 				} break;
254 				case OBJ_MENU_EXTEND_SCRIPT: {
255 
256 					if (Object::cast_to<Node>(owner))
257 						EditorNode::get_singleton()->get_scene_tree_dock()->open_script_dialog(Object::cast_to<Node>(owner), true);
258 
259 				} break;
260 				case OBJ_MENU_SHOW_IN_FILE_SYSTEM: {
261 					RES r = v;
262 					FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock();
263 					file_system_dock->navigate_to_path(r->get_path());
264 					// Ensure that the FileSystem dock is visible.
265 					TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
266 					tab_container->set_current_tab(file_system_dock->get_position_in_parent());
267 				} break;
268 				default: {
269 
270 					if (p_which >= CONVERT_BASE_ID) {
271 
272 						int to_type = p_which - CONVERT_BASE_ID;
273 
274 						Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
275 
276 						ERR_FAIL_INDEX(to_type, conversions.size());
277 
278 						Ref<Resource> new_res = conversions[to_type]->convert(v);
279 
280 						v = new_res;
281 						emit_signal("variant_changed");
282 						break;
283 					}
284 					ERR_FAIL_COND(inheritors_array.empty());
285 
286 					String intype = inheritors_array[p_which - TYPE_BASE_ID];
287 
288 					if (intype == "ViewportTexture") {
289 
290 						scene_tree->set_title(TTR("Pick a Viewport"));
291 						scene_tree->popup_centered_ratio();
292 						picking_viewport = true;
293 						return;
294 					}
295 
296 					Object *obj = ClassDB::instance(intype);
297 
298 					if (!obj) {
299 						if (ScriptServer::is_global_class(intype)) {
300 							obj = EditorNode::get_editor_data().script_class_instance(intype);
301 						} else {
302 							obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
303 						}
304 					}
305 
306 					ERR_BREAK(!obj);
307 					Resource *res = Object::cast_to<Resource>(obj);
308 					ERR_BREAK(!res);
309 					if (owner && hint == PROPERTY_HINT_RESOURCE_TYPE && hint_text == "Script") {
310 						//make visual script the right type
311 						res->call("set_instance_base_type", owner->get_class());
312 					}
313 
314 					v = Ref<Resource>(res).get_ref_ptr();
315 					emit_signal("variant_changed");
316 
317 				} break;
318 			}
319 
320 		} break;
321 		default: {
322 		}
323 	}
324 }
325 
hide_menu()326 void CustomPropertyEditor::hide_menu() {
327 	menu->hide();
328 }
329 
get_variant() const330 Variant CustomPropertyEditor::get_variant() const {
331 
332 	return v;
333 }
334 
get_name() const335 String CustomPropertyEditor::get_name() const {
336 
337 	return name;
338 }
339 
edit(Object * p_owner,const String & p_name,Variant::Type p_type,const Variant & p_variant,int p_hint,String p_hint_text)340 bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::Type p_type, const Variant &p_variant, int p_hint, String p_hint_text) {
341 
342 	owner = p_owner;
343 	updating = true;
344 	name = p_name;
345 	v = p_variant;
346 	field_names.clear();
347 	hint = p_hint;
348 	hint_text = p_hint_text;
349 	type_button->hide();
350 	if (color_picker)
351 		color_picker->hide();
352 	texture_preview->hide();
353 	inheritors_array.clear();
354 	text_edit->hide();
355 	easing_draw->hide();
356 	spinbox->hide();
357 	slider->hide();
358 	menu->clear();
359 	menu->set_size(Size2(1, 1) * EDSCALE);
360 
361 	for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
362 
363 		value_editor[i]->hide();
364 		value_label[i]->hide();
365 		if (i < 4)
366 			scroll[i]->hide();
367 	}
368 
369 	for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
370 
371 		action_buttons[i]->hide();
372 	}
373 
374 	checks20gc->hide();
375 	for (int i = 0; i < 20; i++)
376 		checks20[i]->hide();
377 
378 	type = (p_variant.get_type() != Variant::NIL && p_variant.get_type() != Variant::_RID && p_type != Variant::OBJECT) ? p_variant.get_type() : p_type;
379 
380 	switch (type) {
381 
382 		case Variant::BOOL: {
383 
384 			checks20gc->show();
385 
386 			CheckBox *c = checks20[0];
387 			c->set_text("True");
388 			checks20gc->set_position(Vector2(4, 4) * EDSCALE);
389 			c->set_pressed(v);
390 			c->show();
391 
392 			checks20gc->set_size(checks20gc->get_minimum_size());
393 			set_size(checks20gc->get_position() + checks20gc->get_size() + c->get_size() + Vector2(4, 4) * EDSCALE);
394 
395 		} break;
396 		case Variant::INT:
397 		case Variant::REAL: {
398 
399 			if (hint == PROPERTY_HINT_RANGE) {
400 
401 				int c = hint_text.get_slice_count(",");
402 				float min = 0, max = 100, step = type == Variant::REAL ? .01 : 1;
403 				if (c >= 1) {
404 
405 					if (!hint_text.get_slice(",", 0).empty())
406 						min = hint_text.get_slice(",", 0).to_double();
407 				}
408 				if (c >= 2) {
409 
410 					if (!hint_text.get_slice(",", 1).empty())
411 						max = hint_text.get_slice(",", 1).to_double();
412 				}
413 
414 				if (c >= 3) {
415 
416 					if (!hint_text.get_slice(",", 2).empty())
417 						step = hint_text.get_slice(",", 2).to_double();
418 				}
419 
420 				if (c >= 4 && hint_text.get_slice(",", 3) == "slider") {
421 					slider->set_min(min);
422 					slider->set_max(max);
423 					slider->set_step(step);
424 					slider->set_value(v);
425 					slider->show();
426 					set_size(Size2(110, 30) * EDSCALE);
427 				} else {
428 					spinbox->set_min(min);
429 					spinbox->set_max(max);
430 					spinbox->set_step(step);
431 					spinbox->set_value(v);
432 					spinbox->show();
433 					set_size(Size2(70, 35) * EDSCALE);
434 				}
435 
436 			} else if (hint == PROPERTY_HINT_ENUM) {
437 
438 				Vector<String> options = hint_text.split(",");
439 				int current_val = 0;
440 				for (int i = 0; i < options.size(); i++) {
441 					Vector<String> text_split = options[i].split(":");
442 					if (text_split.size() != 1)
443 						current_val = text_split[1].to_int();
444 					menu->add_item(text_split[0]);
445 					menu->set_item_metadata(i, current_val);
446 					current_val += 1;
447 				}
448 				menu->set_position(get_position());
449 				menu->popup();
450 				hide();
451 				updating = false;
452 				return false;
453 
454 			} else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
455 
456 				String basename;
457 				switch (hint) {
458 					case PROPERTY_HINT_LAYERS_2D_RENDER:
459 						basename = "layer_names/2d_render";
460 						break;
461 					case PROPERTY_HINT_LAYERS_2D_PHYSICS:
462 						basename = "layer_names/2d_physics";
463 						break;
464 					case PROPERTY_HINT_LAYERS_3D_RENDER:
465 						basename = "layer_names/3d_render";
466 						break;
467 					case PROPERTY_HINT_LAYERS_3D_PHYSICS:
468 						basename = "layer_names/3d_physics";
469 						break;
470 				}
471 
472 				checks20gc->show();
473 				uint32_t flgs = v;
474 				for (int i = 0; i < 2; i++) {
475 
476 					Point2 ofs(4, 4);
477 					ofs.y += 22 * i;
478 					for (int j = 0; j < 10; j++) {
479 
480 						int idx = i * 10 + j;
481 						CheckBox *c = checks20[idx];
482 						c->set_text(ProjectSettings::get_singleton()->get(basename + "/layer_" + itos(idx + 1)));
483 						c->set_pressed(flgs & (1 << (i * 10 + j)));
484 						c->show();
485 					}
486 				}
487 
488 				show();
489 
490 				checks20gc->set_position(Vector2(4, 4) * EDSCALE);
491 				checks20gc->set_size(checks20gc->get_minimum_size());
492 
493 				set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size());
494 
495 			} else if (hint == PROPERTY_HINT_EXP_EASING) {
496 
497 				easing_draw->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5 * EDSCALE);
498 				easing_draw->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -5 * EDSCALE);
499 				easing_draw->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 5 * EDSCALE);
500 				easing_draw->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -30 * EDSCALE);
501 				type_button->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 3 * EDSCALE);
502 				type_button->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -3 * EDSCALE);
503 				type_button->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -25 * EDSCALE);
504 				type_button->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -7 * EDSCALE);
505 				type_button->set_text(TTR("Preset..."));
506 				type_button->get_popup()->clear();
507 				type_button->get_popup()->add_item(TTR("Linear"), EASING_LINEAR);
508 				type_button->get_popup()->add_item(TTR("Ease In"), EASING_EASE_IN);
509 				type_button->get_popup()->add_item(TTR("Ease Out"), EASING_EASE_OUT);
510 				if (hint_text != "attenuation") {
511 					type_button->get_popup()->add_item(TTR("Zero"), EASING_ZERO);
512 					type_button->get_popup()->add_item(TTR("Easing In-Out"), EASING_IN_OUT);
513 					type_button->get_popup()->add_item(TTR("Easing Out-In"), EASING_OUT_IN);
514 				}
515 
516 				type_button->show();
517 				easing_draw->show();
518 				set_size(Size2(200, 150) * EDSCALE);
519 			} else if (hint == PROPERTY_HINT_FLAGS) {
520 				Vector<String> flags = hint_text.split(",");
521 				for (int i = 0; i < flags.size(); i++) {
522 					String flag = flags[i];
523 					if (flag == "")
524 						continue;
525 					menu->add_check_item(flag, i);
526 					int f = v;
527 					if (f & (1 << i))
528 						menu->set_item_checked(menu->get_item_index(i), true);
529 				}
530 				menu->set_position(get_position());
531 				menu->popup();
532 				hide();
533 				updating = false;
534 				return false;
535 
536 			} else {
537 				List<String> names;
538 				names.push_back("value:");
539 				config_value_editors(1, 1, 50, names);
540 				value_editor[0]->set_text(String::num(v));
541 			}
542 
543 		} break;
544 		case Variant::STRING: {
545 
546 			if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
547 
548 				List<String> names;
549 				names.push_back(TTR("File..."));
550 				names.push_back(TTR("Clear"));
551 				config_action_buttons(names);
552 
553 			} else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
554 
555 				List<String> names;
556 				names.push_back(TTR("Dir..."));
557 				names.push_back(TTR("Clear"));
558 				config_action_buttons(names);
559 			} else if (hint == PROPERTY_HINT_ENUM) {
560 
561 				Vector<String> options = hint_text.split(",");
562 				for (int i = 0; i < options.size(); i++) {
563 					menu->add_item(options[i], i);
564 				}
565 				menu->set_position(get_position());
566 				menu->popup();
567 				hide();
568 				updating = false;
569 				return false;
570 
571 			} else if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
572 
573 				text_edit->show();
574 				text_edit->set_text(v);
575 				text_edit->deselect();
576 
577 				int button_margin = get_constant("button_margin", "Dialogs");
578 				int margin = get_constant("margin", "Dialogs");
579 
580 				action_buttons[0]->set_anchor(MARGIN_LEFT, ANCHOR_END);
581 				action_buttons[0]->set_anchor(MARGIN_TOP, ANCHOR_END);
582 				action_buttons[0]->set_anchor(MARGIN_RIGHT, ANCHOR_END);
583 				action_buttons[0]->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
584 				action_buttons[0]->set_begin(Point2(-70 * EDSCALE, -button_margin + 5 * EDSCALE));
585 				action_buttons[0]->set_end(Point2(-margin, -margin));
586 				action_buttons[0]->set_text(TTR("Close"));
587 				action_buttons[0]->show();
588 
589 			} else if (hint == PROPERTY_HINT_TYPE_STRING) {
590 
591 				if (!create_dialog) {
592 					create_dialog = memnew(CreateDialog);
593 					create_dialog->connect("create", this, "_create_dialog_callback");
594 					add_child(create_dialog);
595 				}
596 
597 				if (hint_text != String()) {
598 					create_dialog->set_base_type(hint_text);
599 				} else {
600 					create_dialog->set_base_type("Object");
601 				}
602 
603 				create_dialog->popup_create(false);
604 				hide();
605 				updating = false;
606 				return false;
607 
608 			} else if (hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE) {
609 #define MAKE_PROPSELECT                                                          \
610 	if (!property_select) {                                                      \
611 		property_select = memnew(PropertySelector);                              \
612 		property_select->connect("selected", this, "_create_selected_property"); \
613 		add_child(property_select);                                              \
614 	}                                                                            \
615 	hide();
616 
617 				MAKE_PROPSELECT;
618 
619 				Variant::Type type = Variant::NIL;
620 				for (int i = 0; i < Variant::VARIANT_MAX; i++) {
621 					if (hint_text == Variant::get_type_name(Variant::Type(i))) {
622 						type = Variant::Type(i);
623 					}
624 				}
625 				if (type != Variant::NIL)
626 					property_select->select_method_from_basic_type(type, v);
627 				updating = false;
628 				return false;
629 
630 			} else if (hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE) {
631 				MAKE_PROPSELECT
632 
633 				property_select->select_method_from_base_type(hint_text, v);
634 
635 				updating = false;
636 				return false;
637 
638 			} else if (hint == PROPERTY_HINT_METHOD_OF_INSTANCE) {
639 
640 				MAKE_PROPSELECT
641 
642 				Object *instance = ObjectDB::get_instance(hint_text.to_int64());
643 				if (instance)
644 					property_select->select_method_from_instance(instance, v);
645 				updating = false;
646 				return false;
647 
648 			} else if (hint == PROPERTY_HINT_METHOD_OF_SCRIPT) {
649 				MAKE_PROPSELECT
650 
651 				Object *obj = ObjectDB::get_instance(hint_text.to_int64());
652 				if (Object::cast_to<Script>(obj)) {
653 					property_select->select_method_from_script(Object::cast_to<Script>(obj), v);
654 				}
655 
656 				updating = false;
657 				return false;
658 
659 			} else if (hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE) {
660 
661 				MAKE_PROPSELECT
662 				Variant::Type type = Variant::NIL;
663 				String tname = hint_text;
664 				if (tname.find(".") != -1)
665 					tname = tname.get_slice(".", 0);
666 				for (int i = 0; i < Variant::VARIANT_MAX; i++) {
667 					if (tname == Variant::get_type_name(Variant::Type(i))) {
668 						type = Variant::Type(Variant::Type(i));
669 					}
670 				}
671 
672 				if (type != Variant::NIL)
673 					property_select->select_property_from_basic_type(type, v);
674 
675 				updating = false;
676 				return false;
677 
678 			} else if (hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE) {
679 
680 				MAKE_PROPSELECT
681 
682 				property_select->select_property_from_base_type(hint_text, v);
683 
684 				updating = false;
685 				return false;
686 
687 			} else if (hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE) {
688 
689 				MAKE_PROPSELECT
690 
691 				Object *instance = ObjectDB::get_instance(hint_text.to_int64());
692 				if (instance)
693 					property_select->select_property_from_instance(instance, v);
694 
695 				updating = false;
696 				return false;
697 
698 			} else if (hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
699 				MAKE_PROPSELECT
700 
701 				Object *obj = ObjectDB::get_instance(hint_text.to_int64());
702 				if (Object::cast_to<Script>(obj)) {
703 					property_select->select_property_from_script(Object::cast_to<Script>(obj), v);
704 				}
705 
706 				updating = false;
707 				return false;
708 
709 			} else {
710 				List<String> names;
711 				names.push_back("string:");
712 				config_value_editors(1, 1, 50, names);
713 				value_editor[0]->set_text(v);
714 			}
715 
716 		} break;
717 		case Variant::VECTOR2: {
718 
719 			field_names.push_back("x");
720 			field_names.push_back("y");
721 			config_value_editors(2, 2, 10, field_names);
722 			Vector2 vec = v;
723 			value_editor[0]->set_text(String::num(vec.x));
724 			value_editor[1]->set_text(String::num(vec.y));
725 		} break;
726 		case Variant::RECT2: {
727 
728 			field_names.push_back("x");
729 			field_names.push_back("y");
730 			field_names.push_back("w");
731 			field_names.push_back("h");
732 			config_value_editors(4, 4, 10, field_names);
733 			Rect2 r = v;
734 			value_editor[0]->set_text(String::num(r.position.x));
735 			value_editor[1]->set_text(String::num(r.position.y));
736 			value_editor[2]->set_text(String::num(r.size.x));
737 			value_editor[3]->set_text(String::num(r.size.y));
738 		} break;
739 		case Variant::VECTOR3: {
740 
741 			field_names.push_back("x");
742 			field_names.push_back("y");
743 			field_names.push_back("z");
744 			config_value_editors(3, 3, 10, field_names);
745 			Vector3 vec = v;
746 			value_editor[0]->set_text(String::num(vec.x));
747 			value_editor[1]->set_text(String::num(vec.y));
748 			value_editor[2]->set_text(String::num(vec.z));
749 		} break;
750 		case Variant::PLANE: {
751 
752 			field_names.push_back("x");
753 			field_names.push_back("y");
754 			field_names.push_back("z");
755 			field_names.push_back("d");
756 			config_value_editors(4, 4, 10, field_names);
757 			Plane plane = v;
758 			value_editor[0]->set_text(String::num(plane.normal.x));
759 			value_editor[1]->set_text(String::num(plane.normal.y));
760 			value_editor[2]->set_text(String::num(plane.normal.z));
761 			value_editor[3]->set_text(String::num(plane.d));
762 
763 		} break;
764 		case Variant::QUAT: {
765 
766 			field_names.push_back("x");
767 			field_names.push_back("y");
768 			field_names.push_back("z");
769 			field_names.push_back("w");
770 			config_value_editors(4, 4, 10, field_names);
771 			Quat q = v;
772 			value_editor[0]->set_text(String::num(q.x));
773 			value_editor[1]->set_text(String::num(q.y));
774 			value_editor[2]->set_text(String::num(q.z));
775 			value_editor[3]->set_text(String::num(q.w));
776 
777 		} break;
778 		case Variant::AABB: {
779 
780 			field_names.push_back("px");
781 			field_names.push_back("py");
782 			field_names.push_back("pz");
783 			field_names.push_back("sx");
784 			field_names.push_back("sy");
785 			field_names.push_back("sz");
786 			config_value_editors(6, 3, 16, field_names);
787 
788 			AABB aabb = v;
789 			value_editor[0]->set_text(String::num(aabb.position.x));
790 			value_editor[1]->set_text(String::num(aabb.position.y));
791 			value_editor[2]->set_text(String::num(aabb.position.z));
792 			value_editor[3]->set_text(String::num(aabb.size.x));
793 			value_editor[4]->set_text(String::num(aabb.size.y));
794 			value_editor[5]->set_text(String::num(aabb.size.z));
795 
796 		} break;
797 		case Variant::TRANSFORM2D: {
798 
799 			field_names.push_back("xx");
800 			field_names.push_back("xy");
801 			field_names.push_back("yx");
802 			field_names.push_back("yy");
803 			field_names.push_back("ox");
804 			field_names.push_back("oy");
805 			config_value_editors(6, 2, 16, field_names);
806 
807 			Transform2D basis = v;
808 			for (int i = 0; i < 6; i++) {
809 
810 				value_editor[i]->set_text(String::num(basis.elements[i / 2][i % 2]));
811 			}
812 
813 		} break;
814 		case Variant::BASIS: {
815 
816 			field_names.push_back("xx");
817 			field_names.push_back("xy");
818 			field_names.push_back("xz");
819 			field_names.push_back("yx");
820 			field_names.push_back("yy");
821 			field_names.push_back("yz");
822 			field_names.push_back("zx");
823 			field_names.push_back("zy");
824 			field_names.push_back("zz");
825 			config_value_editors(9, 3, 16, field_names);
826 
827 			Basis basis = v;
828 			for (int i = 0; i < 9; i++) {
829 
830 				value_editor[i]->set_text(String::num(basis.elements[i / 3][i % 3]));
831 			}
832 
833 		} break;
834 		case Variant::TRANSFORM: {
835 
836 			field_names.push_back("xx");
837 			field_names.push_back("xy");
838 			field_names.push_back("xz");
839 			field_names.push_back("xo");
840 			field_names.push_back("yx");
841 			field_names.push_back("yy");
842 			field_names.push_back("yz");
843 			field_names.push_back("yo");
844 			field_names.push_back("zx");
845 			field_names.push_back("zy");
846 			field_names.push_back("zz");
847 			field_names.push_back("zo");
848 			config_value_editors(12, 4, 16, field_names);
849 
850 			Transform tr = v;
851 			for (int i = 0; i < 9; i++) {
852 
853 				value_editor[(i / 3) * 4 + i % 3]->set_text(String::num(tr.basis.elements[i / 3][i % 3]));
854 			}
855 
856 			value_editor[3]->set_text(String::num(tr.origin.x));
857 			value_editor[7]->set_text(String::num(tr.origin.y));
858 			value_editor[11]->set_text(String::num(tr.origin.z));
859 
860 		} break;
861 		case Variant::COLOR: {
862 
863 			if (!color_picker) {
864 				//late init for performance
865 				color_picker = memnew(ColorPicker);
866 				color_picker->set_deferred_mode(true);
867 				add_child(color_picker);
868 				color_picker->hide();
869 				color_picker->connect("color_changed", this, "_color_changed");
870 
871 				// get default color picker mode from editor settings
872 				int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode");
873 				if (default_color_mode == 1)
874 					color_picker->set_hsv_mode(true);
875 				else if (default_color_mode == 2)
876 					color_picker->set_raw_mode(true);
877 			}
878 
879 			color_picker->show();
880 			color_picker->set_edit_alpha(hint != PROPERTY_HINT_COLOR_NO_ALPHA);
881 			color_picker->set_pick_color(v);
882 			color_picker->set_focus_on_line_edit();
883 
884 		} break;
885 
886 		case Variant::NODE_PATH: {
887 
888 			List<String> names;
889 			names.push_back(TTR("Assign"));
890 			names.push_back(TTR("Clear"));
891 
892 			if (owner && owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v))
893 				names.push_back(TTR("Select Node"));
894 
895 			config_action_buttons(names);
896 
897 		} break;
898 		case Variant::OBJECT: {
899 
900 			if (hint != PROPERTY_HINT_RESOURCE_TYPE)
901 				break;
902 
903 			if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) {
904 				menu->add_icon_item(get_icon("Script", "EditorIcons"), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
905 				menu->add_separator();
906 			} else if (hint_text != "") {
907 				int idx = 0;
908 
909 				Vector<EditorData::CustomType> custom_resources;
910 
911 				if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
912 					custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
913 				}
914 
915 				for (int i = 0; i < hint_text.get_slice_count(","); i++) {
916 
917 					String base = hint_text.get_slice(",", i);
918 
919 					Set<String> valid_inheritors;
920 					valid_inheritors.insert(base);
921 					List<StringName> inheritors;
922 					ClassDB::get_inheriters_from_class(base.strip_edges(), &inheritors);
923 
924 					for (int j = 0; j < custom_resources.size(); j++) {
925 						inheritors.push_back(custom_resources[j].name);
926 					}
927 
928 					List<StringName>::Element *E = inheritors.front();
929 					while (E) {
930 						valid_inheritors.insert(E->get());
931 						E = E->next();
932 					}
933 
934 					for (Set<String>::Element *j = valid_inheritors.front(); j; j = j->next()) {
935 						const String &t = j->get();
936 
937 						bool is_custom_resource = false;
938 						Ref<Texture> icon;
939 						if (!custom_resources.empty()) {
940 							for (int k = 0; k < custom_resources.size(); k++) {
941 								if (custom_resources[k].name == t) {
942 									is_custom_resource = true;
943 									if (custom_resources[k].icon.is_valid())
944 										icon = custom_resources[k].icon;
945 									break;
946 								}
947 							}
948 						}
949 
950 						if (!is_custom_resource && !ClassDB::can_instance(t))
951 							continue;
952 
953 						inheritors_array.push_back(t);
954 
955 						int id = TYPE_BASE_ID + idx;
956 
957 						if (!icon.is_valid() && has_icon(t, "EditorIcons")) {
958 							icon = get_icon(t, "EditorIcons");
959 						}
960 
961 						if (icon.is_valid()) {
962 
963 							menu->add_icon_item(icon, vformat(TTR("New %s"), t), id);
964 						} else {
965 
966 							menu->add_item(vformat(TTR("New %s"), t), id);
967 						}
968 
969 						idx++;
970 					}
971 				}
972 
973 				if (menu->get_item_count())
974 					menu->add_separator();
975 			}
976 
977 			menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Load"), OBJ_MENU_LOAD);
978 
979 			if (!RES(v).is_null()) {
980 
981 				menu->add_icon_item(get_icon("Edit", "EditorIcons"), TTR("Edit"), OBJ_MENU_EDIT);
982 				menu->add_icon_item(get_icon("Clear", "EditorIcons"), TTR("Clear"), OBJ_MENU_CLEAR);
983 				menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
984 				RES r = v;
985 				if (r.is_valid() && r->get_path().is_resource_file()) {
986 					menu->add_separator();
987 					menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
988 				}
989 			}
990 
991 			RES cb = EditorSettings::get_singleton()->get_resource_clipboard();
992 			bool paste_valid = false;
993 			if (cb.is_valid()) {
994 				if (hint_text == "")
995 					paste_valid = true;
996 				else
997 					for (int i = 0; i < hint_text.get_slice_count(","); i++)
998 						if (ClassDB::is_parent_class(cb->get_class(), hint_text.get_slice(",", i))) {
999 							paste_valid = true;
1000 							break;
1001 						}
1002 			}
1003 
1004 			if (!RES(v).is_null() || paste_valid) {
1005 				menu->add_separator();
1006 
1007 				if (!RES(v).is_null()) {
1008 
1009 					menu->add_item(TTR("Copy"), OBJ_MENU_COPY);
1010 				}
1011 
1012 				if (paste_valid) {
1013 
1014 					menu->add_item(TTR("Paste"), OBJ_MENU_PASTE);
1015 				}
1016 			}
1017 
1018 			if (!RES(v).is_null()) {
1019 
1020 				Vector<Ref<EditorResourceConversionPlugin> > conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(RES(v));
1021 				if (conversions.size()) {
1022 					menu->add_separator();
1023 				}
1024 				for (int i = 0; i < conversions.size(); i++) {
1025 					String what = conversions[i]->converts_to();
1026 					Ref<Texture> icon;
1027 					if (has_icon(what, "EditorIcons")) {
1028 
1029 						icon = get_icon(what, "EditorIcons");
1030 					} else {
1031 
1032 						icon = get_icon(what, "Resource");
1033 					}
1034 
1035 					menu->add_icon_item(icon, vformat(TTR("Convert To %s"), what), CONVERT_BASE_ID + i);
1036 				}
1037 			}
1038 
1039 			menu->set_position(get_position());
1040 			menu->popup();
1041 			hide();
1042 			updating = false;
1043 			return false;
1044 
1045 		} break;
1046 		case Variant::DICTIONARY: {
1047 
1048 		} break;
1049 		case Variant::POOL_BYTE_ARRAY: {
1050 
1051 		} break;
1052 		case Variant::POOL_INT_ARRAY: {
1053 
1054 		} break;
1055 		case Variant::POOL_REAL_ARRAY: {
1056 
1057 		} break;
1058 		case Variant::POOL_STRING_ARRAY: {
1059 
1060 		} break;
1061 		case Variant::POOL_VECTOR3_ARRAY: {
1062 
1063 		} break;
1064 		case Variant::POOL_COLOR_ARRAY: {
1065 
1066 		} break;
1067 		default: {
1068 		}
1069 	}
1070 
1071 	updating = false;
1072 	return true;
1073 }
1074 
_file_selected(String p_file)1075 void CustomPropertyEditor::_file_selected(String p_file) {
1076 
1077 	switch (type) {
1078 
1079 		case Variant::STRING: {
1080 
1081 			if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_DIR) {
1082 
1083 				v = ProjectSettings::get_singleton()->localize_path(p_file);
1084 				emit_signal("variant_changed");
1085 				hide();
1086 			}
1087 
1088 			if (hint == PROPERTY_HINT_GLOBAL_FILE || hint == PROPERTY_HINT_GLOBAL_DIR) {
1089 
1090 				v = p_file;
1091 				emit_signal("variant_changed");
1092 				hide();
1093 			}
1094 
1095 		} break;
1096 		case Variant::OBJECT: {
1097 
1098 			String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
1099 
1100 			RES res = ResourceLoader::load(p_file, type);
1101 			if (res.is_null()) {
1102 				error->set_text(TTR("Error loading file: Not a resource!"));
1103 				error->popup_centered_minsize();
1104 				break;
1105 			}
1106 			v = res.get_ref_ptr();
1107 			emit_signal("variant_changed");
1108 			hide();
1109 		} break;
1110 		default: {
1111 		}
1112 	}
1113 }
1114 
_type_create_selected(int p_idx)1115 void CustomPropertyEditor::_type_create_selected(int p_idx) {
1116 
1117 	if (type == Variant::INT || type == Variant::REAL) {
1118 
1119 		float newval = 0;
1120 		switch (p_idx) {
1121 
1122 			case EASING_LINEAR: {
1123 
1124 				newval = 1;
1125 			} break;
1126 			case EASING_EASE_IN: {
1127 
1128 				newval = 2.0;
1129 			} break;
1130 			case EASING_EASE_OUT: {
1131 				newval = 0.5;
1132 			} break;
1133 			case EASING_ZERO: {
1134 
1135 				newval = 0;
1136 			} break;
1137 			case EASING_IN_OUT: {
1138 
1139 				newval = -0.5;
1140 			} break;
1141 			case EASING_OUT_IN: {
1142 				newval = -2.0;
1143 			} break;
1144 		}
1145 
1146 		v = newval;
1147 		emit_signal("variant_changed");
1148 		easing_draw->update();
1149 
1150 	} else if (type == Variant::OBJECT) {
1151 
1152 		ERR_FAIL_INDEX(p_idx, inheritors_array.size());
1153 
1154 		String intype = inheritors_array[p_idx];
1155 
1156 		Object *obj = ClassDB::instance(intype);
1157 
1158 		if (!obj) {
1159 			if (ScriptServer::is_global_class(intype)) {
1160 				obj = EditorNode::get_editor_data().script_class_instance(intype);
1161 			} else {
1162 				obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
1163 			}
1164 		}
1165 
1166 		ERR_FAIL_COND(!obj);
1167 
1168 		Resource *res = Object::cast_to<Resource>(obj);
1169 		ERR_FAIL_COND(!res);
1170 
1171 		v = Ref<Resource>(res).get_ref_ptr();
1172 		emit_signal("variant_changed");
1173 		hide();
1174 	}
1175 }
1176 
_color_changed(const Color & p_color)1177 void CustomPropertyEditor::_color_changed(const Color &p_color) {
1178 
1179 	v = p_color;
1180 	emit_signal("variant_changed");
1181 }
1182 
_node_path_selected(NodePath p_path)1183 void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
1184 
1185 	if (picking_viewport) {
1186 
1187 		Node *to_node = get_node(p_path);
1188 		if (!Object::cast_to<Viewport>(to_node)) {
1189 			EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!"));
1190 			return;
1191 		}
1192 
1193 		Ref<ViewportTexture> vt;
1194 		vt.instance();
1195 		vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
1196 		vt->setup_local_to_scene();
1197 		v = vt;
1198 		emit_signal("variant_changed");
1199 		return;
1200 	}
1201 
1202 	if (hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && hint_text != String()) {
1203 
1204 		Node *node = get_node(hint_text);
1205 		if (node) {
1206 
1207 			Node *tonode = node->get_node(p_path);
1208 			if (tonode) {
1209 				p_path = node->get_path_to(tonode);
1210 			}
1211 		}
1212 
1213 	} else if (owner) {
1214 
1215 		Node *node = NULL;
1216 
1217 		if (owner->is_class("Node"))
1218 			node = Object::cast_to<Node>(owner);
1219 		else if (owner->is_class("ArrayPropertyEdit"))
1220 			node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node();
1221 		else if (owner->is_class("DictionaryPropertyEdit"))
1222 			node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node();
1223 		if (!node) {
1224 			v = p_path;
1225 			emit_signal("variant_changed");
1226 			call_deferred("hide"); //to not mess with dialogs
1227 			return;
1228 		}
1229 
1230 		Node *tonode = node->get_node(p_path);
1231 		if (tonode) {
1232 			p_path = node->get_path_to(tonode);
1233 		}
1234 	}
1235 
1236 	v = p_path;
1237 	emit_signal("variant_changed");
1238 	call_deferred("hide"); //to not mess with dialogs
1239 }
1240 
_action_pressed(int p_which)1241 void CustomPropertyEditor::_action_pressed(int p_which) {
1242 
1243 	if (updating)
1244 		return;
1245 
1246 	switch (type) {
1247 		case Variant::BOOL: {
1248 			v = checks20[0]->is_pressed();
1249 			emit_signal("variant_changed");
1250 		} break;
1251 		case Variant::INT: {
1252 
1253 			if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
1254 
1255 				uint32_t f = v;
1256 				if (checks20[p_which]->is_pressed())
1257 					f |= (1 << p_which);
1258 				else
1259 					f &= ~(1 << p_which);
1260 
1261 				v = f;
1262 				emit_signal("variant_changed");
1263 			}
1264 
1265 		} break;
1266 		case Variant::STRING: {
1267 
1268 			if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
1269 
1270 				hide();
1271 
1272 			} else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
1273 				if (p_which == 0) {
1274 
1275 					if (hint == PROPERTY_HINT_FILE)
1276 						file->set_access(EditorFileDialog::ACCESS_RESOURCES);
1277 					else
1278 						file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
1279 
1280 					file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
1281 					file->clear_filters();
1282 
1283 					file->clear_filters();
1284 
1285 					if (hint_text != "") {
1286 						Vector<String> extensions = hint_text.split(",");
1287 						for (int i = 0; i < extensions.size(); i++) {
1288 
1289 							String filter = extensions[i];
1290 							if (filter.begins_with("."))
1291 								filter = "*" + extensions[i];
1292 							else if (!filter.begins_with("*"))
1293 								filter = "*." + extensions[i];
1294 
1295 							file->add_filter(filter + " ; " + extensions[i].to_upper());
1296 						}
1297 					}
1298 					file->popup_centered_ratio();
1299 				} else {
1300 
1301 					v = "";
1302 					emit_signal("variant_changed");
1303 					hide();
1304 				}
1305 
1306 			} else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
1307 
1308 				if (p_which == 0) {
1309 
1310 					if (hint == PROPERTY_HINT_DIR)
1311 						file->set_access(EditorFileDialog::ACCESS_RESOURCES);
1312 					else
1313 						file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
1314 					file->set_mode(EditorFileDialog::MODE_OPEN_DIR);
1315 					file->clear_filters();
1316 					file->popup_centered_ratio();
1317 				} else {
1318 
1319 					v = "";
1320 					emit_signal("variant_changed");
1321 					hide();
1322 				}
1323 			}
1324 
1325 		} break;
1326 		case Variant::NODE_PATH: {
1327 
1328 			if (p_which == 0) {
1329 
1330 				picking_viewport = false;
1331 				scene_tree->set_title(TTR("Pick a Node"));
1332 				scene_tree->popup_centered_ratio();
1333 
1334 			} else if (p_which == 1) {
1335 
1336 				v = NodePath();
1337 				emit_signal("variant_changed");
1338 				hide();
1339 			} else if (p_which == 2) {
1340 
1341 				if (owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v)) {
1342 
1343 					Node *target_node = Object::cast_to<Node>(owner)->get_node(v);
1344 					EditorNode::get_singleton()->get_editor_selection()->clear();
1345 					EditorNode::get_singleton()->get_scene_tree_dock()->set_selected(target_node);
1346 				}
1347 
1348 				hide();
1349 			}
1350 
1351 		} break;
1352 		case Variant::OBJECT: {
1353 
1354 			if (p_which == 0) {
1355 
1356 				ERR_FAIL_COND(inheritors_array.empty());
1357 
1358 				String intype = inheritors_array[0];
1359 
1360 				if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
1361 
1362 					Object *obj = ClassDB::instance(intype);
1363 
1364 					if (!obj) {
1365 						if (ScriptServer::is_global_class(intype)) {
1366 							obj = EditorNode::get_editor_data().script_class_instance(intype);
1367 						} else {
1368 							obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
1369 						}
1370 					}
1371 
1372 					ERR_BREAK(!obj);
1373 					Resource *res = Object::cast_to<Resource>(obj);
1374 					ERR_BREAK(!res);
1375 
1376 					v = Ref<Resource>(res).get_ref_ptr();
1377 					emit_signal("variant_changed");
1378 					hide();
1379 				}
1380 			} else if (p_which == 1) {
1381 
1382 				file->set_access(EditorFileDialog::ACCESS_RESOURCES);
1383 				file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
1384 				List<String> extensions;
1385 				String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
1386 
1387 				ResourceLoader::get_recognized_extensions_for_type(type, &extensions);
1388 				file->clear_filters();
1389 				for (List<String>::Element *E = extensions.front(); E; E = E->next()) {
1390 
1391 					file->add_filter("*." + E->get() + " ; " + E->get().to_upper());
1392 				}
1393 
1394 				file->popup_centered_ratio();
1395 
1396 			} else if (p_which == 2) {
1397 
1398 				RefPtr RefPtr = v;
1399 
1400 				if (!RefPtr.is_null()) {
1401 
1402 					emit_signal("resource_edit_request");
1403 					hide();
1404 				}
1405 
1406 			} else if (p_which == 3) {
1407 
1408 				v = Variant();
1409 				emit_signal("variant_changed");
1410 				hide();
1411 			} else if (p_which == 4) {
1412 
1413 				RefPtr RefPtr = v;
1414 				Ref<Resource> res_orig = RefPtr;
1415 				if (res_orig.is_null())
1416 					return;
1417 
1418 				List<PropertyInfo> property_list;
1419 				res_orig->get_property_list(&property_list);
1420 				List<Pair<String, Variant> > propvalues;
1421 
1422 				for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
1423 
1424 					Pair<String, Variant> p;
1425 					PropertyInfo &pi = E->get();
1426 					if (pi.usage & PROPERTY_USAGE_STORAGE) {
1427 
1428 						p.first = pi.name;
1429 						p.second = res_orig->get(pi.name);
1430 					}
1431 
1432 					propvalues.push_back(p);
1433 				}
1434 
1435 				Ref<Resource> res = Ref<Resource>(ClassDB::instance(res_orig->get_class()));
1436 
1437 				ERR_FAIL_COND(res.is_null());
1438 
1439 				for (List<Pair<String, Variant> >::Element *E = propvalues.front(); E; E = E->next()) {
1440 
1441 					Pair<String, Variant> &p = E->get();
1442 					res->set(p.first, p.second);
1443 				}
1444 
1445 				v = res.get_ref_ptr();
1446 				emit_signal("variant_changed");
1447 				hide();
1448 			}
1449 
1450 		} break;
1451 
1452 		default: {
1453 		};
1454 	}
1455 }
1456 
_drag_easing(const Ref<InputEvent> & p_ev)1457 void CustomPropertyEditor::_drag_easing(const Ref<InputEvent> &p_ev) {
1458 
1459 	Ref<InputEventMouseMotion> mm = p_ev;
1460 
1461 	if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
1462 
1463 		float rel = mm->get_relative().x;
1464 		if (rel == 0)
1465 			return;
1466 
1467 		bool flip = hint_text == "attenuation";
1468 
1469 		if (flip)
1470 			rel = -rel;
1471 
1472 		float val = v;
1473 		if (val == 0)
1474 			return;
1475 		bool sg = val < 0;
1476 		val = Math::absf(val);
1477 
1478 		val = Math::log(val) / Math::log((float)2.0);
1479 		//logspace
1480 		val += rel * 0.05;
1481 
1482 		val = Math::pow(2.0f, val);
1483 		if (sg)
1484 			val = -val;
1485 
1486 		v = val;
1487 		easing_draw->update();
1488 		emit_signal("variant_changed");
1489 	}
1490 }
1491 
_draw_easing()1492 void CustomPropertyEditor::_draw_easing() {
1493 
1494 	RID ci = easing_draw->get_canvas_item();
1495 
1496 	Size2 s = easing_draw->get_size();
1497 	Rect2 r(Point2(), s);
1498 	r = r.grow(3);
1499 	get_stylebox("normal", "LineEdit")->draw(ci, r);
1500 
1501 	int points = 48;
1502 
1503 	float prev = 1.0;
1504 	float exp = v;
1505 	bool flip = hint_text == "attenuation";
1506 
1507 	Ref<Font> f = get_font("font", "Label");
1508 	Color color = get_color("font_color", "Label");
1509 
1510 	for (int i = 1; i <= points; i++) {
1511 
1512 		float ifl = i / float(points);
1513 		float iflp = (i - 1) / float(points);
1514 
1515 		float h = 1.0 - Math::ease(ifl, exp);
1516 
1517 		if (flip) {
1518 			ifl = 1.0 - ifl;
1519 			iflp = 1.0 - iflp;
1520 		}
1521 
1522 		VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color);
1523 		prev = h;
1524 	}
1525 
1526 	f->draw(ci, Point2(10, 10 + f->get_ascent()), String::num(exp, 2), color);
1527 }
1528 
_text_edit_changed()1529 void CustomPropertyEditor::_text_edit_changed() {
1530 
1531 	v = text_edit->get_text();
1532 	emit_signal("variant_changed");
1533 }
1534 
_create_dialog_callback()1535 void CustomPropertyEditor::_create_dialog_callback() {
1536 
1537 	v = create_dialog->get_selected_type();
1538 	emit_signal("variant_changed");
1539 }
1540 
_create_selected_property(const String & p_prop)1541 void CustomPropertyEditor::_create_selected_property(const String &p_prop) {
1542 
1543 	v = p_prop;
1544 	emit_signal("variant_changed");
1545 }
1546 
_modified(String p_string)1547 void CustomPropertyEditor::_modified(String p_string) {
1548 
1549 	if (updating)
1550 		return;
1551 
1552 	updating = true;
1553 	switch (type) {
1554 		case Variant::INT: {
1555 			String text = value_editor[0]->get_text();
1556 			Ref<Expression> expr;
1557 			expr.instance();
1558 			Error err = expr->parse(text);
1559 			if (err != OK) {
1560 				v = value_editor[0]->get_text().to_int();
1561 				return;
1562 			} else {
1563 				v = expr->execute(Array(), NULL, false);
1564 			}
1565 			emit_signal("variant_changed");
1566 
1567 		} break;
1568 		case Variant::REAL: {
1569 
1570 			if (hint != PROPERTY_HINT_EXP_EASING) {
1571 				String text = value_editor[0]->get_text();
1572 				v = _parse_real_expression(text);
1573 				emit_signal("variant_changed");
1574 			}
1575 
1576 		} break;
1577 		case Variant::STRING: {
1578 
1579 			v = value_editor[0]->get_text();
1580 			emit_signal("variant_changed");
1581 		} break;
1582 		case Variant::VECTOR2: {
1583 
1584 			Vector2 vec;
1585 			vec.x = _parse_real_expression(value_editor[0]->get_text());
1586 			vec.y = _parse_real_expression(value_editor[1]->get_text());
1587 			v = vec;
1588 			_emit_changed_whole_or_field();
1589 
1590 		} break;
1591 		case Variant::RECT2: {
1592 
1593 			Rect2 r2;
1594 
1595 			r2.position.x = _parse_real_expression(value_editor[0]->get_text());
1596 			r2.position.y = _parse_real_expression(value_editor[1]->get_text());
1597 			r2.size.x = _parse_real_expression(value_editor[2]->get_text());
1598 			r2.size.y = _parse_real_expression(value_editor[3]->get_text());
1599 			v = r2;
1600 			_emit_changed_whole_or_field();
1601 
1602 		} break;
1603 
1604 		case Variant::VECTOR3: {
1605 
1606 			Vector3 vec;
1607 			vec.x = _parse_real_expression(value_editor[0]->get_text());
1608 			vec.y = _parse_real_expression(value_editor[1]->get_text());
1609 			vec.z = _parse_real_expression(value_editor[2]->get_text());
1610 			v = vec;
1611 			_emit_changed_whole_or_field();
1612 
1613 		} break;
1614 		case Variant::PLANE: {
1615 
1616 			Plane pl;
1617 			pl.normal.x = _parse_real_expression(value_editor[0]->get_text());
1618 			pl.normal.y = _parse_real_expression(value_editor[1]->get_text());
1619 			pl.normal.z = _parse_real_expression(value_editor[2]->get_text());
1620 			pl.d = _parse_real_expression(value_editor[3]->get_text());
1621 			v = pl;
1622 			_emit_changed_whole_or_field();
1623 
1624 		} break;
1625 		case Variant::QUAT: {
1626 
1627 			Quat q;
1628 			q.x = _parse_real_expression(value_editor[0]->get_text());
1629 			q.y = _parse_real_expression(value_editor[1]->get_text());
1630 			q.z = _parse_real_expression(value_editor[2]->get_text());
1631 			q.w = _parse_real_expression(value_editor[3]->get_text());
1632 			v = q;
1633 			_emit_changed_whole_or_field();
1634 
1635 		} break;
1636 		case Variant::AABB: {
1637 
1638 			Vector3 pos;
1639 			Vector3 size;
1640 
1641 			pos.x = _parse_real_expression(value_editor[0]->get_text());
1642 			pos.y = _parse_real_expression(value_editor[1]->get_text());
1643 			pos.z = _parse_real_expression(value_editor[2]->get_text());
1644 			size.x = _parse_real_expression(value_editor[3]->get_text());
1645 			size.y = _parse_real_expression(value_editor[4]->get_text());
1646 			size.z = _parse_real_expression(value_editor[5]->get_text());
1647 			v = AABB(pos, size);
1648 			_emit_changed_whole_or_field();
1649 
1650 		} break;
1651 		case Variant::TRANSFORM2D: {
1652 
1653 			Transform2D m;
1654 			for (int i = 0; i < 6; i++) {
1655 				m.elements[i / 2][i % 2] = _parse_real_expression(value_editor[i]->get_text());
1656 			}
1657 
1658 			v = m;
1659 			_emit_changed_whole_or_field();
1660 
1661 		} break;
1662 		case Variant::BASIS: {
1663 
1664 			Basis m;
1665 			for (int i = 0; i < 9; i++) {
1666 				m.elements[i / 3][i % 3] = _parse_real_expression(value_editor[i]->get_text());
1667 			}
1668 
1669 			v = m;
1670 			_emit_changed_whole_or_field();
1671 
1672 		} break;
1673 		case Variant::TRANSFORM: {
1674 
1675 			Basis basis;
1676 			for (int i = 0; i < 9; i++) {
1677 				basis.elements[i / 3][i % 3] = _parse_real_expression(value_editor[(i / 3) * 4 + i % 3]->get_text());
1678 			}
1679 
1680 			Vector3 origin;
1681 
1682 			origin.x = _parse_real_expression(value_editor[3]->get_text());
1683 			origin.y = _parse_real_expression(value_editor[7]->get_text());
1684 			origin.z = _parse_real_expression(value_editor[11]->get_text());
1685 
1686 			v = Transform(basis, origin);
1687 			_emit_changed_whole_or_field();
1688 
1689 		} break;
1690 		case Variant::COLOR: {
1691 
1692 		} break;
1693 
1694 		case Variant::NODE_PATH: {
1695 
1696 			v = NodePath(value_editor[0]->get_text());
1697 			emit_signal("variant_changed");
1698 		} break;
1699 		case Variant::DICTIONARY: {
1700 
1701 		} break;
1702 		case Variant::POOL_BYTE_ARRAY: {
1703 
1704 		} break;
1705 		case Variant::POOL_INT_ARRAY: {
1706 
1707 		} break;
1708 		case Variant::POOL_REAL_ARRAY: {
1709 
1710 		} break;
1711 		case Variant::POOL_STRING_ARRAY: {
1712 
1713 		} break;
1714 		case Variant::POOL_VECTOR3_ARRAY: {
1715 
1716 		} break;
1717 		case Variant::POOL_COLOR_ARRAY: {
1718 
1719 		} break;
1720 		default: {
1721 		}
1722 	}
1723 
1724 	updating = false;
1725 }
1726 
_parse_real_expression(String text)1727 real_t CustomPropertyEditor::_parse_real_expression(String text) {
1728 	Ref<Expression> expr;
1729 	expr.instance();
1730 	Error err = expr->parse(text);
1731 	real_t out;
1732 	if (err != OK) {
1733 		out = value_editor[0]->get_text().to_double();
1734 	} else {
1735 		out = expr->execute(Array(), NULL, false);
1736 	}
1737 	return out;
1738 }
1739 
_emit_changed_whole_or_field()1740 void CustomPropertyEditor::_emit_changed_whole_or_field() {
1741 
1742 	if (!Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
1743 		emit_signal("variant_changed");
1744 	} else {
1745 		emit_signal("variant_field_changed", field_names[focused_value_editor]);
1746 	}
1747 }
1748 
_range_modified(double p_value)1749 void CustomPropertyEditor::_range_modified(double p_value) {
1750 	v = p_value;
1751 	emit_signal("variant_changed");
1752 }
1753 
_focus_enter()1754 void CustomPropertyEditor::_focus_enter() {
1755 	switch (type) {
1756 		case Variant::REAL:
1757 		case Variant::STRING:
1758 		case Variant::VECTOR2:
1759 		case Variant::RECT2:
1760 		case Variant::VECTOR3:
1761 		case Variant::PLANE:
1762 		case Variant::QUAT:
1763 		case Variant::AABB:
1764 		case Variant::TRANSFORM2D:
1765 		case Variant::BASIS:
1766 		case Variant::TRANSFORM: {
1767 			for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
1768 				if (value_editor[i]->has_focus()) {
1769 					focused_value_editor = i;
1770 					value_editor[i]->select_all();
1771 					break;
1772 				}
1773 			}
1774 		} break;
1775 		default: {
1776 		}
1777 	}
1778 }
1779 
_focus_exit()1780 void CustomPropertyEditor::_focus_exit() {
1781 	switch (type) {
1782 		case Variant::REAL:
1783 		case Variant::STRING:
1784 		case Variant::VECTOR2:
1785 		case Variant::RECT2:
1786 		case Variant::VECTOR3:
1787 		case Variant::PLANE:
1788 		case Variant::QUAT:
1789 		case Variant::AABB:
1790 		case Variant::TRANSFORM2D:
1791 		case Variant::BASIS:
1792 		case Variant::TRANSFORM: {
1793 			for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
1794 				value_editor[i]->select(0, 0);
1795 			}
1796 		} break;
1797 		default: {
1798 		}
1799 	}
1800 }
1801 
config_action_buttons(const List<String> & p_strings)1802 void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
1803 
1804 	Ref<StyleBox> sb = get_stylebox("panel");
1805 	int margin_top = sb->get_margin(MARGIN_TOP);
1806 	int margin_left = sb->get_margin(MARGIN_LEFT);
1807 	int margin_bottom = sb->get_margin(MARGIN_BOTTOM);
1808 	int margin_right = sb->get_margin(MARGIN_RIGHT);
1809 
1810 	int max_width = 0;
1811 	int height = 0;
1812 
1813 	for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
1814 
1815 		if (i < p_strings.size()) {
1816 
1817 			action_buttons[i]->show();
1818 			action_buttons[i]->set_text(p_strings[i]);
1819 
1820 			Size2 btn_m_size = action_buttons[i]->get_minimum_size();
1821 			if (btn_m_size.width > max_width)
1822 				max_width = btn_m_size.width;
1823 
1824 		} else {
1825 			action_buttons[i]->hide();
1826 		}
1827 	}
1828 
1829 	for (int i = 0; i < p_strings.size(); i++) {
1830 
1831 		Size2 btn_m_size = action_buttons[i]->get_size();
1832 		action_buttons[i]->set_position(Point2(0, height) + Point2(margin_left, margin_top));
1833 		action_buttons[i]->set_size(Size2(max_width, btn_m_size.height));
1834 
1835 		height += btn_m_size.height;
1836 	}
1837 	set_size(Size2(max_width, height) + Size2(margin_left + margin_right, margin_top + margin_bottom));
1838 }
1839 
config_value_editors(int p_amount,int p_columns,int p_label_w,const List<String> & p_strings)1840 void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings) {
1841 
1842 	int cell_width = 95;
1843 	int cell_height = 25;
1844 	int cell_margin = 5;
1845 	int hor_spacing = 5; // Spacing between labels and their values
1846 
1847 	int rows = ((p_amount - 1) / p_columns) + 1;
1848 
1849 	set_size(Size2(cell_margin + p_label_w + (cell_width + cell_margin + p_label_w) * p_columns, cell_margin + (cell_height + cell_margin) * rows) * EDSCALE);
1850 
1851 	for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
1852 
1853 		int c = i % p_columns;
1854 		int r = i / p_columns;
1855 
1856 		if (i < p_amount) {
1857 			value_editor[i]->show();
1858 			value_label[i]->show();
1859 			value_label[i]->set_text(i < p_strings.size() ? p_strings[i] : String(""));
1860 			value_editor[i]->set_position(Point2(cell_margin + p_label_w + hor_spacing + (cell_width + cell_margin + p_label_w + hor_spacing) * c, cell_margin + (cell_height + cell_margin) * r) * EDSCALE);
1861 			value_editor[i]->set_size(Size2(cell_width, cell_height));
1862 			value_label[i]->set_position(Point2(cell_margin + (cell_width + cell_margin + p_label_w + hor_spacing) * c, cell_margin + (cell_height + cell_margin) * r) * EDSCALE);
1863 			value_editor[i]->set_editable(!read_only);
1864 		} else {
1865 			value_editor[i]->hide();
1866 			value_label[i]->hide();
1867 		}
1868 	}
1869 }
1870 
_bind_methods()1871 void CustomPropertyEditor::_bind_methods() {
1872 
1873 	ClassDB::bind_method("_focus_enter", &CustomPropertyEditor::_focus_enter);
1874 	ClassDB::bind_method("_focus_exit", &CustomPropertyEditor::_focus_exit);
1875 	ClassDB::bind_method("_modified", &CustomPropertyEditor::_modified);
1876 	ClassDB::bind_method("_range_modified", &CustomPropertyEditor::_range_modified);
1877 	ClassDB::bind_method("_action_pressed", &CustomPropertyEditor::_action_pressed);
1878 	ClassDB::bind_method("_file_selected", &CustomPropertyEditor::_file_selected);
1879 	ClassDB::bind_method("_type_create_selected", &CustomPropertyEditor::_type_create_selected);
1880 	ClassDB::bind_method("_node_path_selected", &CustomPropertyEditor::_node_path_selected);
1881 	ClassDB::bind_method("_color_changed", &CustomPropertyEditor::_color_changed);
1882 	ClassDB::bind_method("_draw_easing", &CustomPropertyEditor::_draw_easing);
1883 	ClassDB::bind_method("_drag_easing", &CustomPropertyEditor::_drag_easing);
1884 	ClassDB::bind_method("_text_edit_changed", &CustomPropertyEditor::_text_edit_changed);
1885 	ClassDB::bind_method("_menu_option", &CustomPropertyEditor::_menu_option);
1886 	ClassDB::bind_method("_create_dialog_callback", &CustomPropertyEditor::_create_dialog_callback);
1887 	ClassDB::bind_method("_create_selected_property", &CustomPropertyEditor::_create_selected_property);
1888 
1889 	ADD_SIGNAL(MethodInfo("variant_changed"));
1890 	ADD_SIGNAL(MethodInfo("variant_field_changed", PropertyInfo(Variant::STRING, "field")));
1891 	ADD_SIGNAL(MethodInfo("resource_edit_request"));
1892 }
1893 
CustomPropertyEditor()1894 CustomPropertyEditor::CustomPropertyEditor() {
1895 
1896 	read_only = false;
1897 	updating = false;
1898 
1899 	for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
1900 
1901 		value_editor[i] = memnew(LineEdit);
1902 		add_child(value_editor[i]);
1903 		value_label[i] = memnew(Label);
1904 		add_child(value_label[i]);
1905 		value_editor[i]->hide();
1906 		value_label[i]->hide();
1907 		value_editor[i]->connect("text_entered", this, "_modified");
1908 		value_editor[i]->connect("focus_entered", this, "_focus_enter");
1909 		value_editor[i]->connect("focus_exited", this, "_focus_exit");
1910 	}
1911 	focused_value_editor = -1;
1912 
1913 	for (int i = 0; i < 4; i++) {
1914 
1915 		scroll[i] = memnew(HScrollBar);
1916 		scroll[i]->hide();
1917 		scroll[i]->set_min(0);
1918 		scroll[i]->set_max(1.0);
1919 		scroll[i]->set_step(0.01);
1920 		add_child(scroll[i]);
1921 	}
1922 
1923 	checks20gc = memnew(GridContainer);
1924 	add_child(checks20gc);
1925 	checks20gc->set_columns(11);
1926 
1927 	for (int i = 0; i < 20; i++) {
1928 		if (i == 5 || i == 15) {
1929 			Control *space = memnew(Control);
1930 			space->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
1931 			checks20gc->add_child(space);
1932 		}
1933 
1934 		checks20[i] = memnew(CheckBox);
1935 		checks20[i]->set_toggle_mode(true);
1936 		checks20[i]->set_focus_mode(FOCUS_NONE);
1937 		checks20gc->add_child(checks20[i]);
1938 		checks20[i]->hide();
1939 		checks20[i]->connect("pressed", this, "_action_pressed", make_binds(i));
1940 		checks20[i]->set_tooltip(vformat(TTR("Bit %d, val %d."), i, 1 << i));
1941 	}
1942 
1943 	text_edit = memnew(TextEdit);
1944 	add_child(text_edit);
1945 	text_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5);
1946 	text_edit->set_margin(MARGIN_BOTTOM, -30);
1947 
1948 	text_edit->hide();
1949 	text_edit->connect("text_changed", this, "_text_edit_changed");
1950 
1951 	for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
1952 
1953 		action_buttons[i] = memnew(Button);
1954 		action_buttons[i]->hide();
1955 		add_child(action_buttons[i]);
1956 		Vector<Variant> binds;
1957 		binds.push_back(i);
1958 		action_buttons[i]->connect("pressed", this, "_action_pressed", binds);
1959 		action_buttons[i]->set_flat(true);
1960 	}
1961 
1962 	color_picker = NULL;
1963 
1964 	set_as_toplevel(true);
1965 	file = memnew(EditorFileDialog);
1966 	add_child(file);
1967 	file->hide();
1968 
1969 	file->connect("file_selected", this, "_file_selected");
1970 	file->connect("dir_selected", this, "_file_selected");
1971 
1972 	error = memnew(ConfirmationDialog);
1973 	error->set_title(TTR("Error!"));
1974 	add_child(error);
1975 
1976 	scene_tree = memnew(SceneTreeDialog);
1977 	add_child(scene_tree);
1978 	scene_tree->connect("selected", this, "_node_path_selected");
1979 	scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
1980 
1981 	texture_preview = memnew(TextureRect);
1982 	add_child(texture_preview);
1983 	texture_preview->hide();
1984 
1985 	easing_draw = memnew(Control);
1986 	add_child(easing_draw);
1987 	easing_draw->hide();
1988 	easing_draw->connect("draw", this, "_draw_easing");
1989 	easing_draw->connect("gui_input", this, "_drag_easing");
1990 	easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE);
1991 
1992 	type_button = memnew(MenuButton);
1993 	add_child(type_button);
1994 	type_button->hide();
1995 	type_button->get_popup()->connect("id_pressed", this, "_type_create_selected");
1996 
1997 	menu = memnew(PopupMenu);
1998 	menu->set_pass_on_modal_close_click(false);
1999 	add_child(menu);
2000 	menu->connect("id_pressed", this, "_menu_option");
2001 
2002 	evaluator = NULL;
2003 
2004 	spinbox = memnew(SpinBox);
2005 	add_child(spinbox);
2006 	spinbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5);
2007 	spinbox->connect("value_changed", this, "_range_modified");
2008 
2009 	slider = memnew(HSlider);
2010 	add_child(slider);
2011 	slider->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5);
2012 	slider->connect("value_changed", this, "_range_modified");
2013 
2014 	create_dialog = NULL;
2015 	property_select = NULL;
2016 }
2017