Bläddra i källkod

Merge pull request #47163 from bruvzg/macos_sandbox_file_dialog

FileDialog: add Back/Forward buttons, add message for inaccessible folders.
Rémi Verschelde 4 år sedan
förälder
incheckning
c6b9ceadf2

+ 2 - 0
core/os/dir_access.h

@@ -84,6 +84,8 @@ public:
 
 	virtual bool file_exists(String p_file) = 0;
 	virtual bool dir_exists(String p_dir) = 0;
+	virtual bool is_readable(String p_dir) { return true; };
+	virtual bool is_writable(String p_dir) { return true; };
 	static bool exists(String p_dir);
 	virtual size_t get_space_left() = 0;
 

+ 6 - 0
doc/classes/FileDialog.xml

@@ -133,6 +133,9 @@
 		</constant>
 	</constants>
 	<theme_items>
+		<theme_item name="back_folder" type="Texture2D">
+			Custom icon for the back arrow.
+		</theme_item>
 		<theme_item name="file" type="Texture2D">
 			Custom icon for files.
 		</theme_item>
@@ -148,6 +151,9 @@
 		<theme_item name="folder_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )">
 			The color modulation applied to the folder icon.
 		</theme_item>
+		<theme_item name="forward_folder" type="Texture2D">
+			Custom icon for the forward arrow.
+		</theme_item>
 		<theme_item name="parent_folder" type="Texture2D">
 			Custom icon for the parent folder arrow.
 		</theme_item>

+ 22 - 0
drivers/unix/dir_access_unix.cpp

@@ -102,6 +102,28 @@ bool DirAccessUnix::dir_exists(String p_dir) {
 	return (success && S_ISDIR(flags.st_mode));
 }
 
+bool DirAccessUnix::is_readable(String p_dir) {
+	GLOBAL_LOCK_FUNCTION
+
+	if (p_dir.is_rel_path()) {
+		p_dir = get_current_dir().plus_file(p_dir);
+	}
+
+	p_dir = fix_path(p_dir);
+	return (access(p_dir.utf8().get_data(), R_OK) == 0);
+}
+
+bool DirAccessUnix::is_writable(String p_dir) {
+	GLOBAL_LOCK_FUNCTION
+
+	if (p_dir.is_rel_path()) {
+		p_dir = get_current_dir().plus_file(p_dir);
+	}
+
+	p_dir = fix_path(p_dir);
+	return (access(p_dir.utf8().get_data(), W_OK) == 0);
+}
+
 uint64_t DirAccessUnix::get_modified_time(String p_file) {
 	if (p_file.is_rel_path()) {
 		p_file = current_dir.plus_file(p_file);

+ 2 - 0
drivers/unix/dir_access_unix.h

@@ -71,6 +71,8 @@ public:
 
 	virtual bool file_exists(String p_file);
 	virtual bool dir_exists(String p_dir);
+	virtual bool is_readable(String p_dir);
+	virtual bool is_writable(String p_dir);
 
 	virtual uint64_t get_modified_time(String p_file);
 

+ 2 - 0
editor/editor_themes.cpp

@@ -1262,6 +1262,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	// FileDialog
 	theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
 	theme->set_icon("parent_folder", "FileDialog", theme->get_icon("ArrowUp", "EditorIcons"));
+	theme->set_icon("back_folder", "FileDialog", theme->get_icon("Back", "EditorIcons"));
+	theme->set_icon("forward_folder", "FileDialog", theme->get_icon("Forward", "EditorIcons"));
 	theme->set_icon("reload", "FileDialog", theme->get_icon("Reload", "EditorIcons"));
 	theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon("GuiVisibilityVisible", "EditorIcons"));
 	// Use a different color for folder icons to make them easier to distinguish from files.

+ 88 - 0
scene/gui/file_dialog.cpp

@@ -57,6 +57,14 @@ void FileDialog::_theme_changed() {
 	dir_up->add_theme_color_override("icon_hover_color", font_hover_color);
 	dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color);
 
+	dir_prev->add_theme_color_override("icon_color_normal", font_color);
+	dir_prev->add_theme_color_override("icon_color_hover", font_hover_color);
+	dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
+	dir_next->add_theme_color_override("icon_color_normal", font_color);
+	dir_next->add_theme_color_override("icon_color_hover", font_hover_color);
+	dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
 	refresh->add_theme_color_override("icon_normal_color", font_color);
 	refresh->add_theme_color_override("icon_hover_color", font_hover_color);
 	refresh->add_theme_color_override("icon_pressed_color", font_pressed_color);
@@ -74,6 +82,13 @@ void FileDialog::_notification(int p_what) {
 	}
 	if (p_what == NOTIFICATION_ENTER_TREE) {
 		dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog"));
+		if (vbox->is_layout_rtl()) {
+			dir_prev->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+			dir_next->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+		} else {
+			dir_prev->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+			dir_next->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+		}
 		refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog"));
 		show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog"));
 		_theme_changed();
@@ -144,6 +159,7 @@ void FileDialog::_dir_entered(String p_dir) {
 	file->set_text("");
 	invalidate();
 	update_dir();
+	_push_history();
 }
 
 void FileDialog::_file_entered(const String &p_file) {
@@ -177,6 +193,21 @@ void FileDialog::_post_popup() {
 	} else {
 		file_box->set_visible(true);
 	}
+
+	local_history.clear();
+	local_history_pos = -1;
+	_push_history();
+}
+
+void FileDialog::_push_history() {
+	local_history.resize(local_history_pos + 1);
+	String new_path = dir_access->get_current_dir();
+	if (local_history.size() == 0 || new_path != local_history[local_history_pos]) {
+		local_history.push_back(new_path);
+		local_history_pos++;
+		dir_prev->set_disabled(local_history_pos == 0);
+		dir_next->set_disabled(true);
+	}
 }
 
 void FileDialog::_action_pressed() {
@@ -316,6 +347,35 @@ void FileDialog::_go_up() {
 	dir_access->change_dir("..");
 	update_file_list();
 	update_dir();
+	_push_history();
+}
+
+void FileDialog::_go_back() {
+	if (local_history_pos <= 0) {
+		return;
+	}
+
+	local_history_pos--;
+	dir_access->change_dir(local_history[local_history_pos]);
+	update_file_list();
+	update_dir();
+
+	dir_prev->set_disabled(local_history_pos == 0);
+	dir_next->set_disabled(local_history_pos == local_history.size() - 1);
+}
+
+void FileDialog::_go_forward() {
+	if (local_history_pos == local_history.size() - 1) {
+		return;
+	}
+
+	local_history_pos++;
+	dir_access->change_dir(local_history[local_history_pos]);
+	update_file_list();
+	update_dir();
+
+	dir_prev->set_disabled(local_history_pos == 0);
+	dir_next->set_disabled(local_history_pos == local_history.size() - 1);
 }
 
 void FileDialog::deselect_all() {
@@ -377,6 +437,7 @@ void FileDialog::_tree_item_activated() {
 		}
 		call_deferred("_update_file_list");
 		call_deferred("_update_dir");
+		_push_history();
 	} else {
 		_action_pressed();
 	}
@@ -415,6 +476,13 @@ void FileDialog::update_file_list() {
 	bool is_hidden;
 	String item;
 
+	if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) {
+		message->hide();
+	} else {
+		message->set_text(TTRC("You don't have permission to access contents of this folder."));
+		message->show();
+	}
+
 	while ((item = dir_access->get_next()) != "") {
 		if (item == "." || item == "..") {
 			continue;
@@ -602,6 +670,7 @@ void FileDialog::set_current_dir(const String &p_dir) {
 	dir_access->change_dir(p_dir);
 	update_dir();
 	invalidate();
+	_push_history();
 }
 
 void FileDialog::set_current_file(const String &p_file) {
@@ -737,6 +806,7 @@ void FileDialog::_make_dir_confirm() {
 		invalidate();
 		update_filters();
 		update_dir();
+		_push_history();
 	} else {
 		mkdirerr->popup_centered(Size2(250, 50));
 	}
@@ -754,6 +824,7 @@ void FileDialog::_select_drive(int p_idx) {
 	file->set_text("");
 	invalidate();
 	update_dir();
+	_push_history();
 }
 
 void FileDialog::_update_drives() {
@@ -861,10 +932,20 @@ FileDialog::FileDialog() {
 
 	HBoxContainer *hbc = memnew(HBoxContainer);
 
+	dir_prev = memnew(Button);
+	dir_prev->set_flat(true);
+	dir_prev->set_tooltip(TTRC("Go to previous folder."));
+	dir_next = memnew(Button);
+	dir_next->set_flat(true);
+	dir_next->set_tooltip(TTRC("Go to next folder."));
 	dir_up = memnew(Button);
 	dir_up->set_flat(true);
 	dir_up->set_tooltip(TTRC("Go to parent folder."));
+	hbc->add_child(dir_prev);
+	hbc->add_child(dir_next);
 	hbc->add_child(dir_up);
+	dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back));
+	dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward));
 	dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up));
 
 	hbc->add_child(memnew(Label(TTRC("Path:"))));
@@ -908,6 +989,13 @@ FileDialog::FileDialog() {
 	tree->set_hide_root(true);
 	vbox->add_margin_child(TTRC("Directories & Files:"), tree, true);
 
+	message = memnew(Label);
+	message->hide();
+	message->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+	message->set_align(Label::ALIGN_CENTER);
+	message->set_valign(Label::VALIGN_CENTER);
+	tree->add_child(message);
+
 	file_box = memnew(HBoxContainer);
 	file_box->add_child(memnew(Label(TTRC("File:"))));
 	file = memnew(LineEdit);

+ 10 - 0
scene/gui/file_dialog.h

@@ -86,6 +86,10 @@ private:
 	DirAccess *dir_access;
 	ConfirmationDialog *confirm_save;
 
+	Label *message;
+
+	Button *dir_prev;
+	Button *dir_next;
 	Button *dir_up;
 
 	Button *refresh;
@@ -93,6 +97,10 @@ private:
 
 	Vector<String> filters;
 
+	Vector<String> local_history;
+	int local_history_pos = 0;
+	void _push_history();
+
 	bool mode_overrides_title = true;
 
 	static bool default_show_hidden_files;
@@ -119,6 +127,8 @@ private:
 	void _make_dir();
 	void _make_dir_confirm();
 	void _go_up();
+	void _go_back();
+	void _go_forward();
 
 	void _update_drives();
 

+ 2 - 0
scene/resources/default_theme/default_theme.cpp

@@ -632,6 +632,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
 	// File Dialog
 
 	theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png));
+	theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png));
+	theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png));
 	theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png));
 	theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png));