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