diff --git a/README.md b/README.md index c7d6fa89..bee1795c 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ use std::sync::Arc; use egui_file_dialog::FileDialog; FileDialog::new() - .initial_directory(PathBuf::from("/path/to/app")) + .initial_path(PathBuf::from("/path/to/app")) .default_file_name("app.cfg") .default_size([600.0, 400.0]) .resizable(false) diff --git a/examples/pick_file.rs b/examples/pick_file.rs index 72a16cb6..ced26007 100644 --- a/examples/pick_file.rs +++ b/examples/pick_file.rs @@ -1,4 +1,4 @@ -use egui_file_dialog::FileDialog; +use egui_file_dialog::{FileDialog, OpeningMode}; use std::path::PathBuf; use eframe::egui; @@ -6,6 +6,7 @@ use eframe::egui; struct MyApp { file_dialog: FileDialog, picked_file: Option, + remember_pick: bool, } impl MyApp { @@ -13,6 +14,7 @@ impl MyApp { Self { file_dialog: FileDialog::new(), picked_file: None, + remember_pick: false, } } } @@ -21,9 +23,19 @@ impl eframe::App for MyApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| { if ui.button("Picked file").clicked() { + let cfg = self.file_dialog.config_mut(); + cfg.opening_mode = OpeningMode::LastVisitedDir; + if self.remember_pick { + if let Some(picked_file) = &self.picked_file { + cfg.initial_path.clone_from(picked_file); + cfg.opening_mode = OpeningMode::AlwaysInitialPath; + } + } self.file_dialog.pick_file(); } + ui.checkbox(&mut self.remember_pick, "Remember last pick"); + ui.label(format!("Picked file: {:?}", self.picked_file)); if let Some(path) = self.file_dialog.update(ctx).picked() { diff --git a/src/config/mod.rs b/src/config/mod.rs index 17799806..be58b5ee 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -37,8 +37,8 @@ impl PinnedFolder { /// Sets which directory is loaded when opening the file dialog. #[derive(Debug, PartialEq, Eq, Clone)] pub enum OpeningMode { - /// The configured initial directory (`FileDialog::initial_directory`) should always be opened. - AlwaysInitialDir, + /// The configured initial directory (`FileDialog::initial_path`) should always be opened. + AlwaysInitialPath, /// The directory most recently visited by the user should be opened regardless of /// whether anything was picked. LastVisitedDir, @@ -52,7 +52,7 @@ pub enum OpeningMode { /// /// If you only need to configure a single file dialog, you don't need to /// manually use a `FileDialogConfig` object. `FileDialog` provides setter methods for -/// each of these configuration options, for example: `FileDialog::initial_directory` +/// each of these configuration options, for example: `FileDialog::initial_path` /// or `FileDialog::default_size`. /// /// `FileDialogConfig` is useful when you need to configure multiple `FileDialog` objects with the @@ -64,7 +64,7 @@ pub enum OpeningMode { /// use egui_file_dialog::{FileDialog, FileDialogConfig}; /// /// let config = FileDialogConfig { -/// initial_directory: std::path::PathBuf::from("/app/config"), +/// initial_path: std::path::PathBuf::from("/app/config"), /// fixed_pos: Some(egui::Pos2::new(40.0, 40.0)), /// show_left_panel: false, /// ..Default::default() @@ -96,7 +96,10 @@ pub struct FileDialogConfig { /// Color of the overlay that is displayed under the modal to prevent user interaction. pub modal_overlay_color: egui::Color32, /// The first directory that will be opened when the dialog opens. - pub initial_directory: PathBuf, + /// + /// If the path is a file, the parent directory will be opened, and the file will be + /// selected as a pick candidate. + pub initial_path: PathBuf, /// The default filename when opening the dialog in `DialogMode::SaveFile` mode. pub default_file_name: String, /// If the user is allowed to select an already existing file when the dialog is @@ -243,7 +246,7 @@ impl FileDialogConfig { opening_mode: OpeningMode::LastPickedDir, as_modal: true, modal_overlay_color: egui::Color32::from_rgba_premultiplied(0, 0, 0, 120), - initial_directory: file_system.current_dir().unwrap_or_default(), + initial_path: file_system.current_dir().unwrap_or_default(), default_file_name: String::from("Untitled"), allow_file_overwrite: true, allow_path_edit_to_save_file_without_extension: false, diff --git a/src/file_dialog.rs b/src/file_dialog.rs index 4374b293..09985018 100644 --- a/src/file_dialog.rs +++ b/src/file_dialog.rs @@ -290,7 +290,7 @@ impl FileDialog { #[must_use] pub fn with_file_system(file_system: Arc) -> Self { let mut obj = Self::new(); - obj.config.initial_directory = file_system.current_dir().unwrap_or_default(); + obj.config.initial_path = file_system.current_dir().unwrap_or_default(); obj.config.file_system = file_system; obj.create_directory_dialog = CreateDirectoryDialog::from_filesystem(obj.config.file_system.clone()); @@ -376,14 +376,24 @@ impl FileDialog { .id .map_or_else(|| egui::Id::new(self.get_window_title()), |id| id); - self.load_directory(&self.get_initial_directory()); + let init_dir = self.get_initial_directory(); + self.load_directory(&init_dir); + let init_path = &self.config.initial_path; + // If the initial path has an extra component, use it to pre-select an item. + if init_path != &init_dir && init_path.starts_with(init_dir) { + self.select_item(&mut DirectoryEntry::from_path( + &self.config, + &self.config.initial_path, + &*self.config.file_system, + )); + } } /// Shortcut function to open the file dialog to prompt the user to pick a directory. /// If used, no files in the directories will be shown to the user. /// Use the `open()` method instead, if you still want to display files to the user. /// This function resets the file dialog. Configuration variables such as - /// `initial_directory` are retained. + /// `initial_path` are retained. /// /// The function ignores the result of the initial directory loading operation. pub fn pick_directory(&mut self) { @@ -394,7 +404,7 @@ impl FileDialog { /// Shortcut function to open the file dialog to prompt the user to pick a file. /// This function resets the file dialog. Configuration variables such as - /// `initial_directory` are retained. + /// `initial_path` are retained. /// /// The function ignores the result of the initial directory loading operation. pub fn pick_file(&mut self) { @@ -405,7 +415,7 @@ impl FileDialog { /// Shortcut function to open the file dialog to prompt the user to pick multiple /// files and folders. - /// This function resets the file dialog. Configuration variables such as `initial_directory` + /// This function resets the file dialog. Configuration variables such as `initial_path` /// are retained. /// /// The function ignores the result of the initial directory loading operation. @@ -417,7 +427,7 @@ impl FileDialog { /// Shortcut function to open the file dialog to prompt the user to save a file. /// This function resets the file dialog. Configuration variables such as - /// `initial_directory` are retained. + /// `initial_path` are retained. /// /// The function ignores the result of the initial directory loading operation. pub fn save_file(&mut self) { @@ -540,15 +550,17 @@ impl FileDialog { } /// Sets the first loaded directory when the dialog opens. - /// If the path is a file, the file's parent directory is used. If the path then has no - /// parent directory or cannot be loaded, the user will receive an error. + /// If the path is a file, the file's parent directory is used, + /// and the file will become selected. + /// If the path then has no parent directory or cannot be loaded, + /// the user will receive an error. /// However, the user directories and system disk allow the user to still select a file in /// the event of an error. /// /// Since `fs::canonicalize` is used, both absolute paths and relative paths are allowed. /// See `FileDialog::canonicalize_paths` for more information. - pub fn initial_directory(mut self, directory: PathBuf) -> Self { - self.config.initial_directory = directory; + pub fn initial_path(mut self, directory: PathBuf) -> Self { + self.config.initial_path = directory; self } @@ -1885,36 +1897,36 @@ impl FileDialog { let user_directories = std::mem::take(&mut self.user_directories); let labels = std::mem::take(&mut self.config.labels); - let mut visible = false; - - if let Some(dirs) = &user_directories { - ui.add_space(spacing); - ui.label(labels.heading_places.as_str()); + let visible = match &user_directories { + Some(dirs) => { + ui.add_space(spacing); + ui.label(labels.heading_places.as_str()); - if let Some(path) = dirs.home_dir() { - self.ui_update_left_panel_entry(ui, &labels.home_dir, path); - } - if let Some(path) = dirs.desktop_dir() { - self.ui_update_left_panel_entry(ui, &labels.desktop_dir, path); - } - if let Some(path) = dirs.document_dir() { - self.ui_update_left_panel_entry(ui, &labels.documents_dir, path); - } - if let Some(path) = dirs.download_dir() { - self.ui_update_left_panel_entry(ui, &labels.downloads_dir, path); - } - if let Some(path) = dirs.audio_dir() { - self.ui_update_left_panel_entry(ui, &labels.audio_dir, path); - } - if let Some(path) = dirs.picture_dir() { - self.ui_update_left_panel_entry(ui, &labels.pictures_dir, path); - } - if let Some(path) = dirs.video_dir() { - self.ui_update_left_panel_entry(ui, &labels.videos_dir, path); + if let Some(path) = dirs.home_dir() { + self.ui_update_left_panel_entry(ui, &labels.home_dir, path); + } + if let Some(path) = dirs.desktop_dir() { + self.ui_update_left_panel_entry(ui, &labels.desktop_dir, path); + } + if let Some(path) = dirs.document_dir() { + self.ui_update_left_panel_entry(ui, &labels.documents_dir, path); + } + if let Some(path) = dirs.download_dir() { + self.ui_update_left_panel_entry(ui, &labels.downloads_dir, path); + } + if let Some(path) = dirs.audio_dir() { + self.ui_update_left_panel_entry(ui, &labels.audio_dir, path); + } + if let Some(path) = dirs.picture_dir() { + self.ui_update_left_panel_entry(ui, &labels.pictures_dir, path); + } + if let Some(path) = dirs.video_dir() { + self.ui_update_left_panel_entry(ui, &labels.videos_dir, path); + } + true } - - visible = true; - } + None => false, + }; self.user_directories = user_directories; self.config.labels = labels; @@ -3188,17 +3200,17 @@ impl FileDialog { /// - Attempts to use the parent directory if the path is a file fn get_initial_directory(&self) -> PathBuf { let path = match self.config.opening_mode { - OpeningMode::AlwaysInitialDir => &self.config.initial_directory, + OpeningMode::AlwaysInitialPath => &self.config.initial_path, OpeningMode::LastVisitedDir => self .storage .last_visited_dir .as_deref() - .unwrap_or(&self.config.initial_directory), + .unwrap_or(&self.config.initial_path), OpeningMode::LastPickedDir => self .storage .last_picked_dir .as_deref() - .unwrap_or(&self.config.initial_directory), + .unwrap_or(&self.config.initial_path), }; let mut path = self.canonicalize_path(path); diff --git a/src/lib.rs b/src/lib.rs index f084cf26..b1f2d66b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,7 @@ //! use egui_file_dialog::FileDialog; //! //! FileDialog::new() -//! .initial_directory(PathBuf::from("/path/to/app")) +//! .initial_path(PathBuf::from("/path/to/app")) //! .default_file_name("app.cfg") //! .default_size([600.0, 400.0]) //! .resizable(false)