1 /*************************************************************************/
2 /*  resource_preloader_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 "resource_preloader_editor_plugin.h"
31 #include "editor/editor_settings.h"
32 #include "globals.h"
33 #include "io/resource_loader.h"
34 #include "scene/resources/scene_preloader.h"
35 
_input_event(InputEvent p_event)36 void ResourcePreloaderEditor::_input_event(InputEvent p_event) {
37 }
38 
_notification(int p_what)39 void ResourcePreloaderEditor::_notification(int p_what) {
40 
41 	if (p_what == NOTIFICATION_FIXED_PROCESS) {
42 	}
43 
44 	if (p_what == NOTIFICATION_ENTER_TREE) {
45 		load->set_icon(get_icon("Folder", "EditorIcons"));
46 		_delete->set_icon(get_icon("Del", "EditorIcons"));
47 	}
48 
49 	if (p_what == NOTIFICATION_READY) {
50 
51 		//		NodePath("/root")->connect("node_removed", this,"_node_removed",Vector<Variant>(),true);
52 	}
53 
54 	if (p_what == NOTIFICATION_DRAW) {
55 	}
56 }
57 
_files_load_request(const Vector<String> & p_paths)58 void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) {
59 
60 	for (int i = 0; i < p_paths.size(); i++) {
61 
62 		String path = p_paths[i];
63 
64 		RES resource;
65 		resource = ResourceLoader::load(path);
66 
67 		if (resource.is_null()) {
68 			dialog->set_text(TTR("ERROR: Couldn't load resource!"));
69 			dialog->set_title(TTR("Error!"));
70 			//dialog->get_cancel()->set_text("Close");
71 			dialog->get_ok()->set_text(TTR("Close"));
72 			dialog->popup_centered_minsize();
73 			return; ///beh should show an error i guess
74 		}
75 
76 		String basename = path.get_file().basename();
77 		String name = basename;
78 		int counter = 1;
79 		while (preloader->has_resource(name)) {
80 			counter++;
81 			name = basename + " " + itos(counter);
82 		}
83 
84 		undo_redo->create_action(TTR("Add Resource"));
85 		undo_redo->add_do_method(preloader, "add_resource", name, resource);
86 		undo_redo->add_undo_method(preloader, "remove_resource", name);
87 		undo_redo->add_do_method(this, "_update_library");
88 		undo_redo->add_undo_method(this, "_update_library");
89 		undo_redo->commit_action();
90 	}
91 }
92 
_load_pressed()93 void ResourcePreloaderEditor::_load_pressed() {
94 
95 	loading_scene = false;
96 
97 	file->clear_filters();
98 	List<String> extensions;
99 	ResourceLoader::get_recognized_extensions_for_type("", &extensions);
100 	for (int i = 0; i < extensions.size(); i++)
101 		file->add_filter("*." + extensions[i]);
102 
103 	file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
104 
105 	file->popup_centered_ratio();
106 }
107 
_item_edited()108 void ResourcePreloaderEditor::_item_edited() {
109 
110 	if (!tree->get_selected())
111 		return;
112 
113 	TreeItem *s = tree->get_selected();
114 
115 	if (tree->get_selected_column() == 0) {
116 		// renamed
117 		String old_name = s->get_metadata(0);
118 		String new_name = s->get_text(0);
119 		if (old_name == new_name)
120 			return;
121 
122 		if (new_name == "" || new_name.find("\\") != -1 || new_name.find("/") != -1 || preloader->has_resource(new_name)) {
123 
124 			s->set_text(0, old_name);
125 			return;
126 		}
127 
128 		RES samp = preloader->get_resource(old_name);
129 		undo_redo->create_action(TTR("Rename Resource"));
130 		undo_redo->add_do_method(preloader, "remove_resource", old_name);
131 		undo_redo->add_do_method(preloader, "add_resource", new_name, samp);
132 		undo_redo->add_undo_method(preloader, "remove_resource", new_name);
133 		undo_redo->add_undo_method(preloader, "add_resource", old_name, samp);
134 		undo_redo->add_do_method(this, "_update_library");
135 		undo_redo->add_undo_method(this, "_update_library");
136 		undo_redo->commit_action();
137 	}
138 }
139 
_delete_confirm_pressed()140 void ResourcePreloaderEditor::_delete_confirm_pressed() {
141 
142 	if (!tree->get_selected())
143 		return;
144 
145 	String to_remove = tree->get_selected()->get_text(0);
146 	undo_redo->create_action(TTR("Delete Resource"));
147 	undo_redo->add_do_method(preloader, "remove_resource", to_remove);
148 	undo_redo->add_undo_method(preloader, "add_resource", to_remove, preloader->get_resource(to_remove));
149 	undo_redo->add_do_method(this, "_update_library");
150 	undo_redo->add_undo_method(this, "_update_library");
151 	undo_redo->commit_action();
152 }
153 
_paste_pressed()154 void ResourcePreloaderEditor::_paste_pressed() {
155 
156 	RES r = EditorSettings::get_singleton()->get_resource_clipboard();
157 	if (!r.is_valid()) {
158 		dialog->set_text(TTR("Resource clipboard is empty!"));
159 		dialog->set_title(TTR("Error!"));
160 		//dialog->get_cancel()->set_text("Close");
161 		dialog->get_ok()->set_text(TTR("Close"));
162 		dialog->popup_centered_minsize();
163 		return; ///beh should show an error i guess
164 	}
165 
166 	String name = r->get_name();
167 	if (name == "")
168 		name = r->get_path().get_file();
169 	if (name == "")
170 		name = r->get_type();
171 
172 	String basename = name;
173 	int counter = 1;
174 	while (preloader->has_resource(name)) {
175 		counter++;
176 		name = basename + " " + itos(counter);
177 	}
178 
179 	undo_redo->create_action(TTR("Paste Resource"));
180 	undo_redo->add_do_method(preloader, "add_resource", name, r);
181 	undo_redo->add_undo_method(preloader, "remove_resource", name);
182 	undo_redo->add_do_method(this, "_update_library");
183 	undo_redo->add_undo_method(this, "_update_library");
184 	undo_redo->commit_action();
185 }
186 
_delete_pressed()187 void ResourcePreloaderEditor::_delete_pressed() {
188 
189 	if (!tree->get_selected())
190 		return;
191 
192 	_delete_confirm_pressed(); //it has undo.. why bother with a dialog..
193 	/*
194 	dialog->set_title("Confirm...");
195 	dialog->set_text("Remove Resource '"+tree->get_selected()->get_text(0)+"' ?");
196 	//dialog->get_cancel()->set_text("Cancel");
197 	//dialog->get_ok()->show();
198 	dialog->get_ok()->set_text("Remove");
199 	dialog->popup_centered(Size2(300,60));*/
200 }
201 
_update_library()202 void ResourcePreloaderEditor::_update_library() {
203 
204 	tree->clear();
205 	tree->set_hide_root(true);
206 	TreeItem *root = tree->create_item(NULL);
207 
208 	List<StringName> rnames;
209 	preloader->get_resource_list(&rnames);
210 
211 	List<String> names;
212 	for (List<StringName>::Element *E = rnames.front(); E; E = E->next()) {
213 		names.push_back(E->get());
214 	}
215 
216 	names.sort();
217 
218 	for (List<String>::Element *E = names.front(); E; E = E->next()) {
219 
220 		TreeItem *ti = tree->create_item(root);
221 		ti->set_cell_mode(0, TreeItem::CELL_MODE_STRING);
222 		ti->set_editable(0, true);
223 		ti->set_selectable(0, true);
224 		ti->set_text(0, E->get());
225 		ti->set_metadata(0, E->get());
226 
227 		RES r = preloader->get_resource(E->get());
228 
229 		ERR_CONTINUE(r.is_null());
230 
231 		ti->set_tooltip(0, r->get_path());
232 		String type = r->get_type();
233 		ti->set_text(1, type);
234 		ti->set_selectable(1, false);
235 
236 		if (has_icon(type, "EditorIcons"))
237 			ti->set_icon(1, get_icon(type, "EditorIcons"));
238 	}
239 
240 	//player->add_resource("default",resource);
241 }
242 
edit(ResourcePreloader * p_preloader)243 void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) {
244 
245 	preloader = p_preloader;
246 
247 	if (p_preloader) {
248 		_update_library();
249 	} else {
250 
251 		hide();
252 		set_fixed_process(false);
253 	}
254 }
255 
get_drag_data_fw(const Point2 & p_point,Control * p_from)256 Variant ResourcePreloaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
257 
258 	TreeItem *ti = tree->get_item_at_pos(p_point);
259 	if (!ti)
260 		return Variant();
261 
262 	String name = ti->get_metadata(0);
263 
264 	RES res = preloader->get_resource(name);
265 	if (!res.is_valid())
266 		return Variant();
267 
268 	return EditorNode::get_singleton()->drag_resource(res, p_from);
269 }
270 
can_drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from) const271 bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
272 
273 	Dictionary d = p_data;
274 
275 	if (!d.has("type"))
276 		return false;
277 
278 	if (d.has("from") && (Object *)(d["from"]) == tree)
279 		return false;
280 
281 	if (String(d["type"]) == "resource" && d.has("resource")) {
282 		RES r = d["resource"];
283 
284 		return r.is_valid();
285 	}
286 
287 	if (String(d["type"]) == "files") {
288 
289 		Vector<String> files = d["files"];
290 
291 		if (files.size() == 0)
292 			return false;
293 
294 		return true;
295 	}
296 	return false;
297 }
298 
drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from)299 void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
300 
301 	if (!can_drop_data_fw(p_point, p_data, p_from))
302 		return;
303 
304 	Dictionary d = p_data;
305 
306 	if (!d.has("type"))
307 		return;
308 
309 	if (String(d["type"]) == "resource" && d.has("resource")) {
310 		RES r = d["resource"];
311 
312 		if (r.is_valid()) {
313 
314 			String basename;
315 			if (r->get_name() != "") {
316 				basename = r->get_name();
317 			} else if (r->get_path().is_resource_file()) {
318 				basename = r->get_path().basename();
319 			} else {
320 				basename = "Resource";
321 			}
322 
323 			String name = basename;
324 			int counter = 0;
325 			while (preloader->has_resource(name)) {
326 				counter++;
327 				name = basename + "_" + itos(counter);
328 			}
329 
330 			undo_redo->create_action(TTR("Add Resource"));
331 			undo_redo->add_do_method(preloader, "add_resource", name, r);
332 			undo_redo->add_undo_method(preloader, "remove_resource", name);
333 			undo_redo->add_do_method(this, "_update_library");
334 			undo_redo->add_undo_method(this, "_update_library");
335 			undo_redo->commit_action();
336 		}
337 	}
338 
339 	if (String(d["type"]) == "files") {
340 
341 		Vector<String> files = d["files"];
342 
343 		_files_load_request(files);
344 	}
345 }
346 
_bind_methods()347 void ResourcePreloaderEditor::_bind_methods() {
348 
349 	ObjectTypeDB::bind_method(_MD("_input_event"), &ResourcePreloaderEditor::_input_event);
350 	ObjectTypeDB::bind_method(_MD("_load_pressed"), &ResourcePreloaderEditor::_load_pressed);
351 	ObjectTypeDB::bind_method(_MD("_item_edited"), &ResourcePreloaderEditor::_item_edited);
352 	ObjectTypeDB::bind_method(_MD("_delete_pressed"), &ResourcePreloaderEditor::_delete_pressed);
353 	ObjectTypeDB::bind_method(_MD("_paste_pressed"), &ResourcePreloaderEditor::_paste_pressed);
354 	ObjectTypeDB::bind_method(_MD("_delete_confirm_pressed"), &ResourcePreloaderEditor::_delete_confirm_pressed);
355 	ObjectTypeDB::bind_method(_MD("_files_load_request"), &ResourcePreloaderEditor::_files_load_request);
356 	ObjectTypeDB::bind_method(_MD("_update_library"), &ResourcePreloaderEditor::_update_library);
357 
358 	ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw);
359 	ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw);
360 	ObjectTypeDB::bind_method(_MD("drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw);
361 }
362 
ResourcePreloaderEditor()363 ResourcePreloaderEditor::ResourcePreloaderEditor() {
364 
365 	//add_style_override("panel", get_stylebox("panel","Panel"));
366 
367 	VBoxContainer *vbc = memnew(VBoxContainer);
368 	add_child(vbc);
369 
370 	HBoxContainer *hbc = memnew(HBoxContainer);
371 	vbc->add_child(hbc);
372 
373 	load = memnew(Button);
374 	load->set_tooltip(TTR("Load Resource"));
375 	hbc->add_child(load);
376 
377 	_delete = memnew(Button);
378 	hbc->add_child(_delete);
379 
380 	paste = memnew(Button);
381 	paste->set_text(TTR("Paste"));
382 	hbc->add_child(paste);
383 
384 	file = memnew(EditorFileDialog);
385 	add_child(file);
386 
387 	tree = memnew(Tree);
388 	tree->set_columns(2);
389 	tree->set_column_min_width(0, 3);
390 	tree->set_column_min_width(1, 1);
391 	tree->set_column_expand(0, true);
392 	tree->set_column_expand(1, true);
393 	tree->set_v_size_flags(SIZE_EXPAND_FILL);
394 
395 	tree->set_drag_forwarding(this);
396 	vbc->add_child(tree);
397 
398 	dialog = memnew(AcceptDialog);
399 	add_child(dialog);
400 
401 	load->connect("pressed", this, "_load_pressed");
402 	_delete->connect("pressed", this, "_delete_pressed");
403 	paste->connect("pressed", this, "_paste_pressed");
404 	file->connect("files_selected", this, "_files_load_request");
405 	//dialog->connect("confirmed", this,"_delete_confirm_pressed");
406 	tree->connect("item_edited", this, "_item_edited");
407 	loading_scene = false;
408 }
409 
edit(Object * p_object)410 void ResourcePreloaderEditorPlugin::edit(Object *p_object) {
411 
412 	preloader_editor->set_undo_redo(&get_undo_redo());
413 	ResourcePreloader *s = p_object->cast_to<ResourcePreloader>();
414 	if (!s)
415 		return;
416 
417 	preloader_editor->edit(s);
418 }
419 
handles(Object * p_object) const420 bool ResourcePreloaderEditorPlugin::handles(Object *p_object) const {
421 
422 	return p_object->is_type("ResourcePreloader");
423 }
424 
make_visible(bool p_visible)425 void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) {
426 
427 	if (p_visible) {
428 		//preloader_editor->show();
429 		button->show();
430 		editor->make_bottom_panel_item_visible(preloader_editor);
431 		//		preloader_editor->set_process(true);
432 	} else {
433 
434 		if (preloader_editor->is_visible())
435 			editor->hide_bottom_panel();
436 		button->hide();
437 		//preloader_editor->hide();
438 		//		preloader_editor->set_process(false);
439 	}
440 }
441 
ResourcePreloaderEditorPlugin(EditorNode * p_node)442 ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node) {
443 
444 	editor = p_node;
445 	preloader_editor = memnew(ResourcePreloaderEditor);
446 	preloader_editor->set_custom_minimum_size(Size2(0, 250));
447 
448 	button = editor->add_bottom_panel_item("ResourcePreloader", preloader_editor);
449 	button->hide();
450 
451 	//	preloader_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
452 	//	preloader_editor->set_margin( MARGIN_TOP, 120 );
453 }
454 
~ResourcePreloaderEditorPlugin()455 ResourcePreloaderEditorPlugin::~ResourcePreloaderEditorPlugin() {
456 }
457