mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 10:17:02 -06:00
Merge pull request #3166 from sungjea713/export-selection-single-asset
Export Selection: the selection becomes one asset, not one per object
This commit is contained in:
@@ -52,7 +52,7 @@ fn assets(app: &mut VectorcraftApp) -> Vec<Value> {
|
||||
fn export_selection_collects_the_selection_and_opens_the_assets_tab() {
|
||||
let (mut app, log, _) = app(true);
|
||||
assert!(crate::menus::enabled(&app, "file.exportSelection"));
|
||||
let r = app.run("file.exportSelection", json!({})).unwrap();
|
||||
let r = app.run("file.exportSelection", json!({"multiple": true})).unwrap();
|
||||
let list = assets(&mut app);
|
||||
assert_eq!(list.len(), 2, "one asset per object");
|
||||
let ids: Vec<Value> = list.iter().map(|a| a["id"].clone()).collect();
|
||||
@@ -61,7 +61,7 @@ fn export_selection_collects_the_selection_and_opens_the_assets_tab() {
|
||||
assert_eq!((field(&app, "tab"), field(&app, "assets")), (json!("assets"), json!(ids)));
|
||||
// Collecting the same art again opens on the same assets.
|
||||
super::cancel(&mut app);
|
||||
app.run("file.exportSelection", json!({})).unwrap();
|
||||
app.run("file.exportSelection", json!({"multiple": true})).unwrap();
|
||||
assert_eq!(assets(&mut app).len(), 2);
|
||||
assert_eq!(field(&app, "assets"), json!(ids));
|
||||
let text = painted_text(&mut app, |app, ui| super::show(app, ui.ctx()));
|
||||
@@ -80,12 +80,15 @@ fn export_selection_collects_the_selection_and_opens_the_assets_tab() {
|
||||
|
||||
#[test]
|
||||
fn export_selection_as_one_asset() {
|
||||
let (mut app, _, ids) = app(true);
|
||||
app.run("file.exportSelection", json!({"multiple": false})).unwrap();
|
||||
let list = assets(&mut app);
|
||||
assert_eq!(list.len(), 1);
|
||||
assert_eq!(list[0]["nodes"], json!(ids));
|
||||
assert_eq!(field(&app, "assets"), json!([list[0]["id"]]));
|
||||
// By default the selection, ungrouped, becomes one asset of it all; `multiple: false` says so too.
|
||||
for p in [json!({}), json!({"multiple": false})] {
|
||||
let (mut app, _, ids) = app(true);
|
||||
app.run("file.exportSelection", p.clone()).unwrap();
|
||||
let list = assets(&mut app);
|
||||
assert_eq!(list.len(), 1, "{p}");
|
||||
assert_eq!(list[0]["nodes"], json!(ids), "{p}");
|
||||
assert_eq!(field(&app, "assets"), json!([list[0]["id"]]), "{p}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -843,7 +843,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
|
||||
"file.exportSelection",
|
||||
"Export Selection…",
|
||||
"",
|
||||
"{multiple?: true} collect the selected objects as assets (assets.add: one per object; false: one of them all) and open Export for Screens on its Assets tab with them checked → {assets: [asset id…]}; document.exportSelection exports the selection in one go instead",
|
||||
"{multiple?: false} collect the selected objects as assets (assets.add: one of them all, as one image; true: one per object) and open Export for Screens on its Assets tab with them checked → {assets: [asset id…]}; document.exportSelection exports the selection in one go instead",
|
||||
),
|
||||
(
|
||||
"css.copy",
|
||||
@@ -1666,13 +1666,15 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
|
||||
"file.saveForWeb" if p.as_object().is_none_or(|o| o.is_empty()) => crate::dialogs::save_for_web::open(app),
|
||||
"file.saveForWeb" => crate::dialogs::save_for_web::save(app, p.clone()),
|
||||
"file.saveForWeb.browser" => crate::dialogs::save_for_web::browser_preview(app, p),
|
||||
// File → Export Selection…: the selection becomes assets, shown checked on Export for
|
||||
// Screens' Assets tab.
|
||||
"file.exportSelection" => app.run("assets.add", json!({ "multiple": p.get("multiple").and_then(Value::as_bool).unwrap_or(true) })).map(|r| {
|
||||
let ids: Vec<u64> = r["assets"].as_array().into_iter().flatten().filter_map(Value::as_u64).collect();
|
||||
crate::dialogs::open_export_for_screens_assets(app, Some(&ids));
|
||||
json!({ "assets": ids })
|
||||
}),
|
||||
// File → Export Selection…: the selection becomes one asset (`multiple: true`: one per
|
||||
// object), shown checked on Export for Screens' Assets tab.
|
||||
"file.exportSelection" => {
|
||||
app.run("assets.add", json!({ "multiple": p.get("multiple").and_then(Value::as_bool).unwrap_or(false) })).map(|r| {
|
||||
let ids: Vec<u64> = r["assets"].as_array().into_iter().flatten().filter_map(Value::as_u64).collect();
|
||||
crate::dialogs::open_export_for_screens_assets(app, Some(&ids));
|
||||
json!({ "assets": ids })
|
||||
})
|
||||
}
|
||||
"css.copy" => crate::panels::css_properties::copy(app, p),
|
||||
"css.exportFile" => crate::panels::css_properties::export_file(app, p),
|
||||
// File → Print…: its dialog; with params, print (or save the job as a PDF) without it.
|
||||
|
||||
@@ -121,7 +121,7 @@ the two can still win that race.
|
||||
| Background Save / Export | `app.save`, `app.export {path}`, `file.save`, `file.saveAs`, `file.saveCopy` | with the `backgroundSave` / `backgroundExport` preferences on (the default) the desktop app writes the file from a snapshot on a worker thread: the call returns `{path, background: true, status}` at once, `ui.inspect` lists the jobs still running in `background` (labels such as `"Saving a.vectorcraft"`), and the document counts as saved (as of the snapshot) once its file is written. Quit and Close wait for them. With the preferences off (`prefs.set`), saves return once written |
|
||||
| `engine.execute` `file.exportForScreens` | `{}` / `{…document.exportForScreens params}` | without params opens `exportForScreens` on the settings the document last exported with (`document.exportSettings`). While the Artboard tool is in use, the artboards it has selected (its `selected` option, the rows the Artboards panel highlights) are checked instead, and `select` is `range`, or `all` when every artboard is selected. Fields: `tab` (`artboards` \| `assets` \| `layers` \| `selection`; OK reads Export Layer or Export Selection on those), `layers` ([layer id…] checked), `selectionMode` (`one` \| `each`), `name` (the file name pattern of `document.exportForScreens`), `counterStart`, `folders` (`none` \| `rows` \| `format` \| `item` \| `itemFormat`), `exportPreset` (the preset applied last), `__savePreset` (the name typed to save one), `select` (`all` \| `range` \| `full`), `range` ("1-3, 5"), `boards` (a bool per artboard; checking them sets `select` and `range`), `includeBleed`, `folder` (desktop; default the Desktop, else home), `openLocation`, `subfolders`, `prefix`, `preset` (`""` \| `mobile` \| `density`), `formats` (rows `{format, scale: "2x" \| "100w" \| "100h" \| "72ppi", suffix, quality?, folder?}`), `settings` (`{png \| png8 \| jpg \| webp \| gif \| svg \| pdf: {…options}}`, the gear's Format Settings; `__settings` names the format shown). `ui.dialog.confirm` exports (a bad range or no folder keeps it open); on the web OK reads "Download" and the files download (several as one `.zip`). With params it runs `document.exportForScreens`: no `folder` returns the files (or with `zip: true` one store-only zip) as `dataBase64`; with `openLocation` the first file is shown in the file manager. When `warnings` is not empty, an export into a folder or a download shows the first in the status bar as Save As shows a save's notes |
|
||||
| Export for Screens' Assets tab, Asset Export panel | `ui.dialog.set` `tab: "assets"`, `assets: [asset id…]`; `window.panel {panel: "assetExport"}` | on the Assets tab of `exportForScreens` the `assets` field lists the checked asset ids (all of them when it opens); `ui.dialog.confirm` runs `document.exportForScreens {assets}` (nothing checked keeps it open) and OK reads "Export Asset". The Asset Export panel acts through `assets.*` and shares the format rows with the dialog (`assets.settings.set`) |
|
||||
| `engine.execute` `file.exportSelection` | `{multiple?}` | File › Export Selection…: collects the selected objects as assets (`assets.add`; one per object unless `multiple` is false) and opens `exportForScreens` on its Assets tab with just them checked → `{assets}`. `document.exportSelection` still exports the selection in one go, without the dialog |
|
||||
| `engine.execute` `file.exportSelection` | `{multiple?}` | File › Export Selection…: collects the selected objects as one asset (`assets.add`; one per object with `multiple: true`) and opens `exportForScreens` on its Assets tab with just them checked → `{assets}`. `document.exportSelection` still exports the selection in one go, without the dialog |
|
||||
| CSS Properties panel | `window.panel {panel: "cssProperties"}`; `engine.execute` `css.copy` / `css.exportFile` | the panel shows `css.selection` of the selection (after Generate CSS, while nothing is selected, `css.generate`); its menu holds the options the commands take (`units`, `position`, `dimensions`, `unnamed`, `rasterize`). `css.copy {scope?, …options}` copies the CSS to the clipboard → `{css, rules}`; `css.exportFile {path?, scope?, …options}` writes `css.export` to `path` (else a picked file; the web downloads it) with the pictures of rasterized art next to it → `{path, rules, images, warnings}`, and the status bar shows the first of `warnings` as Export As shows an export's notes |
|
||||
|
||||
| `ui.dialog.*` on `importPdf` | `{field: "page" \| "allPages" \| "range" \| "cropTo" \| "password", value}` | opening (`app.open`, `file.open`) a PDF or `.ai` with several pages or a password, or placing one (`file.place` without `page`), opens the Import PDF dialog (`mode`: `open` or `place`; `pageCount`). While `__locked` is true, set `password` and `ui.dialog.confirm` to unlock it (a one-page file then opens or is placed). Then set `allPages: false` and `range` ("2-3, 5") to open some pages, or `page` to place one, and `cropTo` (`bounding`, `art`, `crop`, `trim`, `bleed`, `media`); `ui.dialog.confirm` opens or places them (placing keeps the other `file.place` params, such as `link`, `template` and `at`, in `__place`). `document.open {pages, cropTo, password}` and `file.place {page, crop, password}` do the same without the dialog |
|
||||
|
||||
Reference in New Issue
Block a user