diff --git a/crates/ui-egui/src/addons/document/tests.rs b/crates/ui-egui/src/addons/document/tests.rs index 7ef678308..6e637c718 100644 --- a/crates/ui-egui/src/addons/document/tests.rs +++ b/crates/ui-egui/src/addons/document/tests.rs @@ -71,6 +71,39 @@ fn ai_copies_name_the_views_active_artboard() { } } +/// Export All Open Documents as `.ai` names each document's own active artboard, also for a +/// document whose artboard changed in its view after the last command and that is not active. +#[test] +fn export_all_names_each_documents_active_artboard() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + for name in ["first", "second"] { + app.run("file.new", json!({"width": 60, "height": 40, "artboards": 3, "name": name})).unwrap(); + app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap(); + } + app.sync_views(); + // Choosing a tab and an artboard runs no command. + assert!(app.session.set_active(0)); + if let Some(v) = app.view_mut() { + v.artboard = 2; + } + assert!(app.session.set_active(1)); + if let Some(v) = app.view_mut() { + v.artboard = 1; + } + let dir = folder("export-all-active-artboards"); + let r = app.run(EXPORT_ALL, json!({"folder": dir, "format": "ai"})).unwrap(); + let opts = vectorcraft_engine::cmd::fileio::LoadOptions { native: false, ..Default::default() }; + let written = r["files"].as_array().unwrap(); + assert_eq!(written.len(), 2, "{r}"); + for (f, artboard) in written.iter().zip([2, 1]) { + let bytes = std::fs::read(f["path"].as_str().unwrap()).unwrap(); + let l = vectorcraft_engine::cmd::fileio::load_with("a.ai", &bytes, &opts).unwrap(); + assert!(l.editing_data && !l.restored, "{:?}", l.warnings); + assert_eq!(l.doc.opened_artboard.and_then(|id| l.doc.artboards.iter().position(|a| a.id == id)), Some(artboard), "{}", f["title"]); + } + let _ = std::fs::remove_dir_all(&dir); +} + #[test] fn an_unsaved_document_asks_for_a_folder() { let dir = folder("picked"); diff --git a/crates/ui-egui/src/io/save.rs b/crates/ui-egui/src/io/save.rs index 3d81aff54..98e52a2c3 100644 --- a/crates/ui-egui/src/io/save.rs +++ b/crates/ui-egui/src/io/save.rs @@ -172,7 +172,7 @@ pub(super) fn target_path_keeping( } /// Keep the active document's saved view current before a save (native files reopen at it), and -/// its active artboard ([`remember_active_artboard`]). +/// each document's active artboard ([`remember_active_artboard`]). pub fn remember_view(app: &mut VectorcraftApp) { remember_active_artboard(app); let Some(v) = app.view().copied().filter(|v| v.fitted) else { return }; @@ -181,14 +181,17 @@ pub fn remember_view(app: &mut VectorcraftApp) { } } -/// Keep the active document's active artboard current (a `.ai` file saved or exported names it -/// as its active one): the view's, an index past the last artboard being the last one as in the -/// Artboards panel; `None` without a view. +/// Keep every open document's active artboard current (a `.ai` file saved or exported names it as +/// its active one, also in Export All Open Documents): its own view's, an index past the last +/// artboard being the last one as in the Artboards panel; `None` without a view. pub fn remember_active_artboard(app: &mut VectorcraftApp) { - let index = app.view().map(|v| v.artboard); - if let Some(st) = app.session.active_mut() { - let last = st.doc.artboards.len().saturating_sub(1); - st.active_artboard = index.and_then(|i| st.doc.artboards.get(i.min(last))).map(|a| a.id); + let uids: Vec = app.session.documents().iter().map(|d| d.uid).collect(); + for uid in uids { + let index = app.view_uids.iter().position(|u| *u == uid).and_then(|k| app.views.get(k)).map(|v| v.artboard); + if let Some(st) = app.session.document_mut(uid) { + let last = st.doc.artboards.len().saturating_sub(1); + st.active_artboard = index.and_then(|i| st.doc.artboards.get(i.min(last))).map(|a| a.id); + } } }