1 /*************************************************************************/
2 /* file_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 "file_dialog.h"
31 #include "os/keyboard.h"
32 #include "print_string.h"
33 #include "scene/gui/label.h"
34
35 FileDialog::GetIconFunc FileDialog::get_icon_func = NULL;
36 FileDialog::GetIconFunc FileDialog::get_large_icon_func = NULL;
37
38 FileDialog::RegisterFunc FileDialog::register_func = NULL;
39 FileDialog::RegisterFunc FileDialog::unregister_func = NULL;
40
get_vbox()41 VBoxContainer *FileDialog::get_vbox() {
42 return vbox;
43 }
44
_notification(int p_what)45 void FileDialog::_notification(int p_what) {
46
47 if (p_what == NOTIFICATION_ENTER_TREE) {
48
49 refresh->set_icon(get_icon("reload"));
50 }
51
52 if (p_what == NOTIFICATION_DRAW) {
53
54 //RID ci = get_canvas_item();
55 //get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
56 }
57
58 if (p_what == NOTIFICATION_POPUP_HIDE) {
59
60 set_process_unhandled_input(false);
61 }
62 }
63
_unhandled_input(const InputEvent & p_event)64 void FileDialog::_unhandled_input(const InputEvent &p_event) {
65
66 if (p_event.type == InputEvent::KEY && is_window_modal_on_top()) {
67
68 const InputEventKey &k = p_event.key;
69
70 if (k.pressed) {
71
72 bool handled = true;
73
74 switch (k.scancode) {
75
76 case KEY_H: {
77
78 if (k.mod.command) {
79 set_show_hidden_files(!show_hidden_files);
80 } else {
81 handled = false;
82 }
83
84 } break;
85 case KEY_F5: {
86
87 invalidate();
88 } break;
89 default: { handled = false; }
90 }
91
92 if (handled)
93 accept_event();
94 }
95 }
96 }
97
set_enable_multiple_selection(bool p_enable)98 void FileDialog::set_enable_multiple_selection(bool p_enable) {
99
100 tree->set_select_mode(p_enable ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
101 };
102
get_selected_files() const103 Vector<String> FileDialog::get_selected_files() const {
104
105 Vector<String> list;
106
107 TreeItem *item = tree->get_root();
108 while ((item = tree->get_next_selected(item))) {
109
110 list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
111 };
112
113 return list;
114 };
115
update_dir()116 void FileDialog::update_dir() {
117
118 dir->set_text(dir_access->get_current_dir());
119 }
120
_dir_entered(String p_dir)121 void FileDialog::_dir_entered(String p_dir) {
122
123 dir_access->change_dir(p_dir);
124 file->set_text("");
125 invalidate();
126 update_dir();
127 }
128
_file_entered(const String & p_file)129 void FileDialog::_file_entered(const String &p_file) {
130
131 _action_pressed();
132 }
133
_save_confirm_pressed()134 void FileDialog::_save_confirm_pressed() {
135 String f = dir_access->get_current_dir().plus_file(file->get_text());
136 emit_signal("file_selected", f);
137 hide();
138 }
139
_post_popup()140 void FileDialog::_post_popup() {
141
142 ConfirmationDialog::_post_popup();
143 if (invalidated) {
144 update_file_list();
145 invalidated = false;
146 }
147 if (mode == MODE_SAVE_FILE)
148 file->grab_focus();
149 else
150 tree->grab_focus();
151
152 set_process_unhandled_input(true);
153 }
154
_action_pressed()155 void FileDialog::_action_pressed() {
156
157 if (mode == MODE_OPEN_FILES) {
158
159 TreeItem *ti = tree->get_next_selected(NULL);
160 String fbase = dir_access->get_current_dir();
161
162 DVector<String> files;
163 while (ti) {
164
165 files.push_back(fbase.plus_file(ti->get_text(0)));
166 ti = tree->get_next_selected(ti);
167 }
168
169 if (files.size()) {
170 emit_signal("files_selected", files);
171 hide();
172 }
173
174 return;
175 }
176
177 String f = dir_access->get_current_dir().plus_file(file->get_text());
178
179 if ((mode == MODE_OPEN_ANY || mode == MODE_OPEN_FILE) && dir_access->file_exists(f)) {
180 emit_signal("file_selected", f);
181 hide();
182 } else if (mode == MODE_OPEN_ANY || mode == MODE_OPEN_DIR) {
183
184 String path = dir_access->get_current_dir();
185 /*if (tree->get_selected()) {
186 Dictionary d = tree->get_selected()->get_metadata(0);
187 if (d["dir"]) {
188 path=path+"/"+String(d["name"]);
189 }
190 }*/
191 path = path.replace("\\", "/");
192 emit_signal("dir_selected", path);
193 hide();
194 }
195
196 if (mode == MODE_SAVE_FILE) {
197
198 bool valid = false;
199
200 if (filter->get_selected() == filter->get_item_count() - 1) {
201 valid = true; //match none
202 } else if (filters.size() > 1 && filter->get_selected() == 0) {
203 // match all filters
204 for (int i = 0; i < filters.size(); i++) {
205
206 String flt = filters[i].get_slice(";", 0);
207 for (int j = 0; j < flt.get_slice_count(","); j++) {
208
209 String str = flt.get_slice(",", j).strip_edges();
210 if (f.match(str)) {
211 valid = true;
212 break;
213 }
214 }
215 if (valid)
216 break;
217 }
218 } else {
219 int idx = filter->get_selected();
220 if (filters.size() > 1)
221 idx--;
222 if (idx >= 0 && idx < filters.size()) {
223
224 String flt = filters[idx].get_slice(";", 0);
225 int filterSliceCount = flt.get_slice_count(",");
226 for (int j = 0; j < filterSliceCount; j++) {
227
228 String str = (flt.get_slice(",", j).strip_edges());
229 if (f.match(str)) {
230 valid = true;
231 break;
232 }
233 }
234
235 if (!valid && filterSliceCount > 0) {
236 String str = (flt.get_slice(",", 0).strip_edges());
237 f += str.substr(1, str.length() - 1);
238 file->set_text(f.get_file());
239 valid = true;
240 }
241 } else {
242 valid = true;
243 }
244 }
245
246 if (!valid) {
247
248 exterr->popup_centered_minsize(Size2(250, 80));
249 return;
250 }
251
252 if (dir_access->file_exists(f)) {
253 confirm_save->set_text(RTR("File Exists, Overwrite?"));
254 confirm_save->popup_centered(Size2(200, 80));
255 } else {
256
257 emit_signal("file_selected", f);
258 hide();
259 }
260 }
261 }
262
_cancel_pressed()263 void FileDialog::_cancel_pressed() {
264
265 file->set_text("");
266 invalidate();
267 hide();
268 }
269
_tree_selected()270 void FileDialog::_tree_selected() {
271
272 TreeItem *ti = tree->get_selected();
273 if (!ti)
274 return;
275 Dictionary d = ti->get_metadata(0);
276
277 if (!d["dir"]) {
278
279 file->set_text(d["name"]);
280 }
281 }
282
_tree_dc_selected()283 void FileDialog::_tree_dc_selected() {
284
285 TreeItem *ti = tree->get_selected();
286 if (!ti)
287 return;
288
289 Dictionary d = ti->get_metadata(0);
290
291 if (d["dir"]) {
292
293 dir_access->change_dir(d["name"]);
294 if (mode == MODE_OPEN_FILE || mode == MODE_OPEN_FILES || mode == MODE_OPEN_DIR || mode == MODE_OPEN_ANY)
295 file->set_text("");
296 call_deferred("_update_file_list");
297 call_deferred("_update_dir");
298 } else {
299
300 _action_pressed();
301 }
302 }
303
update_file_list()304 void FileDialog::update_file_list() {
305
306 tree->clear();
307 dir_access->list_dir_begin();
308
309 TreeItem *root = tree->create_item();
310 Ref<Texture> folder = get_icon("folder");
311 List<String> files;
312 List<String> dirs;
313
314 bool isdir;
315 bool ishidden;
316 bool show_hidden = show_hidden_files;
317 String item;
318
319 while ((item = dir_access->get_next(&isdir)) != "") {
320
321 ishidden = dir_access->current_is_hidden();
322
323 if (show_hidden || !ishidden) {
324 if (!isdir)
325 files.push_back(item);
326 else
327 dirs.push_back(item);
328 }
329 }
330
331 if (dirs.find("..") == NULL) {
332 //may happen if lacking permissions
333 dirs.push_back("..");
334 }
335
336 dirs.sort_custom<NoCaseComparator>();
337 files.sort_custom<NoCaseComparator>();
338
339 while (!dirs.empty()) {
340
341 if (dirs.front()->get() != ".") {
342 TreeItem *ti = tree->create_item(root);
343 ti->set_text(0, dirs.front()->get() + "/");
344 ti->set_icon(0, folder);
345 Dictionary d;
346 d["name"] = dirs.front()->get();
347 d["dir"] = true;
348 ti->set_metadata(0, d);
349 }
350 dirs.pop_front();
351 }
352
353 dirs.clear();
354
355 List<String> patterns;
356 // build filter
357 if (filter->get_selected() == filter->get_item_count() - 1) {
358
359 // match all
360 } else if (filters.size() > 1 && filter->get_selected() == 0) {
361 // match all filters
362 for (int i = 0; i < filters.size(); i++) {
363
364 String f = filters[i].get_slice(";", 0);
365 for (int j = 0; j < f.get_slice_count(","); j++) {
366
367 patterns.push_back(f.get_slice(",", j).strip_edges());
368 }
369 }
370 } else {
371 int idx = filter->get_selected();
372 if (filters.size() > 1)
373 idx--;
374
375 if (idx >= 0 && idx < filters.size()) {
376
377 String f = filters[idx].get_slice(";", 0);
378 for (int j = 0; j < f.get_slice_count(","); j++) {
379
380 patterns.push_back(f.get_slice(",", j).strip_edges());
381 }
382 }
383 }
384
385 String base_dir = dir_access->get_current_dir();
386
387 while (!files.empty()) {
388
389 bool match = patterns.empty();
390 String match_str;
391
392 for (List<String>::Element *E = patterns.front(); E; E = E->next()) {
393
394 if (files.front()->get().matchn(E->get())) {
395 match_str = E->get();
396 match = true;
397 break;
398 }
399 }
400
401 if (match) {
402 TreeItem *ti = tree->create_item(root);
403 ti->set_text(0, files.front()->get());
404
405 if (get_icon_func) {
406
407 Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
408 ti->set_icon(0, icon);
409 }
410
411 if (mode == MODE_OPEN_DIR) {
412 ti->set_custom_color(0, get_color("files_disabled"));
413 ti->set_selectable(0, false);
414 }
415 Dictionary d;
416 d["name"] = files.front()->get();
417 d["dir"] = false;
418 ti->set_metadata(0, d);
419
420 if (file->get_text() == files.front()->get() || match_str == files.front()->get())
421 ti->select(0);
422 }
423
424 files.pop_front();
425 }
426
427 if (tree->get_root() && tree->get_root()->get_children() && tree->get_selected() == NULL)
428 tree->get_root()->get_children()->select(0);
429
430 files.clear();
431 }
432
_filter_selected(int)433 void FileDialog::_filter_selected(int) {
434
435 update_file_list();
436 }
437
update_filters()438 void FileDialog::update_filters() {
439
440 filter->clear();
441
442 if (filters.size() > 1) {
443 String all_filters;
444
445 const int max_filters = 5;
446
447 for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
448 String flt = filters[i].get_slice(";", 0);
449 if (i > 0)
450 all_filters += ",";
451 all_filters += flt;
452 }
453
454 if (max_filters < filters.size())
455 all_filters += ", ...";
456
457 filter->add_item(RTR("All Recognized") + " ( " + all_filters + " )");
458 }
459 for (int i = 0; i < filters.size(); i++) {
460
461 String flt = filters[i].get_slice(";", 0).strip_edges();
462 String desc = filters[i].get_slice(";", 1).strip_edges();
463 if (desc.length())
464 filter->add_item(String(XL_MESSAGE(desc)) + " ( " + flt + " )");
465 else
466 filter->add_item("( " + flt + " )");
467 }
468
469 filter->add_item(RTR("All Files (*)"));
470 }
471
clear_filters()472 void FileDialog::clear_filters() {
473
474 filters.clear();
475 update_filters();
476 invalidate();
477 }
add_filter(const String & p_filter)478 void FileDialog::add_filter(const String &p_filter) {
479
480 filters.push_back(p_filter);
481 update_filters();
482 invalidate();
483 }
484
set_filters(const Vector<String> & p_filters)485 void FileDialog::set_filters(const Vector<String> &p_filters) {
486 filters = p_filters;
487 update_filters();
488 invalidate();
489 }
490
get_filters() const491 Vector<String> FileDialog::get_filters() const {
492 return filters;
493 }
494
get_current_dir() const495 String FileDialog::get_current_dir() const {
496
497 return dir->get_text();
498 }
get_current_file() const499 String FileDialog::get_current_file() const {
500
501 return file->get_text();
502 }
get_current_path() const503 String FileDialog::get_current_path() const {
504
505 return dir->get_text().plus_file(file->get_text());
506 }
set_current_dir(const String & p_dir)507 void FileDialog::set_current_dir(const String &p_dir) {
508
509 dir_access->change_dir(p_dir);
510 update_dir();
511 invalidate();
512 }
set_current_file(const String & p_file)513 void FileDialog::set_current_file(const String &p_file) {
514
515 file->set_text(p_file);
516 update_dir();
517 invalidate();
518 int lp = p_file.find_last(".");
519 if (lp != -1) {
520 file->select(0, lp);
521 file->grab_focus();
522 }
523 }
set_current_path(const String & p_path)524 void FileDialog::set_current_path(const String &p_path) {
525
526 if (!p_path.size())
527 return;
528 int pos = MAX(p_path.find_last("/"), p_path.find_last("\\"));
529 if (pos == -1) {
530
531 set_current_file(p_path);
532 } else {
533
534 String dir = p_path.substr(0, pos);
535 String file = p_path.substr(pos + 1, p_path.length());
536 set_current_dir(dir);
537 set_current_file(file);
538 }
539 }
540
set_mode(Mode p_mode)541 void FileDialog::set_mode(Mode p_mode) {
542
543 mode = p_mode;
544 switch (mode) {
545
546 case MODE_OPEN_FILE:
547 get_ok()->set_text(RTR("Open"));
548 set_title(RTR("Open a File"));
549 makedir->hide();
550 break;
551 case MODE_OPEN_FILES:
552 get_ok()->set_text(RTR("Open"));
553 set_title(RTR("Open File(s)"));
554 makedir->hide();
555 break;
556 case MODE_OPEN_DIR:
557 get_ok()->set_text(RTR("Open"));
558 set_title(RTR("Open a Directory"));
559 makedir->show();
560 break;
561 case MODE_OPEN_ANY:
562 get_ok()->set_text(RTR("Open"));
563 set_title(RTR("Open a File or Directory"));
564 makedir->show();
565 break;
566 case MODE_SAVE_FILE:
567 get_ok()->set_text(RTR("Save"));
568 set_title(RTR("Save a File"));
569 makedir->show();
570 break;
571 }
572
573 if (mode == MODE_OPEN_FILES) {
574 tree->set_select_mode(Tree::SELECT_MULTI);
575 } else {
576 tree->set_select_mode(Tree::SELECT_SINGLE);
577 }
578 }
579
get_mode() const580 FileDialog::Mode FileDialog::get_mode() const {
581
582 return mode;
583 }
584
set_access(Access p_access)585 void FileDialog::set_access(Access p_access) {
586
587 ERR_FAIL_INDEX(p_access, 3);
588 if (access == p_access)
589 return;
590 memdelete(dir_access);
591 switch (p_access) {
592 case ACCESS_FILESYSTEM: {
593
594 dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
595 } break;
596 case ACCESS_RESOURCES: {
597
598 dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
599 } break;
600 case ACCESS_USERDATA: {
601
602 dir_access = DirAccess::create(DirAccess::ACCESS_USERDATA);
603 } break;
604 }
605 access = p_access;
606 _update_drives();
607 invalidate();
608 update_filters();
609 update_dir();
610 }
611
invalidate()612 void FileDialog::invalidate() {
613
614 if (is_visible()) {
615 update_file_list();
616 invalidated = false;
617 } else {
618 invalidated = true;
619 }
620 }
621
get_access() const622 FileDialog::Access FileDialog::get_access() const {
623
624 return access;
625 }
626
_make_dir_confirm()627 void FileDialog::_make_dir_confirm() {
628
629 Error err = dir_access->make_dir(makedirname->get_text());
630 if (err == OK) {
631 dir_access->change_dir(makedirname->get_text());
632 invalidate();
633 update_filters();
634 update_dir();
635 } else {
636 mkdirerr->popup_centered_minsize(Size2(250, 50));
637 }
638 makedirname->set_text(""); // reset label
639 }
640
_make_dir()641 void FileDialog::_make_dir() {
642
643 makedialog->popup_centered_minsize(Size2(250, 80));
644 makedirname->grab_focus();
645 }
646
_select_drive(int p_idx)647 void FileDialog::_select_drive(int p_idx) {
648
649 String d = drives->get_item_text(p_idx);
650 dir_access->change_dir(d);
651 file->set_text("");
652 invalidate();
653 update_dir();
654 }
655
_update_drives()656 void FileDialog::_update_drives() {
657
658 int dc = dir_access->get_drive_count();
659 if (dc == 0 || access != ACCESS_FILESYSTEM) {
660 drives->hide();
661 } else {
662 drives->clear();
663 drives->show();
664
665 for (int i = 0; i < dir_access->get_drive_count(); i++) {
666 String d = dir_access->get_drive(i);
667 drives->add_item(dir_access->get_drive(i));
668 }
669
670 drives->select(dir_access->get_current_drive());
671 }
672 }
673
674 bool FileDialog::default_show_hidden_files = false;
675
_bind_methods()676 void FileDialog::_bind_methods() {
677
678 ObjectTypeDB::bind_method(_MD("_unhandled_input"), &FileDialog::_unhandled_input);
679
680 ObjectTypeDB::bind_method(_MD("_tree_selected"), &FileDialog::_tree_selected);
681 ObjectTypeDB::bind_method(_MD("_tree_db_selected"), &FileDialog::_tree_dc_selected);
682 ObjectTypeDB::bind_method(_MD("_dir_entered"), &FileDialog::_dir_entered);
683 ObjectTypeDB::bind_method(_MD("_file_entered"), &FileDialog::_file_entered);
684 ObjectTypeDB::bind_method(_MD("_action_pressed"), &FileDialog::_action_pressed);
685 ObjectTypeDB::bind_method(_MD("_cancel_pressed"), &FileDialog::_cancel_pressed);
686 ObjectTypeDB::bind_method(_MD("_filter_selected"), &FileDialog::_filter_selected);
687 ObjectTypeDB::bind_method(_MD("_save_confirm_pressed"), &FileDialog::_save_confirm_pressed);
688
689 ObjectTypeDB::bind_method(_MD("clear_filters"), &FileDialog::clear_filters);
690 ObjectTypeDB::bind_method(_MD("add_filter", "filter"), &FileDialog::add_filter);
691 ObjectTypeDB::bind_method(_MD("set_filters", "filters"), &FileDialog::set_filters);
692 ObjectTypeDB::bind_method(_MD("get_filters"), &FileDialog::get_filters);
693 ObjectTypeDB::bind_method(_MD("get_current_dir"), &FileDialog::get_current_dir);
694 ObjectTypeDB::bind_method(_MD("get_current_file"), &FileDialog::get_current_file);
695 ObjectTypeDB::bind_method(_MD("get_current_path"), &FileDialog::get_current_path);
696 ObjectTypeDB::bind_method(_MD("set_current_dir", "dir"), &FileDialog::set_current_dir);
697 ObjectTypeDB::bind_method(_MD("set_current_file", "file"), &FileDialog::set_current_file);
698 ObjectTypeDB::bind_method(_MD("set_current_path", "path"), &FileDialog::set_current_path);
699 ObjectTypeDB::bind_method(_MD("set_mode", "mode"), &FileDialog::set_mode);
700 ObjectTypeDB::bind_method(_MD("get_mode"), &FileDialog::get_mode);
701 ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"), &FileDialog::get_vbox);
702 ObjectTypeDB::bind_method(_MD("set_access", "access"), &FileDialog::set_access);
703 ObjectTypeDB::bind_method(_MD("get_access"), &FileDialog::get_access);
704 ObjectTypeDB::bind_method(_MD("set_show_hidden_files", "show"), &FileDialog::set_show_hidden_files);
705 ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"), &FileDialog::is_showing_hidden_files);
706 ObjectTypeDB::bind_method(_MD("_select_drive"), &FileDialog::_select_drive);
707 ObjectTypeDB::bind_method(_MD("_make_dir"), &FileDialog::_make_dir);
708 ObjectTypeDB::bind_method(_MD("_make_dir_confirm"), &FileDialog::_make_dir_confirm);
709 ObjectTypeDB::bind_method(_MD("_update_file_list"), &FileDialog::update_file_list);
710 ObjectTypeDB::bind_method(_MD("_update_dir"), &FileDialog::update_dir);
711
712 ObjectTypeDB::bind_method(_MD("invalidate"), &FileDialog::invalidate);
713
714 ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path")));
715 ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::STRING_ARRAY, "paths")));
716 ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir")));
717
718 BIND_CONSTANT(MODE_OPEN_FILE);
719 BIND_CONSTANT(MODE_OPEN_FILES);
720 BIND_CONSTANT(MODE_OPEN_DIR);
721 BIND_CONSTANT(MODE_OPEN_ANY);
722
723 BIND_CONSTANT(MODE_SAVE_FILE);
724
725 BIND_CONSTANT(ACCESS_RESOURCES);
726 BIND_CONSTANT(ACCESS_USERDATA);
727 BIND_CONSTANT(ACCESS_FILESYSTEM);
728
729 ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), _SCS("set_mode"), _SCS("get_mode"));
730 ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), _SCS("set_access"), _SCS("get_access"));
731 ADD_PROPERTY(PropertyInfo(Variant::STRING_ARRAY, "filters"), _SCS("set_filters"), _SCS("get_filters"));
732 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), _SCS("set_show_hidden_files"), _SCS("is_showing_hidden_files"));
733 }
734
set_show_hidden_files(bool p_show)735 void FileDialog::set_show_hidden_files(bool p_show) {
736 show_hidden_files = p_show;
737 invalidate();
738 }
739
is_showing_hidden_files() const740 bool FileDialog::is_showing_hidden_files() const {
741 return show_hidden_files;
742 }
743
set_default_show_hidden_files(bool p_show)744 void FileDialog::set_default_show_hidden_files(bool p_show) {
745 default_show_hidden_files = p_show;
746 }
747
FileDialog()748 FileDialog::FileDialog() {
749
750 show_hidden_files = default_show_hidden_files;
751
752 VBoxContainer *vbc = memnew(VBoxContainer);
753 add_child(vbc);
754 set_child_rect(vbc);
755
756 mode = MODE_SAVE_FILE;
757 set_title(RTR("Save a File"));
758
759 dir = memnew(LineEdit);
760 HBoxContainer *pathhb = memnew(HBoxContainer);
761 pathhb->add_child(dir);
762 dir->set_h_size_flags(SIZE_EXPAND_FILL);
763
764 refresh = memnew(ToolButton);
765 refresh->connect("pressed", this, "_update_file_list");
766 pathhb->add_child(refresh);
767
768 drives = memnew(OptionButton);
769 pathhb->add_child(drives);
770 drives->connect("item_selected", this, "_select_drive");
771
772 makedir = memnew(Button);
773 makedir->set_text(RTR("Create Folder"));
774 makedir->connect("pressed", this, "_make_dir");
775 pathhb->add_child(makedir);
776
777 vbc->add_margin_child(RTR("Path:"), pathhb);
778
779 tree = memnew(Tree);
780 tree->set_hide_root(true);
781 vbc->add_margin_child(RTR("Directories & Files:"), tree, true);
782
783 file = memnew(LineEdit);
784 //add_child(file);
785 vbc->add_margin_child(RTR("File:"), file);
786
787 filter = memnew(OptionButton);
788 //add_child(filter);
789 vbc->add_margin_child(RTR("Filter:"), filter);
790 filter->set_clip_text(true); //too many extensions overflow it
791
792 dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
793 access = ACCESS_RESOURCES;
794 _update_drives();
795
796 connect("confirmed", this, "_action_pressed");
797 //cancel->connect("pressed", this,"_cancel_pressed");
798 tree->connect("cell_selected", this, "_tree_selected", varray(), CONNECT_DEFERRED);
799 tree->connect("item_activated", this, "_tree_db_selected", varray());
800 dir->connect("text_entered", this, "_dir_entered");
801 file->connect("text_entered", this, "_file_entered");
802 filter->connect("item_selected", this, "_filter_selected");
803
804 confirm_save = memnew(ConfirmationDialog);
805 confirm_save->set_as_toplevel(true);
806 add_child(confirm_save);
807
808 confirm_save->connect("confirmed", this, "_save_confirm_pressed");
809
810 makedialog = memnew(ConfirmationDialog);
811 makedialog->set_title(RTR("Create Folder"));
812 VBoxContainer *makevb = memnew(VBoxContainer);
813 makedialog->add_child(makevb);
814 makedialog->set_child_rect(makevb);
815 makedirname = memnew(LineEdit);
816 makevb->add_margin_child(RTR("Name:"), makedirname);
817 add_child(makedialog);
818 makedialog->register_text_enter(makedirname);
819 makedialog->connect("confirmed", this, "_make_dir_confirm");
820 mkdirerr = memnew(AcceptDialog);
821 mkdirerr->set_text(RTR("Could not create folder."));
822 add_child(mkdirerr);
823
824 exterr = memnew(AcceptDialog);
825 exterr->set_text(RTR("Must use a valid extension."));
826 add_child(exterr);
827
828 //update_file_list();
829 update_filters();
830 update_dir();
831
832 set_hide_on_ok(false);
833 vbox = vbc;
834
835 invalidated = true;
836 if (register_func)
837 register_func(this);
838 }
839
~FileDialog()840 FileDialog::~FileDialog() {
841
842 if (unregister_func)
843 unregister_func(this);
844 memdelete(dir_access);
845 }
846
_bind_methods()847 void LineEditFileChooser::_bind_methods() {
848
849 ObjectTypeDB::bind_method(_MD("_browse"), &LineEditFileChooser::_browse);
850 ObjectTypeDB::bind_method(_MD("_chosen"), &LineEditFileChooser::_chosen);
851 ObjectTypeDB::bind_method(_MD("get_button:Button"), &LineEditFileChooser::get_button);
852 ObjectTypeDB::bind_method(_MD("get_line_edit:LineEdit"), &LineEditFileChooser::get_line_edit);
853 ObjectTypeDB::bind_method(_MD("get_file_dialog:FileDialog"), &LineEditFileChooser::get_file_dialog);
854 }
855
_chosen(const String & p_text)856 void LineEditFileChooser::_chosen(const String &p_text) {
857
858 line_edit->set_text(p_text);
859 line_edit->emit_signal("text_entered", p_text);
860 }
861
_browse()862 void LineEditFileChooser::_browse() {
863
864 dialog->popup_centered_ratio();
865 }
866
LineEditFileChooser()867 LineEditFileChooser::LineEditFileChooser() {
868
869 line_edit = memnew(LineEdit);
870 add_child(line_edit);
871 line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
872 button = memnew(Button);
873 button->set_text(" .. ");
874 add_child(button);
875 button->connect("pressed", this, "_browse");
876 dialog = memnew(FileDialog);
877 add_child(dialog);
878 dialog->connect("file_selected", this, "_chosen");
879 dialog->connect("dir_selected", this, "_chosen");
880 dialog->connect("files_selected", this, "_chosen");
881 }
882