.ai save: Export All names each document's own active artboard

Export All Open Documents read the active artboard recorded for each
document, which was kept current only for the active one. A document
whose artboard changed in its view while another tab was active wrote
that stale artboard as the file's active one. Before each command the
app now records every open document's active artboard from that
document's own view.
This commit is contained in:
dotCooCoo
2026-11-07 05:14:57 +07:00
committed by bflatastic
parent 5216632e6b
commit 5ce8ce486e
2 changed files with 44 additions and 8 deletions
@@ -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");
+11 -8
View File
@@ -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<u64> = 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);
}
}
}