diff --git a/Cargo.lock b/Cargo.lock index fe79be8..a4c873d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -318,28 +318,6 @@ dependencies = [ "libloading", ] -[[package]] -name = "ashpd" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3" -dependencies = [ - "async-fs", - "async-net", - "enumflags2", - "futures-channel", - "futures-util", - "rand", - "raw-window-handle", - "serde", - "serde_repr", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus", -] - [[package]] name = "async-broadcast" version = "0.7.1" @@ -377,17 +355,6 @@ dependencies = [ "slab", ] -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - [[package]] name = "async-io" version = "2.4.0" @@ -418,17 +385,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-net" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" -dependencies = [ - "async-io", - "blocking", - "futures-lite", -] - [[package]] name = "async-process" version = "2.3.0" @@ -889,7 +845,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45b1f4c00870f07dc34adcac82bb6a72cc5aabca8536ba1797e01df51d2ce9a0" dependencies = [ - "directories 5.0.1", + "directories", "serde", "thiserror 1.0.69", "toml 0.8.19", @@ -1020,16 +976,7 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "directories" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" -dependencies = [ - "dirs-sys 0.5.0", + "dirs-sys", ] [[package]] @@ -1040,22 +987,10 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users 0.4.6", + "redox_users", "windows-sys 0.48.0", ] -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.0", - "windows-sys 0.61.2", -] - [[package]] name = "dispatch" version = "0.2.0" @@ -1069,6 +1004,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", + "libc", "objc2 0.6.4", ] @@ -1113,12 +1050,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "ecolor" version = "0.34.1" @@ -1185,19 +1116,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "egui-file-dialog" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b530b58f428bcffb58281ad1c3a59ee559ffd2354aa54d5bf1a2ef418fdcebb3" -dependencies = [ - "directories 6.0.0", - "dunce", - "egui", - "serde", - "sysinfo", -] - [[package]] name = "egui-wgpu" version = "0.34.1" @@ -1623,15 +1541,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - [[package]] name = "futures-core" version = "0.3.31" @@ -2489,7 +2398,6 @@ dependencies = [ "confy", "console_error_panic_hook", "eframe", - "egui-file-dialog", "egui_dnd", "egui_kittest", "egui_plot", @@ -2876,6 +2784,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -2997,16 +2906,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "objc2-io-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" -dependencies = [ - "libc", - "objc2-core-foundation", -] - [[package]] name = "objc2-io-surface" version = "0.3.2" @@ -3697,17 +3596,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 2.0.18", -] - [[package]] name = "regex" version = "1.11.1" @@ -3745,26 +3633,29 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] name = "rfd" -version = "0.15.2" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a24763657bff09769a8ccf12c8b8a50416fb035fe199263b4c5071e4e3f006f" +checksum = "20dafead71c16a34e1ff357ddefc8afc11e7d51d6d2b9fbd07eaa48e3e540220" dependencies = [ - "ashpd", - "block2 0.5.1", - "core-foundation 0.10.0", - "core-foundation-sys", + "block2 0.6.2", + "dispatch2", "js-sys", + "libc", "log", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", + "objc2 0.6.4", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "percent-encoding", "pollster", "raw-window-handle", - "urlencoding", "wasm-bindgen", "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", "web-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4189,18 +4080,6 @@ dependencies = [ "syn", ] -[[package]] -name = "sysinfo" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" -dependencies = [ - "libc", - "objc2-core-foundation", - "objc2-io-kit", - "windows", -] - [[package]] name = "system-deps" version = "6.2.2" @@ -4492,15 +4371,8 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf16_iter" version = "1.0.5" @@ -5761,7 +5633,6 @@ dependencies = [ "endi", "enumflags2", "serde", - "url", "winnow 0.7.3", "zvariant_derive", "zvariant_utils", diff --git a/crates/maps/Cargo.toml b/crates/maps/Cargo.toml index 8e347d3..f313859 100644 --- a/crates/maps/Cargo.toml +++ b/crates/maps/Cargo.toml @@ -33,7 +33,7 @@ maps_rendering = { workspace = true } confy = "0.6.1" eframe = {version = "0.34.0", features = ["wgpu"]} egui_dnd = "0.15.0" -egui-file-dialog = "0.13.0" +rfd = "0.17.2" egui_plot = "0.35.0" egui_tiles = "0.15.0" image = { workspace = true } @@ -57,7 +57,6 @@ env_logger = "0.11.5" wasm-bindgen-futures = "0.4" web-sys = "0.3.70" console_error_panic_hook = "0.1.7" # wasm error messages in the browser console -rfd = "0.15.2" # Enable selected pedantic lints. # To check all pedantic lints, alternatively add pedantic = "warn" here. diff --git a/crates/maps/src/app.rs b/crates/maps/src/app.rs index 7d0a49a..0870487 100644 --- a/crates/maps/src/app.rs +++ b/crates/maps/src/app.rs @@ -1,11 +1,10 @@ //! Main application state and options. use std::collections::{BTreeMap, HashMap}; -use std::path::absolute; +use std::path::{PathBuf, absolute}; use std::vec::Vec; use eframe::egui; -use egui_file_dialog::FileDialog; use serde::{Deserialize, Serialize}; use strum_macros::{Display, EnumString, VariantNames}; @@ -31,11 +30,6 @@ use crate::wasm::async_data::AsyncData; #[cfg(target_arch = "wasm32")] use std::sync::{Arc, Mutex}; -#[cfg(not(target_arch = "wasm32"))] -use crate::app_impl::file_dialog_builder; -#[cfg(not(target_arch = "wasm32"))] -use image::DynamicImage; - #[derive( Clone, Debug, Default, PartialEq, Display, EnumString, VariantNames, Serialize, Deserialize, )] @@ -160,10 +154,6 @@ pub struct SessionData { pub draw_order: DrawOrder, pub grid_lenses: HashMap, - #[cfg(not(target_arch = "wasm32"))] - #[serde(skip)] - pub screenshot: Option, - #[cfg(target_arch = "wasm32")] #[serde(skip)] pub(crate) wasm_io: Arc>, @@ -205,12 +195,7 @@ pub struct AppState { pub data: SessionData, pub status: StatusInfo, pub tracing: Tracing, - pub load_meta_file_dialog: FileDialog, - pub load_map_pose_file_dialog: FileDialog, - pub save_map_pose_file_dialog: FileDialog, - pub load_session_file_dialog: FileDialog, - pub save_session_file_dialog: FileDialog, - pub save_screenshot_dialog: FileDialog, + pub last_file_dir: Option, pub tile_manager: Tiles, } @@ -237,20 +222,7 @@ impl AppState { } } - #[cfg(not(target_arch = "wasm32"))] - { - state.load_meta_file_dialog = file_dialog_builder::yaml(_default_dir.as_ref()); - state.load_map_pose_file_dialog = file_dialog_builder::yaml(_default_dir.as_ref()); - state.save_map_pose_file_dialog = file_dialog_builder::yaml(_default_dir.as_ref()) - .allow_file_overwrite(true) - .default_file_name("map_pose.yaml"); - state.load_session_file_dialog = file_dialog_builder::toml(_default_dir.as_ref()); - state.save_session_file_dialog = file_dialog_builder::toml(_default_dir.as_ref()) - .allow_file_overwrite(true) - .default_file_name("maps_session.toml"); - state.save_screenshot_dialog = file_dialog_builder::png(_default_dir.as_ref()) - .default_file_name("maps_screenshot.png"); - } + state.last_file_dir = _default_dir; const TRACING_BUFFER_SIZE: usize = 600; state.tracing = Tracing::new("frame update", TRACING_BUFFER_SIZE); diff --git a/crates/maps/src/app_impl/file_dialog_builder.rs b/crates/maps/src/app_impl/file_dialog_builder.rs deleted file mode 100644 index 336e26c..0000000 --- a/crates/maps/src/app_impl/file_dialog_builder.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Simple builders for creating file dialogs with some defaults used by this crate. - -use std::{env::current_dir, path::Path, path::PathBuf}; - -use eframe::egui; -use egui_file_dialog::{FileDialog, Filter}; - -/// Creates a file dialog for YAML files. -pub fn yaml(initial_dir: Option<&PathBuf>) -> FileDialog { - FileDialogBuilder::new(initial_dir) - .with_filter("YAML", vec!["yaml", "yml"]) - .build() -} - -/// Creates a file dialog for TOML files. -pub fn toml(initial_dir: Option<&PathBuf>) -> FileDialog { - FileDialogBuilder::new(initial_dir) - .with_filter("TOML", vec!["toml"]) - .build() -} - -/// Creates a file dialog for PNG files. -pub fn png(initial_dir: Option<&PathBuf>) -> FileDialog { - FileDialogBuilder::new(initial_dir) - .with_filter("PNG", vec!["png"]) - .build() -} - -pub(crate) struct FileDialogBuilder { - dialog: FileDialog, -} - -impl FileDialogBuilder { - pub fn new(initial_dir: Option<&PathBuf>) -> Self { - FileDialogBuilder { - dialog: FileDialog::new() - .anchor(egui::Align2::CENTER_CENTER, egui::vec2(0., 0.)) - .initial_directory( - initial_dir - .cloned() - .unwrap_or(current_dir().expect("wtf no cwd??")), - ), - } - } - - pub fn with_filter<'a>(mut self, name: &str, suffixes: impl Into>) -> Self { - let suffixes_vec: Vec = suffixes.into().iter().map(|s| s.to_string()).collect(); - self.dialog = self - .dialog - .add_file_filter( - name, - Filter::new(move |path: &Path| { - suffixes_vec.iter().any(|suffix| { - path.extension() - .unwrap_or_default() - .to_str() - .unwrap_or_default() - .ends_with(suffix) - }) - }), - ) - .default_file_filter(name); - - self - } - - pub fn build(self) -> FileDialog { - self.dialog - } -} diff --git a/crates/maps/src/app_impl/keys.rs b/crates/maps/src/app_impl/keys.rs index 13d3aa1..d802acc 100644 --- a/crates/maps/src/app_impl/keys.rs +++ b/crates/maps/src/app_impl/keys.rs @@ -1,5 +1,4 @@ use eframe::egui; -use egui_file_dialog::DialogState; use crate::app::{ActiveMovable, ActiveTool, AppState}; use crate::app_impl::screenshot; @@ -7,14 +6,7 @@ use crate::movable::{DragDirection, Draggable, MovableAmounts, Rotatable}; impl AppState { fn dialogs_open(&self) -> bool { - *self.load_meta_file_dialog.state() == DialogState::Open - || *self.load_map_pose_file_dialog.state() == DialogState::Open - || *self.save_map_pose_file_dialog.state() == DialogState::Open - || *self.load_session_file_dialog.state() == DialogState::Open - || *self.save_session_file_dialog.state() == DialogState::Open - || *self.save_screenshot_dialog.state() == DialogState::Open - || self.status.quit_modal_active - || !self.status.error.is_empty() + self.status.quit_modal_active || !self.status.error.is_empty() } fn text_editing(&self) -> bool { diff --git a/crates/maps/src/app_impl/load_delete.rs b/crates/maps/src/app_impl/load_delete.rs index d2b1e2e..bdbe8f5 100644 --- a/crates/maps/src/app_impl/load_delete.rs +++ b/crates/maps/src/app_impl/load_delete.rs @@ -28,21 +28,21 @@ impl AppState { #[cfg(not(target_arch = "wasm32"))] pub(crate) fn load_meta_button(&mut self, ui: &mut egui::Ui) { if ui.button("📂 Load Maps").clicked() { - self.load_meta_file_dialog.pick_multiple(); - } - self.load_meta_file_dialog.update(ui.ctx()); - - if let Some(paths) = self.load_meta_file_dialog.take_picked_multiple() { - for path in paths { - ui.ctx().request_repaint(); - match self.load_meta(&path) { - Ok(_) => { - // Start from the same path the next time. - self.load_meta_file_dialog.config_mut().initial_directory = path; - } - Err(e) => { - self.status.error = e.to_string(); - error!("{e}"); + let mut dialog = rfd::FileDialog::new().add_filter("YAML", &["yaml", "yml"]); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); + } + if let Some(paths) = dialog.pick_files() { + for path in paths { + ui.ctx().request_repaint(); + match self.load_meta(&path) { + Ok(_) => { + self.last_file_dir = path.parent().map(std::path::Path::to_path_buf); + } + Err(e) => { + self.status.error = e.to_string(); + error!("{e}"); + } } } } @@ -154,27 +154,22 @@ impl AppState { .on_hover_text("Load a map pose from a YAML file.") .clicked() { - self.load_map_pose_file_dialog.pick_file(); - } - self.load_map_pose_file_dialog.update(ui.ctx()); - - if let Some(path) = self.load_map_pose_file_dialog.take_picked() { - debug!("Loading pose file: {path:?}"); - match MapPose::from_yaml_file(&path) { - Ok(map_pose) => { - self.add_map_pose(map_name, map_pose); - // Start from the same path the next time, also for saving. - self.load_map_pose_file_dialog - .config_mut() - .initial_directory = path.clone(); - self.save_map_pose_file_dialog - .config_mut() - .initial_directory = path; - self.status.unsaved_changes = true; - } - Err(e) => { - self.status.error = e.to_string(); - error!("{e}"); + let mut dialog = rfd::FileDialog::new().add_filter("YAML", &["yaml", "yml"]); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); + } + if let Some(path) = dialog.pick_file() { + debug!("Loading pose file: {path:?}"); + match MapPose::from_yaml_file(&path) { + Ok(map_pose) => { + self.add_map_pose(map_name, map_pose); + self.last_file_dir = path.parent().map(std::path::Path::to_path_buf); + self.status.unsaved_changes = true; + } + Err(e) => { + self.status.error = e.to_string(); + error!("{e}"); + } } } } @@ -187,32 +182,29 @@ impl AppState { .on_hover_text("Save the map pose to a YAML file.") .clicked() { - self.save_map_pose_file_dialog.save_file(); - } - self.save_map_pose_file_dialog.update(ui.ctx()); - - if let Some(path) = self.save_map_pose_file_dialog.take_picked() { - ui.ctx().request_repaint(); - debug!("Saving pose file: {path:?}"); - let Some(map) = self.data.maps.get(map_name) else { - self.status.error = format!("Can't save pose, map doesn't exist: {map_name}"); - error!("{}", self.status.error); - return; - }; - match map.pose.to_yaml_file(&path) { - Ok(_) => { - info!("Saved pose file: {path:?}"); - // Start from the same path the next time, also for loading. - self.save_map_pose_file_dialog - .config_mut() - .initial_directory = path.clone(); - self.load_map_pose_file_dialog - .config_mut() - .initial_directory = path; - } - Err(e) => { - self.status.error = e.to_string(); - error!("{e}"); + let mut dialog = rfd::FileDialog::new() + .add_filter("YAML", &["yaml", "yml"]) + .set_file_name("map_pose.yaml"); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); + } + if let Some(path) = dialog.save_file() { + ui.ctx().request_repaint(); + debug!("Saving pose file: {path:?}"); + let Some(map) = self.data.maps.get(map_name) else { + self.status.error = format!("Can't save pose, map doesn't exist: {map_name}"); + error!("{}", self.status.error); + return; + }; + match map.pose.to_yaml_file(&path) { + Ok(_) => { + info!("Saved pose file: {path:?}"); + self.last_file_dir = path.parent().map(std::path::Path::to_path_buf); + } + Err(e) => { + self.status.error = e.to_string(); + error!("{e}"); + } } } } @@ -222,8 +214,7 @@ impl AppState { let deserialized_session = persistence::load_session(path)?; // Start from the same path the next time. - self.load_session_file_dialog.config_mut().initial_directory = path.clone(); - self.save_session_file_dialog.config_mut().initial_directory = path.clone(); + self.last_file_dir = path.parent().map(std::path::Path::to_path_buf); // Keep the draw order of the session, if it was saved. // If it was not saved (older versions), add_map() will take care of it. @@ -287,15 +278,19 @@ impl AppState { .on_disabled_hover_text("Only supported in native builds.") .clicked() { - self.load_session_file_dialog.pick_file(); - } - self.load_session_file_dialog.update(ui.ctx()); - - if let Some(path) = self.load_session_file_dialog.take_picked() { - self.load_session(&path).unwrap_or_else(|e| { - self.status.error = e.to_string(); - error!("{e}"); - }); + #[cfg(not(target_arch = "wasm32"))] + { + let mut dialog = rfd::FileDialog::new().add_filter("TOML", &["toml"]); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); + } + if let Some(path) = dialog.pick_file() { + self.load_session(&path).unwrap_or_else(|e| { + self.status.error = e.to_string(); + error!("{e}"); + }); + } + } } } @@ -318,30 +313,30 @@ impl AppState { .on_disabled_hover_text(disabled_hover_text) .clicked() { - self.save_session_file_dialog.save_file(); - self.status.quit_after_save = quit_after_save; - self.status.quit_modal_active = false; - // TODO: Why is the dialog not visible when no button is visible? - // Make sure the menu is visible from the menu panel. - self.options.menu_visible = true; - } - self.save_session_file_dialog.update(ui.ctx()); - - if let Some(path) = self.save_session_file_dialog.take_picked() { - match persistence::save_session(&path, &self.data) { - Ok(_) => { - // Start from the same path the next time. - self.save_session_file_dialog.config_mut().initial_directory = path.clone(); - self.load_session_file_dialog.config_mut().initial_directory = path; - self.status.unsaved_changes = false; - if self.status.quit_after_save { - ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); - } + #[cfg(not(target_arch = "wasm32"))] + { + let mut dialog = rfd::FileDialog::new() + .add_filter("TOML", &["toml"]) + .set_file_name("maps_session.toml"); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); } - Err(e) => { - self.status.error = e.to_string(); - error!("{e}"); + if let Some(path) = dialog.save_file() { + match persistence::save_session(&path, &self.data) { + Ok(_) => { + self.last_file_dir = path.parent().map(std::path::Path::to_path_buf); + self.status.unsaved_changes = false; + if quit_after_save { + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Close); + } + } + Err(e) => { + self.status.error = e.to_string(); + error!("{e}"); + } + } } + self.status.quit_modal_active = false; } } } diff --git a/crates/maps/src/app_impl/mod.rs b/crates/maps/src/app_impl/mod.rs index e5abe81..a176b7e 100644 --- a/crates/maps/src/app_impl/mod.rs +++ b/crates/maps/src/app_impl/mod.rs @@ -5,8 +5,6 @@ mod compat; pub(crate) mod constants; pub(crate) mod debug_window; pub(crate) mod error_modal; -#[cfg(not(target_arch = "wasm32"))] -pub(crate) mod file_dialog_builder; pub(crate) mod footer_panel; mod grid_settings; pub(crate) mod header_panel; diff --git a/crates/maps/src/app_impl/screenshot.rs b/crates/maps/src/app_impl/screenshot.rs index 884e2c4..6b4a049 100644 --- a/crates/maps/src/app_impl/screenshot.rs +++ b/crates/maps/src/app_impl/screenshot.rs @@ -70,8 +70,25 @@ impl AppState { #[cfg(not(target_arch = "wasm32"))] { - self.data.screenshot = Some(image); - self.save_screenshot_dialog.save_file(); + let mut dialog = rfd::FileDialog::new() + .add_filter("PNG", &["png"]) + .set_file_name("maps_screenshot.png"); + if let Some(dir) = &self.last_file_dir { + dialog = dialog.set_directory(dir); + } + if let Some(file_path) = dialog.save_file() { + match save_image(&file_path, &image) { + Ok(_) => { + info!("Saved screenshot to {file_path:?}"); + self.last_file_dir = + file_path.parent().map(std::path::Path::to_path_buf); + } + Err(e) => { + self.status.error = format!("Failed to save screenshot: {e}"); + error!("{e}"); + } + } + } } #[cfg(target_arch = "wasm32")] { @@ -82,24 +99,5 @@ impl AppState { ); } } - - #[cfg(not(target_arch = "wasm32"))] - { - self.save_screenshot_dialog.update(ctx); - - if let Some(file_path) = self.save_screenshot_dialog.take_picked() - && let Some(image) = self.data.screenshot.take() - { - match save_image(&file_path, &image) { - Ok(_) => { - info!("Saved screenshot to {file_path:?}"); - } - Err(e) => { - self.status.error = format!("Failed to save screenshot: {e}"); - error!("{e}"); - } - } - } - } } }