Procházet zdrojové kódy

Merge pull request #59089 from KoBeWi/I_am_root

Add `root_subfolder` to FileDialog
Rémi Verschelde před 3 roky
rodič
revize
daec5bed57
3 změnil soubory, kde provedl 63 přidání a 24 odebrání
  1. 3 0
      doc/classes/FileDialog.xml
  2. 54 24
      scene/gui/file_dialog.cpp
  3. 6 0
      scene/gui/file_dialog.h

+ 3 - 0
doc/classes/FileDialog.xml

@@ -75,6 +75,9 @@
 		<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
 			If [code]true[/code], changing the [code]Mode[/code] property will set the window title accordingly (e.g. setting mode to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File").
 		</member>
+		<member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default="&quot;&quot;">
+			If non-empty, the given sub-folder will be "root" of this [FileDialog], i.e. user won't be able to go to its parent directory.
+		</member>
 		<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
 			If [code]true[/code], the dialog will show hidden files.
 		</member>

+ 54 - 24
scene/gui/file_dialog.cpp

@@ -170,7 +170,11 @@ Vector<String> FileDialog::get_selected_files() const {
 };
 
 void FileDialog::update_dir() {
-	dir->set_text(dir_access->get_current_dir(false));
+	if (root_prefix.is_empty()) {
+		dir->set_text(dir_access->get_current_dir(false));
+	} else {
+		dir->set_text(dir_access->get_current_dir(false).trim_prefix(root_prefix).trim_prefix("/"));
+	}
 
 	if (drives->is_visible()) {
 		if (dir_access->get_current_dir().is_network_share_path()) {
@@ -188,10 +192,8 @@ void FileDialog::update_dir() {
 }
 
 void FileDialog::_dir_submitted(String p_dir) {
-	dir_access->change_dir(p_dir);
+	_change_dir(root_prefix.plus_file(p_dir));
 	file->set_text("");
-	invalidate();
-	update_dir();
 	_push_history();
 }
 
@@ -378,9 +380,7 @@ bool FileDialog::_is_open_should_be_disabled() {
 }
 
 void FileDialog::_go_up() {
-	dir_access->change_dir("..");
-	update_file_list();
-	update_dir();
+	_change_dir("..");
 	_push_history();
 }
 
@@ -390,9 +390,7 @@ void FileDialog::_go_back() {
 	}
 
 	local_history_pos--;
-	dir_access->change_dir(local_history[local_history_pos]);
-	update_file_list();
-	update_dir();
+	_change_dir(local_history[local_history_pos]);
 
 	dir_prev->set_disabled(local_history_pos == 0);
 	dir_next->set_disabled(local_history_pos == local_history.size() - 1);
@@ -404,9 +402,7 @@ void FileDialog::_go_forward() {
 	}
 
 	local_history_pos++;
-	dir_access->change_dir(local_history[local_history_pos]);
-	update_file_list();
-	update_dir();
+	_change_dir(local_history[local_history_pos]);
 
 	dir_prev->set_disabled(local_history_pos == 0);
 	dir_next->set_disabled(local_history_pos == local_history.size() - 1);
@@ -465,12 +461,10 @@ void FileDialog::_tree_item_activated() {
 	Dictionary d = ti->get_metadata(0);
 
 	if (d["dir"]) {
-		dir_access->change_dir(d["name"]);
+		_change_dir(d["name"]);
 		if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) {
 			file->set_text("");
 		}
-		call_deferred(SNAME("_update_file_list"));
-		call_deferred(SNAME("_update_dir"));
 		_push_history();
 	} else {
 		_action_pressed();
@@ -704,9 +698,7 @@ String FileDialog::get_current_path() const {
 }
 
 void FileDialog::set_current_dir(const String &p_dir) {
-	dir_access->change_dir(p_dir);
-	update_dir();
-	invalidate();
+	_change_dir(p_dir);
 	_push_history();
 }
 
@@ -732,6 +724,27 @@ void FileDialog::set_current_path(const String &p_path) {
 	}
 }
 
+void FileDialog::set_root_subfolder(const String &p_root) {
+	root_subfolder = p_root;
+	ERR_FAIL_COND_MSG(!dir_access->dir_exists(p_root), "root_subfolder must be an existing sub-directory.");
+
+	local_history.clear();
+	local_history_pos = -1;
+
+	dir_access->change_dir(root_subfolder);
+	if (root_subfolder.is_empty()) {
+		root_prefix = "";
+	} else {
+		root_prefix = dir_access->get_current_dir();
+	}
+	invalidate();
+	update_dir();
+}
+
+String FileDialog::get_root_subfolder() const {
+	return root_subfolder;
+}
+
 void FileDialog::set_mode_overrides_title(bool p_override) {
 	mode_overrides_title = p_override;
 }
@@ -810,6 +823,8 @@ void FileDialog::set_access(Access p_access) {
 		} break;
 	}
 	access = p_access;
+	root_prefix = "";
+	root_subfolder = "";
 	_update_drives();
 	invalidate();
 	update_filters();
@@ -832,10 +847,8 @@ FileDialog::Access FileDialog::get_access() const {
 void FileDialog::_make_dir_confirm() {
 	Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
 	if (err == OK) {
-		dir_access->change_dir(makedirname->get_text().strip_edges());
-		invalidate();
+		_change_dir(makedirname->get_text().strip_edges());
 		update_filters();
-		update_dir();
 		_push_history();
 	} else {
 		mkdirerr->popup_centered(Size2(250, 50));
@@ -850,11 +863,25 @@ void FileDialog::_make_dir() {
 
 void FileDialog::_select_drive(int p_idx) {
 	String d = drives->get_item_text(p_idx);
-	dir_access->change_dir(d);
+	_change_dir(d);
 	file->set_text("");
+	_push_history();
+}
+
+void FileDialog::_change_dir(const String &p_new_dir) {
+	if (root_prefix.is_empty()) {
+		dir_access->change_dir(p_new_dir);
+	} else {
+		String old_dir = dir_access->get_current_dir();
+		dir_access->change_dir(p_new_dir);
+		if (!dir_access->get_current_dir(false).begins_with(root_prefix)) {
+			dir_access->change_dir(old_dir);
+			return;
+		}
+	}
+
 	invalidate();
 	update_dir();
-	_push_history();
 }
 
 void FileDialog::_update_drives(bool p_select) {
@@ -904,6 +931,8 @@ void FileDialog::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_line_edit"), &FileDialog::get_line_edit);
 	ClassDB::bind_method(D_METHOD("set_access", "access"), &FileDialog::set_access);
 	ClassDB::bind_method(D_METHOD("get_access"), &FileDialog::get_access);
+	ClassDB::bind_method(D_METHOD("set_root_subfolder", "dir"), &FileDialog::set_root_subfolder);
+	ClassDB::bind_method(D_METHOD("get_root_subfolder"), &FileDialog::get_root_subfolder);
 	ClassDB::bind_method(D_METHOD("set_show_hidden_files", "show"), &FileDialog::set_show_hidden_files);
 	ClassDB::bind_method(D_METHOD("is_showing_hidden_files"), &FileDialog::is_showing_hidden_files);
 	ClassDB::bind_method(D_METHOD("_update_file_name"), &FileDialog::update_file_name);
@@ -916,6 +945,7 @@ void FileDialog::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_file_mode", "get_file_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access");
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder");
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir");

+ 6 - 0
scene/gui/file_dialog.h

@@ -101,6 +101,8 @@ private:
 	void _push_history();
 
 	bool mode_overrides_title = true;
+	String root_subfolder;
+	String root_prefix;
 
 	static bool default_show_hidden_files;
 	bool show_hidden_files = false;
@@ -131,6 +133,7 @@ private:
 	void _go_back();
 	void _go_forward();
 
+	void _change_dir(const String &p_new_dir);
 	void _update_drives(bool p_select = true);
 
 	virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
@@ -162,6 +165,9 @@ public:
 	void set_current_file(const String &p_file);
 	void set_current_path(const String &p_path);
 
+	void set_root_subfolder(const String &p_root);
+	String get_root_subfolder() const;
+
 	void set_mode_overrides_title(bool p_override);
 	bool is_mode_overriding_title() const;