use std::path::{Path, PathBuf}; use rfd::FileDialog; use winit::window::Window; const DEFAULT_FILE_NAME: &str = "map.json"; /// Show the platform-native Save dialog. The caller owns the returned path and /// decides when to write, which keeps dialogs entirely out of unit tests. pub fn choose_map_save_path(window: &Window, current: Option<&Path>) -> Option { let mut dialog = map_dialog(window, "Сохранить карту"); if let Some(directory) = starting_directory(current) { dialog = dialog.set_directory(directory); } let suggested_name = current .and_then(Path::file_name) .and_then(|name| name.to_str()) .unwrap_or(DEFAULT_FILE_NAME); dialog .set_file_name(suggested_name) .save_file() .map(ensure_json_extension) } /// Show the platform-native Open dialog for one versioned JSON map. pub fn choose_map_open_path(window: &Window, current: Option<&Path>) -> Option { let mut dialog = map_dialog(window, "Открыть карту"); if let Some(directory) = starting_directory(current) { dialog = dialog.set_directory(directory); } dialog.pick_file() } fn map_dialog(window: &Window, title: &str) -> FileDialog { FileDialog::new() .set_parent(window) .set_title(title) .add_filter("Карта Ray Marching (JSON)", &["json"]) } fn starting_directory(current: Option<&Path>) -> Option { current .and_then(|path| { if path.is_dir() { Some(path) } else { path.parent() } }) .filter(|path| !path.as_os_str().is_empty()) .map(Path::to_owned) .or_else(|| std::env::current_dir().ok()) } pub(crate) fn ensure_json_extension(mut path: PathBuf) -> PathBuf { let is_json = path .extension() .and_then(|extension| extension.to_str()) .is_some_and(|extension| extension.eq_ignore_ascii_case("json")); if !is_json { path.set_extension("json"); } path } #[cfg(test)] mod tests { use super::*; #[test] fn save_path_gets_one_json_extension() { assert_eq!( ensure_json_extension(PathBuf::from("level")), PathBuf::from("level.json") ); assert_eq!( ensure_json_extension(PathBuf::from("level.JSON")), PathBuf::from("level.JSON") ); assert_eq!( ensure_json_extension(PathBuf::from("level.txt")), PathBuf::from("level.json") ); } }