1 /*************************************************************************/
2 /*  visual_script_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 "visual_script_editor.h"
32 
33 #include "core/object.h"
34 #include "core/os/input.h"
35 #include "core/os/keyboard.h"
36 #include "core/script_language.h"
37 #include "core/variant.h"
38 #include "editor/editor_node.h"
39 #include "editor/editor_resource_preview.h"
40 #include "editor/editor_scale.h"
41 #include "scene/main/viewport.h"
42 #include "visual_script_expression.h"
43 #include "visual_script_flow_control.h"
44 #include "visual_script_func_nodes.h"
45 #include "visual_script_nodes.h"
46 
47 #ifdef TOOLS_ENABLED
48 class VisualScriptEditorSignalEdit : public Object {
49 
50 	GDCLASS(VisualScriptEditorSignalEdit, Object);
51 
52 	StringName sig;
53 
54 public:
55 	UndoRedo *undo_redo;
56 	Ref<VisualScript> script;
57 
58 protected:
_bind_methods()59 	static void _bind_methods() {
60 		ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed);
61 		ADD_SIGNAL(MethodInfo("changed"));
62 	}
63 
_sig_changed()64 	void _sig_changed() {
65 
66 		_change_notify();
67 		emit_signal("changed");
68 	}
69 
_set(const StringName & p_name,const Variant & p_value)70 	bool _set(const StringName &p_name, const Variant &p_value) {
71 
72 		if (sig == StringName())
73 			return false;
74 
75 		if (p_name == "argument_count") {
76 
77 			int new_argc = p_value;
78 			int argc = script->custom_signal_get_argument_count(sig);
79 			if (argc == new_argc)
80 				return true;
81 
82 			undo_redo->create_action(TTR("Change Signal Arguments"));
83 
84 			if (new_argc < argc) {
85 				for (int i = new_argc; i < argc; i++) {
86 					undo_redo->add_do_method(script.ptr(), "custom_signal_remove_argument", sig, new_argc);
87 					undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", sig, script->custom_signal_get_argument_name(sig, i), script->custom_signal_get_argument_type(sig, i), -1);
88 				}
89 			} else if (new_argc > argc) {
90 
91 				for (int i = argc; i < new_argc; i++) {
92 
93 					undo_redo->add_do_method(script.ptr(), "custom_signal_add_argument", sig, Variant::NIL, "arg" + itos(i + 1), -1);
94 					undo_redo->add_undo_method(script.ptr(), "custom_signal_remove_argument", sig, argc);
95 				}
96 			}
97 
98 			undo_redo->add_do_method(this, "_sig_changed");
99 			undo_redo->add_undo_method(this, "_sig_changed");
100 
101 			undo_redo->commit_action();
102 
103 			return true;
104 		}
105 		if (String(p_name).begins_with("argument/")) {
106 			int idx = String(p_name).get_slice("/", 1).to_int() - 1;
107 			ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);
108 			String what = String(p_name).get_slice("/", 2);
109 			if (what == "type") {
110 
111 				int old_type = script->custom_signal_get_argument_type(sig, idx);
112 				int new_type = p_value;
113 				undo_redo->create_action(TTR("Change Argument Type"));
114 				undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, new_type);
115 				undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, old_type);
116 				undo_redo->commit_action();
117 
118 				return true;
119 			}
120 
121 			if (what == "name") {
122 
123 				String old_name = script->custom_signal_get_argument_name(sig, idx);
124 				String new_name = p_value;
125 				undo_redo->create_action(TTR("Change Argument name"));
126 				undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, new_name);
127 				undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, old_name);
128 				undo_redo->commit_action();
129 				return true;
130 			}
131 		}
132 
133 		return false;
134 	}
135 
_get(const StringName & p_name,Variant & r_ret) const136 	bool _get(const StringName &p_name, Variant &r_ret) const {
137 
138 		if (sig == StringName())
139 			return false;
140 
141 		if (p_name == "argument_count") {
142 			r_ret = script->custom_signal_get_argument_count(sig);
143 			return true;
144 		}
145 		if (String(p_name).begins_with("argument/")) {
146 			int idx = String(p_name).get_slice("/", 1).to_int() - 1;
147 			ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);
148 			String what = String(p_name).get_slice("/", 2);
149 			if (what == "type") {
150 				r_ret = script->custom_signal_get_argument_type(sig, idx);
151 				return true;
152 			}
153 			if (what == "name") {
154 				r_ret = script->custom_signal_get_argument_name(sig, idx);
155 				return true;
156 			}
157 		}
158 
159 		return false;
160 	}
_get_property_list(List<PropertyInfo> * p_list) const161 	void _get_property_list(List<PropertyInfo> *p_list) const {
162 
163 		if (sig == StringName())
164 			return;
165 
166 		p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256"));
167 		String argt = "Variant";
168 		for (int i = 1; i < Variant::VARIANT_MAX; i++) {
169 			argt += "," + Variant::get_type_name(Variant::Type(i));
170 		}
171 
172 		for (int i = 0; i < script->custom_signal_get_argument_count(sig); i++) {
173 			p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
174 			p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name"));
175 		}
176 	}
177 
178 public:
edit(const StringName & p_sig)179 	void edit(const StringName &p_sig) {
180 
181 		sig = p_sig;
182 		_change_notify();
183 	}
184 
VisualScriptEditorSignalEdit()185 	VisualScriptEditorSignalEdit() { undo_redo = NULL; }
186 };
187 
188 class VisualScriptEditorVariableEdit : public Object {
189 
190 	GDCLASS(VisualScriptEditorVariableEdit, Object);
191 
192 	StringName var;
193 
194 public:
195 	UndoRedo *undo_redo;
196 	Ref<VisualScript> script;
197 
198 protected:
_bind_methods()199 	static void _bind_methods() {
200 		ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed);
201 		ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed);
202 		ADD_SIGNAL(MethodInfo("changed"));
203 	}
204 
_var_changed()205 	void _var_changed() {
206 
207 		_change_notify();
208 		emit_signal("changed");
209 	}
_var_value_changed()210 	void _var_value_changed() {
211 
212 		_change_notify("value"); //so the whole tree is not redrawn, makes editing smoother in general
213 		emit_signal("changed");
214 	}
215 
_set(const StringName & p_name,const Variant & p_value)216 	bool _set(const StringName &p_name, const Variant &p_value) {
217 
218 		if (var == StringName())
219 			return false;
220 
221 		if (String(p_name) == "value") {
222 			undo_redo->create_action(TTR("Set Variable Default Value"));
223 			Variant current = script->get_variable_default_value(var);
224 			undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, p_value);
225 			undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, current);
226 			undo_redo->add_do_method(this, "_var_value_changed");
227 			undo_redo->add_undo_method(this, "_var_value_changed");
228 			undo_redo->commit_action();
229 			return true;
230 		}
231 
232 		Dictionary d = script->call("get_variable_info", var);
233 
234 		if (String(p_name) == "type") {
235 
236 			Dictionary dc = d.duplicate();
237 			dc["type"] = p_value;
238 			undo_redo->create_action(TTR("Set Variable Type"));
239 			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
240 			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
241 			undo_redo->add_do_method(this, "_var_changed");
242 			undo_redo->add_undo_method(this, "_var_changed");
243 			undo_redo->commit_action();
244 			return true;
245 		}
246 
247 		if (String(p_name) == "hint") {
248 
249 			Dictionary dc = d.duplicate();
250 			dc["hint"] = p_value;
251 			undo_redo->create_action(TTR("Set Variable Type"));
252 			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
253 			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
254 			undo_redo->add_do_method(this, "_var_changed");
255 			undo_redo->add_undo_method(this, "_var_changed");
256 			undo_redo->commit_action();
257 			return true;
258 		}
259 
260 		if (String(p_name) == "hint_string") {
261 
262 			Dictionary dc = d.duplicate();
263 			dc["hint_string"] = p_value;
264 			undo_redo->create_action(TTR("Set Variable Type"));
265 			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
266 			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
267 			undo_redo->add_do_method(this, "_var_changed");
268 			undo_redo->add_undo_method(this, "_var_changed");
269 			undo_redo->commit_action();
270 			return true;
271 		}
272 
273 		if (String(p_name) == "export") {
274 			script->set_variable_export(var, p_value);
275 			EditorNode::get_singleton()->get_inspector()->update_tree();
276 			return true;
277 		}
278 
279 		return false;
280 	}
281 
_get(const StringName & p_name,Variant & r_ret) const282 	bool _get(const StringName &p_name, Variant &r_ret) const {
283 
284 		if (var == StringName())
285 			return false;
286 
287 		if (String(p_name) == "value") {
288 			r_ret = script->get_variable_default_value(var);
289 			return true;
290 		}
291 
292 		PropertyInfo pinfo = script->get_variable_info(var);
293 
294 		if (String(p_name) == "type") {
295 			r_ret = pinfo.type;
296 			return true;
297 		}
298 		if (String(p_name) == "hint") {
299 			r_ret = pinfo.hint;
300 			return true;
301 		}
302 		if (String(p_name) == "hint_string") {
303 			r_ret = pinfo.hint_string;
304 			return true;
305 		}
306 
307 		if (String(p_name) == "export") {
308 			r_ret = script->get_variable_export(var);
309 			return true;
310 		}
311 
312 		return false;
313 	}
_get_property_list(List<PropertyInfo> * p_list) const314 	void _get_property_list(List<PropertyInfo> *p_list) const {
315 
316 		if (var == StringName())
317 			return;
318 
319 		String argt = "Variant";
320 		for (int i = 1; i < Variant::VARIANT_MAX; i++) {
321 			argt += "," + Variant::get_type_name(Variant::Type(i));
322 		}
323 		p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt));
324 		p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT));
325 		// Update this when PropertyHint changes
326 		p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,PlaceholderText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig,NodePathValidTypes"));
327 		p_list->push_back(PropertyInfo(Variant::STRING, "hint_string"));
328 		p_list->push_back(PropertyInfo(Variant::BOOL, "export"));
329 	}
330 
331 public:
edit(const StringName & p_var)332 	void edit(const StringName &p_var) {
333 
334 		var = p_var;
335 		_change_notify();
336 	}
337 
VisualScriptEditorVariableEdit()338 	VisualScriptEditorVariableEdit() { undo_redo = NULL; }
339 };
340 
_color_from_type(Variant::Type p_type,bool dark_theme=true)341 static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
342 	Color color;
343 	if (dark_theme)
344 		switch (p_type) {
345 			case Variant::NIL: color = Color(0.41, 0.93, 0.74); break;
346 
347 			case Variant::BOOL: color = Color(0.55, 0.65, 0.94); break;
348 			case Variant::INT: color = Color(0.49, 0.78, 0.94); break;
349 			case Variant::REAL: color = Color(0.38, 0.85, 0.96); break;
350 			case Variant::STRING: color = Color(0.42, 0.65, 0.93); break;
351 
352 			case Variant::VECTOR2: color = Color(0.74, 0.57, 0.95); break;
353 			case Variant::RECT2: color = Color(0.95, 0.57, 0.65); break;
354 			case Variant::VECTOR3: color = Color(0.84, 0.49, 0.93); break;
355 			case Variant::TRANSFORM2D: color = Color(0.77, 0.93, 0.41); break;
356 			case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
357 			case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
358 			case Variant::AABB: color = Color(0.93, 0.47, 0.57); break;
359 			case Variant::BASIS: color = Color(0.89, 0.93, 0.41); break;
360 			case Variant::TRANSFORM: color = Color(0.96, 0.66, 0.43); break;
361 
362 			case Variant::COLOR: color = Color(0.62, 1.0, 0.44); break;
363 			case Variant::NODE_PATH: color = Color(0.41, 0.58, 0.93); break;
364 			case Variant::_RID: color = Color(0.41, 0.93, 0.6); break;
365 			case Variant::OBJECT: color = Color(0.47, 0.95, 0.91); break;
366 			case Variant::DICTIONARY: color = Color(0.47, 0.93, 0.69); break;
367 
368 			case Variant::ARRAY: color = Color(0.88, 0.88, 0.88); break;
369 			case Variant::POOL_BYTE_ARRAY: color = Color(0.67, 0.96, 0.78); break;
370 			case Variant::POOL_INT_ARRAY: color = Color(0.69, 0.86, 0.96); break;
371 			case Variant::POOL_REAL_ARRAY: color = Color(0.59, 0.91, 0.97); break;
372 			case Variant::POOL_STRING_ARRAY: color = Color(0.62, 0.77, 0.95); break;
373 			case Variant::POOL_VECTOR2_ARRAY: color = Color(0.82, 0.7, 0.96); break;
374 			case Variant::POOL_VECTOR3_ARRAY: color = Color(0.87, 0.61, 0.95); break;
375 			case Variant::POOL_COLOR_ARRAY: color = Color(0.91, 1.0, 0.59); break;
376 
377 			default:
378 				color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7);
379 		}
380 	else
381 		switch (p_type) {
382 			case Variant::NIL: color = Color(0.15, 0.89, 0.63); break;
383 
384 			case Variant::BOOL: color = Color(0.43, 0.56, 0.92); break;
385 			case Variant::INT: color = Color(0.31, 0.7, 0.91); break;
386 			case Variant::REAL: color = Color(0.15, 0.8, 0.94); break;
387 			case Variant::STRING: color = Color(0.27, 0.56, 0.91); break;
388 
389 			case Variant::VECTOR2: color = Color(0.68, 0.46, 0.93); break;
390 			case Variant::RECT2: color = Color(0.93, 0.46, 0.56); break;
391 			case Variant::VECTOR3: color = Color(0.86, 0.42, 0.93); break;
392 			case Variant::TRANSFORM2D: color = Color(0.59, 0.81, 0.1); break;
393 			case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break;
394 			case Variant::QUAT: color = Color(0.93, 0.41, 0.64); break;
395 			case Variant::AABB: color = Color(0.93, 0.47, 0.57); break;
396 			case Variant::BASIS: color = Color(0.7, 0.73, 0.1); break;
397 			case Variant::TRANSFORM: color = Color(0.96, 0.56, 0.28); break;
398 
399 			case Variant::COLOR: color = Color(0.24, 0.75, 0.0); break;
400 			case Variant::NODE_PATH: color = Color(0.41, 0.58, 0.93); break;
401 			case Variant::_RID: color = Color(0.17, 0.9, 0.45); break;
402 			case Variant::OBJECT: color = Color(0.07, 0.84, 0.76); break;
403 			case Variant::DICTIONARY: color = Color(0.34, 0.91, 0.62); break;
404 
405 			case Variant::ARRAY: color = Color(0.45, 0.45, 0.45); break;
406 			case Variant::POOL_BYTE_ARRAY: color = Color(0.38, 0.92, 0.6); break;
407 			case Variant::POOL_INT_ARRAY: color = Color(0.38, 0.73, 0.92); break;
408 			case Variant::POOL_REAL_ARRAY: color = Color(0.25, 0.83, 0.95); break;
409 			case Variant::POOL_STRING_ARRAY: color = Color(0.38, 0.62, 0.92); break;
410 			case Variant::POOL_VECTOR2_ARRAY: color = Color(0.62, 0.36, 0.92); break;
411 			case Variant::POOL_VECTOR3_ARRAY: color = Color(0.79, 0.35, 0.92); break;
412 			case Variant::POOL_COLOR_ARRAY: color = Color(0.57, 0.73, 0.0); break;
413 
414 			default:
415 				color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3);
416 		}
417 
418 	return color;
419 }
420 
_update_graph_connections()421 void VisualScriptEditor::_update_graph_connections() {
422 
423 	graph->clear_connections();
424 
425 	List<StringName> funcs;
426 	script->get_function_list(&funcs);
427 
428 	if (funcs.size() <= 0) {
429 		updating_graph = false;
430 		return;
431 	}
432 
433 	for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) {
434 
435 		List<VisualScript::SequenceConnection> sequence_conns;
436 		script->get_sequence_connection_list(F->get(), &sequence_conns);
437 
438 		for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
439 
440 			graph->connect_node(itos(E->get().from_node), E->get().from_output, itos(E->get().to_node), 0);
441 		}
442 
443 		List<VisualScript::DataConnection> data_conns;
444 		script->get_data_connection_list(F->get(), &data_conns);
445 
446 		for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
447 
448 			VisualScript::DataConnection dc = E->get();
449 
450 			Ref<VisualScriptNode> from_node = script->get_node(F->get(), E->get().from_node);
451 			Ref<VisualScriptNode> to_node = script->get_node(F->get(), E->get().to_node);
452 
453 			if (to_node->has_input_sequence_port()) {
454 				dc.to_port++;
455 			}
456 
457 			dc.from_port += from_node->get_output_sequence_port_count();
458 
459 			graph->connect_node(itos(E->get().from_node), dc.from_port, itos(E->get().to_node), dc.to_port);
460 		}
461 	}
462 }
463 
_update_graph(int p_only_id)464 void VisualScriptEditor::_update_graph(int p_only_id) {
465 
466 	if (updating_graph)
467 		return;
468 
469 	updating_graph = true;
470 
471 	//byebye all nodes
472 	if (p_only_id >= 0) {
473 		if (graph->has_node(itos(p_only_id))) {
474 			Node *gid = graph->get_node(itos(p_only_id));
475 			if (gid)
476 				memdelete(gid);
477 		}
478 	} else {
479 
480 		for (int i = 0; i < graph->get_child_count(); i++) {
481 
482 			if (Object::cast_to<GraphNode>(graph->get_child(i))) {
483 				memdelete(graph->get_child(i));
484 				i--;
485 			}
486 		}
487 	}
488 
489 	List<StringName> funcs;
490 	script->get_function_list(&funcs);
491 
492 	if (funcs.size() <= 0) {
493 		graph->hide();
494 		select_func_text->show();
495 		updating_graph = false;
496 		return;
497 	}
498 
499 	graph->show();
500 	select_func_text->hide();
501 
502 	Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
503 		Control::get_icon("Variant", "EditorIcons"),
504 		Control::get_icon("bool", "EditorIcons"),
505 		Control::get_icon("int", "EditorIcons"),
506 		Control::get_icon("float", "EditorIcons"),
507 		Control::get_icon("String", "EditorIcons"),
508 		Control::get_icon("Vector2", "EditorIcons"),
509 		Control::get_icon("Rect2", "EditorIcons"),
510 		Control::get_icon("Vector3", "EditorIcons"),
511 		Control::get_icon("Transform2D", "EditorIcons"),
512 		Control::get_icon("Plane", "EditorIcons"),
513 		Control::get_icon("Quat", "EditorIcons"),
514 		Control::get_icon("AABB", "EditorIcons"),
515 		Control::get_icon("Basis", "EditorIcons"),
516 		Control::get_icon("Transform", "EditorIcons"),
517 		Control::get_icon("Color", "EditorIcons"),
518 		Control::get_icon("NodePath", "EditorIcons"),
519 		Control::get_icon("RID", "EditorIcons"),
520 		Control::get_icon("MiniObject", "EditorIcons"),
521 		Control::get_icon("Dictionary", "EditorIcons"),
522 		Control::get_icon("Array", "EditorIcons"),
523 		Control::get_icon("PoolByteArray", "EditorIcons"),
524 		Control::get_icon("PoolIntArray", "EditorIcons"),
525 		Control::get_icon("PoolRealArray", "EditorIcons"),
526 		Control::get_icon("PoolStringArray", "EditorIcons"),
527 		Control::get_icon("PoolVector2Array", "EditorIcons"),
528 		Control::get_icon("PoolVector3Array", "EditorIcons"),
529 		Control::get_icon("PoolColorArray", "EditorIcons")
530 	};
531 
532 	Ref<Texture> seq_port = Control::get_icon("VisualShaderPort", "EditorIcons");
533 
534 	for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) { // loop through all the functions
535 
536 		List<int> ids;
537 		script->get_node_list(F->get(), &ids);
538 		StringName editor_icons = "EditorIcons";
539 
540 		for (List<int>::Element *E = ids.front(); E; E = E->next()) {
541 
542 			if (p_only_id >= 0 && p_only_id != E->get())
543 				continue;
544 
545 			Ref<VisualScriptNode> node = script->get_node(F->get(), E->get());
546 			Vector2 pos = script->get_node_position(F->get(), E->get());
547 
548 			GraphNode *gnode = memnew(GraphNode);
549 			gnode->set_title(node->get_caption());
550 			gnode->set_offset(pos * EDSCALE);
551 			if (error_line == E->get()) {
552 				gnode->set_overlay(GraphNode::OVERLAY_POSITION);
553 			} else if (node->is_breakpoint()) {
554 				gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
555 			}
556 
557 			gnode->set_meta("__vnode", node);
558 			gnode->set_name(itos(E->get()));
559 			gnode->connect("dragged", this, "_node_moved", varray(E->get()));
560 			gnode->connect("close_request", this, "_remove_node", varray(E->get()), CONNECT_DEFERRED);
561 
562 			if (E->get() != script->get_function_node_id(F->get())) {
563 				//function can't be erased
564 				gnode->set_show_close_button(true);
565 			}
566 
567 			bool has_gnode_text = false;
568 
569 			Ref<VisualScriptLists> nd_list = node;
570 			bool is_vslist = nd_list.is_valid();
571 			if (is_vslist) {
572 				HBoxContainer *hbnc = memnew(HBoxContainer);
573 				if (nd_list->is_input_port_editable()) {
574 					has_gnode_text = true;
575 					Button *btn = memnew(Button);
576 					btn->set_text(TTR("Add Input Port"));
577 					hbnc->add_child(btn);
578 					btn->connect("pressed", this, "_add_input_port", varray(E->get()), CONNECT_DEFERRED);
579 				}
580 				if (nd_list->is_output_port_editable()) {
581 					if (nd_list->is_input_port_editable())
582 						hbnc->add_spacer();
583 					has_gnode_text = true;
584 					Button *btn = memnew(Button);
585 					btn->set_text(TTR("Add Output Port"));
586 					hbnc->add_child(btn);
587 					btn->connect("pressed", this, "_add_output_port", varray(E->get()), CONNECT_DEFERRED);
588 				}
589 				gnode->add_child(hbnc);
590 			} else if (Object::cast_to<VisualScriptExpression>(node.ptr())) {
591 				has_gnode_text = true;
592 				LineEdit *line_edit = memnew(LineEdit);
593 				line_edit->set_text(node->get_text());
594 				line_edit->set_expand_to_text_length(true);
595 				line_edit->add_font_override("font", get_font("source", "EditorFonts"));
596 				gnode->add_child(line_edit);
597 				line_edit->connect("text_changed", this, "_expression_text_changed", varray(E->get()));
598 			} else {
599 				String text = node->get_text();
600 				if (!text.empty()) {
601 					has_gnode_text = true;
602 					Label *label = memnew(Label);
603 					label->set_text(text);
604 					gnode->add_child(label);
605 				}
606 			}
607 
608 			if (Object::cast_to<VisualScriptComment>(node.ptr())) {
609 				Ref<VisualScriptComment> vsc = node;
610 				gnode->set_comment(true);
611 				gnode->set_resizable(true);
612 				gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE);
613 				gnode->connect("resize_request", this, "_comment_node_resized", varray(E->get()));
614 			}
615 
616 			if (node_styles.has(node->get_category())) {
617 				Ref<StyleBoxFlat> sbf = node_styles[node->get_category()];
618 				if (gnode->is_comment())
619 					sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox("comment", "GraphNode");
620 
621 				Color c = sbf->get_border_color();
622 				c.a = 1;
623 				if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
624 					Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
625 					mono_color.a = 0.85;
626 					c = mono_color;
627 				}
628 				gnode->add_color_override("title_color", c);
629 				c.a = 0.7;
630 				gnode->add_color_override("close_color", c);
631 				gnode->add_color_override("resizer_color", c);
632 				gnode->add_style_override("frame", sbf);
633 			}
634 
635 			const Color mono_color = get_color("mono_color", "Editor");
636 
637 			int slot_idx = 0;
638 
639 			bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();
640 			if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) {
641 				// IF has_gnode_text is true BUT we have no sequence ports to draw (in here),
642 				// we still draw the disabled default ones to shift up the slots by one,
643 				// so the slots DON'T start with the content text.
644 
645 				// IF has_gnode_text is false, but we DO want to draw default sequence ports,
646 				// we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly.
647 				if (!has_gnode_text) {
648 					Label *dummy = memnew(Label);
649 					dummy->set_text(" ");
650 					gnode->add_child(dummy);
651 				}
652 				gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
653 				slot_idx++;
654 			}
655 
656 			int mixed_seq_ports = 0;
657 
658 			if (!single_seq_output) {
659 
660 				if (node->has_mixed_input_and_sequence_ports()) {
661 					mixed_seq_ports = node->get_output_sequence_port_count();
662 				} else {
663 					for (int i = 0; i < node->get_output_sequence_port_count(); i++) {
664 
665 						Label *text2 = memnew(Label);
666 						text2->set_text(node->get_output_sequence_port_text(i));
667 						text2->set_align(Label::ALIGN_RIGHT);
668 						gnode->add_child(text2);
669 						gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
670 						slot_idx++;
671 					}
672 				}
673 			}
674 
675 			for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) {
676 
677 				bool left_ok = false;
678 				Variant::Type left_type = Variant::NIL;
679 				String left_name;
680 
681 				if (i < node->get_input_value_port_count()) {
682 					PropertyInfo pi = node->get_input_value_port_info(i);
683 					left_ok = true;
684 					left_type = pi.type;
685 					left_name = pi.name;
686 				}
687 
688 				bool right_ok = false;
689 				Variant::Type right_type = Variant::NIL;
690 				String right_name;
691 
692 				if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) {
693 					PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports);
694 					right_ok = true;
695 					right_type = pi.type;
696 					right_name = pi.name;
697 				}
698 				VBoxContainer *vbc = memnew(VBoxContainer);
699 				HBoxContainer *hbc = memnew(HBoxContainer);
700 				HBoxContainer *hbc2 = memnew(HBoxContainer);
701 				vbc->add_child(hbc);
702 				vbc->add_child(hbc2);
703 				if (left_ok) {
704 
705 					Ref<Texture> t;
706 					if (left_type >= 0 && left_type < Variant::VARIANT_MAX) {
707 						t = type_icons[left_type];
708 					}
709 					if (t.is_valid()) {
710 						TextureRect *tf = memnew(TextureRect);
711 						tf->set_texture(t);
712 						tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
713 						hbc->add_child(tf);
714 					}
715 
716 					if (is_vslist) {
717 						if (nd_list->is_input_port_name_editable()) {
718 							LineEdit *name_box = memnew(LineEdit);
719 							hbc->add_child(name_box);
720 							name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
721 							name_box->set_text(left_name);
722 							name_box->set_expand_to_text_length(true);
723 							name_box->connect("resized", this, "_update_node_size", varray(E->get()));
724 							name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, E->get(), i, true));
725 						} else {
726 							hbc->add_child(memnew(Label(left_name)));
727 						}
728 
729 						if (nd_list->is_input_port_type_editable()) {
730 							OptionButton *opbtn = memnew(OptionButton);
731 							for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
732 								opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
733 							}
734 							opbtn->select(left_type);
735 							opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
736 							hbc->add_child(opbtn);
737 							opbtn->connect("item_selected", this, "_change_port_type", varray(E->get(), i, true), CONNECT_DEFERRED);
738 						}
739 
740 						Button *rmbtn = memnew(Button);
741 						rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
742 						hbc->add_child(rmbtn);
743 						rmbtn->connect("pressed", this, "_remove_input_port", varray(E->get(), i), CONNECT_DEFERRED);
744 					} else {
745 						hbc->add_child(memnew(Label(left_name)));
746 					}
747 
748 					if (left_type != Variant::NIL && !script->is_input_value_port_connected(F->get(), E->get(), i)) {
749 
750 						PropertyInfo pi = node->get_input_value_port_info(i);
751 						Button *button = memnew(Button);
752 						Variant value = node->get_default_input_value(i);
753 						if (value.get_type() != left_type) {
754 							//different type? for now convert
755 							//not the same, reconvert
756 							Variant::CallError ce;
757 							const Variant *existingp = &value;
758 							value = Variant::construct(left_type, &existingp, 1, ce, false);
759 						}
760 
761 						if (left_type == Variant::COLOR) {
762 							button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
763 							button->connect("draw", this, "_draw_color_over_button", varray(button, value));
764 						} else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) {
765 
766 							Ref<Resource> res = value;
767 							Array arr;
768 							arr.push_back(button->get_instance_id());
769 							arr.push_back(String(value));
770 							EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
771 
772 						} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
773 
774 							button->set_text(pi.hint_string.get_slice(",", value));
775 						} else {
776 
777 							button->set_text(value);
778 						}
779 						button->connect("pressed", this, "_default_value_edited", varray(button, E->get(), i));
780 						hbc2->add_child(button);
781 					}
782 				} else {
783 					Control *c = memnew(Control);
784 					c->set_custom_minimum_size(Size2(10, 0) * EDSCALE);
785 					hbc->add_child(c);
786 				}
787 
788 				hbc->add_spacer();
789 				hbc2->add_spacer();
790 
791 				if (i < mixed_seq_ports) {
792 
793 					Label *text2 = memnew(Label);
794 					text2->set_text(node->get_output_sequence_port_text(i));
795 					text2->set_align(Label::ALIGN_RIGHT);
796 					hbc->add_child(text2);
797 				}
798 
799 				if (right_ok) {
800 
801 					if (is_vslist) {
802 						Button *rmbtn = memnew(Button);
803 						rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
804 						hbc->add_child(rmbtn);
805 						rmbtn->connect("pressed", this, "_remove_output_port", varray(E->get(), i), CONNECT_DEFERRED);
806 
807 						if (nd_list->is_output_port_type_editable()) {
808 							OptionButton *opbtn = memnew(OptionButton);
809 							for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
810 								opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
811 							}
812 							opbtn->select(right_type);
813 							opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
814 							hbc->add_child(opbtn);
815 							opbtn->connect("item_selected", this, "_change_port_type", varray(E->get(), i, false), CONNECT_DEFERRED);
816 						}
817 
818 						if (nd_list->is_output_port_name_editable()) {
819 							LineEdit *name_box = memnew(LineEdit);
820 							hbc->add_child(name_box);
821 							name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
822 							name_box->set_text(right_name);
823 							name_box->set_expand_to_text_length(true);
824 							name_box->connect("resized", this, "_update_node_size", varray(E->get()));
825 							name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, E->get(), i, false));
826 						} else {
827 							hbc->add_child(memnew(Label(right_name)));
828 						}
829 					} else {
830 						hbc->add_child(memnew(Label(right_name)));
831 					}
832 
833 					Ref<Texture> t;
834 					if (right_type >= 0 && right_type < Variant::VARIANT_MAX) {
835 						t = type_icons[right_type];
836 					}
837 					if (t.is_valid()) {
838 						TextureRect *tf = memnew(TextureRect);
839 						tf->set_texture(t);
840 						tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
841 						hbc->add_child(tf);
842 					}
843 				}
844 
845 				gnode->add_child(vbc);
846 
847 				bool dark_theme = get_constant("dark_theme", "Editor");
848 				if (i < mixed_seq_ports) {
849 					gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture>(), seq_port);
850 				} else {
851 					gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme));
852 				}
853 
854 				slot_idx++;
855 			}
856 
857 			graph->add_child(gnode);
858 
859 			if (gnode->is_comment()) {
860 				graph->move_child(gnode, 0);
861 			}
862 		}
863 	}
864 	_update_graph_connections();
865 	// use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything
866 	graph->call_deferred("set_scroll_ofs", script->get_function_scroll(default_func) * EDSCALE);
867 	updating_graph = false;
868 }
869 
_change_port_type(int p_select,int p_id,int p_port,bool is_input)870 void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, bool is_input) {
871 
872 	StringName func = _get_function_of_node(p_id);
873 
874 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
875 	if (!vsn.is_valid())
876 		return;
877 
878 	undo_redo->create_action("Change Port Type");
879 	if (is_input) {
880 		undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_type", p_port, Variant::Type(p_select));
881 		undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_type", p_port, vsn->get_input_value_port_info(p_port).type);
882 	} else {
883 		undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_type", p_port, Variant::Type(p_select));
884 		undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_type", p_port, vsn->get_output_value_port_info(p_port).type);
885 	}
886 	undo_redo->commit_action();
887 }
888 
_update_node_size(int p_id)889 void VisualScriptEditor::_update_node_size(int p_id) {
890 
891 	Node *node = graph->get_node(itos(p_id));
892 	if (Object::cast_to<Control>(node))
893 		Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); //shrink if text is smaller
894 }
_port_name_focus_out(const Node * p_name_box,int p_id,int p_port,bool is_input)895 void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input) {
896 	StringName func = _get_function_of_node(p_id);
897 
898 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
899 	if (!vsn.is_valid())
900 		return;
901 
902 	String text;
903 
904 	if (Object::cast_to<LineEdit>(p_name_box))
905 		text = Object::cast_to<LineEdit>(p_name_box)->get_text();
906 	else
907 		return;
908 
909 	undo_redo->create_action("Change Port Name");
910 	if (is_input) {
911 		undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_name", p_port, text);
912 		undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_name", p_port, vsn->get_input_value_port_info(p_port).name);
913 	} else {
914 		undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_name", p_port, text);
915 		undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_name", p_port, vsn->get_output_value_port_info(p_port).name);
916 	}
917 	undo_redo->commit_action();
918 }
919 
_update_members()920 void VisualScriptEditor::_update_members() {
921 	ERR_FAIL_COND(!script.is_valid());
922 
923 	updating_members = true;
924 
925 	members->clear();
926 	TreeItem *root = members->create_item();
927 
928 	TreeItem *functions = members->create_item(root);
929 	functions->set_selectable(0, false);
930 	functions->set_text(0, TTR("Functions:"));
931 	functions->add_button(0, Control::get_icon("Override", "EditorIcons"), 1, false, TTR("Override an existing built-in function."));
932 	functions->add_button(0, Control::get_icon("Add", "EditorIcons"), 0, false, TTR("Create a new function."));
933 	functions->set_custom_color(0, Control::get_color("mono_color", "Editor"));
934 
935 	List<StringName> func_names;
936 	script->get_function_list(&func_names);
937 	for (List<StringName>::Element *E = func_names.front(); E; E = E->next()) {
938 
939 		if (E->get() == default_func) {
940 			continue;
941 		}
942 
943 		TreeItem *ti = members->create_item(functions);
944 		ti->set_text(0, E->get());
945 		ti->set_selectable(0, true);
946 		ti->set_metadata(0, E->get());
947 		ti->add_button(0, Control::get_icon("Edit", "EditorIcons"), 0);
948 		if (selected == E->get())
949 			ti->select(0);
950 	}
951 
952 	TreeItem *variables = members->create_item(root);
953 	variables->set_selectable(0, false);
954 	variables->set_text(0, TTR("Variables:"));
955 	variables->add_button(0, Control::get_icon("Add", "EditorIcons"), -1, false, TTR("Create a new variable."));
956 	variables->set_custom_color(0, Control::get_color("mono_color", "Editor"));
957 
958 	Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
959 		Control::get_icon("Variant", "EditorIcons"),
960 		Control::get_icon("bool", "EditorIcons"),
961 		Control::get_icon("int", "EditorIcons"),
962 		Control::get_icon("float", "EditorIcons"),
963 		Control::get_icon("String", "EditorIcons"),
964 		Control::get_icon("Vector2", "EditorIcons"),
965 		Control::get_icon("Rect2", "EditorIcons"),
966 		Control::get_icon("Vector3", "EditorIcons"),
967 		Control::get_icon("Transform2D", "EditorIcons"),
968 		Control::get_icon("Plane", "EditorIcons"),
969 		Control::get_icon("Quat", "EditorIcons"),
970 		Control::get_icon("AABB", "EditorIcons"),
971 		Control::get_icon("Basis", "EditorIcons"),
972 		Control::get_icon("Transform", "EditorIcons"),
973 		Control::get_icon("Color", "EditorIcons"),
974 		Control::get_icon("NodePath", "EditorIcons"),
975 		Control::get_icon("RID", "EditorIcons"),
976 		Control::get_icon("MiniObject", "EditorIcons"),
977 		Control::get_icon("Dictionary", "EditorIcons"),
978 		Control::get_icon("Array", "EditorIcons"),
979 		Control::get_icon("PoolByteArray", "EditorIcons"),
980 		Control::get_icon("PoolIntArray", "EditorIcons"),
981 		Control::get_icon("PoolRealArray", "EditorIcons"),
982 		Control::get_icon("PoolStringArray", "EditorIcons"),
983 		Control::get_icon("PoolVector2Array", "EditorIcons"),
984 		Control::get_icon("PoolVector3Array", "EditorIcons"),
985 		Control::get_icon("PoolColorArray", "EditorIcons")
986 	};
987 
988 	List<StringName> var_names;
989 	script->get_variable_list(&var_names);
990 	for (List<StringName>::Element *E = var_names.front(); E; E = E->next()) {
991 		TreeItem *ti = members->create_item(variables);
992 
993 		ti->set_text(0, E->get());
994 		Variant var = script->get_variable_default_value(E->get());
995 		ti->set_suffix(0, "= " + String(var));
996 		ti->set_icon(0, type_icons[script->get_variable_info(E->get()).type]);
997 
998 		ti->set_selectable(0, true);
999 		ti->set_editable(0, true);
1000 		ti->set_metadata(0, E->get());
1001 		if (selected == E->get())
1002 			ti->select(0);
1003 	}
1004 
1005 	TreeItem *_signals = members->create_item(root);
1006 	_signals->set_selectable(0, false);
1007 	_signals->set_text(0, TTR("Signals:"));
1008 	_signals->add_button(0, Control::get_icon("Add", "EditorIcons"), -1, false, TTR("Create a new signal."));
1009 	_signals->set_custom_color(0, Control::get_color("mono_color", "Editor"));
1010 
1011 	List<StringName> signal_names;
1012 	script->get_custom_signal_list(&signal_names);
1013 	for (List<StringName>::Element *E = signal_names.front(); E; E = E->next()) {
1014 		TreeItem *ti = members->create_item(_signals);
1015 		ti->set_text(0, E->get());
1016 		ti->set_selectable(0, true);
1017 		ti->set_editable(0, true);
1018 		ti->set_metadata(0, E->get());
1019 		if (selected == E->get())
1020 			ti->select(0);
1021 	}
1022 
1023 	String base_type = script->get_instance_base_type();
1024 	String icon_type = base_type;
1025 	if (!Control::has_icon(base_type, "EditorIcons")) {
1026 		icon_type = "Object";
1027 	}
1028 
1029 	base_type_select->set_text(base_type);
1030 	base_type_select->set_icon(Control::get_icon(icon_type, "EditorIcons"));
1031 
1032 	updating_members = false;
1033 }
1034 
_member_selected()1035 void VisualScriptEditor::_member_selected() {
1036 
1037 	if (updating_members)
1038 		return;
1039 
1040 	TreeItem *ti = members->get_selected();
1041 	ERR_FAIL_COND(!ti);
1042 
1043 	selected = ti->get_metadata(0);
1044 
1045 	if (ti->get_parent() == members->get_root()->get_children()) {
1046 
1047 #ifdef OSX_ENABLED
1048 		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);
1049 #else
1050 		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
1051 #endif
1052 		if (held_ctrl) {
1053 			ERR_FAIL_COND(!script->has_function(selected));
1054 			_center_on_node(selected, script->get_function_node_id(selected));
1055 		}
1056 	}
1057 }
1058 
_member_edited()1059 void VisualScriptEditor::_member_edited() {
1060 
1061 	if (updating_members)
1062 		return;
1063 
1064 	TreeItem *ti = members->get_edited();
1065 	ERR_FAIL_COND(!ti);
1066 
1067 	String name = ti->get_metadata(0);
1068 	String new_name = ti->get_text(0);
1069 
1070 	if (name == new_name)
1071 		return;
1072 
1073 	if (!new_name.is_valid_identifier()) {
1074 
1075 		EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);
1076 		updating_members = true;
1077 		ti->set_text(0, name);
1078 		updating_members = false;
1079 		return;
1080 	}
1081 
1082 	if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
1083 
1084 		EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);
1085 		updating_members = true;
1086 		ti->set_text(0, name);
1087 		updating_members = false;
1088 		return;
1089 	}
1090 
1091 	TreeItem *root = members->get_root();
1092 
1093 	if (ti->get_parent() == root->get_children()) {
1094 
1095 		selected = new_name;
1096 
1097 		int node_id = script->get_function_node_id(name);
1098 		Ref<VisualScriptFunction> func;
1099 		if (script->has_node(name, node_id)) {
1100 			func = script->get_node(name, node_id);
1101 		}
1102 		undo_redo->create_action(TTR("Rename Function"));
1103 		undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
1104 		undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);
1105 		if (func.is_valid()) {
1106 			undo_redo->add_do_method(func.ptr(), "set_name", new_name);
1107 			undo_redo->add_undo_method(func.ptr(), "set_name", name);
1108 		}
1109 
1110 		// also fix all function calls
1111 		List<StringName> flst;
1112 		script->get_function_list(&flst);
1113 		for (List<StringName>::Element *E = flst.front(); E; E = E->next()) {
1114 			List<int> lst;
1115 			script->get_node_list(E->get(), &lst);
1116 			for (List<int>::Element *F = lst.front(); F; F = F->next()) {
1117 				Ref<VisualScriptFunctionCall> fncall = script->get_node(E->get(), F->get());
1118 				if (!fncall.is_valid())
1119 					continue;
1120 				if (fncall->get_function() == name) {
1121 					undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
1122 					undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
1123 				}
1124 			}
1125 		}
1126 
1127 		undo_redo->add_do_method(this, "_update_members");
1128 		undo_redo->add_undo_method(this, "_update_members");
1129 		undo_redo->add_do_method(this, "_update_graph");
1130 		undo_redo->add_undo_method(this, "_update_graph");
1131 		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1132 		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1133 		undo_redo->commit_action();
1134 
1135 		return; //or crash because it will become invalid
1136 	}
1137 
1138 	if (ti->get_parent() == root->get_children()->get_next()) {
1139 
1140 		selected = new_name;
1141 		undo_redo->create_action(TTR("Rename Variable"));
1142 		undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
1143 		undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name);
1144 		undo_redo->add_do_method(this, "_update_members");
1145 		undo_redo->add_undo_method(this, "_update_members");
1146 		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1147 		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1148 		undo_redo->commit_action();
1149 
1150 		return; //or crash because it will become invalid
1151 	}
1152 
1153 	if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
1154 
1155 		selected = new_name;
1156 		undo_redo->create_action(TTR("Rename Signal"));
1157 		undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
1158 		undo_redo->add_undo_method(script.ptr(), "rename_custom_signal", new_name, name);
1159 		undo_redo->add_do_method(this, "_update_members");
1160 		undo_redo->add_undo_method(this, "_update_members");
1161 		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1162 		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1163 		undo_redo->commit_action();
1164 
1165 		return; //or crash because it will become invalid
1166 	}
1167 }
1168 
_create_function_dialog()1169 void VisualScriptEditor::_create_function_dialog() {
1170 	function_create_dialog->popup_centered();
1171 	func_name_box->set_text("");
1172 	func_name_box->grab_focus();
1173 	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
1174 		Node *nd = func_input_vbox->get_child(i);
1175 		nd->queue_delete();
1176 	}
1177 }
1178 
_create_function()1179 void VisualScriptEditor::_create_function() {
1180 	String name = _validate_name((func_name_box->get_text() == "") ? "new_func" : func_name_box->get_text());
1181 	selected = name;
1182 	Vector2 ofs = _get_available_pos();
1183 
1184 	Ref<VisualScriptFunction> func_node;
1185 	func_node.instance();
1186 	func_node->set_name(name);
1187 
1188 	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
1189 		OptionButton *opbtn = Object::cast_to<OptionButton>(func_input_vbox->get_child(i)->get_child(3));
1190 		LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));
1191 		if (!opbtn || !lne)
1192 			continue;
1193 		Variant::Type arg_type = Variant::Type(opbtn->get_selected());
1194 		String arg_name = lne->get_text();
1195 		func_node->add_argument(arg_type, arg_name);
1196 	}
1197 
1198 	undo_redo->create_action(TTR("Add Function"));
1199 	undo_redo->add_do_method(script.ptr(), "add_function", name);
1200 	undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
1201 	undo_redo->add_undo_method(script.ptr(), "remove_function", name);
1202 	undo_redo->add_do_method(this, "_update_members");
1203 	undo_redo->add_undo_method(this, "_update_members");
1204 	undo_redo->add_do_method(this, "_update_graph");
1205 	undo_redo->add_undo_method(this, "_update_graph");
1206 	undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1207 	undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1208 	undo_redo->commit_action();
1209 
1210 	_update_graph();
1211 }
1212 
_add_node_dialog()1213 void VisualScriptEditor::_add_node_dialog() {
1214 	_generic_search(script->get_instance_base_type(), graph->get_global_position() + Vector2(55, 80), true);
1215 }
1216 
_add_func_input()1217 void VisualScriptEditor::_add_func_input() {
1218 	HBoxContainer *hbox = memnew(HBoxContainer);
1219 	hbox->set_h_size_flags(SIZE_EXPAND_FILL);
1220 
1221 	Label *name_label = memnew(Label);
1222 	name_label->set_text(TTR("Name:"));
1223 	hbox->add_child(name_label);
1224 
1225 	LineEdit *name_box = memnew(LineEdit);
1226 	name_box->set_h_size_flags(SIZE_EXPAND_FILL);
1227 	name_box->set_text("input");
1228 	name_box->connect("focus_entered", this, "_deselect_input_names");
1229 	hbox->add_child(name_box);
1230 
1231 	Label *type_label = memnew(Label);
1232 	type_label->set_text(TTR("Type:"));
1233 	hbox->add_child(type_label);
1234 
1235 	OptionButton *type_box = memnew(OptionButton);
1236 	type_box->set_custom_minimum_size(Size2(120 * EDSCALE, 0));
1237 	for (int i = Variant::NIL; i < Variant::VARIANT_MAX; i++)
1238 		type_box->add_item(Variant::get_type_name(Variant::Type(i)));
1239 	type_box->select(1);
1240 	hbox->add_child(type_box);
1241 
1242 	Button *delete_button = memnew(Button);
1243 	delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
1244 	delete_button->set_tooltip(vformat(TTR("Delete input port")));
1245 	hbox->add_child(delete_button);
1246 
1247 	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
1248 		LineEdit *line_edit = (LineEdit *)func_input_vbox->get_child(i)->get_child(1);
1249 		line_edit->deselect();
1250 	}
1251 
1252 	func_input_vbox->add_child(hbox);
1253 	hbox->set_meta("id", hbox->get_position_in_parent());
1254 
1255 	delete_button->connect("pressed", this, "_remove_func_input", varray(hbox));
1256 
1257 	name_box->select_all();
1258 	name_box->grab_focus();
1259 }
1260 
_remove_func_input(Node * p_node)1261 void VisualScriptEditor::_remove_func_input(Node *p_node) {
1262 	func_input_vbox->remove_child(p_node);
1263 	p_node->queue_delete();
1264 }
1265 
_deselect_input_names()1266 void VisualScriptEditor::_deselect_input_names() {
1267 	int cn = func_input_vbox->get_child_count();
1268 	for (int i = 0; i < cn; i++) {
1269 		LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));
1270 		if (lne)
1271 			lne->deselect();
1272 	}
1273 }
1274 
_member_button(Object * p_item,int p_column,int p_button)1275 void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) {
1276 
1277 	TreeItem *ti = Object::cast_to<TreeItem>(p_item);
1278 
1279 	TreeItem *root = members->get_root();
1280 
1281 	if (ti->get_parent() == root) {
1282 		//main buttons
1283 		if (ti == root->get_children()) {
1284 			//add function, this one uses menu
1285 
1286 			if (p_button == 1) {
1287 				new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), String(), true);
1288 
1289 				return;
1290 			} else if (p_button == 0) {
1291 
1292 				String name = _validate_name("new_function");
1293 				selected = name;
1294 				Vector2 ofs = _get_available_pos();
1295 
1296 				Ref<VisualScriptFunction> func_node;
1297 				func_node.instance();
1298 				func_node->set_name(name);
1299 
1300 				undo_redo->create_action(TTR("Add Function"));
1301 				undo_redo->add_do_method(script.ptr(), "add_function", name);
1302 				undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
1303 				undo_redo->add_undo_method(script.ptr(), "remove_function", name);
1304 				undo_redo->add_do_method(this, "_update_members");
1305 				undo_redo->add_undo_method(this, "_update_members");
1306 				undo_redo->add_do_method(this, "_update_graph");
1307 				undo_redo->add_undo_method(this, "_update_graph");
1308 				undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1309 				undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1310 				undo_redo->commit_action();
1311 
1312 				_update_graph();
1313 			}
1314 
1315 			return; //or crash because it will become invalid
1316 		}
1317 
1318 		if (ti == root->get_children()->get_next()) {
1319 			//add variable
1320 			String name = _validate_name("new_variable");
1321 			selected = name;
1322 
1323 			undo_redo->create_action(TTR("Add Variable"));
1324 			undo_redo->add_do_method(script.ptr(), "add_variable", name);
1325 			undo_redo->add_undo_method(script.ptr(), "remove_variable", name);
1326 			undo_redo->add_do_method(this, "_update_members");
1327 			undo_redo->add_undo_method(this, "_update_members");
1328 			undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1329 			undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1330 			undo_redo->commit_action();
1331 			return; //or crash because it will become invalid
1332 		}
1333 
1334 		if (ti == root->get_children()->get_next()->get_next()) {
1335 			//add variable
1336 			String name = _validate_name("new_signal");
1337 			selected = name;
1338 
1339 			undo_redo->create_action(TTR("Add Signal"));
1340 			undo_redo->add_do_method(script.ptr(), "add_custom_signal", name);
1341 			undo_redo->add_undo_method(script.ptr(), "remove_custom_signal", name);
1342 			undo_redo->add_do_method(this, "_update_members");
1343 			undo_redo->add_undo_method(this, "_update_members");
1344 			undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1345 			undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1346 			undo_redo->commit_action();
1347 			return; //or crash because it will become invalid
1348 		}
1349 	} else if (ti->get_parent() == root->get_children()) {
1350 		selected = ti->get_text(0);
1351 		function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
1352 		function_name_edit->popup();
1353 		function_name_box->set_text(selected);
1354 		function_name_box->select_all();
1355 	}
1356 }
1357 
_add_input_port(int p_id)1358 void VisualScriptEditor::_add_input_port(int p_id) {
1359 
1360 	StringName func = _get_function_of_node(p_id);
1361 
1362 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
1363 	if (!vsn.is_valid())
1364 		return;
1365 
1366 	updating_graph = true;
1367 
1368 	undo_redo->create_action(TTR("Add Input Port"), UndoRedo::MERGE_ENDS);
1369 	undo_redo->add_do_method(vsn.ptr(), "add_input_data_port", Variant::NIL, "arg", -1);
1370 	undo_redo->add_do_method(this, "_update_graph", p_id);
1371 
1372 	undo_redo->add_undo_method(vsn.ptr(), "remove_input_data_port", vsn->get_input_value_port_count());
1373 	undo_redo->add_undo_method(this, "_update_graph", p_id);
1374 
1375 	updating_graph = false;
1376 
1377 	undo_redo->commit_action();
1378 }
1379 
_add_output_port(int p_id)1380 void VisualScriptEditor::_add_output_port(int p_id) {
1381 
1382 	StringName func = _get_function_of_node(p_id);
1383 
1384 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
1385 	if (!vsn.is_valid())
1386 		return;
1387 
1388 	updating_graph = true;
1389 
1390 	undo_redo->create_action(TTR("Add Output Port"), UndoRedo::MERGE_ENDS);
1391 	undo_redo->add_do_method(vsn.ptr(), "add_output_data_port", Variant::NIL, "arg", -1);
1392 	undo_redo->add_do_method(this, "_update_graph", p_id);
1393 
1394 	undo_redo->add_undo_method(vsn.ptr(), "remove_output_data_port", vsn->get_output_value_port_count());
1395 	undo_redo->add_undo_method(this, "_update_graph", p_id);
1396 
1397 	updating_graph = false;
1398 
1399 	undo_redo->commit_action();
1400 }
1401 
_remove_input_port(int p_id,int p_port)1402 void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {
1403 
1404 	StringName func = _get_function_of_node(p_id);
1405 
1406 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
1407 	if (!vsn.is_valid())
1408 		return;
1409 
1410 	updating_graph = true;
1411 
1412 	undo_redo->create_action(TTR("Remove Input Port"), UndoRedo::MERGE_ENDS);
1413 
1414 	int conn_from = -1, conn_port = -1;
1415 	script->get_input_value_port_connection_source(func, p_id, p_port, &conn_from, &conn_port);
1416 
1417 	if (conn_from != -1)
1418 		undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_id, p_port);
1419 
1420 	undo_redo->add_do_method(vsn.ptr(), "remove_input_data_port", p_port);
1421 	undo_redo->add_do_method(this, "_update_graph", p_id);
1422 
1423 	if (conn_from != -1)
1424 		undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_id, p_port);
1425 
1426 	undo_redo->add_undo_method(vsn.ptr(), "add_input_data_port", vsn->get_input_value_port_info(p_port).type, vsn->get_input_value_port_info(p_port).name, p_port);
1427 	undo_redo->add_undo_method(this, "_update_graph", p_id);
1428 
1429 	updating_graph = false;
1430 
1431 	undo_redo->commit_action();
1432 }
1433 
_remove_output_port(int p_id,int p_port)1434 void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
1435 
1436 	StringName func = _get_function_of_node(p_id);
1437 
1438 	Ref<VisualScriptLists> vsn = script->get_node(func, p_id);
1439 	if (!vsn.is_valid())
1440 		return;
1441 
1442 	updating_graph = true;
1443 
1444 	undo_redo->create_action(TTR("Remove Output Port"), UndoRedo::MERGE_ENDS);
1445 
1446 	List<VisualScript::DataConnection> data_connections;
1447 	script->get_data_connection_list(func, &data_connections);
1448 
1449 	HashMap<int, Set<int> > conn_map;
1450 	for (const List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
1451 		if (E->get().from_node == p_id && E->get().from_port == p_port) {
1452 			// push into the connections map
1453 			if (!conn_map.has(E->get().to_node))
1454 				conn_map.set(E->get().to_node, Set<int>());
1455 			conn_map[E->get().to_node].insert(E->get().to_port);
1456 		}
1457 	}
1458 
1459 	undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port);
1460 	undo_redo->add_do_method(this, "_update_graph", p_id);
1461 
1462 	List<int> keys;
1463 	conn_map.get_key_list(&keys);
1464 	for (const List<int>::Element *E = keys.front(); E; E = E->next()) {
1465 		for (const Set<int>::Element *F = conn_map[E->get()].front(); F; F = F->next()) {
1466 			undo_redo->add_undo_method(script.ptr(), "data_connect", func, p_id, p_port, E->get(), F->get());
1467 		}
1468 	}
1469 
1470 	undo_redo->add_undo_method(vsn.ptr(), "add_output_data_port", vsn->get_output_value_port_info(p_port).type, vsn->get_output_value_port_info(p_port).name, p_port);
1471 	undo_redo->add_undo_method(this, "_update_graph", p_id);
1472 
1473 	updating_graph = false;
1474 
1475 	undo_redo->commit_action();
1476 }
1477 
_expression_text_changed(const String & p_text,int p_id)1478 void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id) {
1479 
1480 	StringName func = _get_function_of_node(p_id);
1481 
1482 	Ref<VisualScriptExpression> vse = script->get_node(func, p_id);
1483 	if (!vse.is_valid())
1484 		return;
1485 
1486 	updating_graph = true;
1487 
1488 	undo_redo->create_action(TTR("Change Expression"), UndoRedo::MERGE_ENDS);
1489 	undo_redo->add_do_property(vse.ptr(), "expression", p_text);
1490 	undo_redo->add_undo_property(vse.ptr(), "expression", vse->get("expression"));
1491 	undo_redo->add_do_method(this, "_update_graph", p_id);
1492 	undo_redo->add_undo_method(this, "_update_graph", p_id);
1493 	undo_redo->commit_action();
1494 
1495 	Node *node = graph->get_node(itos(p_id));
1496 	if (Object::cast_to<Control>(node))
1497 		Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); //shrink if text is smaller
1498 
1499 	updating_graph = false;
1500 }
1501 
_get_available_pos(bool centered,Vector2 ofs) const1502 Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const {
1503 	if (centered)
1504 		ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5;
1505 
1506 	if (graph->is_using_snap()) {
1507 		int snap = graph->get_snap();
1508 		ofs = ofs.snapped(Vector2(snap, snap));
1509 	}
1510 
1511 	ofs /= EDSCALE;
1512 
1513 	while (true) {
1514 		bool exists = false;
1515 		List<StringName> all_fn;
1516 		script->get_function_list(&all_fn);
1517 		for (List<StringName>::Element *F = all_fn.front(); F; F = F->next()) {
1518 			StringName curr_fn = F->get();
1519 			List<int> existing;
1520 			script->get_node_list(curr_fn, &existing);
1521 			for (List<int>::Element *E = existing.front(); E; E = E->next()) {
1522 				Point2 pos = script->get_node_position(curr_fn, E->get());
1523 				if (pos.distance_to(ofs) < 50) {
1524 					ofs += Vector2(graph->get_snap(), graph->get_snap());
1525 					exists = true;
1526 					break;
1527 				}
1528 			}
1529 		}
1530 		if (exists)
1531 			continue;
1532 		break;
1533 	}
1534 
1535 	return ofs;
1536 }
1537 
_validate_name(const String & p_name) const1538 String VisualScriptEditor::_validate_name(const String &p_name) const {
1539 
1540 	String valid = p_name;
1541 
1542 	int counter = 1;
1543 	while (true) {
1544 
1545 		bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid);
1546 
1547 		if (exists) {
1548 			counter++;
1549 			valid = p_name + "_" + itos(counter);
1550 			continue;
1551 		}
1552 
1553 		break;
1554 	}
1555 
1556 	return valid;
1557 }
1558 
_on_nodes_delete()1559 void VisualScriptEditor::_on_nodes_delete() {
1560 
1561 	// delete all the selected nodes
1562 
1563 	List<int> to_erase;
1564 
1565 	for (int i = 0; i < graph->get_child_count(); i++) {
1566 		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
1567 		if (gn) {
1568 			if (gn->is_selected() && gn->is_close_button_visible()) {
1569 				to_erase.push_back(gn->get_name().operator String().to_int());
1570 			}
1571 		}
1572 	}
1573 
1574 	if (to_erase.empty())
1575 		return;
1576 
1577 	undo_redo->create_action(TTR("Remove VisualScript Nodes"));
1578 
1579 	for (List<int>::Element *F = to_erase.front(); F; F = F->next()) {
1580 
1581 		int cr_node = F->get();
1582 
1583 		StringName func = _get_function_of_node(cr_node);
1584 
1585 		undo_redo->add_do_method(script.ptr(), "remove_node", func, cr_node);
1586 		undo_redo->add_undo_method(script.ptr(), "add_node", func, cr_node, script->get_node(func, cr_node), script->get_node_position(func, cr_node));
1587 
1588 		List<VisualScript::SequenceConnection> sequence_conns;
1589 		script->get_sequence_connection_list(func, &sequence_conns);
1590 
1591 		for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
1592 
1593 			if (E->get().from_node == cr_node || E->get().to_node == cr_node) {
1594 				undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, E->get().from_node, E->get().from_output, E->get().to_node);
1595 			}
1596 		}
1597 
1598 		List<VisualScript::DataConnection> data_conns;
1599 		script->get_data_connection_list(func, &data_conns);
1600 
1601 		for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
1602 
1603 			if (E->get().from_node == F->get() || E->get().to_node == F->get()) {
1604 				undo_redo->add_undo_method(script.ptr(), "data_connect", func, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
1605 			}
1606 		}
1607 	}
1608 	undo_redo->add_do_method(this, "_update_graph");
1609 	undo_redo->add_undo_method(this, "_update_graph");
1610 
1611 	undo_redo->commit_action();
1612 }
1613 
_on_nodes_duplicate()1614 void VisualScriptEditor::_on_nodes_duplicate() {
1615 
1616 	Set<int> to_duplicate;
1617 	List<StringName> funcs;
1618 
1619 	for (int i = 0; i < graph->get_child_count(); i++) {
1620 		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
1621 		if (gn) {
1622 			if (gn->is_selected() && gn->is_close_button_visible()) {
1623 				int id = gn->get_name().operator String().to_int();
1624 				to_duplicate.insert(id);
1625 				funcs.push_back(_get_function_of_node(id));
1626 			}
1627 		}
1628 	}
1629 
1630 	if (to_duplicate.empty())
1631 		return;
1632 
1633 	undo_redo->create_action(TTR("Duplicate VisualScript Nodes"));
1634 	int idc = script->get_available_id() + 1;
1635 
1636 	Set<int> to_select;
1637 	HashMap<int, int> remap;
1638 
1639 	for (Set<int>::Element *F = to_duplicate.front(); F; F = F->next()) {
1640 
1641 		// duplicate from the specific function but place it into the default func as it would lack the connections
1642 		StringName func = _get_function_of_node(F->get());
1643 		Ref<VisualScriptNode> node = script->get_node(func, F->get());
1644 
1645 		Ref<VisualScriptNode> dupe = node->duplicate(true);
1646 
1647 		int new_id = idc++;
1648 		remap.set(F->get(), new_id);
1649 
1650 		to_select.insert(new_id);
1651 		undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, dupe, script->get_node_position(func, F->get()) + Vector2(20, 20));
1652 		undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
1653 	}
1654 
1655 	for (List<StringName>::Element *F = funcs.front(); F; F = F->next()) {
1656 		List<VisualScript::SequenceConnection> seqs;
1657 		script->get_sequence_connection_list(F->get(), &seqs);
1658 		for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) {
1659 			if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
1660 				undo_redo->add_do_method(script.ptr(), "sequence_connect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
1661 			}
1662 		}
1663 
1664 		List<VisualScript::DataConnection> data;
1665 		script->get_data_connection_list(F->get(), &data);
1666 		for (List<VisualScript::DataConnection>::Element *E = data.front(); E; E = E->next()) {
1667 			if (to_duplicate.has(E->get().from_node) && to_duplicate.has(E->get().to_node)) {
1668 				undo_redo->add_do_method(script.ptr(), "data_connect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
1669 			}
1670 		}
1671 	}
1672 
1673 	undo_redo->add_do_method(this, "_update_graph");
1674 	undo_redo->add_undo_method(this, "_update_graph");
1675 
1676 	undo_redo->commit_action();
1677 
1678 	for (int i = 0; i < graph->get_child_count(); i++) {
1679 		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
1680 		if (gn) {
1681 			int id = gn->get_name().operator String().to_int();
1682 			gn->set_selected(to_select.has(id));
1683 		}
1684 	}
1685 
1686 	if (to_select.size()) {
1687 		EditorNode::get_singleton()->push_item(script->get_node(default_func, to_select.front()->get()).ptr());
1688 	}
1689 }
1690 
_generic_search(String p_base_type,Vector2 pos,bool node_centered)1691 void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool node_centered) {
1692 	if (node_centered)
1693 		port_action_pos = graph->get_size() / 2.0f;
1694 	else
1695 		port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position();
1696 
1697 	new_connect_node_select->select_from_visual_script(p_base_type, false, false); // neither connecting nor reset text
1698 
1699 	// ensure that the dialog fits inside the graph
1700 	Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
1701 	pos.x = pos.x > bounds.x ? bounds.x : pos.x;
1702 	pos.y = pos.y > bounds.y ? bounds.y : pos.y;
1703 
1704 	if (pos != Vector2())
1705 		new_connect_node_select->set_position(pos);
1706 }
1707 
_input(const Ref<InputEvent> & p_event)1708 void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
1709 	// GUI input for VS Editor Plugin
1710 	Ref<InputEventMouseButton> key = p_event;
1711 
1712 	if (key.is_valid() && !key->is_pressed()) {
1713 		mouse_up_position = Input::get_singleton()->get_mouse_position();
1714 	}
1715 }
1716 
_graph_gui_input(const Ref<InputEvent> & p_event)1717 void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
1718 	Ref<InputEventMouseButton> key = p_event;
1719 
1720 	if (key.is_valid() && key->is_pressed() && key->get_button_mask() == BUTTON_RIGHT) {
1721 		saved_position = graph->get_local_mouse_position();
1722 
1723 		Point2 gpos = Input::get_singleton()->get_mouse_position();
1724 		_generic_search(script->get_instance_base_type(), gpos);
1725 	}
1726 }
1727 
_members_gui_input(const Ref<InputEvent> & p_event)1728 void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
1729 
1730 	Ref<InputEventKey> key = p_event;
1731 	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
1732 		if (members->has_focus()) {
1733 			TreeItem *ti = members->get_selected();
1734 			if (ti) {
1735 				TreeItem *root = members->get_root();
1736 				if (ti->get_parent() == root->get_children()) {
1737 					member_type = MEMBER_FUNCTION;
1738 				}
1739 				if (ti->get_parent() == root->get_children()->get_next()) {
1740 					member_type = MEMBER_VARIABLE;
1741 				}
1742 				if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
1743 					member_type = MEMBER_SIGNAL;
1744 				}
1745 				member_name = ti->get_text(0);
1746 			}
1747 			if (ED_IS_SHORTCUT("visual_script_editor/delete_selected", p_event)) {
1748 				_member_option(MEMBER_REMOVE);
1749 			}
1750 			if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) {
1751 				_member_option(MEMBER_EDIT);
1752 			}
1753 		}
1754 	}
1755 
1756 	Ref<InputEventMouseButton> btn = p_event;
1757 	if (btn.is_valid() && btn->is_doubleclick()) {
1758 		TreeItem *ti = members->get_selected();
1759 		if (ti && ti->get_parent() == members->get_root()->get_children()) // to check if it's a function
1760 			_center_on_node(ti->get_metadata(0), script->get_function_node_id(ti->get_metadata(0)));
1761 	}
1762 }
1763 
_rename_function(const String & name,const String & new_name)1764 void VisualScriptEditor::_rename_function(const String &name, const String &new_name) {
1765 
1766 	if (!new_name.is_valid_identifier()) {
1767 
1768 		EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);
1769 		return;
1770 	}
1771 
1772 	if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
1773 
1774 		EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);
1775 		return;
1776 	}
1777 
1778 	int node_id = script->get_function_node_id(name);
1779 	Ref<VisualScriptFunction> func;
1780 	if (script->has_node(name, node_id)) {
1781 		func = script->get_node(name, node_id);
1782 	}
1783 	undo_redo->create_action(TTR("Rename Function"));
1784 	undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
1785 	undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);
1786 	if (func.is_valid()) {
1787 		undo_redo->add_do_method(func.ptr(), "set_name", new_name);
1788 		undo_redo->add_undo_method(func.ptr(), "set_name", name);
1789 	}
1790 
1791 	// also fix all function calls
1792 	List<StringName> flst;
1793 	script->get_function_list(&flst);
1794 	for (List<StringName>::Element *E = flst.front(); E; E = E->next()) {
1795 		List<int> lst;
1796 		script->get_node_list(E->get(), &lst);
1797 		for (List<int>::Element *F = lst.front(); F; F = F->next()) {
1798 			Ref<VisualScriptFunctionCall> fncall = script->get_node(E->get(), F->get());
1799 			if (!fncall.is_valid())
1800 				continue;
1801 			if (fncall->get_function() == name) {
1802 				undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
1803 				undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
1804 			}
1805 		}
1806 	}
1807 
1808 	undo_redo->add_do_method(this, "_update_members");
1809 	undo_redo->add_undo_method(this, "_update_members");
1810 	undo_redo->add_do_method(this, "_update_graph");
1811 	undo_redo->add_undo_method(this, "_update_graph");
1812 	undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
1813 	undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
1814 	undo_redo->commit_action();
1815 }
1816 
_fn_name_box_input(const Ref<InputEvent> & p_event)1817 void VisualScriptEditor::_fn_name_box_input(const Ref<InputEvent> &p_event) {
1818 
1819 	if (!function_name_edit->is_visible())
1820 		return;
1821 
1822 	Ref<InputEventKey> key = p_event;
1823 	if (key.is_valid() && key->is_pressed() && key->get_scancode() == KEY_ENTER) {
1824 		function_name_edit->hide();
1825 		_rename_function(selected, function_name_box->get_text());
1826 		function_name_box->clear();
1827 	}
1828 }
1829 
get_drag_data_fw(const Point2 & p_point,Control * p_from)1830 Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
1831 
1832 	if (p_from == members) {
1833 
1834 		TreeItem *it = members->get_item_at_position(p_point);
1835 		if (!it)
1836 			return Variant();
1837 
1838 		String type = it->get_metadata(0);
1839 
1840 		if (type == String())
1841 			return Variant();
1842 
1843 		Dictionary dd;
1844 		TreeItem *root = members->get_root();
1845 
1846 		if (it->get_parent() == root->get_children()) {
1847 
1848 			dd["type"] = "visual_script_function_drag";
1849 			dd["function"] = type;
1850 		} else if (it->get_parent() == root->get_children()->get_next()) {
1851 
1852 			dd["type"] = "visual_script_variable_drag";
1853 			dd["variable"] = type;
1854 		} else if (it->get_parent() == root->get_children()->get_next()->get_next()) {
1855 
1856 			dd["type"] = "visual_script_signal_drag";
1857 			dd["signal"] = type;
1858 
1859 		} else {
1860 			return Variant();
1861 		}
1862 
1863 		Label *label = memnew(Label);
1864 		label->set_text(it->get_text(0));
1865 		set_drag_preview(label);
1866 		return dd;
1867 	}
1868 	return Variant();
1869 }
1870 
can_drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from) const1871 bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
1872 
1873 	if (p_from == graph) {
1874 
1875 		Dictionary d = p_data;
1876 		if (d.has("type") &&
1877 				(String(d["type"]) == "visual_script_node_drag" ||
1878 						String(d["type"]) == "visual_script_function_drag" ||
1879 						String(d["type"]) == "visual_script_variable_drag" ||
1880 						String(d["type"]) == "visual_script_signal_drag" ||
1881 						String(d["type"]) == "obj_property" ||
1882 						String(d["type"]) == "resource" ||
1883 						String(d["type"]) == "files" ||
1884 						String(d["type"]) == "nodes")) {
1885 
1886 			if (String(d["type"]) == "obj_property") {
1887 
1888 #ifdef OSX_ENABLED
1889 				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Getter. Hold Shift to drop a generic signature."), find_keycode_name(KEY_META)));
1890 #else
1891 				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."));
1892 #endif
1893 			}
1894 
1895 			if (String(d["type"]) == "nodes") {
1896 
1897 #ifdef OSX_ENABLED
1898 				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a simple reference to the node."), find_keycode_name(KEY_META)));
1899 #else
1900 				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node."));
1901 #endif
1902 			}
1903 
1904 			if (String(d["type"]) == "visual_script_variable_drag") {
1905 
1906 #ifdef OSX_ENABLED
1907 				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Variable Setter."), find_keycode_name(KEY_META)));
1908 #else
1909 				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter."));
1910 #endif
1911 			}
1912 
1913 			return true;
1914 		}
1915 	}
1916 
1917 	return false;
1918 }
1919 
_find_script_node(Node * p_edited_scene,Node * p_current_node,const Ref<Script> & script)1920 static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
1921 
1922 	if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene)
1923 		return NULL;
1924 
1925 	Ref<Script> scr = p_current_node->get_script();
1926 
1927 	if (scr.is_valid() && scr == script)
1928 		return p_current_node;
1929 
1930 	for (int i = 0; i < p_current_node->get_child_count(); i++) {
1931 		Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
1932 		if (n)
1933 			return n;
1934 	}
1935 
1936 	return NULL;
1937 }
1938 
drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from)1939 void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
1940 
1941 	if (p_from != graph) {
1942 		return;
1943 	}
1944 
1945 	Dictionary d = p_data;
1946 
1947 	if (!d.has("type")) {
1948 		return;
1949 	}
1950 
1951 	if (String(d["type"]) == "visual_script_node_drag") {
1952 		if (!d.has("node_type") || String(d["node_type"]) == "Null") {
1953 			return;
1954 		}
1955 
1956 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
1957 
1958 		if (graph->is_using_snap()) {
1959 			int snap = graph->get_snap();
1960 			ofs = ofs.snapped(Vector2(snap, snap));
1961 		}
1962 
1963 		ofs /= EDSCALE;
1964 
1965 		int new_id = _create_new_node_from_name(d["node_type"], ofs, default_func);
1966 
1967 		Node *node = graph->get_node(itos(new_id));
1968 		if (node) {
1969 			graph->set_selected(node);
1970 			_node_selected(node);
1971 		}
1972 	}
1973 
1974 	if (String(d["type"]) == "visual_script_variable_drag") {
1975 
1976 #ifdef OSX_ENABLED
1977 		bool use_set = Input::get_singleton()->is_key_pressed(KEY_META);
1978 #else
1979 		bool use_set = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
1980 #endif
1981 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
1982 		if (graph->is_using_snap()) {
1983 			int snap = graph->get_snap();
1984 			ofs = ofs.snapped(Vector2(snap, snap));
1985 		}
1986 
1987 		ofs /= EDSCALE;
1988 
1989 		Ref<VisualScriptNode> vnode;
1990 		if (use_set) {
1991 			Ref<VisualScriptVariableSet> vnodes;
1992 			vnodes.instance();
1993 			vnodes->set_variable(d["variable"]);
1994 			vnode = vnodes;
1995 		} else {
1996 
1997 			Ref<VisualScriptVariableGet> vnodeg;
1998 			vnodeg.instance();
1999 			vnodeg->set_variable(d["variable"]);
2000 			vnode = vnodeg;
2001 		}
2002 
2003 		int new_id = script->get_available_id();
2004 
2005 		undo_redo->create_action(TTR("Add Node"));
2006 		undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
2007 		undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
2008 		undo_redo->add_do_method(this, "_update_graph");
2009 		undo_redo->add_undo_method(this, "_update_graph");
2010 		undo_redo->commit_action();
2011 
2012 		Node *node = graph->get_node(itos(new_id));
2013 		if (node) {
2014 			graph->set_selected(node);
2015 			_node_selected(node);
2016 		}
2017 	}
2018 
2019 	if (String(d["type"]) == "visual_script_function_drag") {
2020 
2021 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2022 		if (graph->is_using_snap()) {
2023 			int snap = graph->get_snap();
2024 			ofs = ofs.snapped(Vector2(snap, snap));
2025 		}
2026 
2027 		ofs /= EDSCALE;
2028 
2029 		Ref<VisualScriptFunctionCall> vnode;
2030 		vnode.instance();
2031 		vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);
2032 
2033 		int new_id = script->get_available_id();
2034 
2035 		undo_redo->create_action(TTR("Add Node"));
2036 		undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
2037 		undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type());
2038 		undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]);
2039 
2040 		undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
2041 		undo_redo->add_do_method(this, "_update_graph");
2042 		undo_redo->add_undo_method(this, "_update_graph");
2043 		undo_redo->commit_action();
2044 
2045 		Node *node = graph->get_node(itos(new_id));
2046 		if (node) {
2047 			graph->set_selected(node);
2048 			_node_selected(node);
2049 		}
2050 	}
2051 
2052 	if (String(d["type"]) == "visual_script_signal_drag") {
2053 
2054 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2055 		if (graph->is_using_snap()) {
2056 			int snap = graph->get_snap();
2057 			ofs = ofs.snapped(Vector2(snap, snap));
2058 		}
2059 
2060 		ofs /= EDSCALE;
2061 
2062 		Ref<VisualScriptEmitSignal> vnode;
2063 		vnode.instance();
2064 		vnode->set_signal(d["signal"]);
2065 
2066 		int new_id = script->get_available_id();
2067 
2068 		undo_redo->create_action(TTR("Add Node"));
2069 		undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, vnode, ofs);
2070 		undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
2071 		undo_redo->add_do_method(this, "_update_graph");
2072 		undo_redo->add_undo_method(this, "_update_graph");
2073 		undo_redo->commit_action();
2074 
2075 		Node *node = graph->get_node(itos(new_id));
2076 		if (node) {
2077 			graph->set_selected(node);
2078 			_node_selected(node);
2079 		}
2080 	}
2081 
2082 	if (String(d["type"]) == "resource") {
2083 
2084 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2085 		if (graph->is_using_snap()) {
2086 			int snap = graph->get_snap();
2087 			ofs = ofs.snapped(Vector2(snap, snap));
2088 		}
2089 
2090 		ofs /= EDSCALE;
2091 
2092 		Ref<VisualScriptPreload> prnode;
2093 		prnode.instance();
2094 		prnode->set_preload(d["resource"]);
2095 
2096 		int new_id = script->get_available_id();
2097 
2098 		undo_redo->create_action(TTR("Add Preload Node"));
2099 		undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, prnode, ofs);
2100 		undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
2101 		undo_redo->add_do_method(this, "_update_graph");
2102 		undo_redo->add_undo_method(this, "_update_graph");
2103 		undo_redo->commit_action();
2104 
2105 		Node *node = graph->get_node(itos(new_id));
2106 		if (node) {
2107 			graph->set_selected(node);
2108 			_node_selected(node);
2109 		}
2110 	}
2111 
2112 	if (String(d["type"]) == "files") {
2113 
2114 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2115 		if (graph->is_using_snap()) {
2116 			int snap = graph->get_snap();
2117 			ofs = ofs.snapped(Vector2(snap, snap));
2118 		}
2119 
2120 		ofs /= EDSCALE;
2121 
2122 		Array files = d["files"];
2123 
2124 		List<int> new_ids;
2125 		int new_id = script->get_available_id();
2126 
2127 		if (files.size()) {
2128 			undo_redo->create_action(TTR("Add Preload Node"));
2129 
2130 			for (int i = 0; i < files.size(); i++) {
2131 
2132 				Ref<Resource> res = ResourceLoader::load(files[i]);
2133 				if (!res.is_valid())
2134 					continue;
2135 
2136 				Ref<VisualScriptPreload> prnode;
2137 				prnode.instance();
2138 				prnode->set_preload(res);
2139 
2140 				undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, prnode, ofs);
2141 				undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
2142 				new_ids.push_back(new_id);
2143 				new_id++;
2144 				ofs += Vector2(20, 20) * EDSCALE;
2145 			}
2146 
2147 			undo_redo->add_do_method(this, "_update_graph");
2148 			undo_redo->add_undo_method(this, "_update_graph");
2149 			undo_redo->commit_action();
2150 		}
2151 
2152 		for (List<int>::Element *E = new_ids.front(); E; E = E->next()) {
2153 
2154 			Node *node = graph->get_node(itos(E->get()));
2155 			if (node) {
2156 				graph->set_selected(node);
2157 				_node_selected(node);
2158 			}
2159 		}
2160 	}
2161 
2162 	if (String(d["type"]) == "nodes") {
2163 
2164 		Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
2165 
2166 		if (!sn) {
2167 			EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name()));
2168 			return;
2169 		}
2170 
2171 #ifdef OSX_ENABLED
2172 		bool use_node = Input::get_singleton()->is_key_pressed(KEY_META);
2173 #else
2174 		bool use_node = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
2175 #endif
2176 
2177 		Array nodes = d["nodes"];
2178 
2179 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2180 
2181 		if (graph->is_using_snap()) {
2182 			int snap = graph->get_snap();
2183 			ofs = ofs.snapped(Vector2(snap, snap));
2184 		}
2185 		ofs /= EDSCALE;
2186 
2187 		undo_redo->create_action(TTR("Add Node(s) From Tree"));
2188 		int base_id = script->get_available_id();
2189 
2190 		if (nodes.size() > 1) {
2191 			use_node = true;
2192 		}
2193 
2194 		for (int i = 0; i < nodes.size(); i++) {
2195 
2196 			NodePath np = nodes[i];
2197 			Node *node = get_node(np);
2198 			if (!node) {
2199 				continue;
2200 			}
2201 
2202 			Ref<VisualScriptNode> n;
2203 
2204 			if (use_node) {
2205 				Ref<VisualScriptSceneNode> scene_node;
2206 				scene_node.instance();
2207 				scene_node->set_node_path(sn->get_path_to(node));
2208 				n = scene_node;
2209 			} else {
2210 				// ! Doesn't work properly
2211 				Ref<VisualScriptFunctionCall> call;
2212 				call.instance();
2213 				call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
2214 				call->set_base_path(sn->get_path_to(node));
2215 				call->set_base_type(node->get_class());
2216 				n = call;
2217 				method_select->select_from_instance(node, "", true, node->get_class());
2218 				selecting_method_id = base_id;
2219 			}
2220 
2221 			undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, n, ofs);
2222 			undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
2223 
2224 			base_id++;
2225 			ofs += Vector2(25, 25);
2226 		}
2227 		undo_redo->add_do_method(this, "_update_graph");
2228 		undo_redo->add_undo_method(this, "_update_graph");
2229 		undo_redo->commit_action();
2230 	}
2231 
2232 	if (String(d["type"]) == "obj_property") {
2233 
2234 		Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
2235 
2236 		if (!sn && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
2237 			EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop properties because script '%s' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."), get_name()));
2238 			return;
2239 		}
2240 
2241 		Object *obj = d["object"];
2242 
2243 		if (!obj)
2244 			return;
2245 
2246 		Node *node = Object::cast_to<Node>(obj);
2247 		Vector2 ofs = graph->get_scroll_ofs() + p_point;
2248 
2249 		if (graph->is_using_snap()) {
2250 			int snap = graph->get_snap();
2251 			ofs = ofs.snapped(Vector2(snap, snap));
2252 		}
2253 
2254 		ofs /= EDSCALE;
2255 #ifdef OSX_ENABLED
2256 		bool use_get = Input::get_singleton()->is_key_pressed(KEY_META);
2257 #else
2258 		bool use_get = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
2259 #endif
2260 
2261 		if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
2262 
2263 			if (use_get)
2264 				undo_redo->create_action(TTR("Add Getter Property"));
2265 			else
2266 				undo_redo->create_action(TTR("Add Setter Property"));
2267 
2268 			int base_id = script->get_available_id();
2269 
2270 			Ref<VisualScriptNode> vnode;
2271 
2272 			if (!use_get) {
2273 
2274 				Ref<VisualScriptPropertySet> pset;
2275 				pset.instance();
2276 				pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
2277 				pset->set_base_type(obj->get_class());
2278 				/*if (use_value) {
2279 						pset->set_use_builtin_value(true);
2280 						pset->set_builtin_value(d["value"]);
2281 					}*/
2282 				vnode = pset;
2283 			} else {
2284 
2285 				Ref<VisualScriptPropertyGet> pget;
2286 				pget.instance();
2287 				pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
2288 				pget->set_base_type(obj->get_class());
2289 
2290 				vnode = pget;
2291 			}
2292 
2293 			undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, vnode, ofs);
2294 			undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
2295 			if (!use_get) {
2296 				undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
2297 			}
2298 
2299 			undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
2300 
2301 			undo_redo->add_do_method(this, "_update_graph");
2302 			undo_redo->add_undo_method(this, "_update_graph");
2303 			undo_redo->commit_action();
2304 
2305 		} else {
2306 
2307 			if (use_get)
2308 				undo_redo->create_action(TTR("Add Getter Property"));
2309 			else
2310 				undo_redo->create_action(TTR("Add Setter Property"));
2311 
2312 			int base_id = script->get_available_id();
2313 
2314 			Ref<VisualScriptNode> vnode;
2315 
2316 			if (!use_get) {
2317 
2318 				Ref<VisualScriptPropertySet> pset;
2319 				pset.instance();
2320 				if (sn == node) {
2321 					pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
2322 				} else {
2323 					pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
2324 					pset->set_base_path(sn->get_path_to(node));
2325 				}
2326 
2327 				vnode = pset;
2328 			} else {
2329 
2330 				Ref<VisualScriptPropertyGet> pget;
2331 				pget.instance();
2332 				if (sn == node) {
2333 					pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
2334 				} else {
2335 					pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
2336 					pget->set_base_path(sn->get_path_to(node));
2337 				}
2338 				vnode = pget;
2339 			}
2340 			undo_redo->add_do_method(script.ptr(), "add_node", default_func, base_id, vnode, ofs);
2341 			undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
2342 			if (!use_get) {
2343 				undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
2344 			}
2345 			undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, base_id);
2346 
2347 			undo_redo->add_do_method(this, "_update_graph");
2348 			undo_redo->add_undo_method(this, "_update_graph");
2349 			undo_redo->commit_action();
2350 		}
2351 	}
2352 }
2353 
_selected_method(const String & p_method,const String & p_type,const bool p_connecting)2354 void VisualScriptEditor::_selected_method(const String &p_method, const String &p_type, const bool p_connecting) {
2355 
2356 	Ref<VisualScriptFunctionCall> vsfc = script->get_node(default_func, selecting_method_id);
2357 	if (!vsfc.is_valid())
2358 		return;
2359 	vsfc->set_function(p_method);
2360 }
2361 
_draw_color_over_button(Object * obj,Color p_color)2362 void VisualScriptEditor::_draw_color_over_button(Object *obj, Color p_color) {
2363 
2364 	Button *button = Object::cast_to<Button>(obj);
2365 	if (!button)
2366 		return;
2367 
2368 	Ref<StyleBox> normal = get_stylebox("normal", "Button");
2369 	button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);
2370 }
2371 
_button_resource_previewed(const String & p_path,const Ref<Texture> & p_preview,const Ref<Texture> & p_small_preview,Variant p_ud)2372 void VisualScriptEditor::_button_resource_previewed(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, Variant p_ud) {
2373 
2374 	Array ud = p_ud;
2375 	ERR_FAIL_COND(ud.size() != 2);
2376 
2377 	ObjectID id = ud[0];
2378 	Object *obj = ObjectDB::get_instance(id);
2379 
2380 	if (!obj)
2381 		return;
2382 
2383 	Button *b = Object::cast_to<Button>(obj);
2384 	ERR_FAIL_COND(!b);
2385 
2386 	if (p_preview.is_null()) {
2387 		b->set_text(ud[1]);
2388 	} else {
2389 
2390 		b->set_icon(p_preview);
2391 	}
2392 }
2393 
2394 /////////////////////////
2395 
apply_code()2396 void VisualScriptEditor::apply_code() {
2397 }
2398 
get_edited_resource() const2399 RES VisualScriptEditor::get_edited_resource() const {
2400 	return script;
2401 }
2402 
set_edited_resource(const RES & p_res)2403 void VisualScriptEditor::set_edited_resource(const RES &p_res) {
2404 
2405 	script = p_res;
2406 	signal_editor->script = script;
2407 	signal_editor->undo_redo = undo_redo;
2408 	variable_editor->script = script;
2409 	variable_editor->undo_redo = undo_redo;
2410 
2411 	script->connect("node_ports_changed", this, "_node_ports_changed");
2412 
2413 	default_func = script->get_default_func();
2414 
2415 	if (!script->has_function(default_func)) // this is the supposed default function
2416 	{
2417 		script->add_function(default_func);
2418 		script->set_edited(true); //so that if a function was added it's saved
2419 	}
2420 
2421 	_update_graph();
2422 	_update_members();
2423 }
2424 
get_functions()2425 Vector<String> VisualScriptEditor::get_functions() {
2426 
2427 	return Vector<String>();
2428 }
2429 
reload_text()2430 void VisualScriptEditor::reload_text() {
2431 }
2432 
get_name()2433 String VisualScriptEditor::get_name() {
2434 
2435 	String name;
2436 
2437 	if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {
2438 		name = script->get_path().get_file();
2439 		if (is_unsaved()) {
2440 			name += "(*)";
2441 		}
2442 	} else if (script->get_name() != "")
2443 		name = script->get_name();
2444 	else
2445 		name = script->get_class() + "(" + itos(script->get_instance_id()) + ")";
2446 
2447 	return name;
2448 }
2449 
get_icon()2450 Ref<Texture> VisualScriptEditor::get_icon() {
2451 
2452 	return Control::get_icon("VisualScript", "EditorIcons");
2453 }
2454 
is_unsaved()2455 bool VisualScriptEditor::is_unsaved() {
2456 
2457 	return script->is_edited() || script->are_subnodes_edited();
2458 }
2459 
get_edit_state()2460 Variant VisualScriptEditor::get_edit_state() {
2461 
2462 	Dictionary d;
2463 	d["function"] = default_func;
2464 	d["scroll"] = graph->get_scroll_ofs();
2465 	d["zoom"] = graph->get_zoom();
2466 	d["using_snap"] = graph->is_using_snap();
2467 	d["snap"] = graph->get_snap();
2468 	return d;
2469 }
2470 
set_edit_state(const Variant & p_state)2471 void VisualScriptEditor::set_edit_state(const Variant &p_state) {
2472 
2473 	Dictionary d = p_state;
2474 	if (d.has("function")) {
2475 		selected = default_func;
2476 	}
2477 
2478 	_update_graph();
2479 	_update_members();
2480 
2481 	if (d.has("scroll")) {
2482 		graph->set_scroll_ofs(d["scroll"]);
2483 	}
2484 	if (d.has("zoom")) {
2485 		graph->set_zoom(d["zoom"]);
2486 	}
2487 	if (d.has("snap")) {
2488 		graph->set_snap(d["snap"]);
2489 	}
2490 	if (d.has("snap_enabled")) {
2491 		graph->set_use_snap(d["snap_enabled"]);
2492 	}
2493 }
2494 
_center_on_node(const StringName & p_func,int p_id)2495 void VisualScriptEditor::_center_on_node(const StringName &p_func, int p_id) {
2496 
2497 	Node *n = graph->get_node(itos(p_id));
2498 	GraphNode *gn = Object::cast_to<GraphNode>(n);
2499 
2500 	// clear selection
2501 	for (int i = 0; i < graph->get_child_count(); i++) {
2502 		GraphNode *gnd = Object::cast_to<GraphNode>(graph->get_child(i));
2503 		if (gnd)
2504 			gnd->set_selected(false);
2505 	}
2506 
2507 	if (gn) {
2508 		gn->set_selected(true);
2509 		Vector2 new_scroll = gn->get_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
2510 		graph->set_scroll_ofs(new_scroll);
2511 		script->set_function_scroll(p_func, new_scroll / EDSCALE);
2512 		script->set_edited(true);
2513 	}
2514 }
2515 
goto_line(int p_line,bool p_with_error)2516 void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
2517 
2518 	p_line += 1; //add one because script lines begin from 0.
2519 
2520 	if (p_with_error)
2521 		error_line = p_line;
2522 
2523 	List<StringName> functions;
2524 	script->get_function_list(&functions);
2525 	for (List<StringName>::Element *E = functions.front(); E; E = E->next()) {
2526 
2527 		if (script->has_node(E->get(), p_line)) {
2528 
2529 			_update_graph();
2530 			_update_members();
2531 
2532 			call_deferred("call_deferred", "_center_on_node", E->get(), p_line); //editor might be just created and size might not exist yet
2533 			return;
2534 		}
2535 	}
2536 }
2537 
set_executing_line(int p_line)2538 void VisualScriptEditor::set_executing_line(int p_line) {
2539 	// todo: add a way to show which node is executing right now.
2540 }
2541 
clear_executing_line()2542 void VisualScriptEditor::clear_executing_line() {
2543 	// todo: add a way to show which node is executing right now.
2544 }
2545 
trim_trailing_whitespace()2546 void VisualScriptEditor::trim_trailing_whitespace() {
2547 }
2548 
insert_final_newline()2549 void VisualScriptEditor::insert_final_newline() {
2550 }
2551 
convert_indent_to_spaces()2552 void VisualScriptEditor::convert_indent_to_spaces() {
2553 }
2554 
convert_indent_to_tabs()2555 void VisualScriptEditor::convert_indent_to_tabs() {
2556 }
2557 
ensure_focus()2558 void VisualScriptEditor::ensure_focus() {
2559 
2560 	graph->grab_focus();
2561 }
2562 
tag_saved_version()2563 void VisualScriptEditor::tag_saved_version() {
2564 }
2565 
reload(bool p_soft)2566 void VisualScriptEditor::reload(bool p_soft) {
2567 	_update_graph();
2568 }
2569 
get_breakpoints(List<int> * p_breakpoints)2570 void VisualScriptEditor::get_breakpoints(List<int> *p_breakpoints) {
2571 
2572 	List<StringName> functions;
2573 	script->get_function_list(&functions);
2574 	for (List<StringName>::Element *E = functions.front(); E; E = E->next()) {
2575 
2576 		List<int> nodes;
2577 		script->get_node_list(E->get(), &nodes);
2578 		for (List<int>::Element *F = nodes.front(); F; F = F->next()) {
2579 
2580 			Ref<VisualScriptNode> vsn = script->get_node(E->get(), F->get());
2581 			if (vsn->is_breakpoint()) {
2582 				p_breakpoints->push_back(F->get() - 1); //subtract 1 because breakpoints in text start from zero
2583 			}
2584 		}
2585 	}
2586 }
2587 
add_callback(const String & p_function,PoolStringArray p_args)2588 void VisualScriptEditor::add_callback(const String &p_function, PoolStringArray p_args) {
2589 
2590 	if (script->has_function(p_function)) {
2591 		_update_members();
2592 		_update_graph();
2593 		_center_on_node(p_function, script->get_function_node_id(p_function));
2594 		return;
2595 	}
2596 
2597 	Ref<VisualScriptFunction> func;
2598 	func.instance();
2599 	for (int i = 0; i < p_args.size(); i++) {
2600 
2601 		String name = p_args[i];
2602 		Variant::Type type = Variant::NIL;
2603 
2604 		if (name.find(":") != -1) {
2605 			String tt = name.get_slice(":", 1);
2606 			name = name.get_slice(":", 0);
2607 			for (int j = 0; j < Variant::VARIANT_MAX; j++) {
2608 
2609 				String tname = Variant::get_type_name(Variant::Type(j));
2610 				if (tname == tt) {
2611 					type = Variant::Type(j);
2612 					break;
2613 				}
2614 			}
2615 		}
2616 
2617 		func->add_argument(type, name);
2618 	}
2619 
2620 	func->set_name(p_function);
2621 	script->add_function(p_function);
2622 	script->add_node(p_function, script->get_available_id(), func);
2623 
2624 	_update_members();
2625 	_update_graph();
2626 
2627 	_center_on_node(p_function, script->get_function_node_id(p_function));
2628 }
2629 
show_members_overview()2630 bool VisualScriptEditor::show_members_overview() {
2631 	return false;
2632 }
2633 
update_settings()2634 void VisualScriptEditor::update_settings() {
2635 
2636 	_update_graph();
2637 }
2638 
set_debugger_active(bool p_active)2639 void VisualScriptEditor::set_debugger_active(bool p_active) {
2640 	if (!p_active) {
2641 		error_line = -1;
2642 		_update_graph(); //clear line break
2643 	}
2644 }
2645 
set_tooltip_request_func(String p_method,Object * p_obj)2646 void VisualScriptEditor::set_tooltip_request_func(String p_method, Object *p_obj) {
2647 }
2648 
get_edit_menu()2649 Control *VisualScriptEditor::get_edit_menu() {
2650 
2651 	return edit_menu;
2652 }
2653 
_change_base_type()2654 void VisualScriptEditor::_change_base_type() {
2655 
2656 	select_base_type->popup_create(true, true);
2657 }
2658 
_toggle_tool_script()2659 void VisualScriptEditor::_toggle_tool_script() {
2660 	script->set_tool_enabled(!script->is_tool());
2661 }
2662 
clear_edit_menu()2663 void VisualScriptEditor::clear_edit_menu() {
2664 	memdelete(edit_menu);
2665 	memdelete(members_section);
2666 }
2667 
_change_base_type_callback()2668 void VisualScriptEditor::_change_base_type_callback() {
2669 
2670 	String bt = select_base_type->get_selected_type();
2671 
2672 	ERR_FAIL_COND(bt == String());
2673 	undo_redo->create_action(TTR("Change Base Type"));
2674 	undo_redo->add_do_method(script.ptr(), "set_instance_base_type", bt);
2675 	undo_redo->add_undo_method(script.ptr(), "set_instance_base_type", script->get_instance_base_type());
2676 	undo_redo->add_do_method(this, "_update_members");
2677 	undo_redo->add_undo_method(this, "_update_members");
2678 	undo_redo->commit_action();
2679 }
2680 
_node_selected(Node * p_node)2681 void VisualScriptEditor::_node_selected(Node *p_node) {
2682 
2683 	Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode");
2684 	if (vnode.is_null())
2685 		return;
2686 
2687 	EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector
2688 }
2689 
_get_out_slot(const Ref<VisualScriptNode> & p_node,int p_slot,int & r_real_slot,bool & r_sequence)2690 static bool _get_out_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {
2691 
2692 	if (p_slot < p_node->get_output_sequence_port_count()) {
2693 		r_sequence = true;
2694 		r_real_slot = p_slot;
2695 
2696 		return true;
2697 	}
2698 
2699 	r_real_slot = p_slot - p_node->get_output_sequence_port_count();
2700 	r_sequence = false;
2701 
2702 	return (r_real_slot < p_node->get_output_value_port_count());
2703 }
2704 
_get_in_slot(const Ref<VisualScriptNode> & p_node,int p_slot,int & r_real_slot,bool & r_sequence)2705 static bool _get_in_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {
2706 
2707 	if (p_slot == 0 && p_node->has_input_sequence_port()) {
2708 		r_sequence = true;
2709 		r_real_slot = 0;
2710 		return true;
2711 	}
2712 
2713 	r_real_slot = p_slot - (p_node->has_input_sequence_port() ? 1 : 0);
2714 	r_sequence = false;
2715 
2716 	return r_real_slot < p_node->get_input_value_port_count();
2717 }
2718 
_begin_node_move()2719 void VisualScriptEditor::_begin_node_move() {
2720 
2721 	undo_redo->create_action(TTR("Move Node(s)"));
2722 }
2723 
_end_node_move()2724 void VisualScriptEditor::_end_node_move() {
2725 
2726 	undo_redo->commit_action();
2727 }
2728 
_move_node(const StringName & p_func,int p_id,const Vector2 & p_to)2729 void VisualScriptEditor::_move_node(const StringName &p_func, int p_id, const Vector2 &p_to) {
2730 
2731 	if (!script->has_function(p_func))
2732 		return;
2733 
2734 	Node *node = graph->get_node(itos(p_id));
2735 
2736 	if (Object::cast_to<GraphNode>(node))
2737 		Object::cast_to<GraphNode>(node)->set_offset(p_to);
2738 
2739 	script->set_node_position(p_func, p_id, p_to / EDSCALE);
2740 }
2741 
_get_function_of_node(int p_id) const2742 StringName VisualScriptEditor::_get_function_of_node(int p_id) const {
2743 
2744 	List<StringName> funcs;
2745 	script->get_function_list(&funcs);
2746 	for (List<StringName>::Element *E = funcs.front(); E; E = E->next()) {
2747 		if (script->has_node(E->get(), p_id)) {
2748 			return E->get();
2749 		}
2750 	}
2751 
2752 	return ""; // this is passed to avoid crash and is tested against later
2753 }
2754 
_node_moved(Vector2 p_from,Vector2 p_to,int p_id)2755 void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) {
2756 
2757 	StringName func = _get_function_of_node(p_id);
2758 
2759 	undo_redo->add_do_method(this, "_move_node", func, p_id, p_to);
2760 	undo_redo->add_undo_method(this, "_move_node", func, p_id, p_from);
2761 }
2762 
_remove_node(int p_id)2763 void VisualScriptEditor::_remove_node(int p_id) {
2764 
2765 	undo_redo->create_action(TTR("Remove VisualScript Node"));
2766 
2767 	StringName func = _get_function_of_node(p_id);
2768 
2769 	undo_redo->add_do_method(script.ptr(), "remove_node", func, p_id);
2770 	undo_redo->add_undo_method(script.ptr(), "add_node", func, p_id, script->get_node(func, p_id), script->get_node_position(func, p_id));
2771 
2772 	List<VisualScript::SequenceConnection> sequence_conns;
2773 	script->get_sequence_connection_list(func, &sequence_conns);
2774 
2775 	for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
2776 
2777 		if (E->get().from_node == p_id || E->get().to_node == p_id) {
2778 			undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, E->get().from_node, E->get().from_output, E->get().to_node);
2779 		}
2780 	}
2781 
2782 	List<VisualScript::DataConnection> data_conns;
2783 	script->get_data_connection_list(func, &data_conns);
2784 
2785 	for (List<VisualScript::DataConnection>::Element *E = data_conns.front(); E; E = E->next()) {
2786 
2787 		if (E->get().from_node == p_id || E->get().to_node == p_id) {
2788 			undo_redo->add_undo_method(script.ptr(), "data_connect", func, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
2789 		}
2790 	}
2791 
2792 	undo_redo->add_do_method(this, "_update_graph");
2793 	undo_redo->add_undo_method(this, "_update_graph");
2794 
2795 	undo_redo->commit_action();
2796 }
2797 
_node_ports_changed(const String & p_func,int p_id)2798 void VisualScriptEditor::_node_ports_changed(const String &p_func, int p_id) {
2799 
2800 	_update_graph(p_id);
2801 }
2802 
node_has_sequence_connections(const StringName & p_func,int p_id)2803 bool VisualScriptEditor::node_has_sequence_connections(const StringName &p_func, int p_id) {
2804 	List<VisualScript::SequenceConnection> sequence_conns;
2805 	script->get_sequence_connection_list(p_func, &sequence_conns);
2806 
2807 	for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
2808 		int from = E->get().from_node;
2809 		int to = E->get().to_node;
2810 
2811 		if (to == p_id || from == p_id)
2812 			return true;
2813 	}
2814 
2815 	return false;
2816 }
2817 
_graph_connected(const String & p_from,int p_from_slot,const String & p_to,int p_to_slot)2818 void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
2819 
2820 	StringName from_func = _get_function_of_node(p_from.to_int());
2821 
2822 	Ref<VisualScriptNode> from_node = script->get_node(from_func, p_from.to_int());
2823 	ERR_FAIL_COND(!from_node.is_valid());
2824 
2825 	bool from_seq;
2826 	int from_port;
2827 
2828 	if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq))
2829 		return; //can't connect this, it's invalid
2830 
2831 	StringName to_func = _get_function_of_node(p_to.to_int());
2832 
2833 	Ref<VisualScriptNode> to_node = script->get_node(to_func, p_to.to_int());
2834 	ERR_FAIL_COND(!to_node.is_valid());
2835 
2836 	bool to_seq;
2837 	int to_port;
2838 
2839 	if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq))
2840 		return; //can't connect this, it's invalid
2841 
2842 	ERR_FAIL_COND(from_seq != to_seq);
2843 
2844 	// Do all the checks here
2845 	StringName func; // this the func where we store the one the nodes at the end of the resolution on having multiple nodes
2846 
2847 	undo_redo->create_action(TTR("Connect Nodes"));
2848 
2849 	if (from_func == to_func) {
2850 		func = to_func;
2851 	} else if (from_seq) {
2852 		// this is a sequence connection
2853 		_move_nodes_with_rescan(to_func, from_func, p_to.to_int()); // this function moves the nodes from func1 to func2
2854 		func = from_func;
2855 	} else {
2856 		if (node_has_sequence_connections(to_func, p_to.to_int())) {
2857 			if (node_has_sequence_connections(from_func, p_from.to_int())) {
2858 				ERR_PRINT("Trying to connect between different sequence node trees");
2859 				return;
2860 			} else {
2861 				_move_nodes_with_rescan(from_func, to_func, p_from.to_int());
2862 				func = to_func;
2863 			}
2864 		} else if (node_has_sequence_connections(from_func, p_from.to_int())) {
2865 			if (from_func == default_func) {
2866 				_move_nodes_with_rescan(from_func, to_func, p_from.to_int());
2867 				func = to_func;
2868 			} else {
2869 				_move_nodes_with_rescan(to_func, from_func, p_to.to_int());
2870 				func = from_func;
2871 			}
2872 		} else {
2873 			if (to_func == default_func) {
2874 				_move_nodes_with_rescan(to_func, from_func, p_to.to_int());
2875 				func = from_func;
2876 			} else {
2877 				_move_nodes_with_rescan(from_func, to_func, p_from.to_int());
2878 				func = to_func;
2879 			}
2880 		}
2881 	}
2882 
2883 	if (from_seq) {
2884 		undo_redo->add_do_method(script.ptr(), "sequence_connect", func, p_from.to_int(), from_port, p_to.to_int());
2885 		// this undo error on undo after move can't be removed without painful gymnastics
2886 		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, p_from.to_int(), from_port, p_to.to_int());
2887 	} else {
2888 		bool converted = false;
2889 		int conv_node = -1;
2890 
2891 		Ref<VisualScriptOperator> oper = to_node;
2892 		if (oper.is_valid() && oper->get_typed() == Variant::NIL) {
2893 			// it's an operator Node and if the type is already nil
2894 			if (from_node->get_output_value_port_info(from_port).type != Variant::NIL) {
2895 				oper->set_typed(from_node->get_output_value_port_info(from_port).type);
2896 			}
2897 		}
2898 
2899 		Ref<VisualScriptOperator> operf = from_node;
2900 		if (operf.is_valid() && operf->get_typed() == Variant::NIL) {
2901 			// it's an operator Node and if the type is already nil
2902 			if (to_node->get_input_value_port_info(to_port).type != Variant::NIL) {
2903 				operf->set_typed(to_node->get_input_value_port_info(to_port).type);
2904 			}
2905 		}
2906 
2907 		Variant::Type to_type = to_node->get_input_value_port_info(to_port).type;
2908 		Variant::Type from_type = from_node->get_output_value_port_info(from_port).type;
2909 
2910 		if (to_type != Variant::NIL && from_type != Variant::NIL && to_type != from_type) {
2911 			// add a constructor node between the ports
2912 			bool exceptions = false; // true if there are any exceptions
2913 			exceptions = exceptions || (to_type == Variant::INT && from_type == Variant::REAL);
2914 			exceptions = exceptions || (to_type == Variant::REAL && from_type == Variant::INT);
2915 			if (Variant::can_convert(from_type, to_type) && !exceptions) {
2916 				MethodInfo mi;
2917 				mi.name = Variant::get_type_name(to_type);
2918 				PropertyInfo pi;
2919 				pi.name = "from";
2920 				pi.type = from_type;
2921 				mi.arguments.push_back(pi);
2922 				mi.return_val.type = to_type;
2923 				// we know that this is allowed so create a new constructor node
2924 				Ref<VisualScriptConstructor> constructor;
2925 				constructor.instance();
2926 				constructor->set_constructor_type(to_type);
2927 				constructor->set_constructor(mi);
2928 				// add the new constructor node
2929 
2930 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(p_from));
2931 				GraphNode *gn2 = Object::cast_to<GraphNode>(graph->get_node(p_to));
2932 				if (gn && gn2) {
2933 					Vector2 from_node_size = gn->get_rect().get_size();
2934 					Vector2 to_node_size = gn2->get_rect().get_size();
2935 					Vector2 to_node_pos = script->get_node_position(func, p_to.to_int());
2936 					Vector2 from_node_pos = script->get_node_position(func, p_from.to_int());
2937 					Vector2 new_to_node_pos = from_node_pos;
2938 					Vector2 constructor_pos;
2939 					if ((to_node_pos.x - from_node_pos.x) < 0) {
2940 						// to is behind from node
2941 						if (to_node_pos.x > (from_node_pos.x - to_node_size.x - 240))
2942 							new_to_node_pos.x = from_node_pos.x - to_node_size.x - 240; // approx size of constructor node + padding
2943 						else
2944 							new_to_node_pos.x = to_node_pos.x;
2945 						new_to_node_pos.y = to_node_pos.y;
2946 						constructor_pos.x = from_node_pos.x - 210;
2947 						constructor_pos.y = to_node_pos.y;
2948 					} else {
2949 						// to is ahead of from node
2950 						if (to_node_pos.x < (from_node_size.x + from_node_pos.x + 240))
2951 							new_to_node_pos.x = from_node_size.x + from_node_pos.x + 240; // approx size of constructor node + padding
2952 						else
2953 							new_to_node_pos.x = to_node_pos.x;
2954 						new_to_node_pos.y = to_node_pos.y;
2955 						constructor_pos.x = from_node_size.x + from_node_pos.x + 10;
2956 						constructor_pos.y = to_node_pos.y;
2957 					}
2958 					undo_redo->add_do_method(this, "_move_node", func, p_to.to_int(), new_to_node_pos);
2959 					undo_redo->add_undo_method(this, "_move_node", func, p_to.to_int(), to_node_pos);
2960 					conv_node = script->get_available_id();
2961 					undo_redo->add_do_method(script.ptr(), "add_node", func, conv_node, constructor, _get_available_pos(false, constructor_pos));
2962 					undo_redo->add_undo_method(script.ptr(), "remove_node", func, conv_node);
2963 					converted = true;
2964 				}
2965 			}
2966 		}
2967 
2968 		// disconnect current, and connect the new one
2969 		if (script->is_input_value_port_connected(func, p_to.to_int(), to_port)) {
2970 			if (can_swap && data_disconnect_node == p_to.to_int()) {
2971 				int conn_from;
2972 				int conn_port;
2973 				script->get_input_value_port_connection_source(func, p_to.to_int(), to_port, &conn_from, &conn_port);
2974 				undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_to.to_int(), to_port);
2975 				undo_redo->add_do_method(script.ptr(), "data_connect", func, conn_from, conn_port, data_disconnect_node, data_disconnect_port);
2976 				undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, data_disconnect_node, data_disconnect_port);
2977 				undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_to.to_int(), to_port);
2978 				can_swap = false; // swapped
2979 			} else {
2980 				int conn_from;
2981 				int conn_port;
2982 				script->get_input_value_port_connection_source(func, p_to.to_int(), to_port, &conn_from, &conn_port);
2983 				undo_redo->add_do_method(script.ptr(), "data_disconnect", func, conn_from, conn_port, p_to.to_int(), to_port);
2984 				undo_redo->add_undo_method(script.ptr(), "data_connect", func, conn_from, conn_port, p_to.to_int(), to_port);
2985 			}
2986 		}
2987 		if (!converted) {
2988 			undo_redo->add_do_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
2989 			undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
2990 		} else {
2991 			// this is noice
2992 			undo_redo->add_do_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, conv_node, 0);
2993 			undo_redo->add_do_method(script.ptr(), "data_connect", func, conv_node, 0, p_to.to_int(), to_port);
2994 			// I don't think this is needed but gonna leave it here for now... until I need to finalise it all
2995 			undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, conv_node, 0);
2996 			undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, conv_node, 0, p_to.to_int(), to_port);
2997 		}
2998 		//update nodes in graph
2999 		if (!converted) {
3000 			undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
3001 			undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
3002 			undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
3003 			undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());
3004 		} else {
3005 			undo_redo->add_do_method(this, "_update_graph");
3006 			undo_redo->add_undo_method(this, "_update_graph");
3007 		}
3008 	}
3009 
3010 	undo_redo->add_do_method(this, "_update_graph_connections");
3011 	undo_redo->add_undo_method(this, "_update_graph_connections");
3012 
3013 	undo_redo->commit_action();
3014 }
3015 
_graph_disconnected(const String & p_from,int p_from_slot,const String & p_to,int p_to_slot)3016 void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
3017 
3018 	StringName func = _get_function_of_node(p_from.to_int());
3019 	ERR_FAIL_COND(func != _get_function_of_node(p_to.to_int()));
3020 
3021 	Ref<VisualScriptNode> from_node = script->get_node(func, p_from.to_int());
3022 	ERR_FAIL_COND(!from_node.is_valid());
3023 
3024 	bool from_seq;
3025 	int from_port;
3026 
3027 	if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq))
3028 		return; //can't connect this, it's invalid
3029 
3030 	Ref<VisualScriptNode> to_node = script->get_node(func, p_to.to_int());
3031 	ERR_FAIL_COND(!to_node.is_valid());
3032 
3033 	bool to_seq;
3034 	int to_port;
3035 
3036 	if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq))
3037 		return; //can't connect this, it's invalid
3038 
3039 	ERR_FAIL_COND(from_seq != to_seq);
3040 
3041 	undo_redo->create_action(TTR("Disconnect Nodes"));
3042 
3043 	if (from_seq) {
3044 		undo_redo->add_do_method(script.ptr(), "sequence_disconnect", func, p_from.to_int(), from_port, p_to.to_int());
3045 		undo_redo->add_undo_method(script.ptr(), "sequence_connect", func, p_from.to_int(), from_port, p_to.to_int());
3046 	} else {
3047 
3048 		can_swap = true;
3049 		data_disconnect_node = p_to.to_int();
3050 		data_disconnect_port = to_port;
3051 
3052 		undo_redo->add_do_method(script.ptr(), "data_disconnect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
3053 		undo_redo->add_undo_method(script.ptr(), "data_connect", func, p_from.to_int(), from_port, p_to.to_int(), to_port);
3054 		//update relevant nodes in the graph
3055 		undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
3056 		undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
3057 		undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
3058 		undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());
3059 	}
3060 	undo_redo->add_do_method(this, "_update_graph_connections");
3061 	undo_redo->add_undo_method(this, "_update_graph_connections");
3062 
3063 	undo_redo->commit_action();
3064 }
3065 
_move_nodes_with_rescan(const StringName & p_func_from,const StringName & p_func_to,int p_id)3066 void VisualScriptEditor::_move_nodes_with_rescan(const StringName &p_func_from, const StringName &p_func_to, int p_id) {
3067 
3068 	Set<int> nodes_to_move;
3069 	HashMap<int, Map<int, int> > seqconns_to_move; // from => List(outp, to)
3070 	HashMap<int, Map<int, Pair<int, int> > > dataconns_to_move; // to => List(inp_p => from, outp)
3071 
3072 	nodes_to_move.insert(p_id);
3073 	Set<int> sequence_connections;
3074 	{
3075 		List<VisualScript::SequenceConnection> sequence_conns;
3076 		script->get_sequence_connection_list(p_func_from, &sequence_conns);
3077 
3078 		HashMap<int, Map<int, int> > seqcons; // from => List(out_p => to)
3079 
3080 		for (List<VisualScript::SequenceConnection>::Element *E = sequence_conns.front(); E; E = E->next()) {
3081 			int from = E->get().from_node;
3082 			int to = E->get().to_node;
3083 			int out_p = E->get().from_output;
3084 			if (!seqcons.has(from))
3085 				seqcons.set(from, Map<int, int>());
3086 			seqcons[from].insert(out_p, to);
3087 			sequence_connections.insert(to);
3088 			sequence_connections.insert(from);
3089 		}
3090 
3091 		int conn = p_id;
3092 		List<int> stack;
3093 		HashMap<int, Set<int> > seen; // from, outp
3094 		while (seqcons.has(conn)) {
3095 			for (auto E = seqcons[conn].front(); E; E = E->next()) {
3096 				if (seen.has(conn) && seen[conn].has(E->key())) {
3097 					if (!E->next()) {
3098 						if (stack.size() > 0) {
3099 							conn = stack.back()->get();
3100 							stack.pop_back();
3101 							break;
3102 						}
3103 						conn = -101;
3104 						break;
3105 					}
3106 					continue;
3107 				}
3108 				if (!seen.has(conn))
3109 					seen.set(conn, Set<int>());
3110 				seen[conn].insert(E->key());
3111 				stack.push_back(conn);
3112 				if (!seqconns_to_move.has(conn))
3113 					seqconns_to_move.set(conn, Map<int, int>());
3114 				seqconns_to_move[conn].insert(E->key(), E->get());
3115 				conn = E->get();
3116 				nodes_to_move.insert(conn);
3117 				break;
3118 			}
3119 			if (!seqcons.has(conn) && stack.size() > 0) {
3120 				conn = stack.back()->get();
3121 				stack.pop_back();
3122 			}
3123 		}
3124 	}
3125 
3126 	{
3127 		List<VisualScript::DataConnection> data_connections;
3128 		script->get_data_connection_list(p_func_from, &data_connections);
3129 		int func_from_node_id = script->get_function_node_id(p_func_from);
3130 
3131 		HashMap<int, Map<int, Pair<int, int> > > connections;
3132 
3133 		for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
3134 			int from = E->get().from_node;
3135 			int to = E->get().to_node;
3136 			int out_p = E->get().from_port;
3137 			int in_p = E->get().to_port;
3138 
3139 			// skip if the from_node is a function node
3140 			if (from == func_from_node_id) {
3141 				continue;
3142 			}
3143 
3144 			if (!connections.has(to))
3145 				connections.set(to, Map<int, Pair<int, int> >());
3146 			connections[to].insert(in_p, Pair<int, int>(from, out_p));
3147 		}
3148 
3149 		// go through the HashMap and do all sorts of crazy ass stuff now...
3150 		Set<int> nodes_to_be_added;
3151 		for (Set<int>::Element *F = nodes_to_move.front(); F; F = F->next()) {
3152 			HashMap<int, Set<int> > seen;
3153 			List<int> stack;
3154 			int id = F->get();
3155 			while (connections.has(id)) {
3156 				for (auto E = connections[id].front(); E; E = E->next()) {
3157 					if (seen.has(id) && seen[id].has(E->key())) {
3158 						if (!E->next()) {
3159 							if (stack.size() > 0) {
3160 								id = stack.back()->get();
3161 								stack.pop_back();
3162 								break;
3163 							}
3164 							id = -11; // I assume ids can't be negative should confirm it...
3165 							break;
3166 						}
3167 						continue;
3168 					}
3169 
3170 					if (sequence_connections.has(E->get().first)) {
3171 						if (!nodes_to_move.has(E->get().first)) {
3172 							if (stack.size() > 0) {
3173 								id = stack.back()->get();
3174 								stack.pop_back();
3175 								break;
3176 							}
3177 							id = -11; // I assume ids can't be negative should confirm it...
3178 							break;
3179 						}
3180 					}
3181 
3182 					if (!seen.has(id))
3183 						seen.set(id, Set<int>());
3184 					seen[id].insert(E->key());
3185 					stack.push_back(id);
3186 					if (!dataconns_to_move.has(id))
3187 						dataconns_to_move.set(id, Map<int, Pair<int, int> >());
3188 					dataconns_to_move[id].insert(E->key(), Pair<int, int>(E->get().first, E->get().second));
3189 					id = E->get().first;
3190 					nodes_to_be_added.insert(id);
3191 					break;
3192 				}
3193 				if (!connections.has(id) && stack.size() > 0) {
3194 					id = stack.back()->get();
3195 					stack.pop_back();
3196 				}
3197 			}
3198 		}
3199 		for (Set<int>::Element *E = nodes_to_be_added.front(); E; E = E->next()) {
3200 			nodes_to_move.insert(E->get());
3201 		}
3202 	}
3203 
3204 	// * this is primarily for the sake of the having proper undo
3205 	List<VisualScript::SequenceConnection> seqext;
3206 	List<VisualScript::DataConnection> dataext;
3207 
3208 	List<VisualScript::SequenceConnection> seq_connections;
3209 	script->get_sequence_connection_list(p_func_from, &seq_connections);
3210 
3211 	for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) {
3212 		if (!nodes_to_move.has(E->get().from_node) && nodes_to_move.has(E->get().to_node)) {
3213 			seqext.push_back(E->get());
3214 		} else if (nodes_to_move.has(E->get().from_node) && !nodes_to_move.has(E->get().to_node)) {
3215 			seqext.push_back(E->get());
3216 		}
3217 	}
3218 
3219 	List<VisualScript::DataConnection> data_connections;
3220 	script->get_data_connection_list(p_func_from, &data_connections);
3221 
3222 	for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
3223 		if (!nodes_to_move.has(E->get().from_node) && nodes_to_move.has(E->get().to_node)) {
3224 			dataext.push_back(E->get());
3225 		} else if (nodes_to_move.has(E->get().from_node) && !nodes_to_move.has(E->get().to_node)) {
3226 			dataext.push_back(E->get());
3227 		}
3228 	}
3229 
3230 	// undo_redo->create_action("Rescan Functions");
3231 
3232 	for (Set<int>::Element *E = nodes_to_move.front(); E; E = E->next()) {
3233 		int id = E->get();
3234 
3235 		undo_redo->add_do_method(script.ptr(), "remove_node", p_func_from, id);
3236 		undo_redo->add_do_method(script.ptr(), "add_node", p_func_to, id, script->get_node(p_func_from, id), script->get_node_position(p_func_from, id));
3237 
3238 		undo_redo->add_undo_method(script.ptr(), "remove_node", p_func_to, id);
3239 		undo_redo->add_undo_method(script.ptr(), "add_node", p_func_from, id, script->get_node(p_func_from, id), script->get_node_position(p_func_from, id));
3240 	}
3241 
3242 	List<int> skeys;
3243 	seqconns_to_move.get_key_list(&skeys);
3244 	for (List<int>::Element *E = skeys.front(); E; E = E->next()) {
3245 		int from_node = E->get();
3246 		for (Map<int, int>::Element *F = seqconns_to_move[from_node].front(); F; F = F->next()) {
3247 			int from_port = F->key();
3248 			int to_node = F->get();
3249 			undo_redo->add_do_method(script.ptr(), "sequence_connect", p_func_to, from_node, from_port, to_node);
3250 			undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_func_from, from_node, from_port, to_node);
3251 		}
3252 	}
3253 
3254 	List<int> keys;
3255 	dataconns_to_move.get_key_list(&keys);
3256 	for (List<int>::Element *E = keys.front(); E; E = E->next()) {
3257 		int to_node = E->get(); // to_node
3258 		for (Map<int, Pair<int, int> >::Element *F = dataconns_to_move[E->get()].front(); F; F = F->next()) {
3259 			int inp_p = F->key();
3260 			Pair<int, int> fro = F->get();
3261 
3262 			undo_redo->add_do_method(script.ptr(), "data_connect", p_func_to, fro.first, fro.second, to_node, inp_p);
3263 			undo_redo->add_undo_method(script.ptr(), "data_connect", p_func_from, fro.first, fro.second, to_node, inp_p);
3264 		}
3265 	}
3266 
3267 	// this to have proper undo operations
3268 	for (List<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
3269 		undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_func_from, E->get().from_node, E->get().from_output, E->get().to_node);
3270 	}
3271 	for (List<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
3272 		undo_redo->add_undo_method(script.ptr(), "data_connect", p_func_from, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
3273 	}
3274 	// this doesn't need do methods as they are handled by the subsequent do calls implicitly
3275 
3276 	undo_redo->add_do_method(this, "_update_graph");
3277 	undo_redo->add_undo_method(this, "_update_graph");
3278 
3279 	// undo_redo->commit_action();
3280 }
3281 
_graph_connect_to_empty(const String & p_from,int p_from_slot,const Vector2 & p_release_pos)3282 void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos) {
3283 
3284 	Node *node = graph->get_node(p_from);
3285 	GraphNode *gn = Object::cast_to<GraphNode>(node);
3286 	if (!gn)
3287 		return;
3288 
3289 	StringName func = _get_function_of_node(p_from.to_int());
3290 
3291 	Ref<VisualScriptNode> vsn = script->get_node(func, p_from.to_int());
3292 	if (!vsn.is_valid())
3293 		return;
3294 
3295 	port_action_pos = p_release_pos;
3296 
3297 	if (p_from_slot < vsn->get_output_sequence_port_count()) {
3298 
3299 		port_action_node = p_from.to_int();
3300 		port_action_output = p_from_slot;
3301 		_port_action_menu(CREATE_ACTION, func);
3302 	} else {
3303 		port_action_output = p_from_slot - vsn->get_output_sequence_port_count();
3304 		port_action_node = p_from.to_int();
3305 		_port_action_menu(CREATE_CALL_SET_GET, func);
3306 	}
3307 }
3308 
_guess_output_type(int p_port_action_node,int p_port_action_output,Set<int> & visited_nodes)3309 VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) {
3310 
3311 	VisualScriptNode::TypeGuess tg;
3312 	tg.type = Variant::NIL;
3313 
3314 	if (visited_nodes.has(p_port_action_node))
3315 		return tg; //no loop
3316 
3317 	visited_nodes.insert(p_port_action_node);
3318 
3319 	StringName func = _get_function_of_node(p_port_action_node);
3320 
3321 	Ref<VisualScriptNode> node = script->get_node(func, p_port_action_node);
3322 
3323 	if (!node.is_valid()) {
3324 
3325 		return tg;
3326 	}
3327 
3328 	Vector<VisualScriptNode::TypeGuess> in_guesses;
3329 
3330 	for (int i = 0; i < node->get_input_value_port_count(); i++) {
3331 		PropertyInfo pi = node->get_input_value_port_info(i);
3332 		VisualScriptNode::TypeGuess g;
3333 		g.type = pi.type;
3334 
3335 		if (g.type == Variant::NIL || g.type == Variant::OBJECT) {
3336 			//any or object input, must further guess what this is
3337 			int from_node;
3338 			int from_port;
3339 
3340 			if (script->get_input_value_port_connection_source(func, p_port_action_node, i, &from_node, &from_port)) {
3341 
3342 				g = _guess_output_type(from_node, from_port, visited_nodes);
3343 			} else {
3344 				Variant defval = node->get_default_input_value(i);
3345 				if (defval.get_type() == Variant::OBJECT) {
3346 
3347 					Object *obj = defval;
3348 
3349 					if (obj) {
3350 
3351 						g.type = Variant::OBJECT;
3352 						g.gdclass = obj->get_class();
3353 						g.script = obj->get_script();
3354 					}
3355 				}
3356 			}
3357 		}
3358 
3359 		in_guesses.push_back(g);
3360 	}
3361 
3362 	return node->guess_output_type(in_guesses.ptrw(), p_port_action_output);
3363 }
3364 
_port_action_menu(int p_option,const StringName & func)3365 void VisualScriptEditor::_port_action_menu(int p_option, const StringName &func) {
3366 
3367 	Vector2 ofs = graph->get_scroll_ofs() + port_action_pos;
3368 	if (graph->is_using_snap()) {
3369 		int snap = graph->get_snap();
3370 		ofs = ofs.snapped(Vector2(snap, snap));
3371 	}
3372 	ofs /= EDSCALE;
3373 
3374 	Set<int> vn;
3375 
3376 	switch (p_option) {
3377 
3378 		case CREATE_CALL_SET_GET: {
3379 			Ref<VisualScriptFunctionCall> n;
3380 			n.instance();
3381 
3382 			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
3383 
3384 			if (tg.gdclass != StringName()) {
3385 				n->set_base_type(tg.gdclass);
3386 			} else {
3387 				n->set_base_type("Object");
3388 			}
3389 			String type_string;
3390 			if (script->get_node(func, port_action_node)->get_output_value_port_count() > 0) {
3391 				type_string = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
3392 			}
3393 			if (tg.type == Variant::OBJECT) {
3394 				if (tg.script.is_valid()) {
3395 					new_connect_node_select->select_from_script(tg.script, "");
3396 				} else if (type_string != String()) {
3397 					new_connect_node_select->select_from_base_type(type_string);
3398 				} else {
3399 					new_connect_node_select->select_from_base_type(n->get_base_type());
3400 				}
3401 			} else if (tg.type == Variant::NIL) {
3402 				new_connect_node_select->select_from_base_type("");
3403 			} else {
3404 				new_connect_node_select->select_from_basic_type(tg.type);
3405 			}
3406 			// ensure that the dialog fits inside the graph
3407 			Vector2 pos = mouse_up_position;
3408 			Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
3409 			pos.x = pos.x > bounds.x ? bounds.x : pos.x;
3410 			pos.y = pos.y > bounds.y ? bounds.y : pos.y;
3411 			new_connect_node_select->set_position(pos);
3412 		} break;
3413 		case CREATE_ACTION: {
3414 			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
3415 			PropertyInfo property_info;
3416 			if (script->get_node(func, port_action_node)->get_output_value_port_count() > 0) {
3417 				property_info = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output);
3418 			}
3419 			if (tg.type == Variant::OBJECT) {
3420 				if (property_info.type == Variant::OBJECT && property_info.hint_string != String()) {
3421 					new_connect_node_select->select_from_action(property_info.hint_string);
3422 				} else {
3423 					new_connect_node_select->select_from_action("");
3424 				}
3425 			} else if (tg.type == Variant::NIL) {
3426 				new_connect_node_select->select_from_action("");
3427 			} else {
3428 				new_connect_node_select->select_from_action(Variant::get_type_name(tg.type));
3429 			}
3430 			// ensure that the dialog fits inside the graph
3431 			Vector2 pos = mouse_up_position;
3432 			Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
3433 			pos.x = pos.x > bounds.x ? bounds.x : pos.x;
3434 			pos.y = pos.y > bounds.y ? bounds.y : pos.y;
3435 			new_connect_node_select->set_position(pos);
3436 		} break;
3437 	}
3438 }
3439 
connect_data(Ref<VisualScriptNode> vnode_old,Ref<VisualScriptNode> vnode,int new_id)3440 void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) {
3441 
3442 	undo_redo->create_action(TTR("Connect Node Data"));
3443 	VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr());
3444 	if (vnode_return != NULL && vnode_old->get_output_value_port_count() > 0) {
3445 		vnode_return->set_enable_return_value(true);
3446 	}
3447 	if (vnode_old->get_output_value_port_count() <= 0) {
3448 		undo_redo->commit_action();
3449 		return;
3450 	}
3451 	if (vnode->get_input_value_port_count() <= 0) {
3452 		undo_redo->commit_action();
3453 		return;
3454 	}
3455 	int port = port_action_output;
3456 	int value_count = vnode_old->get_output_value_port_count();
3457 	if (port >= value_count) {
3458 		port = 0;
3459 	}
3460 	StringName func = _get_function_of_node(port_action_node);
3461 	undo_redo->add_do_method(script.ptr(), "data_connect", func, port_action_node, port, new_id, 0);
3462 	undo_redo->add_undo_method(script.ptr(), "data_disconnect", func, port_action_node, port, new_id, 0);
3463 	undo_redo->commit_action();
3464 }
3465 
_selected_connect_node(const String & p_text,const String & p_category,const bool p_connecting)3466 void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) {
3467 
3468 	Vector2 ofs = graph->get_scroll_ofs() + port_action_pos;
3469 	if (graph->is_using_snap()) {
3470 		int snap = graph->get_snap();
3471 		ofs = ofs.snapped(Vector2(snap, snap));
3472 	}
3473 	ofs /= EDSCALE;
3474 	ofs /= graph->get_zoom();
3475 
3476 	Set<int> vn;
3477 
3478 	bool port_node_exists = true;
3479 
3480 	StringName func = _get_function_of_node(port_action_node);
3481 	if (func == StringName()) {
3482 		func = default_func;
3483 		port_node_exists = false;
3484 	}
3485 
3486 	if (p_category == "visualscript") {
3487 		Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text);
3488 		Ref<VisualScriptNode> vnode_old;
3489 		if (port_node_exists)
3490 			vnode_old = script->get_node(func, port_action_node);
3491 		int new_id = script->get_available_id();
3492 
3493 		if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr()) && vnode_old.is_valid()) {
3494 			Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;
3495 			Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type);
3496 		}
3497 
3498 		if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr()) && vnode_old.is_valid()) {
3499 			Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;
3500 			String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string;
3501 
3502 			if (type == Variant::OBJECT) {
3503 				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name);
3504 			} else if (type == Variant::NIL) {
3505 				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type("");
3506 			} else {
3507 				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type));
3508 			}
3509 		}
3510 
3511 		undo_redo->create_action(TTR("Add Node"));
3512 		undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode_new, ofs);
3513 		if (vnode_old.is_valid() && p_connecting) {
3514 			connect_seq(vnode_old, vnode_new, new_id);
3515 			connect_data(vnode_old, vnode_new, new_id);
3516 		}
3517 
3518 		undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
3519 		undo_redo->add_do_method(this, "_update_graph");
3520 		undo_redo->add_undo_method(this, "_update_graph");
3521 		undo_redo->commit_action();
3522 		return;
3523 	}
3524 
3525 	Ref<VisualScriptNode> vnode;
3526 	Ref<VisualScriptPropertySet> script_prop_set;
3527 
3528 	if (p_category == String("method")) {
3529 
3530 		Ref<VisualScriptFunctionCall> n;
3531 		n.instance();
3532 		vnode = n;
3533 	} else if (p_category == String("set")) {
3534 
3535 		Ref<VisualScriptPropertySet> n;
3536 		n.instance();
3537 		vnode = n;
3538 		script_prop_set = n;
3539 	} else if (p_category == String("get")) {
3540 
3541 		Ref<VisualScriptPropertyGet> n;
3542 		n.instance();
3543 		n->set_property(p_text);
3544 		vnode = n;
3545 	}
3546 
3547 	if (p_category == String("action")) {
3548 		if (p_text == "VisualScriptCondition") {
3549 
3550 			Ref<VisualScriptCondition> n;
3551 			n.instance();
3552 			vnode = n;
3553 		}
3554 		if (p_text == "VisualScriptSwitch") {
3555 
3556 			Ref<VisualScriptSwitch> n;
3557 			n.instance();
3558 			vnode = n;
3559 		} else if (p_text == "VisualScriptSequence") {
3560 
3561 			Ref<VisualScriptSequence> n;
3562 			n.instance();
3563 			vnode = n;
3564 		} else if (p_text == "VisualScriptIterator") {
3565 
3566 			Ref<VisualScriptIterator> n;
3567 			n.instance();
3568 			vnode = n;
3569 		} else if (p_text == "VisualScriptWhile") {
3570 
3571 			Ref<VisualScriptWhile> n;
3572 			n.instance();
3573 			vnode = n;
3574 		} else if (p_text == "VisualScriptReturn") {
3575 
3576 			Ref<VisualScriptReturn> n;
3577 			n.instance();
3578 			vnode = n;
3579 		}
3580 	}
3581 
3582 	int new_id = script->get_available_id();
3583 	undo_redo->create_action(TTR("Add Node"));
3584 	undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode, ofs);
3585 	undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
3586 	undo_redo->add_do_method(this, "_update_graph", new_id);
3587 	undo_redo->add_undo_method(this, "_update_graph", new_id);
3588 	undo_redo->commit_action();
3589 
3590 	if (script_prop_set.is_valid())
3591 		script_prop_set->set_property(p_text);
3592 
3593 	port_action_new_node = new_id;
3594 
3595 	Ref<VisualScriptNode> vsn = script->get_node(func, port_action_new_node);
3596 
3597 	if (Object::cast_to<VisualScriptFunctionCall>(vsn.ptr())) {
3598 
3599 		Ref<VisualScriptFunctionCall> vsfc = vsn;
3600 		vsfc->set_function(p_text);
3601 
3602 		if (port_node_exists && p_connecting) {
3603 			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
3604 
3605 			if (tg.type == Variant::OBJECT) {
3606 				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
3607 				vsfc->set_base_type(String(""));
3608 				if (tg.gdclass != StringName()) {
3609 					vsfc->set_base_type(tg.gdclass);
3610 
3611 				} else if (script->get_node(func, port_action_node).is_valid()) {
3612 					PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
3613 					String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
3614 
3615 					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
3616 						vsfc->set_base_type(base_type);
3617 					}
3618 					if (p_text == "call" || p_text == "call_deferred") {
3619 						vsfc->set_function(String(""));
3620 					}
3621 				}
3622 				if (tg.script.is_valid()) {
3623 					vsfc->set_base_script(tg.script->get_path());
3624 				}
3625 			} else if (tg.type == Variant::NIL) {
3626 				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
3627 				vsfc->set_base_type(String(""));
3628 			} else {
3629 				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
3630 				vsfc->set_basic_type(tg.type);
3631 			}
3632 		}
3633 	}
3634 
3635 	if (port_node_exists && p_connecting) {
3636 		if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) {
3637 			Ref<VisualScriptPropertySet> vsp = vsn;
3638 
3639 			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
3640 			if (tg.type == Variant::OBJECT) {
3641 				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
3642 				vsp->set_base_type(String(""));
3643 				if (tg.gdclass != StringName()) {
3644 					vsp->set_base_type(tg.gdclass);
3645 
3646 				} else if (script->get_node(func, port_action_node).is_valid()) {
3647 					PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
3648 					String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
3649 
3650 					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
3651 						vsp->set_base_type(base_type);
3652 					}
3653 				}
3654 				if (tg.script.is_valid()) {
3655 					vsp->set_base_script(tg.script->get_path());
3656 				}
3657 			} else if (tg.type == Variant::NIL) {
3658 				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
3659 				vsp->set_base_type(String(""));
3660 			} else {
3661 				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);
3662 				vsp->set_basic_type(tg.type);
3663 			}
3664 		}
3665 
3666 		if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) {
3667 			Ref<VisualScriptPropertyGet> vsp = vsn;
3668 
3669 			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
3670 			if (tg.type == Variant::OBJECT) {
3671 				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
3672 				vsp->set_base_type(String(""));
3673 				if (tg.gdclass != StringName()) {
3674 					vsp->set_base_type(tg.gdclass);
3675 
3676 				} else if (script->get_node(func, port_action_node).is_valid()) {
3677 					PropertyHint hint = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint;
3678 					String base_type = script->get_node(func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
3679 					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
3680 						vsp->set_base_type(base_type);
3681 					}
3682 				}
3683 				if (tg.script.is_valid()) {
3684 					vsp->set_base_script(tg.script->get_path());
3685 				}
3686 			} else if (tg.type == Variant::NIL) {
3687 				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
3688 				vsp->set_base_type(String(""));
3689 			} else {
3690 				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);
3691 				vsp->set_basic_type(tg.type);
3692 			}
3693 		}
3694 	}
3695 	if (port_node_exists) {
3696 		Ref<VisualScriptNode> vnode_old = script->get_node(func, port_action_node);
3697 		if (vnode_old.is_valid() && p_connecting) {
3698 			connect_seq(vnode_old, vnode, port_action_new_node);
3699 			connect_data(vnode_old, vnode, port_action_new_node);
3700 		}
3701 	}
3702 	_update_graph(port_action_new_node);
3703 	if (port_node_exists)
3704 		_update_graph_connections();
3705 }
3706 
connect_seq(Ref<VisualScriptNode> vnode_old,Ref<VisualScriptNode> vnode_new,int new_id)3707 void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {
3708 
3709 	VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr());
3710 	if (vnode_operator != NULL && !vnode_operator->has_input_sequence_port()) {
3711 		return;
3712 	}
3713 	VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr());
3714 	if (vnode_constructor != NULL) {
3715 		return;
3716 	}
3717 	if (vnode_old->get_output_sequence_port_count() <= 0) {
3718 		return;
3719 	}
3720 	if (!vnode_new->has_input_sequence_port()) {
3721 		return;
3722 	}
3723 
3724 	StringName func = _get_function_of_node(port_action_node);
3725 
3726 	undo_redo->create_action(TTR("Connect Node Sequence"));
3727 	int pass_port = -vnode_old->get_output_sequence_port_count() + 1;
3728 	int return_port = port_action_output - 1;
3729 	if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") &&
3730 			!script->get_output_sequence_ports_connected(func, port_action_node).has(pass_port)) {
3731 		undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, pass_port, new_id);
3732 		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, pass_port, new_id);
3733 	} else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") &&
3734 			   !script->get_output_sequence_ports_connected(func, port_action_node).has(return_port)) {
3735 		undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, return_port, new_id);
3736 		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, return_port, new_id);
3737 	} else {
3738 		for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) {
3739 			int count = vnode_old->get_output_sequence_port_count();
3740 			if (port_action_output < count && !script->get_output_sequence_ports_connected(func, port_action_node).has(port_action_output)) {
3741 				undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, port_action_output, new_id);
3742 				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, port_action_output, new_id);
3743 				break;
3744 			} else if (!script->get_output_sequence_ports_connected(func, port_action_node).has(port)) {
3745 				undo_redo->add_do_method(script.ptr(), "sequence_connect", func, port_action_node, port, new_id);
3746 				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", func, port_action_node, port, new_id);
3747 				break;
3748 			}
3749 		}
3750 	}
3751 
3752 	undo_redo->commit_action();
3753 }
3754 
_selected_new_virtual_method(const String & p_text,const String & p_category,const bool p_connecting)3755 void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) {
3756 
3757 	String name = p_text;
3758 	if (script->has_function(name)) {
3759 		EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name));
3760 		return;
3761 	}
3762 
3763 	MethodInfo minfo;
3764 	{
3765 		List<MethodInfo> methods;
3766 		bool found = false;
3767 		ClassDB::get_virtual_methods(script->get_instance_base_type(), &methods);
3768 		for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
3769 			if (E->get().name == name) {
3770 				minfo = E->get();
3771 				found = true;
3772 			}
3773 		}
3774 
3775 		ERR_FAIL_COND(!found);
3776 	}
3777 
3778 	selected = name;
3779 	Ref<VisualScriptFunction> func_node;
3780 	func_node.instance();
3781 	func_node->set_name(name);
3782 
3783 	undo_redo->create_action(TTR("Add Function"));
3784 	undo_redo->add_do_method(script.ptr(), "add_function", name);
3785 
3786 	for (int i = 0; i < minfo.arguments.size(); i++) {
3787 		func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string);
3788 	}
3789 
3790 	Vector2 ofs = _get_available_pos();
3791 
3792 	undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id(), func_node, ofs);
3793 	if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
3794 		Ref<VisualScriptReturn> ret_node;
3795 		ret_node.instance();
3796 		ret_node->set_return_type(minfo.return_val.type);
3797 		ret_node->set_enable_return_value(true);
3798 		ret_node->set_name(name);
3799 		undo_redo->add_do_method(script.ptr(), "add_node", name, script->get_available_id() + 1, ret_node, _get_available_pos(false, ofs + Vector2(500, 0)));
3800 	}
3801 
3802 	undo_redo->add_undo_method(script.ptr(), "remove_function", name);
3803 	undo_redo->add_do_method(this, "_update_members");
3804 	undo_redo->add_undo_method(this, "_update_members");
3805 	undo_redo->add_do_method(this, "_update_graph");
3806 	undo_redo->add_undo_method(this, "_update_graph");
3807 
3808 	undo_redo->commit_action();
3809 
3810 	_update_graph();
3811 }
3812 
_cancel_connect_node()3813 void VisualScriptEditor::_cancel_connect_node() {
3814 	// ensure the cancel is done
3815 	port_action_new_node = -1;
3816 }
3817 
_create_new_node_from_name(const String & p_text,const Vector2 & p_point,const StringName & p_func)3818 int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point, const StringName &p_func) {
3819 
3820 	StringName func = default_func;
3821 	if (p_func != StringName())
3822 		func = p_func;
3823 
3824 	Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text);
3825 	int new_id = script->get_available_id();
3826 	undo_redo->create_action(TTR("Add Node"));
3827 	undo_redo->add_do_method(script.ptr(), "add_node", func, new_id, vnode, p_point);
3828 	undo_redo->add_undo_method(script.ptr(), "remove_node", func, new_id);
3829 	undo_redo->add_do_method(this, "_update_graph");
3830 	undo_redo->add_undo_method(this, "_update_graph");
3831 	undo_redo->commit_action();
3832 	return new_id;
3833 }
3834 
_default_value_changed()3835 void VisualScriptEditor::_default_value_changed() {
3836 
3837 	Ref<VisualScriptNode> vsn = script->get_node(_get_function_of_node(editing_id), editing_id);
3838 	if (vsn.is_null())
3839 		return;
3840 
3841 	undo_redo->create_action(TTR("Change Input Value"));
3842 	undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, default_value_edit->get_variant());
3843 	undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input));
3844 
3845 	undo_redo->add_do_method(this, "_update_graph", editing_id);
3846 	undo_redo->add_undo_method(this, "_update_graph", editing_id);
3847 	undo_redo->commit_action();
3848 }
3849 
_default_value_edited(Node * p_button,int p_id,int p_input_port)3850 void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_input_port) {
3851 
3852 	Ref<VisualScriptNode> vsn = script->get_node(_get_function_of_node(p_id), p_id);
3853 	if (vsn.is_null())
3854 		return;
3855 
3856 	PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port);
3857 	Variant existing = vsn->get_default_input_value(p_input_port);
3858 	if (pinfo.type != Variant::NIL && existing.get_type() != pinfo.type) {
3859 
3860 		Variant::CallError ce;
3861 		const Variant *existingp = &existing;
3862 		existing = Variant::construct(pinfo.type, &existingp, 1, ce, false);
3863 	}
3864 
3865 	default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y));
3866 	default_value_edit->set_size(Size2(1, 1));
3867 
3868 	if (pinfo.type == Variant::NODE_PATH) {
3869 
3870 		Node *edited_scene = get_tree()->get_edited_scene_root();
3871 		if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open)
3872 			Node *script_node = _find_script_node(edited_scene, edited_scene, script);
3873 
3874 			if (script_node) {
3875 				//pick a node relative to the script, IF the script exists
3876 				pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
3877 				pinfo.hint_string = script_node->get_path();
3878 			} else {
3879 				//pick a path relative to edited scene
3880 				pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
3881 				pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path();
3882 			}
3883 		}
3884 	}
3885 
3886 	if (default_value_edit->edit(NULL, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
3887 		if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT)
3888 			default_value_edit->popup_centered_ratio();
3889 		else
3890 			default_value_edit->popup();
3891 	}
3892 
3893 	editing_id = p_id;
3894 	editing_input = p_input_port;
3895 }
3896 
_show_hint(const String & p_hint)3897 void VisualScriptEditor::_show_hint(const String &p_hint) {
3898 
3899 	hint_text->set_text(p_hint);
3900 	hint_text->show();
3901 	hint_text_timer->start();
3902 }
3903 
_hide_timer()3904 void VisualScriptEditor::_hide_timer() {
3905 
3906 	hint_text->hide();
3907 }
3908 
_notification(int p_what)3909 void VisualScriptEditor::_notification(int p_what) {
3910 
3911 	switch (p_what) {
3912 		case NOTIFICATION_READY: {
3913 			variable_editor->connect("changed", this, "_update_members");
3914 			signal_editor->connect("changed", this, "_update_members");
3915 			FALLTHROUGH;
3916 		}
3917 		case NOTIFICATION_THEME_CHANGED: {
3918 			if (p_what != NOTIFICATION_READY && !is_visible_in_tree()) {
3919 				return;
3920 			}
3921 
3922 			edit_variable_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
3923 			edit_signal_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
3924 			func_input_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
3925 
3926 			Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
3927 
3928 			bool dark_theme = tm->get_constant("dark_theme", "Editor");
3929 
3930 			List<Pair<String, Color> > colors;
3931 			if (dark_theme) {
3932 				colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96)));
3933 				colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51)));
3934 				colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81)));
3935 				colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87)));
3936 				colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96)));
3937 				colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69)));
3938 			} else {
3939 				colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26)));
3940 				colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38)));
3941 				colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51)));
3942 				colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82)));
3943 				colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95)));
3944 				colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
3945 			}
3946 
3947 			for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) {
3948 				Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
3949 				if (!sb.is_null()) {
3950 					Ref<StyleBoxFlat> frame_style = sb->duplicate();
3951 					Color c = sb->get_border_color();
3952 					Color cn = E->get().second;
3953 					cn.a = c.a;
3954 					frame_style->set_border_color(cn);
3955 					node_styles[E->get().first] = frame_style;
3956 				}
3957 			}
3958 
3959 			if (is_visible_in_tree() && script.is_valid()) {
3960 				_update_members();
3961 				_update_graph();
3962 			}
3963 		} break;
3964 		case NOTIFICATION_VISIBILITY_CHANGED: {
3965 			members_section->set_visible(is_visible_in_tree());
3966 		} break;
3967 	}
3968 }
3969 
_graph_ofs_changed(const Vector2 & p_ofs)3970 void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) {
3971 
3972 	if (updating_graph || !script.is_valid())
3973 		return;
3974 
3975 	updating_graph = true;
3976 
3977 	// Just use the default func for all the properties that need to be handled for drawing rather than adding to the Visual Script Class
3978 	if (script->has_function(default_func)) {
3979 		script->set_function_scroll(default_func, graph->get_scroll_ofs() / EDSCALE);
3980 		script->set_edited(true);
3981 	}
3982 	updating_graph = false;
3983 }
3984 
_comment_node_resized(const Vector2 & p_new_size,int p_node)3985 void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_node) {
3986 
3987 	if (updating_graph)
3988 		return;
3989 
3990 	StringName func = _get_function_of_node(p_node);
3991 
3992 	Ref<VisualScriptComment> vsc = script->get_node(func, p_node);
3993 	if (vsc.is_null())
3994 		return;
3995 
3996 	Node *node = graph->get_node(itos(p_node));
3997 	GraphNode *gn = Object::cast_to<GraphNode>(node);
3998 	if (!gn)
3999 		return;
4000 
4001 	updating_graph = true;
4002 
4003 	graph->set_block_minimum_size_adjust(true); //faster resize
4004 
4005 	undo_redo->create_action(TTR("Resize Comment"), UndoRedo::MERGE_ENDS);
4006 	undo_redo->add_do_method(vsc.ptr(), "set_size", p_new_size / EDSCALE);
4007 	undo_redo->add_undo_method(vsc.ptr(), "set_size", vsc->get_size());
4008 	undo_redo->commit_action();
4009 
4010 	gn->set_custom_minimum_size(p_new_size);
4011 	gn->set_size(Size2(1, 1));
4012 	graph->set_block_minimum_size_adjust(false);
4013 	updating_graph = false;
4014 }
4015 
_menu_option(int p_what)4016 void VisualScriptEditor::_menu_option(int p_what) {
4017 
4018 	switch (p_what) {
4019 		case EDIT_DELETE_NODES: {
4020 			_on_nodes_delete();
4021 		} break;
4022 		case EDIT_TOGGLE_BREAKPOINT: {
4023 
4024 			List<String> reselect;
4025 			for (int i = 0; i < graph->get_child_count(); i++) {
4026 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
4027 				if (gn) {
4028 					if (gn->is_selected()) {
4029 						int id = String(gn->get_name()).to_int();
4030 						StringName func = _get_function_of_node(id);
4031 						Ref<VisualScriptNode> vsn = script->get_node(func, id);
4032 						if (vsn.is_valid()) {
4033 							vsn->set_breakpoint(!vsn->is_breakpoint());
4034 							reselect.push_back(gn->get_name());
4035 						}
4036 					}
4037 				}
4038 			}
4039 
4040 			_update_graph();
4041 
4042 			for (List<String>::Element *E = reselect.front(); E; E = E->next()) {
4043 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E->get()));
4044 				gn->set_selected(true);
4045 			}
4046 
4047 		} break;
4048 		case EDIT_FIND_NODE_TYPE: {
4049 			_generic_search(script->get_instance_base_type());
4050 		} break;
4051 		case EDIT_COPY_NODES:
4052 		case EDIT_CUT_NODES: {
4053 			if (!script->has_function(default_func))
4054 				break;
4055 
4056 			clipboard->nodes.clear();
4057 			clipboard->data_connections.clear();
4058 			clipboard->sequence_connections.clear();
4059 
4060 			Set<String> funcs;
4061 			for (int i = 0; i < graph->get_child_count(); i++) {
4062 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
4063 				if (gn) {
4064 					if (gn->is_selected()) {
4065 
4066 						int id = String(gn->get_name()).to_int();
4067 						StringName func = _get_function_of_node(id);
4068 						Ref<VisualScriptNode> node = script->get_node(func, id);
4069 						if (Object::cast_to<VisualScriptFunction>(*node)) {
4070 							EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node."));
4071 							return;
4072 						}
4073 						if (node.is_valid()) {
4074 							clipboard->nodes[id] = node->duplicate(true);
4075 							clipboard->nodes_positions[id] = script->get_node_position(func, id);
4076 							funcs.insert(String(func));
4077 						}
4078 					}
4079 				}
4080 			}
4081 
4082 			if (clipboard->nodes.empty())
4083 				break;
4084 
4085 			for (Set<String>::Element *F = funcs.front(); F; F = F->next()) {
4086 				List<VisualScript::SequenceConnection> sequence_connections;
4087 
4088 				script->get_sequence_connection_list(F->get(), &sequence_connections);
4089 
4090 				for (List<VisualScript::SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
4091 
4092 					if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
4093 
4094 						clipboard->sequence_connections.insert(E->get());
4095 					}
4096 				}
4097 
4098 				List<VisualScript::DataConnection> data_connections;
4099 
4100 				script->get_data_connection_list(F->get(), &data_connections);
4101 
4102 				for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
4103 
4104 					if (clipboard->nodes.has(E->get().from_node) && clipboard->nodes.has(E->get().to_node)) {
4105 
4106 						clipboard->data_connections.insert(E->get());
4107 					}
4108 				}
4109 			}
4110 			if (p_what == EDIT_CUT_NODES) {
4111 				_on_nodes_delete(); // oh yeah, also delete on cut
4112 			}
4113 
4114 		} break;
4115 		case EDIT_PASTE_NODES: {
4116 			if (!script->has_function(default_func))
4117 				break;
4118 
4119 			if (clipboard->nodes.empty()) {
4120 				EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!"));
4121 				break;
4122 			}
4123 
4124 			Map<int, int> remap;
4125 
4126 			undo_redo->create_action(TTR("Paste VisualScript Nodes"));
4127 			int idc = script->get_available_id() + 1;
4128 
4129 			Set<int> to_select;
4130 
4131 			Set<Vector2> existing_positions;
4132 
4133 			{
4134 				List<StringName> functions;
4135 				script->get_function_list(&functions);
4136 				for (List<StringName>::Element *F = functions.front(); F; F = F->next()) {
4137 					List<int> nodes;
4138 					script->get_node_list(F->get(), &nodes);
4139 					for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
4140 						Vector2 pos = script->get_node_position(F->get(), E->get()).snapped(Vector2(2, 2));
4141 						existing_positions.insert(pos);
4142 					}
4143 				}
4144 			}
4145 
4146 			for (Map<int, Ref<VisualScriptNode> >::Element *E = clipboard->nodes.front(); E; E = E->next()) {
4147 
4148 				Ref<VisualScriptNode> node = E->get()->duplicate();
4149 
4150 				int new_id = idc++;
4151 				to_select.insert(new_id);
4152 
4153 				remap[E->key()] = new_id;
4154 
4155 				Vector2 paste_pos = clipboard->nodes_positions[E->key()];
4156 
4157 				while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) {
4158 					paste_pos += Vector2(20, 20) * EDSCALE;
4159 				}
4160 
4161 				undo_redo->add_do_method(script.ptr(), "add_node", default_func, new_id, node, paste_pos);
4162 				undo_redo->add_undo_method(script.ptr(), "remove_node", default_func, new_id);
4163 			}
4164 
4165 			for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {
4166 
4167 				undo_redo->add_do_method(script.ptr(), "sequence_connect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
4168 				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", default_func, remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
4169 			}
4170 
4171 			for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {
4172 
4173 				undo_redo->add_do_method(script.ptr(), "data_connect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
4174 				undo_redo->add_undo_method(script.ptr(), "data_disconnect", default_func, remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
4175 			}
4176 
4177 			undo_redo->add_do_method(this, "_update_graph");
4178 			undo_redo->add_undo_method(this, "_update_graph");
4179 
4180 			undo_redo->commit_action();
4181 
4182 			for (int i = 0; i < graph->get_child_count(); i++) {
4183 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
4184 				if (gn) {
4185 					int id = gn->get_name().operator String().to_int();
4186 					gn->set_selected(to_select.has(id));
4187 				}
4188 			}
4189 		} break;
4190 		case EDIT_CREATE_FUNCTION: {
4191 
4192 			StringName function = "";
4193 			Map<int, Ref<VisualScriptNode> > nodes;
4194 			Set<int> selections;
4195 			for (int i = 0; i < graph->get_child_count(); i++) {
4196 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
4197 				if (gn) {
4198 					if (gn->is_selected()) {
4199 						int id = String(gn->get_name()).to_int();
4200 						StringName func = _get_function_of_node(id);
4201 						Ref<VisualScriptNode> node = script->get_node(func, id);
4202 						if (Object::cast_to<VisualScriptFunction>(*node)) {
4203 							EditorNode::get_singleton()->show_warning(TTR("Can't create function with a function node."));
4204 							return;
4205 						}
4206 						if (node.is_valid()) {
4207 							if (func != function && function != StringName("")) {
4208 								EditorNode::get_singleton()->show_warning(TTR("Can't create function of nodes from nodes of multiple functions."));
4209 								return;
4210 							}
4211 							nodes.insert(id, node);
4212 							selections.insert(id);
4213 							function = func;
4214 						}
4215 					}
4216 				}
4217 			}
4218 
4219 			if (nodes.size() == 0) {
4220 				return; // nothing to be done if there are no valid nodes selected
4221 			}
4222 
4223 			Set<VisualScript::SequenceConnection> seqmove;
4224 			Set<VisualScript::DataConnection> datamove;
4225 
4226 			Set<VisualScript::SequenceConnection> seqext;
4227 			Set<VisualScript::DataConnection> dataext;
4228 
4229 			int start_node = -1;
4230 			Set<int> end_nodes;
4231 			if (nodes.size() == 1) {
4232 				Ref<VisualScriptNode> nd = script->get_node(function, nodes.front()->key());
4233 				if (nd.is_valid() && nd->has_input_sequence_port())
4234 					start_node = nodes.front()->key();
4235 				else {
4236 					EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));
4237 					return;
4238 				}
4239 			} else {
4240 				List<VisualScript::SequenceConnection> seqs;
4241 				script->get_sequence_connection_list(function, &seqs);
4242 
4243 				if (seqs.size() == 0) {
4244 					// in case there are no sequence connections
4245 					// select the top most node cause that's probably how
4246 					// the user wants to connect the nodes
4247 					int top_nd = -1;
4248 					Vector2 top;
4249 					for (Map<int, Ref<VisualScriptNode> >::Element *E = nodes.front(); E; E = E->next()) {
4250 						Ref<VisualScriptNode> nd = script->get_node(function, E->key());
4251 						if (nd.is_valid() && nd->has_input_sequence_port()) {
4252 							if (top_nd < 0) {
4253 								top_nd = E->key();
4254 								top = script->get_node_position(function, top_nd);
4255 							}
4256 							Vector2 pos = script->get_node_position(function, E->key());
4257 							if (top.y > pos.y) {
4258 								top_nd = E->key();
4259 								top = pos;
4260 							}
4261 						}
4262 					}
4263 					Ref<VisualScriptNode> nd = script->get_node(function, top_nd);
4264 					if (nd.is_valid() && nd->has_input_sequence_port())
4265 						start_node = top_nd;
4266 					else {
4267 						EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));
4268 						return;
4269 					}
4270 				} else {
4271 					// pick the node with input sequence
4272 					Set<int> nodes_from;
4273 					Set<int> nodes_to;
4274 					for (List<VisualScript::SequenceConnection>::Element *E = seqs.front(); E; E = E->next()) {
4275 						if (nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
4276 							seqmove.insert(E->get());
4277 							nodes_from.insert(E->get().from_node);
4278 						} else if (nodes.has(E->get().from_node) && !nodes.has(E->get().to_node)) {
4279 							seqext.insert(E->get());
4280 						} else if (!nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
4281 							if (start_node == -1) {
4282 								seqext.insert(E->get());
4283 								start_node = E->get().to_node;
4284 							} else {
4285 								EditorNode::get_singleton()->show_warning(TTR("Try to only have one sequence input in selection."));
4286 								return;
4287 							}
4288 						}
4289 						nodes_to.insert(E->get().to_node);
4290 					}
4291 
4292 					// to use to add return nodes
4293 					_get_ends(start_node, seqs, selections, end_nodes);
4294 
4295 					if (start_node == -1) {
4296 						// if we still don't have a start node then
4297 						// run through the nodes and select the first tree node
4298 						// ie node without any input sequence but output sequence
4299 						for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {
4300 							if (!nodes_to.has(E->get())) {
4301 								start_node = E->get();
4302 							}
4303 						}
4304 					}
4305 				}
4306 			}
4307 
4308 			if (start_node == -1) {
4309 				return; // this should not happen, but just in case something goes wrong
4310 			}
4311 
4312 			List<Variant::Type> inputs; // input types
4313 			List<Pair<int, int> > input_connections;
4314 			{
4315 				List<VisualScript::DataConnection> dats;
4316 				script->get_data_connection_list(function, &dats);
4317 				for (List<VisualScript::DataConnection>::Element *E = dats.front(); E; E = E->next()) {
4318 					if (nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
4319 						datamove.insert(E->get());
4320 					} else if (!nodes.has(E->get().from_node) && nodes.has(E->get().to_node)) {
4321 						// add all these as inputs for the Function
4322 						Ref<VisualScriptNode> node = script->get_node(function, E->get().to_node);
4323 						if (node.is_valid()) {
4324 							dataext.insert(E->get());
4325 							PropertyInfo pi = node->get_input_value_port_info(E->get().to_port);
4326 							inputs.push_back(pi.type);
4327 							input_connections.push_back(Pair<int, int>(E->get().to_node, E->get().to_port));
4328 						}
4329 					} else if (nodes.has(E->get().from_node) && !nodes.has(E->get().to_node)) {
4330 						dataext.insert(E->get());
4331 					}
4332 				}
4333 			}
4334 
4335 			String new_fn = _validate_name("new_function");
4336 
4337 			Vector2 ofs = _get_available_pos(false, script->get_node_position(function, start_node) - Vector2(80, 150));
4338 
4339 			Ref<VisualScriptFunction> func_node;
4340 			func_node.instance();
4341 			func_node->set_name(new_fn);
4342 
4343 			undo_redo->create_action(TTR("Create Function"));
4344 
4345 			undo_redo->add_do_method(script.ptr(), "add_function", new_fn);
4346 			int fn_id = script->get_available_id();
4347 			undo_redo->add_do_method(script.ptr(), "add_node", new_fn, fn_id, func_node, ofs);
4348 			undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn);
4349 			undo_redo->add_do_method(this, "_update_members");
4350 			undo_redo->add_undo_method(this, "_update_members");
4351 			undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
4352 			undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
4353 
4354 			// Move the nodes
4355 
4356 			for (Map<int, Ref<VisualScriptNode> >::Element *E = nodes.front(); E; E = E->next()) {
4357 				undo_redo->add_do_method(script.ptr(), "remove_node", function, E->key());
4358 				undo_redo->add_do_method(script.ptr(), "add_node", new_fn, E->key(), E->get(), script->get_node_position(function, E->key()));
4359 
4360 				// undo_redo->add_undo_method(script.ptr(), "remove_node", new_fn, E->key()); not needed cause we already remove the function :P
4361 				undo_redo->add_undo_method(script.ptr(), "add_node", function, E->key(), E->get(), script->get_node_position(function, E->key()));
4362 			}
4363 
4364 			for (Set<VisualScript::SequenceConnection>::Element *E = seqmove.front(); E; E = E->next()) {
4365 				undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, E->get().from_node, E->get().from_output, E->get().to_node);
4366 				undo_redo->add_undo_method(script.ptr(), "sequence_connect", function, E->get().from_node, E->get().from_output, E->get().to_node);
4367 			}
4368 
4369 			for (Set<VisualScript::DataConnection>::Element *E = datamove.front(); E; E = E->next()) {
4370 				undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
4371 				undo_redo->add_undo_method(script.ptr(), "data_connect", function, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
4372 			}
4373 
4374 			// Add undo for external connections as well so that it's easier to revert back and forth
4375 			// these didn't require do methods as it's already handled internally by other do calls
4376 			for (Set<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
4377 				undo_redo->add_undo_method(script.ptr(), "sequence_connect", function, E->get().from_node, E->get().from_output, E->get().to_node);
4378 			}
4379 			for (Set<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
4380 				undo_redo->add_undo_method(script.ptr(), "data_connect", function, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
4381 			}
4382 
4383 			// I don't really think we need support for non sequenced functions at this moment
4384 			undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, fn_id, 0, start_node);
4385 
4386 			// end nodes are mapped to the return nodes with data connections if possible
4387 			int m = 1;
4388 			for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) {
4389 				Ref<VisualScriptReturn> ret_node;
4390 				ret_node.instance();
4391 
4392 				int ret_id = fn_id + (m++);
4393 				selections.insert(ret_id);
4394 				Vector2 ofsi = _get_available_pos(false, script->get_node_position(function, G->get()) + Vector2(80, -100));
4395 				undo_redo->add_do_method(script.ptr(), "add_node", new_fn, ret_id, ret_node, ofsi);
4396 				undo_redo->add_undo_method(script.ptr(), "remove_node", new_fn, ret_id);
4397 
4398 				undo_redo->add_do_method(script.ptr(), "sequence_connect", new_fn, G->get(), 0, ret_id);
4399 				// add data outputs from each of the end_nodes
4400 				Ref<VisualScriptNode> vsn = script->get_node(function, G->get());
4401 				if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) {
4402 					ret_node->set_enable_return_value(true);
4403 					// use the zeroth data port cause that's the likely one that is planned to be used
4404 					ret_node->set_return_type(vsn->get_output_value_port_info(0).type);
4405 					undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, G->get(), 0, ret_id, 0);
4406 				}
4407 			}
4408 
4409 			// * might make the system more intelligent by checking port from info.
4410 			int i = 0;
4411 			List<Pair<int, int> >::Element *F = input_connections.front();
4412 			for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {
4413 				func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);
4414 				undo_redo->add_do_method(script.ptr(), "data_connect", new_fn, fn_id, i, F->get().first, F->get().second);
4415 				i++; // increment i
4416 			}
4417 
4418 			undo_redo->add_do_method(this, "_update_graph");
4419 			undo_redo->add_undo_method(this, "_update_graph");
4420 
4421 			undo_redo->commit_action();
4422 
4423 			// make sure all Nodes get marked for selection so that they can be moved together
4424 			selections.insert(fn_id);
4425 			for (int k = 0; k < graph->get_child_count(); k++) {
4426 				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(k));
4427 				if (gn) {
4428 					int id = gn->get_name().operator String().to_int();
4429 					gn->set_selected(selections.has(id));
4430 				}
4431 			}
4432 
4433 			// Ensure Preview Selection is of newly created function node
4434 			if (selections.size()) {
4435 				EditorNode::get_singleton()->push_item(func_node.ptr());
4436 			}
4437 
4438 		} break;
4439 		case REFRESH_GRAPH: {
4440 			_update_graph();
4441 		} break;
4442 	}
4443 }
4444 
4445 // this is likely going to be very slow and I am not sure if I should keep it
4446 // but I hope that it will not be a problem considering that we won't be creating functions so frequently
4447 // and cyclic connections would be a problem but hopefully we won't let them get to this point
_get_ends(int p_node,const List<VisualScript::SequenceConnection> & p_seqs,const Set<int> & p_selected,Set<int> & r_end_nodes)4448 void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes) {
4449 	for (const List<VisualScript::SequenceConnection>::Element *E = p_seqs.front(); E; E = E->next()) {
4450 		int from = E->get().from_node;
4451 		int to = E->get().to_node;
4452 
4453 		if (from == p_node && p_selected.has(to)) {
4454 			// this is an interior connection move forward to the to node
4455 			_get_ends(to, p_seqs, p_selected, r_end_nodes);
4456 		} else if (from == p_node && !p_selected.has(to)) {
4457 			r_end_nodes.insert(from);
4458 		}
4459 	}
4460 }
4461 
_member_rmb_selected(const Vector2 & p_pos)4462 void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
4463 
4464 	TreeItem *ti = members->get_selected();
4465 	ERR_FAIL_COND(!ti);
4466 
4467 	member_popup->clear();
4468 	member_popup->set_position(members->get_global_position() + p_pos);
4469 	member_popup->set_size(Vector2());
4470 
4471 	function_name_edit->set_position(members->get_global_position() + p_pos);
4472 	function_name_edit->set_size(Vector2());
4473 
4474 	TreeItem *root = members->get_root();
4475 
4476 	Ref<Texture> del_icon = Control::get_icon("Remove", "EditorIcons");
4477 
4478 	Ref<Texture> edit_icon = Control::get_icon("Edit", "EditorIcons");
4479 
4480 	if (ti->get_parent() == root->get_children()) {
4481 
4482 		member_type = MEMBER_FUNCTION;
4483 		member_name = ti->get_text(0);
4484 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
4485 		member_popup->add_separator();
4486 		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
4487 		member_popup->popup();
4488 		return;
4489 	}
4490 
4491 	if (ti->get_parent() == root->get_children()->get_next()) {
4492 
4493 		member_type = MEMBER_VARIABLE;
4494 		member_name = ti->get_text(0);
4495 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
4496 		member_popup->add_separator();
4497 		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
4498 		member_popup->popup();
4499 		return;
4500 	}
4501 
4502 	if (ti->get_parent() == root->get_children()->get_next()->get_next()) {
4503 
4504 		member_type = MEMBER_SIGNAL;
4505 		member_name = ti->get_text(0);
4506 		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
4507 		member_popup->add_separator();
4508 		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE);
4509 		member_popup->popup();
4510 		return;
4511 	}
4512 }
4513 
_member_option(int p_option)4514 void VisualScriptEditor::_member_option(int p_option) {
4515 
4516 	switch (member_type) {
4517 		case MEMBER_FUNCTION: {
4518 
4519 			if (p_option == MEMBER_REMOVE) {
4520 				//delete the function
4521 				String name = member_name;
4522 
4523 				undo_redo->create_action(TTR("Remove Function"));
4524 				undo_redo->add_do_method(script.ptr(), "remove_function", name);
4525 				undo_redo->add_undo_method(script.ptr(), "add_function", name);
4526 				List<int> nodes;
4527 				script->get_node_list(name, &nodes);
4528 				for (List<int>::Element *E = nodes.front(); E; E = E->next()) {
4529 					undo_redo->add_undo_method(script.ptr(), "add_node", name, E->get(), script->get_node(name, E->get()), script->get_node_position(name, E->get()));
4530 				}
4531 
4532 				List<VisualScript::SequenceConnection> seq_connections;
4533 
4534 				script->get_sequence_connection_list(name, &seq_connections);
4535 
4536 				for (List<VisualScript::SequenceConnection>::Element *E = seq_connections.front(); E; E = E->next()) {
4537 					undo_redo->add_undo_method(script.ptr(), "sequence_connect", name, E->get().from_node, E->get().from_output, E->get().to_node);
4538 				}
4539 
4540 				List<VisualScript::DataConnection> data_connections;
4541 
4542 				script->get_data_connection_list(name, &data_connections);
4543 
4544 				for (List<VisualScript::DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
4545 					undo_redo->add_undo_method(script.ptr(), "data_connect", name, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
4546 				}
4547 
4548 				undo_redo->add_do_method(this, "_update_members");
4549 				undo_redo->add_undo_method(this, "_update_members");
4550 				undo_redo->add_do_method(this, "_update_graph");
4551 				undo_redo->add_undo_method(this, "_update_graph");
4552 				undo_redo->commit_action();
4553 			} else if (p_option == MEMBER_EDIT) {
4554 				selected = members->get_selected()->get_text(0);
4555 				function_name_edit->popup();
4556 				function_name_box->set_text(selected);
4557 				function_name_box->select_all();
4558 			}
4559 		} break;
4560 		case MEMBER_VARIABLE: {
4561 
4562 			String name = member_name;
4563 
4564 			if (p_option == MEMBER_REMOVE) {
4565 				undo_redo->create_action(TTR("Remove Variable"));
4566 				undo_redo->add_do_method(script.ptr(), "remove_variable", name);
4567 				undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name));
4568 				undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict
4569 				undo_redo->add_do_method(this, "_update_members");
4570 				undo_redo->add_undo_method(this, "_update_members");
4571 				undo_redo->commit_action();
4572 			} else if (p_option == MEMBER_EDIT) {
4573 				variable_editor->edit(name);
4574 				edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name);
4575 				edit_variable_dialog->popup_centered_minsize(Size2(400, 200) * EDSCALE);
4576 			}
4577 		} break;
4578 		case MEMBER_SIGNAL: {
4579 			String name = member_name;
4580 
4581 			if (p_option == MEMBER_REMOVE) {
4582 				undo_redo->create_action(TTR("Remove Signal"));
4583 				undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name);
4584 				undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name);
4585 
4586 				for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) {
4587 					undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i));
4588 				}
4589 
4590 				undo_redo->add_do_method(this, "_update_members");
4591 				undo_redo->add_undo_method(this, "_update_members");
4592 				undo_redo->commit_action();
4593 			} else if (p_option == MEMBER_EDIT) {
4594 				signal_editor->edit(name);
4595 				edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name);
4596 				edit_signal_dialog->popup_centered_minsize(Size2(400, 300) * EDSCALE);
4597 			}
4598 		} break;
4599 	}
4600 }
4601 
add_syntax_highlighter(SyntaxHighlighter * p_highlighter)4602 void VisualScriptEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
4603 }
4604 
set_syntax_highlighter(SyntaxHighlighter * p_highlighter)4605 void VisualScriptEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) {
4606 }
4607 
_bind_methods()4608 void VisualScriptEditor::_bind_methods() {
4609 
4610 	ClassDB::bind_method("_member_button", &VisualScriptEditor::_member_button);
4611 	ClassDB::bind_method("_member_edited", &VisualScriptEditor::_member_edited);
4612 	ClassDB::bind_method("_member_selected", &VisualScriptEditor::_member_selected);
4613 	ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
4614 	ClassDB::bind_method("_members_gui_input", &VisualScriptEditor::_members_gui_input);
4615 	ClassDB::bind_method("_member_rmb_selected", &VisualScriptEditor::_member_rmb_selected);
4616 	ClassDB::bind_method("_member_option", &VisualScriptEditor::_member_option);
4617 	ClassDB::bind_method("_fn_name_box_input", &VisualScriptEditor::_fn_name_box_input);
4618 
4619 	ClassDB::bind_method("_change_base_type", &VisualScriptEditor::_change_base_type);
4620 	ClassDB::bind_method("_change_base_type_callback", &VisualScriptEditor::_change_base_type_callback);
4621 	ClassDB::bind_method("_toggle_tool_script", &VisualScriptEditor::_toggle_tool_script);
4622 	ClassDB::bind_method("_node_selected", &VisualScriptEditor::_node_selected);
4623 	ClassDB::bind_method("_node_moved", &VisualScriptEditor::_node_moved);
4624 	ClassDB::bind_method("_move_node", &VisualScriptEditor::_move_node);
4625 	ClassDB::bind_method("_begin_node_move", &VisualScriptEditor::_begin_node_move);
4626 	ClassDB::bind_method("_end_node_move", &VisualScriptEditor::_end_node_move);
4627 	ClassDB::bind_method("_remove_node", &VisualScriptEditor::_remove_node);
4628 	ClassDB::bind_method("_update_graph", &VisualScriptEditor::_update_graph, DEFVAL(-1));
4629 	ClassDB::bind_method("_node_ports_changed", &VisualScriptEditor::_node_ports_changed);
4630 
4631 	ClassDB::bind_method("_create_function_dialog", &VisualScriptEditor::_create_function_dialog);
4632 	ClassDB::bind_method("_create_function", &VisualScriptEditor::_create_function);
4633 	ClassDB::bind_method("_add_node_dialog", &VisualScriptEditor::_add_node_dialog);
4634 	ClassDB::bind_method("_add_func_input", &VisualScriptEditor::_add_func_input);
4635 	ClassDB::bind_method("_remove_func_input", &VisualScriptEditor::_remove_func_input);
4636 	ClassDB::bind_method("_deselect_input_names", &VisualScriptEditor::_deselect_input_names);
4637 
4638 	ClassDB::bind_method("_default_value_edited", &VisualScriptEditor::_default_value_edited);
4639 	ClassDB::bind_method("_default_value_changed", &VisualScriptEditor::_default_value_changed);
4640 	ClassDB::bind_method("_menu_option", &VisualScriptEditor::_menu_option);
4641 	ClassDB::bind_method("_graph_ofs_changed", &VisualScriptEditor::_graph_ofs_changed);
4642 	ClassDB::bind_method("_center_on_node", &VisualScriptEditor::_center_on_node);
4643 	ClassDB::bind_method("_comment_node_resized", &VisualScriptEditor::_comment_node_resized);
4644 	ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed);
4645 	ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu);
4646 	ClassDB::bind_method("_selected_connect_node", &VisualScriptEditor::_selected_connect_node);
4647 	ClassDB::bind_method("_selected_new_virtual_method", &VisualScriptEditor::_selected_new_virtual_method);
4648 
4649 	ClassDB::bind_method("_cancel_connect_node", &VisualScriptEditor::_cancel_connect_node);
4650 	ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name);
4651 	ClassDB::bind_method("_expression_text_changed", &VisualScriptEditor::_expression_text_changed);
4652 	ClassDB::bind_method("_add_input_port", &VisualScriptEditor::_add_input_port);
4653 	ClassDB::bind_method("_add_output_port", &VisualScriptEditor::_add_output_port);
4654 	ClassDB::bind_method("_remove_input_port", &VisualScriptEditor::_remove_input_port);
4655 	ClassDB::bind_method("_remove_output_port", &VisualScriptEditor::_remove_output_port);
4656 	ClassDB::bind_method("_change_port_type", &VisualScriptEditor::_change_port_type);
4657 	ClassDB::bind_method("_update_node_size", &VisualScriptEditor::_update_node_size);
4658 	ClassDB::bind_method("_port_name_focus_out", &VisualScriptEditor::_port_name_focus_out);
4659 
4660 	ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);
4661 	ClassDB::bind_method("can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);
4662 	ClassDB::bind_method("drop_data_fw", &VisualScriptEditor::drop_data_fw);
4663 
4664 	ClassDB::bind_method("_input", &VisualScriptEditor::_input);
4665 	ClassDB::bind_method("_graph_gui_input", &VisualScriptEditor::_graph_gui_input);
4666 
4667 	ClassDB::bind_method("_on_nodes_delete", &VisualScriptEditor::_on_nodes_delete);
4668 	ClassDB::bind_method("_on_nodes_duplicate", &VisualScriptEditor::_on_nodes_duplicate);
4669 
4670 	ClassDB::bind_method("_hide_timer", &VisualScriptEditor::_hide_timer);
4671 
4672 	ClassDB::bind_method("_graph_connected", &VisualScriptEditor::_graph_connected);
4673 	ClassDB::bind_method("_graph_disconnected", &VisualScriptEditor::_graph_disconnected);
4674 	ClassDB::bind_method("_graph_connect_to_empty", &VisualScriptEditor::_graph_connect_to_empty);
4675 
4676 	ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections);
4677 
4678 	ClassDB::bind_method("_selected_method", &VisualScriptEditor::_selected_method);
4679 	ClassDB::bind_method("_draw_color_over_button", &VisualScriptEditor::_draw_color_over_button);
4680 
4681 	ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);
4682 }
4683 
VisualScriptEditor()4684 VisualScriptEditor::VisualScriptEditor() {
4685 
4686 	if (!clipboard) {
4687 		clipboard = memnew(Clipboard);
4688 	}
4689 	updating_graph = false;
4690 	saved_pos_dirty = false;
4691 	saved_position = Vector2(0, 0);
4692 
4693 	edit_menu = memnew(MenuButton);
4694 	edit_menu->set_text(TTR("Edit"));
4695 	edit_menu->set_switch_on_hover(true);
4696 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/delete_selected"), EDIT_DELETE_NODES);
4697 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);
4698 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);
4699 	edit_menu->get_popup()->add_separator();
4700 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/copy_nodes"), EDIT_COPY_NODES);
4701 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/cut_nodes"), EDIT_CUT_NODES);
4702 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/paste_nodes"), EDIT_PASTE_NODES);
4703 	edit_menu->get_popup()->add_separator();
4704 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/create_function"), EDIT_CREATE_FUNCTION);
4705 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/refresh_nodes"), REFRESH_GRAPH);
4706 	edit_menu->get_popup()->connect("id_pressed", this, "_menu_option");
4707 
4708 	members_section = memnew(VBoxContainer);
4709 	// Add but wait until done setting up this.
4710 	ScriptEditor::get_singleton()->get_left_list_split()->call_deferred("add_child", members_section);
4711 	members_section->set_v_size_flags(SIZE_EXPAND_FILL);
4712 
4713 	CheckButton *tool_script_check = memnew(CheckButton);
4714 	tool_script_check->set_text(TTR("Make Tool:"));
4715 	members_section->add_child(tool_script_check);
4716 	tool_script_check->connect("pressed", this, "_toggle_tool_script");
4717 
4718 	///       Members        ///
4719 
4720 	members = memnew(Tree);
4721 	members_section->add_margin_child(TTR("Members:"), members, true);
4722 	members->set_custom_minimum_size(Size2(0, 50 * EDSCALE));
4723 	members->set_hide_root(true);
4724 	members->connect("button_pressed", this, "_member_button");
4725 	members->connect("item_edited", this, "_member_edited");
4726 	members->connect("cell_selected", this, "_member_selected", varray(), CONNECT_DEFERRED);
4727 	members->connect("gui_input", this, "_members_gui_input");
4728 	members->connect("item_rmb_selected", this, "_member_rmb_selected");
4729 	members->set_allow_rmb_select(true);
4730 	members->set_allow_reselect(true);
4731 	members->set_hide_folding(true);
4732 	members->set_drag_forwarding(this);
4733 
4734 	member_popup = memnew(PopupMenu);
4735 	add_child(member_popup);
4736 	member_popup->connect("id_pressed", this, "_member_option");
4737 
4738 	function_name_edit = memnew(PopupDialog);
4739 	function_name_box = memnew(LineEdit);
4740 	function_name_edit->add_child(function_name_box);
4741 	function_name_edit->set_h_size_flags(SIZE_EXPAND);
4742 	function_name_box->connect("gui_input", this, "_fn_name_box_input");
4743 	function_name_box->set_expand_to_text_length(true);
4744 	add_child(function_name_edit);
4745 
4746 	///       Actual Graph          ///
4747 
4748 	graph = memnew(GraphEdit);
4749 	add_child(graph);
4750 	graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);
4751 	graph->set_anchors_and_margins_preset(Control::PRESET_WIDE);
4752 	graph->connect("node_selected", this, "_node_selected");
4753 	graph->connect("_begin_node_move", this, "_begin_node_move");
4754 	graph->connect("_end_node_move", this, "_end_node_move");
4755 	graph->connect("delete_nodes_request", this, "_on_nodes_delete");
4756 	graph->connect("duplicate_nodes_request", this, "_on_nodes_duplicate");
4757 	graph->connect("gui_input", this, "_graph_gui_input");
4758 	graph->set_drag_forwarding(this);
4759 	graph->hide();
4760 	graph->connect("scroll_offset_changed", this, "_graph_ofs_changed");
4761 
4762 	/// Add Buttons to Top Bar/Zoom bar.
4763 	HBoxContainer *graph_hbc = graph->get_zoom_hbox();
4764 
4765 	Label *base_lbl = memnew(Label);
4766 	base_lbl->set_text(TTR("Change Base Type:") + " ");
4767 	graph_hbc->add_child(base_lbl);
4768 
4769 	base_type_select = memnew(Button);
4770 	base_type_select->connect("pressed", this, "_change_base_type");
4771 	graph_hbc->add_child(base_type_select);
4772 
4773 	Button *add_nds = memnew(Button);
4774 	add_nds->set_text(TTR("Add Nodes..."));
4775 	graph_hbc->add_child(add_nds);
4776 	add_nds->connect("pressed", this, "_add_node_dialog");
4777 
4778 	Button *fn_btn = memnew(Button);
4779 	fn_btn->set_text(TTR("Add Function..."));
4780 	graph_hbc->add_child(fn_btn);
4781 	fn_btn->connect("pressed", this, "_create_function_dialog");
4782 
4783 	// Add Function Dialog.
4784 	VBoxContainer *function_vb = memnew(VBoxContainer);
4785 	function_vb->set_v_size_flags(SIZE_EXPAND_FILL);
4786 	function_vb->set_custom_minimum_size(Size2(450, 300) * EDSCALE);
4787 
4788 	HBoxContainer *func_name_hbox = memnew(HBoxContainer);
4789 	function_vb->add_child(func_name_hbox);
4790 
4791 	Label *func_name_label = memnew(Label);
4792 	func_name_label->set_text(TTR("Name:"));
4793 	func_name_hbox->add_child(func_name_label);
4794 
4795 	func_name_box = memnew(LineEdit);
4796 	func_name_box->set_h_size_flags(SIZE_EXPAND_FILL);
4797 	func_name_box->set_placeholder(TTR("function_name"));
4798 	func_name_box->set_text("");
4799 	func_name_box->connect("focus_entered", this, "_deselect_input_names");
4800 	func_name_hbox->add_child(func_name_box);
4801 
4802 	// Add minor setting for function if needed, here!
4803 
4804 	function_vb->add_child(memnew(HSeparator));
4805 
4806 	Button *add_input_button = memnew(Button);
4807 	add_input_button->set_h_size_flags(SIZE_EXPAND_FILL);
4808 	add_input_button->set_text(TTR("Add Input"));
4809 	add_input_button->connect("pressed", this, "_add_func_input");
4810 	function_vb->add_child(add_input_button);
4811 
4812 	func_input_scroll = memnew(ScrollContainer);
4813 	func_input_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
4814 	function_vb->add_child(func_input_scroll);
4815 
4816 	func_input_vbox = memnew(VBoxContainer);
4817 	func_input_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
4818 	func_input_scroll->add_child(func_input_vbox);
4819 
4820 	function_create_dialog = memnew(ConfirmationDialog);
4821 	function_create_dialog->set_v_size_flags(SIZE_EXPAND_FILL);
4822 	function_create_dialog->set_title(TTR("Create Function"));
4823 	function_create_dialog->add_child(function_vb);
4824 	function_create_dialog->get_ok()->set_text(TTR("Create"));
4825 	function_create_dialog->get_ok()->connect("pressed", this, "_create_function");
4826 	add_child(function_create_dialog);
4827 
4828 	select_func_text = memnew(Label);
4829 	select_func_text->set_text(TTR("Select or create a function to edit its graph."));
4830 	select_func_text->set_align(Label::ALIGN_CENTER);
4831 	select_func_text->set_valign(Label::VALIGN_CENTER);
4832 	select_func_text->set_h_size_flags(SIZE_EXPAND_FILL);
4833 	add_child(select_func_text);
4834 
4835 	hint_text = memnew(Label);
4836 	hint_text->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -100);
4837 	hint_text->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0);
4838 	hint_text->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
4839 	hint_text->set_align(Label::ALIGN_CENTER);
4840 	hint_text->set_valign(Label::VALIGN_CENTER);
4841 	graph->add_child(hint_text);
4842 
4843 	hint_text_timer = memnew(Timer);
4844 	hint_text_timer->set_wait_time(4);
4845 	hint_text_timer->connect("timeout", this, "_hide_timer");
4846 	add_child(hint_text_timer);
4847 
4848 	// Allowed casts (connections).
4849 	for (int i = 0; i < Variant::VARIANT_MAX; i++) {
4850 		graph->add_valid_connection_type(Variant::NIL, i);
4851 		graph->add_valid_connection_type(i, Variant::NIL);
4852 		for (int j = 0; j < Variant::VARIANT_MAX; j++) {
4853 			if (Variant::can_convert(Variant::Type(i), Variant::Type(j))) {
4854 				graph->add_valid_connection_type(i, j);
4855 			}
4856 		}
4857 
4858 		graph->add_valid_right_disconnect_type(i);
4859 	}
4860 
4861 	graph->add_valid_left_disconnect_type(TYPE_SEQUENCE);
4862 
4863 	graph->connect("connection_request", this, "_graph_connected");
4864 	graph->connect("disconnection_request", this, "_graph_disconnected");
4865 	graph->connect("connection_to_empty", this, "_graph_connect_to_empty");
4866 
4867 	edit_signal_dialog = memnew(AcceptDialog);
4868 	edit_signal_dialog->get_ok()->set_text(TTR("Close"));
4869 	add_child(edit_signal_dialog);
4870 
4871 	signal_editor = memnew(VisualScriptEditorSignalEdit);
4872 	edit_signal_edit = memnew(EditorInspector);
4873 	edit_signal_dialog->add_child(edit_signal_edit);
4874 
4875 	edit_signal_edit->edit(signal_editor);
4876 
4877 	edit_variable_dialog = memnew(AcceptDialog);
4878 	edit_variable_dialog->get_ok()->set_text(TTR("Close"));
4879 	add_child(edit_variable_dialog);
4880 
4881 	variable_editor = memnew(VisualScriptEditorVariableEdit);
4882 	edit_variable_edit = memnew(EditorInspector);
4883 	edit_variable_dialog->add_child(edit_variable_edit);
4884 
4885 	edit_variable_edit->edit(variable_editor);
4886 
4887 	select_base_type = memnew(CreateDialog);
4888 	select_base_type->set_base_type("Object"); // Anything goes.
4889 	select_base_type->connect("create", this, "_change_base_type_callback");
4890 	add_child(select_base_type);
4891 
4892 	undo_redo = EditorNode::get_singleton()->get_undo_redo();
4893 
4894 	updating_members = false;
4895 
4896 	set_process_input(true);
4897 	set_process_unhandled_input(true);
4898 
4899 	default_value_edit = memnew(CustomPropertyEditor);
4900 	add_child(default_value_edit);
4901 	default_value_edit->connect("variant_changed", this, "_default_value_changed");
4902 
4903 	method_select = memnew(VisualScriptPropertySelector);
4904 	add_child(method_select);
4905 	method_select->connect("selected", this, "_selected_method");
4906 	error_line = -1;
4907 
4908 	new_connect_node_select = memnew(VisualScriptPropertySelector);
4909 	add_child(new_connect_node_select);
4910 	new_connect_node_select->set_resizable(true);
4911 	new_connect_node_select->connect("selected", this, "_selected_connect_node");
4912 	new_connect_node_select->get_cancel()->connect("pressed", this, "_cancel_connect_node");
4913 
4914 	new_virtual_method_select = memnew(VisualScriptPropertySelector);
4915 	add_child(new_virtual_method_select);
4916 	new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method");
4917 }
4918 
~VisualScriptEditor()4919 VisualScriptEditor::~VisualScriptEditor() {
4920 
4921 	undo_redo->clear_history(); // Avoid crashes.
4922 	memdelete(signal_editor);
4923 	memdelete(variable_editor);
4924 }
4925 
create_editor(const RES & p_resource)4926 static ScriptEditorBase *create_editor(const RES &p_resource) {
4927 
4928 	if (Object::cast_to<VisualScript>(*p_resource)) {
4929 		return memnew(VisualScriptEditor);
4930 	}
4931 
4932 	return NULL;
4933 }
4934 
4935 VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = NULL;
4936 
free_clipboard()4937 void VisualScriptEditor::free_clipboard() {
4938 	if (clipboard)
4939 		memdelete(clipboard);
4940 }
4941 
register_editor_callback()4942 static void register_editor_callback() {
4943 
4944 	ScriptEditor::register_create_script_editor_function(create_editor);
4945 
4946 	ED_SHORTCUT("visual_script_editor/delete_selected", TTR("Delete Selected"), KEY_DELETE);
4947 	ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);
4948 	ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD + KEY_F);
4949 	ED_SHORTCUT("visual_script_editor/copy_nodes", TTR("Copy Nodes"), KEY_MASK_CMD + KEY_C);
4950 	ED_SHORTCUT("visual_script_editor/cut_nodes", TTR("Cut Nodes"), KEY_MASK_CMD + KEY_X);
4951 	ED_SHORTCUT("visual_script_editor/paste_nodes", TTR("Paste Nodes"), KEY_MASK_CMD + KEY_V);
4952 	ED_SHORTCUT("visual_script_editor/create_function", TTR("Make Function"), KEY_MASK_CMD + KEY_G);
4953 	ED_SHORTCUT("visual_script_editor/refresh_nodes", TTR("Refresh Graph"), KEY_MASK_CMD + KEY_R);
4954 	ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KEY_MASK_CMD + KEY_E);
4955 }
4956 
register_editor()4957 void VisualScriptEditor::register_editor() {
4958 
4959 	// Too early to register stuff here, request a callback.
4960 	EditorNode::add_plugin_init_callback(register_editor_callback);
4961 }
4962 
create_node_custom(const String & p_name)4963 Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) {
4964 
4965 	Ref<VisualScriptCustomNode> node;
4966 	node.instance();
4967 	node->set_script(singleton->custom_nodes[p_name]);
4968 	return node;
4969 }
4970 
4971 _VisualScriptEditor *_VisualScriptEditor::singleton = NULL;
4972 Map<String, RefPtr> _VisualScriptEditor::custom_nodes;
4973 
_VisualScriptEditor()4974 _VisualScriptEditor::_VisualScriptEditor() {
4975 	singleton = this;
4976 }
4977 
~_VisualScriptEditor()4978 _VisualScriptEditor::~_VisualScriptEditor() {
4979 	custom_nodes.clear();
4980 }
4981 
add_custom_node(const String & p_name,const String & p_category,const Ref<Script> & p_script)4982 void _VisualScriptEditor::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
4983 	String node_name = "custom/" + p_category + "/" + p_name;
4984 	custom_nodes.insert(node_name, p_script.get_ref_ptr());
4985 	VisualScriptLanguage::singleton->add_register_func(node_name, &_VisualScriptEditor::create_node_custom);
4986 	emit_signal("custom_nodes_updated");
4987 }
4988 
remove_custom_node(const String & p_name,const String & p_category)4989 void _VisualScriptEditor::remove_custom_node(const String &p_name, const String &p_category) {
4990 	String node_name = "custom/" + p_category + "/" + p_name;
4991 	custom_nodes.erase(node_name);
4992 	VisualScriptLanguage::singleton->remove_register_func(node_name);
4993 	emit_signal("custom_nodes_updated");
4994 }
4995 
_bind_methods()4996 void _VisualScriptEditor::_bind_methods() {
4997 	ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &_VisualScriptEditor::add_custom_node);
4998 	ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &_VisualScriptEditor::remove_custom_node);
4999 	ADD_SIGNAL(MethodInfo("custom_nodes_updated"));
5000 }
5001 
validate()5002 void VisualScriptEditor::validate() {
5003 }
5004 #endif
5005