mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 00:42:33 +00:00
.ai save: exports to a path and timestamped copies name the active artboard
A .ai file that File > Export As, its dialog or a control request writes to a path now names the view's active artboard, as document.export and document.serialize do. The UI export records the view's artboard and takes its document from fileio::export_doc, which applies DocState::active_artboard to the export's copy; document.export and document.serialize use the same function. The app now records the view's active artboard before every command, including the commands the UI handles itself, so a .ai copy from Save a Timestamped Copy or Export All Open Documents names it too. Before, these files named the artboard the document opened on, or the first. The open document is unchanged.
This commit is contained in:
@@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||
use serde_json::json;
|
||||
use vectorcraft_engine::Session;
|
||||
|
||||
use super::SAVE_COPY;
|
||||
use super::{EXPORT_ALL, SAVE_COPY};
|
||||
use crate::{VectorcraftApp, menus};
|
||||
|
||||
/// A new, empty folder of its own for test `name`.
|
||||
@@ -46,6 +46,31 @@ fn save_a_timestamped_copy_writes_beside_the_document() {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
/// A `.ai` timestamped copy, and a `.ai` copy Export All Open Documents writes, name the view's
|
||||
/// active artboard as their active one.
|
||||
#[test]
|
||||
fn ai_copies_name_the_views_active_artboard() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 60, "height": 40, "artboards": 3})).unwrap();
|
||||
app.sync_views();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap();
|
||||
let opts = vectorcraft_engine::cmd::fileio::LoadOptions { native: false, ..Default::default() };
|
||||
for (i, (cmd, artboard)) in [(SAVE_COPY, 2), (EXPORT_ALL, 1)].into_iter().enumerate() {
|
||||
let dir = folder(&format!("active-artboard-{i}"));
|
||||
if let Some(v) = app.view_mut() {
|
||||
v.artboard = artboard;
|
||||
}
|
||||
app.run(cmd, json!({"folder": dir, "format": "ai"})).unwrap();
|
||||
let names = files(&dir);
|
||||
assert_eq!(names.len(), 1, "{cmd}: {names:?}");
|
||||
let bytes = std::fs::read(dir.join(&names[0])).unwrap();
|
||||
let l = vectorcraft_engine::cmd::fileio::load_with("a.ai", &bytes, &opts).unwrap();
|
||||
assert!(l.editing_data && !l.restored, "{cmd}: {:?}", l.warnings);
|
||||
assert_eq!(l.doc.opened_artboard.and_then(|id| l.doc.artboards.iter().position(|a| a.id == id)), Some(artboard), "{cmd}");
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_unsaved_document_asks_for_a_folder() {
|
||||
let dir = folder("picked");
|
||||
|
||||
@@ -93,6 +93,9 @@ impl VectorcraftApp {
|
||||
if cfg!(debug_assertions) {
|
||||
menus::check_params(&self.session, id, ¶ms)?;
|
||||
}
|
||||
// A `.ai` file a command writes (a save, an export, a timestamped copy, a batch's save) names
|
||||
// the view's active artboard.
|
||||
io::remember_active_artboard(self);
|
||||
let artboards = self.artboard_tool_state();
|
||||
if let Some(r) = menus::run_ui_command(self, id, ¶ms) {
|
||||
self.follow_artboard_tool(artboards);
|
||||
@@ -173,9 +176,6 @@ impl VectorcraftApp {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
// A `.ai` file a command writes (a save, an export, a batch's save) names the view's
|
||||
// active artboard.
|
||||
io::remember_active_artboard(self);
|
||||
// Native files carry the view they reopen at.
|
||||
if fileio::SaveMode::of(id).is_some() {
|
||||
io::remember_view(self);
|
||||
|
||||
@@ -207,6 +207,33 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// A `.ai` file exported to a path (File › Export As, its dialog, a control request) names the
|
||||
/// view's active artboard as its active one, and the open document is unchanged.
|
||||
#[test]
|
||||
fn an_ai_file_exported_to_a_path_names_the_views_active_artboard() {
|
||||
let (mut app, written) = app();
|
||||
app.run("file.new", json!({"width": 60, "height": 40, "artboards": 3})).unwrap();
|
||||
app.sync_views();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap();
|
||||
let opts = fileio::LoadOptions { native: false, ..Default::default() };
|
||||
let active = |app: &VectorcraftApp| {
|
||||
let bytes = written.borrow_mut().pop().map(|(_, b)| b).unwrap();
|
||||
let l = fileio::load_with("Art.ai", &bytes, &opts).unwrap();
|
||||
assert!(l.editing_data && !l.restored, "{:?}", l.warnings);
|
||||
assert_eq!(app.session.doc().unwrap().doc.opened_artboard, None, "the document is unchanged");
|
||||
l.doc.opened_artboard.and_then(|id| l.doc.artboards.iter().position(|a| a.id == id))
|
||||
};
|
||||
for artboard in [2, 1] {
|
||||
if let Some(v) = app.view_mut() {
|
||||
v.artboard = artboard;
|
||||
}
|
||||
app.run("file.exportAs", json!({"format": "ai", "path": "Art.ai"})).unwrap();
|
||||
assert_eq!(active(&app), Some(artboard), "File › Export As");
|
||||
export(&mut app, Some("ai"), Some("Art.ai".into()), &json!({})).unwrap();
|
||||
assert_eq!(active(&app), Some(artboard), "the Export As dialog");
|
||||
}
|
||||
}
|
||||
|
||||
fn bytes_of(app: &mut VectorcraftApp, cmd: &str, p: Value) -> Vec<u8> {
|
||||
let v = app.session.execute(cmd, &p).unwrap();
|
||||
vectorcraft_format::base64_decode(v["dataBase64"].as_str().unwrap()).unwrap()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::save::{
|
||||
ask_before_losing, export_path, is_web, report_saved, report_write_error, saved_status, target_path, target_path_keeping, view_file,
|
||||
write_encoded, write_named, write_reporting,
|
||||
ask_before_losing, export_path, is_web, remember_active_artboard, report_saved, report_write_error, saved_status, target_path,
|
||||
target_path_keeping, view_file, write_encoded, write_named, write_reporting,
|
||||
};
|
||||
use super::{EngineError, Progress, Value, VectorcraftApp, Writer, background, cancel, fileio, json, progress};
|
||||
|
||||
@@ -33,8 +33,10 @@ pub fn export(app: &mut VectorcraftApp, format: Option<&str>, path: Option<Strin
|
||||
// encoder (an exporter plug-in is told the file it writes).
|
||||
let params = &if params.is_object() { params.clone() } else { json!({}) };
|
||||
let f = fileio::writable_format(format, path.as_deref())?;
|
||||
// A `.ai` file names the view's active artboard.
|
||||
remember_active_artboard(app);
|
||||
let st = app.session.active().ok_or("no document")?;
|
||||
let doc = match fileio::export_source(st, params).map_err(|e| e.to_string())? {
|
||||
let doc = match fileio::export_doc(st, f, params).map_err(|e| e.to_string())? {
|
||||
std::borrow::Cow::Borrowed(_) => st.doc.clone(),
|
||||
std::borrow::Cow::Owned(d) => std::sync::Arc::new(d),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user