mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Fix #3465: Swatch Libraries Other Library lists .ase on Linux
## Summary Linux file portals grey out files that do not match the open dialog's default filter. Other Library… and Locate Library… used File › Open filters, whose first entry is All readable files and omits swatch-library extensions such as .ase. Add library_open_filters with the library formats first (matching Illustrator's Swatch Libraries › Other Library…) and use it from swatch and graphic style library pickers. ## Tests - engine: library_open_filters_list_library_formats_first - ui-egui: other_swatch_library_asks_off_the_ui_thread asserts Swatch libraries is the default filter and includes ase Closes storytold/vectorcraft#3465 Co-authored-by: nrq6993-a11y <nrq6993-a11y@users.noreply.github.com>
This commit is contained in:
committed by
bflatastic
co-authored by
nrq6993-a11y
parent
1388b8ec1a
commit
1fbec667ec
@@ -793,6 +793,17 @@ pub fn open_filters() -> impl Iterator<Item = (&'static str, &'static [&'static
|
||||
.chain(std::iter::once(("Plug-ins", super::plugin::EXTS)))
|
||||
}
|
||||
|
||||
/// Open-dialog filters for Swatch Libraries and Graphic Style Libraries Other Library… and Locate
|
||||
/// Library…. The library formats come first so Linux file portals (which grey out files that don't
|
||||
/// match the default filter) still list `.ase` and the other library extensions; then the same
|
||||
/// filters as [`open_filters`] so a document can be picked for its swatches or graphic styles.
|
||||
pub fn library_open_filters(
|
||||
library_label: &'static str,
|
||||
library_exts: &'static [&'static str],
|
||||
) -> impl Iterator<Item = (&'static str, &'static [&'static str])> {
|
||||
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<Item = (&'static str, &'static [&'static str])> {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -767,7 +767,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result<Va
|
||||
|
||||
/// Other Library…: load the library (or document) at `path`, else one picked in an open dialog.
|
||||
pub(crate) fn other_library(app: &mut VectorcraftApp, path: Option<String>) -> Result<Value, String> {
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -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<Value, Strin
|
||||
return Err(format!("library panel `{given}` isn't missing its library"));
|
||||
}
|
||||
let path = p.get("path").and_then(Value::as_str).map(str::to_string);
|
||||
let Some(path) = pick_library_file(app, path)? else { return Ok(Value::Null) };
|
||||
let filters = library_pick_filters(k.kind);
|
||||
let Some(path) = pick_library_file(app, path, filters)? else { return Ok(Value::Null) };
|
||||
let r = app.run(k.load, json!({ "path": path }))?;
|
||||
let next = r["library"].as_str().unwrap_or_default().to_string();
|
||||
let to = panel_id(k.kind, &next);
|
||||
@@ -529,9 +532,22 @@ fn set(app: &mut VectorcraftApp, panel: &str, mut params: Value) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Open-dialog filters for Other Library… / Locate Library… of library panels of kind `kind`.
|
||||
pub(crate) fn library_pick_filters(kind: &str) -> 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<String>) -> Result<Option<String>, String> {
|
||||
pub(crate) fn pick_library_file(
|
||||
app: &mut VectorcraftApp,
|
||||
path: Option<String>,
|
||||
filters: Vec<(&'static str, &'static [&'static str])>,
|
||||
) -> Result<Option<String>, 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<String>)
|
||||
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)
|
||||
|
||||
@@ -1214,7 +1214,7 @@ pub(crate) fn load_library(app: &mut VectorcraftApp, params: Value) -> Result<Va
|
||||
/// Other Library…: load the library (or document) at `path`, else one picked in an open dialog
|
||||
/// (on the web the picked file arrives later and opens through [`crate::io::open_bytes`]).
|
||||
pub(crate) fn other_library(app: &mut VectorcraftApp, path: Option<String>) -> Result<Value, String> {
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -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::<SwatchLibraries>);
|
||||
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]);
|
||||
|
||||
Reference in New Issue
Block a user