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