Merge pull request #13724 from RayKoopa/editor_file_dialog_context_menu
Add context menu to editor file dialogs
This commit is contained in:
commit
9e2fad7e64
4 changed files with 187 additions and 17 deletions
|
@ -35,6 +35,7 @@
|
|||
#include "scene/gui/tab_container.h"
|
||||
#include "scene/gui/tree.h"
|
||||
|
||||
class EditorFileDialog;
|
||||
class EditorFileSystemDirectory;
|
||||
class EditorNode;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue