1 /*************************************************************************/
2 /* item_list_editor_plugin.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 "item_list_editor_plugin.h"
31
32 #include "io/resource_loader.h"
33
_set(const StringName & p_name,const Variant & p_value)34 bool ItemListPlugin::_set(const StringName &p_name, const Variant &p_value) {
35
36 String name = p_name;
37 int idx = name.get_slice("/", 0).to_int();
38 String what = name.get_slice("/", 1);
39
40 if (what == "text")
41 set_item_text(idx, p_value);
42 else if (what == "icon")
43 set_item_icon(idx, p_value);
44 else if (what == "checkable")
45 set_item_checkable(idx, p_value);
46 else if (what == "checked")
47 set_item_checked(idx, p_value);
48 else if (what == "id")
49 set_item_id(idx, p_value);
50 else if (what == "enabled")
51 set_item_enabled(idx, p_value);
52 else if (what == "separator")
53 set_item_separator(idx, p_value);
54 else
55 return false;
56
57 return true;
58 }
59
_get(const StringName & p_name,Variant & r_ret) const60 bool ItemListPlugin::_get(const StringName &p_name, Variant &r_ret) const {
61
62 String name = p_name;
63 int idx = name.get_slice("/", 0).to_int();
64 String what = name.get_slice("/", 1);
65
66 if (what == "text")
67 r_ret = get_item_text(idx);
68 else if (what == "icon")
69 r_ret = get_item_icon(idx);
70 else if (what == "checkable")
71 r_ret = is_item_checkable(idx);
72 else if (what == "checked")
73 r_ret = is_item_checked(idx);
74 else if (what == "id")
75 r_ret = get_item_id(idx);
76 else if (what == "enabled")
77 r_ret = is_item_enabled(idx);
78 else if (what == "separator")
79 r_ret = is_item_separator(idx);
80 else
81 return false;
82
83 return true;
84 }
_get_property_list(List<PropertyInfo> * p_list) const85 void ItemListPlugin::_get_property_list(List<PropertyInfo> *p_list) const {
86
87 for (int i = 0; i < get_item_count(); i++) {
88
89 String base = itos(i) + "/";
90
91 p_list->push_back(PropertyInfo(Variant::STRING, base + "text"));
92 p_list->push_back(PropertyInfo(Variant::OBJECT, base + "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"));
93
94 int flags = get_flags();
95
96 if (flags & FLAG_CHECKABLE) {
97 p_list->push_back(PropertyInfo(Variant::BOOL, base + "checkable"));
98 p_list->push_back(PropertyInfo(Variant::BOOL, base + "checked"));
99 }
100
101 if (flags & FLAG_ID)
102 p_list->push_back(PropertyInfo(Variant::INT, base + "id", PROPERTY_HINT_RANGE, "-1,4096"));
103
104 if (flags & FLAG_ENABLE)
105 p_list->push_back(PropertyInfo(Variant::BOOL, base + "enabled"));
106
107 if (flags & FLAG_SEPARATOR)
108 p_list->push_back(PropertyInfo(Variant::BOOL, base + "separator"));
109 }
110 }
111
112 ///////////////////////////////////////////////////////////////
113 ///////////////////////// PLUGINS /////////////////////////////
114 ///////////////////////////////////////////////////////////////
115
set_object(Object * p_object)116 void ItemListOptionButtonPlugin::set_object(Object *p_object) {
117
118 ob = p_object->cast_to<OptionButton>();
119 }
120
handles(Object * p_object) const121 bool ItemListOptionButtonPlugin::handles(Object *p_object) const {
122
123 return p_object->is_type("OptionButton");
124 }
125
get_flags() const126 int ItemListOptionButtonPlugin::get_flags() const {
127
128 return FLAG_ICON | FLAG_ID | FLAG_ENABLE;
129 }
130
add_item()131 void ItemListOptionButtonPlugin::add_item() {
132
133 ob->add_item(vformat(TTR("Item %d"), ob->get_item_count()));
134 _change_notify();
135 }
136
get_item_count() const137 int ItemListOptionButtonPlugin::get_item_count() const {
138
139 return ob->get_item_count();
140 }
141
erase(int p_idx)142 void ItemListOptionButtonPlugin::erase(int p_idx) {
143
144 ob->remove_item(p_idx);
145 _change_notify();
146 }
147
ItemListOptionButtonPlugin()148 ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
149
150 ob = NULL;
151 }
152
153 ///////////////////////////////////////////////////////////////
154
set_object(Object * p_object)155 void ItemListPopupMenuPlugin::set_object(Object *p_object) {
156
157 if (p_object->is_type("MenuButton"))
158 pp = p_object->cast_to<MenuButton>()->get_popup();
159 else
160 pp = p_object->cast_to<PopupMenu>();
161 }
162
handles(Object * p_object) const163 bool ItemListPopupMenuPlugin::handles(Object *p_object) const {
164
165 return p_object->is_type("PopupMenu") || p_object->is_type("MenuButton");
166 }
167
get_flags() const168 int ItemListPopupMenuPlugin::get_flags() const {
169
170 return FLAG_ICON | FLAG_CHECKABLE | FLAG_ID | FLAG_ENABLE | FLAG_SEPARATOR;
171 }
172
add_item()173 void ItemListPopupMenuPlugin::add_item() {
174
175 pp->add_item(vformat(TTR("Item %d"), pp->get_item_count()));
176 _change_notify();
177 }
178
get_item_count() const179 int ItemListPopupMenuPlugin::get_item_count() const {
180
181 return pp->get_item_count();
182 }
183
erase(int p_idx)184 void ItemListPopupMenuPlugin::erase(int p_idx) {
185
186 pp->remove_item(p_idx);
187 _change_notify();
188 }
189
ItemListPopupMenuPlugin()190 ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
191
192 pp = NULL;
193 }
194
195 ///////////////////////////////////////////////////////////////
196 ///////////////////////////////////////////////////////////////
197 ///////////////////////////////////////////////////////////////
198
_node_removed(Node * p_node)199 void ItemListEditor::_node_removed(Node *p_node) {
200
201 if (p_node == item_list) {
202 item_list = NULL;
203 hide();
204 dialog->hide();
205 }
206 }
207
_notification(int p_notification)208 void ItemListEditor::_notification(int p_notification) {
209
210 if (p_notification == NOTIFICATION_ENTER_TREE) {
211
212 add_button->set_icon(get_icon("Add", "EditorIcons"));
213 del_button->set_icon(get_icon("Remove", "EditorIcons"));
214 }
215 }
216
_add_pressed()217 void ItemListEditor::_add_pressed() {
218
219 if (selected_idx == -1)
220 return;
221
222 item_plugins[selected_idx]->add_item();
223 }
224
_delete_pressed()225 void ItemListEditor::_delete_pressed() {
226
227 TreeItem *ti = tree->get_selected();
228
229 if (!ti)
230 return;
231
232 if (ti->get_parent() != tree->get_root())
233 return;
234
235 int idx = ti->get_text(0).to_int();
236
237 if (selected_idx == -1)
238 return;
239
240 item_plugins[selected_idx]->erase(idx);
241 }
242
_edit_items()243 void ItemListEditor::_edit_items() {
244
245 dialog->popup_centered(Vector2(300, 400));
246 }
247
edit(Node * p_item_list)248 void ItemListEditor::edit(Node *p_item_list) {
249
250 item_list = p_item_list;
251
252 if (!item_list) {
253 selected_idx = -1;
254 property_editor->edit(NULL);
255 return;
256 }
257
258 for (int i = 0; i < item_plugins.size(); i++) {
259 if (item_plugins[i]->handles(p_item_list)) {
260
261 item_plugins[i]->set_object(p_item_list);
262 property_editor->edit(item_plugins[i]);
263
264 if (has_icon(item_list->get_type(), "EditorIcons"))
265 toolbar_button->set_icon(get_icon(item_list->get_type(), "EditorIcons"));
266 else
267 toolbar_button->set_icon(Ref<Texture>());
268
269 selected_idx = i;
270 return;
271 }
272 }
273
274 selected_idx = -1;
275 property_editor->edit(NULL);
276 }
277
handles(Object * p_object) const278 bool ItemListEditor::handles(Object *p_object) const {
279
280 for (int i = 0; i < item_plugins.size(); i++) {
281 if (item_plugins[i]->handles(p_object)) {
282 return true;
283 }
284 }
285
286 return false;
287 }
288
_bind_methods()289 void ItemListEditor::_bind_methods() {
290
291 ObjectTypeDB::bind_method("_edit_items", &ItemListEditor::_edit_items);
292 ObjectTypeDB::bind_method("_add_button", &ItemListEditor::_add_pressed);
293 ObjectTypeDB::bind_method("_delete_button", &ItemListEditor::_delete_pressed);
294 }
295
ItemListEditor()296 ItemListEditor::ItemListEditor() {
297
298 selected_idx = -1;
299
300 add_child(memnew(VSeparator));
301
302 toolbar_button = memnew(ToolButton);
303 toolbar_button->set_text(TTR("Items"));
304 add_child(toolbar_button);
305 toolbar_button->connect("pressed", this, "_edit_items");
306
307 dialog = memnew(AcceptDialog);
308 dialog->set_title(TTR("Item List Editor"));
309 add_child(dialog);
310
311 VBoxContainer *vbc = memnew(VBoxContainer);
312 dialog->add_child(vbc);
313 dialog->set_child_rect(vbc);
314
315 HBoxContainer *hbc = memnew(HBoxContainer);
316 hbc->set_h_size_flags(SIZE_EXPAND_FILL);
317 vbc->add_child(hbc);
318
319 add_button = memnew(Button);
320 add_button->set_text(TTR("Add"));
321 hbc->add_child(add_button);
322 add_button->connect("pressed", this, "_add_button");
323
324 hbc->add_spacer();
325
326 del_button = memnew(Button);
327 del_button->set_text(TTR("Delete"));
328 hbc->add_child(del_button);
329 del_button->connect("pressed", this, "_delete_button");
330
331 property_editor = memnew(PropertyEditor);
332 property_editor->hide_top_label();
333 property_editor->set_subsection_selectable(true);
334 vbc->add_child(property_editor);
335 property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
336
337 tree = property_editor->get_scene_tree();
338 }
339
~ItemListEditor()340 ItemListEditor::~ItemListEditor() {
341
342 for (int i = 0; i < item_plugins.size(); i++)
343 memdelete(item_plugins[i]);
344 }
345
edit(Object * p_object)346 void ItemListEditorPlugin::edit(Object *p_object) {
347
348 item_list_editor->edit(p_object->cast_to<Node>());
349 }
350
handles(Object * p_object) const351 bool ItemListEditorPlugin::handles(Object *p_object) const {
352
353 return item_list_editor->handles(p_object);
354 }
355
make_visible(bool p_visible)356 void ItemListEditorPlugin::make_visible(bool p_visible) {
357
358 if (p_visible) {
359 item_list_editor->show();
360 } else {
361
362 item_list_editor->hide();
363 item_list_editor->edit(NULL);
364 }
365 }
366
ItemListEditorPlugin(EditorNode * p_node)367 ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) {
368
369 editor = p_node;
370 item_list_editor = memnew(ItemListEditor);
371 CanvasItemEditor::get_singleton()->add_control_to_menu_panel(item_list_editor);
372
373 item_list_editor->hide();
374 item_list_editor->add_plugin(memnew(ItemListOptionButtonPlugin));
375 item_list_editor->add_plugin(memnew(ItemListPopupMenuPlugin));
376 }
377
~ItemListEditorPlugin()378 ItemListEditorPlugin::~ItemListEditorPlugin() {
379 }
380