diff --git a/crates/engine/src/cmd/fileio/mod.rs b/crates/engine/src/cmd/fileio/mod.rs index 3135e2bfa..3931defdb 100644 --- a/crates/engine/src/cmd/fileio/mod.rs +++ b/crates/engine/src/cmd/fileio/mod.rs @@ -793,6 +793,17 @@ pub fn open_filters() -> impl Iterator impl Iterator { + std::iter::once((library_label, library_exts)).chain(open_filters()) +} + /// File → Place dialog filters: "All placeable files", then one per placeable format, then text, /// RTF and Word. pub fn place_filters() -> impl Iterator { diff --git a/crates/engine/src/cmd/fileio/tests.rs b/crates/engine/src/cmd/fileio/tests.rs index fe2dc7251..e656965e1 100644 --- a/crates/engine/src/cmd/fileio/tests.rs +++ b/crates/engine/src/cmd/fileio/tests.rs @@ -384,6 +384,14 @@ fn open_exts_cover_every_readable_format() { assert_eq!(filters.last(), Some(&("Plug-ins", crate::cmd::plugin::EXTS)), "File › Open installs plug-ins"); } +#[test] +fn library_open_filters_list_library_formats_first() { + let filters: Vec<_> = library_open_filters("Swatch libraries", super::swatchlib::LIBRARY_EXTS).collect(); + assert_eq!(filters[0], ("Swatch libraries", super::swatchlib::LIBRARY_EXTS)); + assert!(filters[0].1.contains(&"ase")); + assert_eq!(filters[1], ("All readable files", OPEN_EXTS)); +} + /// The extensions usage texts list for export: one per writable format, each picking that format /// (`.png` picks PNG; PNG-8 is asked for by `format`). #[test] diff --git a/crates/ui-egui/src/panels/graphic_styles.rs b/crates/ui-egui/src/panels/graphic_styles.rs index 5929185fb..8b0f2366c 100644 --- a/crates/ui-egui/src/panels/graphic_styles.rs +++ b/crates/ui-egui/src/panels/graphic_styles.rs @@ -767,7 +767,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result) -> Result { - match library_panel::pick_library_file(app, path)? { + match library_panel::pick_library_file(app, path, library_panel::library_pick_filters(GraphicStyleLibraries::KIND))? { Some(path) => load_library(app, json!({ "path": path })), None => Ok(Value::Null), } diff --git a/crates/ui-egui/src/panels/library_panel.rs b/crates/ui-egui/src/panels/library_panel.rs index b75eefaa0..6ef14648e 100644 --- a/crates/ui-egui/src/panels/library_panel.rs +++ b/crates/ui-egui/src/panels/library_panel.rs @@ -17,7 +17,9 @@ use std::sync::{Mutex, PoisonError}; use egui::{Rect, Sense, Ui}; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; -use vectorcraft_engine::cmd::swatchlib::LibraryInfo; +use vectorcraft_doc::style_libs::STYLES_EXT; +use vectorcraft_engine::cmd::fileio; +use vectorcraft_engine::cmd::swatchlib::{self, LibraryInfo}; use super::swatches::{View, click_selection, folder_tile, list_row, list_row_name, tile_grid}; use super::{pstate, set_pstate}; @@ -503,7 +505,8 @@ pub(crate) fn locate(app: &mut VectorcraftApp, p: &Value) -> Result Vec<(&'static str, &'static [&'static str])> { + match kind { + super::swatches::SwatchLibraries::KIND => fileio::library_open_filters("Swatch libraries", swatchlib::LIBRARY_EXTS).collect(), + super::graphic_styles::GraphicStyleLibraries::KIND => fileio::library_open_filters("Graphic Style Libraries", &[STYLES_EXT]).collect(), + _ => fileio::open_filters().collect(), + } +} + /// Other Library…: the library file at `path`, else one picked in an open dialog; `None` when the /// pick is asynchronous (on the web the picked file arrives later through [`crate::io::open_bytes`]). -pub(crate) fn pick_library_file(app: &mut VectorcraftApp, path: Option) -> Result, String> { +pub(crate) fn pick_library_file( + app: &mut VectorcraftApp, + path: Option, + filters: Vec<(&'static str, &'static [&'static str])>, +) -> Result, String> { if path.is_none() && let Some(f) = app.services.open_async.as_mut() { @@ -539,7 +555,7 @@ pub(crate) fn pick_library_file(app: &mut VectorcraftApp, path: Option) return Ok(None); } path.or_else(|| { - let pick = crate::FilePick { filters: crate::FilePick::filters(vectorcraft_engine::cmd::fileio::open_filters()), ..Default::default() }; + let pick = crate::FilePick { filters: crate::FilePick::filters(filters), ..Default::default() }; crate::picks::open(app, &pick) }) .map(Some) diff --git a/crates/ui-egui/src/panels/swatches.rs b/crates/ui-egui/src/panels/swatches.rs index 17679ca8d..75861ff5c 100644 --- a/crates/ui-egui/src/panels/swatches.rs +++ b/crates/ui-egui/src/panels/swatches.rs @@ -1214,7 +1214,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result) -> Result { - match library_panel::pick_library_file(app, path)? { + match library_panel::pick_library_file(app, path, library_panel::library_pick_filters(SwatchLibraries::KIND))? { Some(path) => load_library(app, json!({ "path": path })), None => Ok(Value::Null), } diff --git a/crates/ui-egui/src/tests_picks.rs b/crates/ui-egui/src/tests_picks.rs index 3aa8f21b3..47fca62ad 100644 --- a/crates/ui-egui/src/tests_picks.rs +++ b/crates/ui-egui/src/tests_picks.rs @@ -260,7 +260,10 @@ fn other_swatch_library_asks_off_the_ui_thread() { app.run("swatch.new", json!({"name": "Signal", "color": "#ff3300"})).unwrap(); let (dir, file) = saved_document(&mut app, "swatches"); click(&mut app, "Other Library…", library_menu::); - assert!(matches!(shown.requests().as_slice(), [PickRequest::Open(_)])); + assert!(matches!( + shown.requests().as_slice(), + [PickRequest::Open(p)] if p.filters.first().is_some_and(|(label, exts)| label == "Swatch libraries" && exts.iter().any(|e| e == "ase")) + )); poll(&mut app); assert!(library_panel::last_open(&app.ui).is_none() && app.ui.status.is_empty(), "{}", app.ui.status); shown.answer(&[&file]);