Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion examples/pick_file.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use egui_file_dialog::FileDialog;
use egui_file_dialog::{FileDialog, OpeningMode};
use std::path::PathBuf;

use eframe::egui;

struct MyApp {
file_dialog: FileDialog,
picked_file: Option<PathBuf>,
remember_pick: bool,
}

impl MyApp {
pub fn new(_cc: &eframe::CreationContext) -> Self {
Self {
file_dialog: FileDialog::new(),
picked_file: None,
remember_pick: false,
}
}
}
Expand All @@ -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() {
Expand Down
15 changes: 9 additions & 6 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
94 changes: 53 additions & 41 deletions src/file_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ impl FileDialog {
#[must_use]
pub fn with_file_system(file_system: Arc<dyn FileSystem + Send + Sync>) -> 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());
Expand Down Expand Up @@ -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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm honestly not sure if this is the best way to go about it, or if we should do a more clear separation of initial directory, and initially selected file at a higher level.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem, if we separate the initial directory and initial file, it can lead to situations where the initial file does not correspond to the initial directory. I think I currently prefer the initial directory idea. But I'll have to try it out for myself to see how it feels when I use it.

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,
));
}
Comment on lines +383 to +389
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to simplify this using:

if self.config.initial_path.is_file() {
     self.select_item(...)
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add:

self.scroll_to_selection = true;

After selecting the item, so egui automatically scrolls to it in the first frame.

}

/// 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) {
Expand All @@ -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) {
Expand All @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
Comment on lines -550 to +563
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you keep the initial_directory method and mark it as deprecated?

self
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading