1 /*************************************************************************/
2 /*  call_dialog.cpp                                                      */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 #include "call_dialog.h"
31 
32 #include "object_type_db.h"
33 #include "print_string.h"
34 #include "scene/gui/label.h"
35 
36 class CallDialogParams : public Object {
37 
38 	OBJ_TYPE(CallDialogParams, Object);
39 
40 public:
_set(const StringName & p_name,const Variant & p_value)41 	bool _set(const StringName &p_name, const Variant &p_value) {
42 
43 		values[p_name] = p_value;
44 		return true;
45 	}
46 
_get(const StringName & p_name,Variant & r_ret) const47 	bool _get(const StringName &p_name, Variant &r_ret) const {
48 
49 		if (values.has(p_name)) {
50 			r_ret = values[p_name];
51 			return true;
52 		}
53 		return false;
54 	}
55 
_get_property_list(List<PropertyInfo> * p_list) const56 	void _get_property_list(List<PropertyInfo> *p_list) const {
57 
58 		for (int i = 0; i < method.arguments.size(); i++)
59 			p_list->push_back(method.arguments[i]);
60 	}
61 
62 	MethodInfo method;
63 	HashMap<String, Variant> values;
64 
CallDialogParams()65 	CallDialogParams() {}
66 };
67 
_notification(int p_what)68 void CallDialog::_notification(int p_what) {
69 
70 	if (p_what == NOTIFICATION_READY) {
71 
72 		call->connect("pressed", this, "_call");
73 		cancel->connect("pressed", this, "_cancel");
74 		//filter->get_path()->connect("text_changed", this,"_text_changed");
75 		_update_method_list();
76 	}
77 
78 	if (p_what == NOTIFICATION_EXIT_TREE) {
79 
80 		call->disconnect("pressed", this, "_call");
81 		cancel->disconnect("pressed", this, "_cancel");
82 
83 		//filter->get_path()->connect("text_changed", this,"_text_changed");
84 		_update_method_list();
85 	}
86 
87 	if (p_what == NOTIFICATION_DRAW) {
88 
89 		RID ci = get_canvas_item();
90 		get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size()));
91 	}
92 }
93 
_call()94 void CallDialog::_call() {
95 
96 	if (!tree->get_selected())
97 		return;
98 
99 	TreeItem *item = tree->get_selected();
100 	ERR_FAIL_COND(!item);
101 	int idx = item->get_metadata(0);
102 	ERR_FAIL_INDEX(idx, methods.size());
103 	MethodInfo &m = methods[idx];
104 
105 	Variant args[VARIANT_ARG_MAX];
106 
107 	for (int i = 0; i < VARIANT_ARG_MAX; i++) {
108 
109 		if (i >= m.arguments.size())
110 			continue;
111 
112 		if (call_params->values.has(m.arguments[i].name))
113 			args[i] = call_params->values[m.arguments[i].name];
114 	}
115 
116 	Variant ret = object->call(m.name, args[0], args[1], args[2], args[3], args[4]);
117 	if (ret.get_type() != Variant::NIL)
118 		return_value->set_text(ret);
119 	else
120 		return_value->set_text("");
121 }
122 
_cancel()123 void CallDialog::_cancel() {
124 
125 	hide();
126 }
127 
_item_selected()128 void CallDialog::_item_selected() {
129 
130 	TreeItem *item = tree->get_selected();
131 	ERR_FAIL_COND(!item);
132 
133 	if (item->get_metadata(0).get_type() == Variant::NIL) {
134 
135 		call->set_disabled(true);
136 		return;
137 	}
138 
139 	call->set_disabled(false);
140 
141 	int idx = item->get_metadata(0);
142 	ERR_FAIL_INDEX(idx, methods.size());
143 
144 	MethodInfo &m = methods[idx];
145 
146 	call_params->values.clear();
147 	call_params->method = m;
148 
149 	property_editor->edit(call_params);
150 	property_editor->update_tree();
151 }
152 
_update_method_list()153 void CallDialog::_update_method_list() {
154 
155 	tree->clear();
156 	if (!object)
157 		return;
158 
159 	TreeItem *root = tree->create_item();
160 
161 	List<MethodInfo> method_list;
162 	object->get_method_list(&method_list);
163 	method_list.sort();
164 	methods.clear();
165 
166 	List<String> inheritance_list;
167 
168 	String type = object->get_type();
169 
170 	while (type != "") {
171 		inheritance_list.push_back(type);
172 		type = ObjectTypeDB::type_inherits_from(type);
173 	}
174 
175 	TreeItem *selected_item = NULL;
176 
177 	for (int i = 0; i < inheritance_list.size(); i++) {
178 
179 		String type = inheritance_list[i];
180 		String parent_type = ObjectTypeDB::type_inherits_from(type);
181 
182 		TreeItem *type_item = NULL;
183 
184 		List<MethodInfo>::Element *N, *E = method_list.front();
185 
186 		while (E) {
187 
188 			N = E->next();
189 
190 			if (parent_type != "" && ObjectTypeDB::get_method(parent_type, E->get().name) != NULL) {
191 				E = N;
192 				continue;
193 			}
194 
195 			if (!type_item) {
196 				type_item = tree->create_item(root);
197 				type_item->set_text(0, type);
198 				if (has_icon(type, "EditorIcons"))
199 					type_item->set_icon(0, get_icon(type, "EditorIcons"));
200 			}
201 
202 			TreeItem *method_item = tree->create_item(type_item);
203 			method_item->set_text(0, E->get().name);
204 			method_item->set_metadata(0, methods.size());
205 			if (E->get().name == selected)
206 				selected_item = method_item;
207 			methods.push_back(E->get());
208 
209 			method_list.erase(E);
210 			E = N;
211 		}
212 	}
213 
214 	if (selected_item)
215 		selected_item->select(0);
216 }
217 
_bind_methods()218 void CallDialog::_bind_methods() {
219 
220 	ObjectTypeDB::bind_method("_call", &CallDialog::_call);
221 	ObjectTypeDB::bind_method("_cancel", &CallDialog::_cancel);
222 	ObjectTypeDB::bind_method("_item_selected", &CallDialog::_item_selected);
223 }
224 
set_object(Object * p_object,StringName p_selected)225 void CallDialog::set_object(Object *p_object, StringName p_selected) {
226 
227 	object = p_object;
228 	selected = p_selected;
229 	property_editor->edit(NULL);
230 	call->set_disabled(true);
231 	return_value->clear();
232 
233 	_update_method_list();
234 	method_label->set_text(vformat(TTR("Method List For '%s':"), p_object->get_type()));
235 }
236 
CallDialog()237 CallDialog::CallDialog() {
238 
239 	object = NULL;
240 
241 	call = memnew(Button);
242 	call->set_anchor(MARGIN_LEFT, ANCHOR_END);
243 	call->set_anchor(MARGIN_TOP, ANCHOR_END);
244 	call->set_anchor(MARGIN_RIGHT, ANCHOR_END);
245 	call->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
246 	call->set_begin(Point2(70, 29));
247 	call->set_end(Point2(15, 15));
248 	call->set_text(TTR("Call"));
249 
250 	add_child(call);
251 
252 	cancel = memnew(Button);
253 	cancel->set_anchor(MARGIN_TOP, ANCHOR_END);
254 	cancel->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
255 	cancel->set_begin(Point2(15, 29));
256 	cancel->set_end(Point2(70, 15));
257 	cancel->set_text(TTR("Close"));
258 
259 	add_child(cancel);
260 
261 	tree = memnew(Tree);
262 
263 	tree->set_anchor(MARGIN_RIGHT, ANCHOR_RATIO);
264 	tree->set_anchor(MARGIN_BOTTOM, ANCHOR_END);
265 	tree->set_begin(Point2(20, 50));
266 	tree->set_margin(MARGIN_BOTTOM, 44);
267 	tree->set_margin(MARGIN_RIGHT, 0.5);
268 	tree->set_select_mode(Tree::SELECT_ROW);
269 	add_child(tree);
270 
271 	tree->connect("item_selected", this, "_item_selected");
272 	tree->set_hide_root(true);
273 
274 	property_editor = memnew(PropertyEditor);
275 
276 	property_editor->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 15);
277 	property_editor->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 50);
278 	property_editor->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.55);
279 	property_editor->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 90);
280 	property_editor->get_scene_tree()->set_hide_root(true);
281 	property_editor->hide_top_label();
282 
283 	add_child(property_editor);
284 	method_label = memnew(Label);
285 	method_label->set_pos(Point2(15, 25));
286 	method_label->set_text(TTR("Method List:"));
287 
288 	add_child(method_label);
289 
290 	Label *label = memnew(Label);
291 	label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.53);
292 	label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 25);
293 	label->set_text(TTR("Arguments:"));
294 
295 	add_child(label);
296 
297 	return_label = memnew(Label);
298 	return_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.53);
299 	return_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, 85);
300 	return_label->set_text(TTR("Return:"));
301 
302 	add_child(return_label);
303 
304 	return_value = memnew(LineEdit);
305 	return_value->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.55);
306 	return_value->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 15);
307 	return_value->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, 65);
308 
309 	add_child(return_value);
310 
311 	/*
312 	label = memnew( Label );
313 	label->set_anchor( MARGIN_TOP, ANCHOR_END );
314 	label->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
315 
316 	label->set_begin( Point2( 15,54) );
317 	label->set_end( Point2( 16,44) );
318 	label->set_text("Parameters:");
319 
320 	add_child(label);
321 	*/
322 
323 	call_params = memnew(CallDialogParams);
324 	set_as_toplevel(true);
325 }
326 
~CallDialog()327 CallDialog::~CallDialog() {
328 	memdelete(call_params);
329 }
330