diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2017-12-06 23:46:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-06 23:46:43 +0100 |
commit | 9e2fad7e647e67aba90fae60ceb5a709eea68759 (patch) | |
tree | a70482cb4435e29d203f8092938393497c6caa58 /editor | |
parent | c2031fc813d4f55a95cfcf702c508e39e1ef099e (diff) | |
parent | 5fbd71af1781b0b808af78ef6ff330086222cd37 (diff) |
Merge pull request #13724 from RayKoopa/editor_file_dialog_context_menu
Add context menu to editor file dialogs
Diffstat (limited to 'editor')
-rw-r--r-- | editor/dependency_editor.h | 1 | ||||
-rw-r--r-- | editor/editor_file_dialog.cpp | 177 | ||||
-rw-r--r-- | editor/editor_file_dialog.h | 20 | ||||
-rw-r--r-- | editor/editor_file_system.cpp | 6 |
4 files changed, 187 insertions, 17 deletions
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index 9b0aca67d5..0cc153945d 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -35,6 +35,7 @@ #include "scene/gui/tab_container.h" #include "scene/gui/tree.h" +class EditorFileDialog; class EditorFileSystemDirectory; class EditorNode; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 6a5cbb88df..eaa57fa46b 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -28,12 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor_file_dialog.h" - +#include "dependency_editor.h" #include "editor_resource_preview.h" #include "editor_scale.h" #include "editor_settings.h" #include "os/file_access.h" #include "os/keyboard.h" +#include "os/os.h" #include "print_string.h" #include "scene/gui/center_container.h" #include "scene/gui/label.h" @@ -159,6 +160,10 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { _make_dir(); handled = true; } + if (ED_IS_SHORTCUT("file_dialog/delete", p_event)) { + _delete_items(); + handled = true; + } if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { dir->grab_focus(); handled = true; @@ -512,6 +517,106 @@ void EditorFileDialog::_item_dc_selected(int p_item) { } } +void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) { + + // Right click on specific file(s) or folder(s). + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + // Allow specific actions only on one item. + bool single_item_selected = item_list->get_selected_items().size() == 1; + + // Disallow deleting the .import folder, Godot kills a cat if you do and it is possibly a senseless novice action. + bool allow_delete = true; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["path"] == "res://.import") { + allow_delete = false; + break; + } + } + + if (single_item_selected) { + item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH); + } + if (allow_delete) { + item_menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE); + } + if (single_item_selected) { + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + } + + if (item_menu->get_item_count() > 0) { + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); + } +} + +void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { + + // Right click on folder background. Deselect all files so that actions are applied on the current folder. + for (int i = 0; i < item_list->get_item_count(); i++) { + item_list->unselect(i); + } + + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + if (can_create_dir) { + item_menu->add_icon_item(get_icon("folder", "FileDialog"), TTR("New Folder.."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N); + } + item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); +} + +void EditorFileDialog::_item_menu_id_pressed(int p_option) { + + switch (p_option) { + + case ITEM_MENU_COPY_PATH: { + Dictionary item_meta = item_list->get_item_metadata(item_list->get_current()); + OS::get_singleton()->set_clipboard(item_meta["path"]); + } break; + + case ITEM_MENU_DELETE: { + _delete_items(); + } break; + + case ITEM_MENU_REFRESH: { + invalidate(); + } break; + + case ITEM_MENU_NEW_FOLDER: { + _make_dir(); + } break; + + case ITEM_MENU_SHOW_IN_EXPLORER: { + String path; + int idx = item_list->get_current(); + if (idx == -1 || item_list->get_selected_items().size() == 0) { + // Folder background was clicked. Open this folder. + path = ProjectSettings::get_singleton()->globalize_path(dir_access->get_current_dir()); + } else { + // Specific item was clicked. Open folders directly, or the folder containing a selected file. + Dictionary item_meta = item_list->get_item_metadata(idx); + path = ProjectSettings::get_singleton()->globalize_path(item_meta["path"]); + if (!item_meta["dir"]) { + path = path.get_base_dir(); + } + } + OS::get_singleton()->shell_open(String("file://") + path); + } break; + } +} + bool EditorFileDialog::_is_open_should_be_disabled() { if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) @@ -617,7 +722,7 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = dir_name; - d["path"] = String(); + d["path"] = cdir.plus_file(dir_name); d["dir"] = true; item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -657,8 +762,6 @@ void EditorFileDialog::update_file_list() { } } - String base_dir = dir_access->get_current_dir(); - while (!files.empty()) { bool match = patterns.empty(); @@ -679,7 +782,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { - Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); + Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode == DISPLAY_THUMBNAILS) { @@ -698,12 +801,11 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = files.front()->get(); d["dir"] = false; - String fullpath = base_dir.plus_file(files.front()->get()); - + String fullpath = cdir.plus_file(files.front()->get()); if (display_mode == DISPLAY_THUMBNAILS) { EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath); } - d["path"] = base_dir.plus_file(files.front()->get()); + d["path"] = fullpath; //ti->set_metadata(0,d); item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -723,7 +825,7 @@ void EditorFileDialog::update_file_list() { fav_down->set_disabled(true); get_ok()->set_disabled(_is_open_should_be_disabled()); for (int i = 0; i < favorites->get_item_count(); i++) { - if (favorites->get_item_metadata(i) == base_dir) { + if (favorites->get_item_metadata(i) == cdir) { favorites->select(i); favorite->set_pressed(true); if (i > 0) { @@ -854,27 +956,27 @@ void EditorFileDialog::set_mode(Mode p_mode) { case MODE_OPEN_FILE: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_FILES: get_ok()->set_text(TTR("Open")); set_title(TTR("Open File(s)")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_DIR: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_OPEN_ANY: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File or Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_SAVE_FILE: get_ok()->set_text(TTR("Save")); set_title(TTR("Save a File")); - makedir->show(); + can_create_dir = true; break; } @@ -883,6 +985,12 @@ void EditorFileDialog::set_mode(Mode p_mode) { } else { item_list->set_select_mode(ItemList::SELECT_SINGLE); } + + if (can_create_dir) { + makedir->show(); + } else { + makedir->hide(); + } } EditorFileDialog::Mode EditorFileDialog::get_mode() const { @@ -954,6 +1062,28 @@ void EditorFileDialog::_make_dir() { makedirname->grab_focus(); } +void EditorFileDialog::_delete_items() { + + // Collect the selected folders and files to delete and check them in the deletion dependency dialog. + Vector<String> folders; + Vector<String> files; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["dir"]) { + folders.push_back(item_meta["path"]); + } else { + files.push_back(item_meta["path"]); + } + } + if (folders.size() + files.size() > 0) { + remove_dialog->set_size(Size2(1, 1)); + remove_dialog->show(folders, files); + } +} + void EditorFileDialog::_select_drive(int p_idx) { String d = drives->get_item_text(p_idx); @@ -1181,6 +1311,9 @@ void EditorFileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_item_selected"), &EditorFileDialog::_item_selected); ClassDB::bind_method(D_METHOD("_items_clear_selection"), &EditorFileDialog::_items_clear_selection); + ClassDB::bind_method(D_METHOD("_item_list_item_rmb_selected"), &EditorFileDialog::_item_list_item_rmb_selected); + ClassDB::bind_method(D_METHOD("_item_list_rmb_clicked"), &EditorFileDialog::_item_list_rmb_clicked); + ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &EditorFileDialog::_item_menu_id_pressed); ClassDB::bind_method(D_METHOD("_item_db_selected"), &EditorFileDialog::_item_dc_selected); ClassDB::bind_method(D_METHOD("_dir_entered"), &EditorFileDialog::_dir_entered); ClassDB::bind_method(D_METHOD("_file_entered"), &EditorFileDialog::_file_entered); @@ -1326,6 +1459,7 @@ EditorFileDialog::EditorFileDialog() { ED_SHORTCUT("file_dialog/toggle_favorite", TTR("Toggle Favorite"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KEY_MASK_ALT | KEY_V); ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KEY_MASK_CMD | KEY_N); + ED_SHORTCUT("file_dialog/delete", TTR("Delete"), KEY_DELETE); ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KEY_MASK_CMD | KEY_D); ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KEY_MASK_CMD | KEY_UP); ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KEY_MASK_CMD | KEY_DOWN); @@ -1432,10 +1566,21 @@ EditorFileDialog::EditorFileDialog() { list_vb->add_child(memnew(Label(TTR("Directories & Files:")))); preview_hb->add_child(list_vb); + // Item (files and folders) list with context menu + item_list = memnew(ItemList); item_list->set_v_size_flags(SIZE_EXPAND_FILL); + item_list->connect("item_rmb_selected", this, "_item_list_item_rmb_selected"); + item_list->connect("rmb_clicked", this, "_item_list_rmb_clicked"); + item_list->set_allow_rmb_select(true); list_vb->add_child(item_list); + item_menu = memnew(PopupMenu); + item_menu->connect("id_pressed", this, "_item_menu_id_pressed"); + add_child(item_menu); + + // Other stuff + preview_vb = memnew(VBoxContainer); preview_hb->add_child(preview_vb); CenterContainer *prev_cc = memnew(CenterContainer); @@ -1474,9 +1619,11 @@ EditorFileDialog::EditorFileDialog() { confirm_save = memnew(ConfirmationDialog); confirm_save->set_as_toplevel(true); add_child(confirm_save); - confirm_save->connect("confirmed", this, "_save_confirm_pressed"); + remove_dialog = memnew(DependencyRemoveDialog); + add_child(remove_dialog); + makedialog = memnew(ConfirmationDialog); makedialog->set_title(TTR("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 0599d222f3..f4a9a174e7 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -39,6 +39,9 @@ #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + +class DependencyRemoveDialog; + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -75,6 +78,14 @@ public: static RegisterFunc unregister_func; private: + enum ItemMenu { + ITEM_MENU_COPY_PATH, + ITEM_MENU_DELETE, + ITEM_MENU_REFRESH, + ITEM_MENU_NEW_FOLDER, + ITEM_MENU_SHOW_IN_EXPLORER + }; + ConfirmationDialog *makedialog; LineEdit *makedirname; @@ -83,6 +94,7 @@ private: //Button *action; VBoxContainer *vbox; Mode mode; + bool can_create_dir; LineEdit *dir; ToolButton *dir_prev; @@ -91,6 +103,7 @@ private: OptionButton *drives; ItemList *item_list; + PopupMenu *item_menu; TextureRect *preview; VBoxContainer *preview_vb; HSplitContainer *list_hb; @@ -100,6 +113,7 @@ private: OptionButton *filter; DirAccess *dir_access; ConfirmationDialog *confirm_save; + DependencyRemoveDialog *remove_dialog; ToolButton *mode_thumbnails; ToolButton *mode_list; @@ -146,6 +160,10 @@ private: void _items_clear_selection(); void _item_dc_selected(int p_item); + void _item_list_item_rmb_selected(int p_item, const Vector2 &p_pos); + void _item_list_rmb_clicked(const Vector2 &p_pos); + void _item_menu_id_pressed(int p_option); + void _select_drive(int p_idx); void _dir_entered(String p_dir); void _file_entered(const String &p_file); @@ -156,6 +174,8 @@ private: void _make_dir(); void _make_dir_confirm(); + void _delete_items(); + void _update_drives(); void _go_up(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 1cc518ff31..d462cce908 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1244,8 +1244,10 @@ void EditorFileSystem::update_file(const String &p_file) { if (!FileAccess::exists(p_file)) { //was removed _delete_internal_files(p_file); - memdelete(fs->files[cpos]); - fs->files.remove(cpos); + if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog). + memdelete(fs->files[cpos]); + fs->files.remove(cpos); + } call_deferred("emit_signal", "filesystem_changed"); //update later return; } |