Export: a progress dialog with Cancel for background exports

While an export runs in the background (Background Export), a dialog shows
what is being exported and how far it has got: artboard by artboard for a
raster export of several artboards, busy otherwise. Cancel (also Esc) stops
it and writes no file; Continue in Background leaves it to the status bar.
It opens after 0.4 s and never over another dialog.

Built on the shared vectorcraft_doc::cancel (#2546): fileio::progress::Progress
wraps its CancelToken and a progress sink, so a cancelled export stops
drawing and keeps no half-drawn pattern tile or effect raster.

- ui: background jobs carry their Progress; export_progress draws the
  dialog; UI commands file.cancelExport and file.exportInBackground.
- i18n: the strings in every language with complete menus, Danish, Dutch
  and Indonesian included; "{n} more exports waiting" is a plural (trn).
- docs: ui-parity, gaps (G12) and ROADMAP rows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dt49z1ubK9x1bPq51APgz3
This commit is contained in:
Fabian GrajalesandClaude Opus 5.5 authored and bflatastic committed 2026-10-18 12:40:20 +07:00
1 parent a275496ef4
commit ec410552cf
34 files changed
+560 -15

No files matched your search

+3 -1
View File
@@ -9,7 +9,7 @@
**Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** minor (about 40 community PRs of 2026-10-18: Word .docx placed as area type, CCITT Group 3 TIFF, Roman Hanging Punctuation, blend spines edited with the Anchor Point tool, shadows and glows in stack order, coloured 3D lights, a Dutch catalog completed; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; about 145 community PRs of 2026-10-17: image-decode overflow guards, opaque floating panels, MCP export cancel and progress, editable Illustrator EPS import, scoped `doc_inspect`, Dutch, Danish and Indonesian, Simplified Chinese messages, screen-reader names; headline numbers unchanged; about 160 community PRs of 2026-10-15/16: PDF import crash fixes, Dimension tool, legacy `.ai` save, Intertwine, web pen input, Image Trace fixes, `.ai`/EPS/PDF import fidelity, Bulgarian, Greek, Swedish and Finnish catalogs; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-18 · **Change:** minor (Background Export progress dialog with Cancel, #2564; about 40 community PRs of 2026-10-18: Word .docx placed as area type, CCITT Group 3 TIFF, Roman Hanging Punctuation, blend spines edited with the Anchor Point tool, shadows and glows in stack order, coloured 3D lights, a Dutch catalog completed; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; about 145 community PRs of 2026-10-17: image-decode overflow guards, opaque floating panels, MCP export cancel and progress, editable Illustrator EPS import, scoped `doc_inspect`, Dutch, Danish and Indonesian, Simplified Chinese messages, screen-reader names; headline numbers unchanged; about 160 community PRs of 2026-10-15/16: PDF import crash fixes, Dimension tool, legacy `.ai` save, Intertwine, web pen input, Image Trace fixes, `.ai`/EPS/PDF import fidelity, Bulgarian, Greek, Swedish and Finnish catalogs; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs
on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON
@@ -135,6 +135,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
| Date | What landed |
|---|---|
| 2026-10-18 | About 40 community PRs landed in one batch through the full gate, with our fixes on top. New: Word `.docx` files place as area type with their formatting (#2766), CCITT Group 3 TIFF files open (#2770), Paragraph panel menu › Roman Hanging Punctuation (#2775), the Anchor Point tool edits blend spine points and handles (#2643, fixes #2544), shadows and glows each draw from the art with the effects before them, without the old exponential cost (#2395), one to ten coloured lights in 3D effects (#2706), Artboard Options X and Y with a reference point (#2739), more Contextual Task Bar actions (#2471), Optical Margin Alignment for a whole thread (#2773), History panel Step Backward/Forward and Set History Limit (#2764), Edit › Undo and Redo name the step as the History panel does (#2774), bounding-box handles snap to the grid, pixels and guides (#2715), Ctrl/Cmd+A in the Artboards panel (#2761), Tabs panel menu items (#2742), Import Data Sets defines variables from header cells (#2736), a Linux option to use X11 when a pen is attached (#2717). Fidelity and robustness: variable fonts named by their default weight and fallback glyphs keep bold and italic (#2733, #2732), legacy `.ai` layer names in Windows Latin-1 (#2722), WMF window mapping (#2721), Magic Wand inside isolation (#2720), type values out of range in files are clamped (#2728, #2757), raster effects stay responsive in drags (#2745), exports and Save for Web report undecodable images (#2762, #2737, #2684), Windows-safe exported file names (#2738), a marquee skips a Shaper Group's originals (#2772). Languages: the Dutch catalog completed (#2730). Headline numbers unchanged (estimated). |
| 2026-10-17 | Background Export shows a progress dialog: the file being exported, the artboard count and a bar, Cancel (Esc) and Continue in Background. It runs on the shared cancel token of #2546, so a cancelled export writes no file and keeps no half-drawn pattern tile or effect raster; translated in every language with complete menus (#2564). Headline numbers unchanged. |
| 2026-10-17 | About 145 community PRs landed in six batches, each through the full gate, plus our fixes on top. Crashes and hostile input: an image's RGBA size is checked from its header before decoding, without overflowing, in the renderer, sampling, recoloring and Crop Image (#2442, #2468, #2407), PDF Add Around and huge art are clamped (#2440), graph axis labels past i64, `+` in hex colours and XML ids are handled (#2610, #2470, #2447), Document Raster Effects resolutions open in range (#2579), Batch names stay in their folder (#2504). Regressions: floating panel groups are opaque again while the docked card keeps its rounded corners (#2499), the Wayland pointer returns over panels (#2502). New: MCP cancels long exports, answers while one runs and reports progress (#2546), `doc_inspect` takes ids, kind and paging (#2543), raster export of a page rectangle (#2511), `text.create` returns bounds (#2478), PDF presets and ICC profiles persist (#2547), screen-reader names for widgets (#2611), Expand on Intertwine (#2622, fixes #2540), Duplicate/Copy/Cut of several artboards (#2567), print presets by name (#2607), TSV data sets (#2608), planar TIFF (#2598), Alt-click a swatch onto a gradient stop (#2623), Shift-click ranges in Links, Graphic Styles and Libraries (#2612, #2613, #2618), Space+Shift rotates the view (#2601), Presentation Mode keys (#2583), Small Caps and super/subscript buttons (#2508). Fidelity: editable vector art from Illustrator EPS (#2571), `.ai` Drop Shadow Darkness (#2513), overprint preview with Darken (#2514), Generic CMYK black round-trips (#2503), PNG sRGB chunk (#2519), kerning at a caret (#2518), tab widths in justified area type (#2487), Transform copies keep their own gradients (#2486), smooth Zig Zag (#2475), Live Corners round up to their neighbours (#2484), kerning across style runs (#2554), SVG letter spacing on justified lines (#2574), Dimension tool snapping (#2482), gradient chips (#2495), Transform panel flips and percentages (#2400, #2404). Later the same day: PostScript `.ps` and `.epsf` files open (#2461), EPS images with CCITTFax compression draw (#2445), Illustrator 3 EPS without layers (#2436), `.ai` type opacity and blend modes (#2420), envelope meshes and compound holes in `.ai` (#2410, #2444), CMYK image soft masks in PDF export (#2448), Show Transparency Grid saved with the document (#2488), Save Selection in the Layers panel menu (#2483), Character and Paragraph Reset Panel (#2479, #2438), Cmd/Ctrl+Shift double-click releases a guide (#2467), Shift+Enter keeps a field active (#2431), Shift keeps reshaped handles perpendicular (#2425), emptied type keeps its style (#2464), Smart Blur radius (#2443), freeform gradients recolour (#2397), mesh slivers (#2456), Recolor wheel handles in CMYK (#2454), and six Image Trace fixes (#2387, #2584, #2586–#2589). Fifth batch: Optical Margin Alignment (#2563), Window › Blend panel (#2573), graph column designs (#2406), Live Paint Gap Options (#2424), the SVG Interactivity panel (#2437), RTF placed as area type (#2524), the Touch Type tool (#2469), pattern fills expand into clipped tiles (#2616), Save and Export ask before replacing a file an added extension names (#2619), the Artboard tool's Control bar and Contextual Task Bar (#2559, #2556), Alt-click New Artboard for its options (#2496), Shift-click in Brushes (#2562), the Move dialog remembers the last move (#2542), PDF export uses the document's assigned profiles (#2536), Printer Setup opens the selected printer's preferences on Windows (#2577). Sixth batch: Effect › Artistic › Cutout, Neon Glow and Poster Edges (#2453), View › Rulers › Change to Global / Artboard Rulers (#2416), Symbol Options 9-slice guides (#2512), Create Gradient Mesh on an embedded image (#2538), Rotate View cursors and the Mac trackpad rotation gesture (#2594, #2644), choice parameters as dropdowns in the inline effect editor (#2582), Group Selection picks and moves one path of a compound path (part of #2441), Shift-click ranges in the Artboards panel (#2626), Lock Variables (#2631), a layer dropped under the last row goes to the bottom (#2632), and robustness work: huge selections draw bounded overlays (#2635, #2645, part of #2460), values out of range in presets and files are clamped (#2656), whole-number checks for counts (#2638, #2659), exports warn about overset type (#2628), symbol instances measured by their art (#2614), colour-managed Eyedropper in CMYK documents (#2664). Later: Effect › Rasterize (#2409), variable-font axis sliders in the Character panel (#2710), Image Trace Create Strokes on an exact distance transform with Guo–Hall thinning and a skeleton graph (#2703–#2705), Auto Color keeps rare colours (#2702), large images trace with a warning (#2700), a 1e9 pt input bound on Reshape Segment, Convert Anchor Point and the Pencil (#2709), task-bar Connect, Corner and Smooth for selected anchors (#2697), PDF 0 w strokes import as hairlines (#2696), threading text from theLine truncated
| 2026-10-16 | Symbol Options › Export Type (Graphic or Movie Clip, default Movie Clip) with Registration; `symbol.options` / `symbol.list` (G5).
| 2026-10-15 | Cursors: 36 more tool states get cursors of their own. Node editing follows the public manual (Direct Selection's anchor squares, Reshape Segment, Group Selection's plus, the arrow hollow on a snap, the Alt-copy arrowheads), the Anchor Point caret, the Curvature pen and Free Transform's side-shear arrows are drawn; Lasso, the freehand, symbolism and other tools borrow a drawn cursor until theirs is drawn. `crates/tools/src/cursors.toml` lists every cursor for whoever draws them, and `cargo xtask cursors` warns about one missing from it. Scores unchanged. |
@@ -183,6 +184,7 @@ The full pre-standard record of what landed is kept in [docs/roadmap.md](docs/ro
| 2026-10-17 | minor | Colored Inflate: shared membrane normals and smooth RGB vector ramps replace flat polygon bands; channel groups are batched per solid-fill surface. White-light Inflate retains its original polygons, paint composition and seam joins; the 0.05 seam minimum is restored. Scores and hour estimates unchanged. |
| 2026-10-16 | minor | 3D lighting: one to ten directional lights, a selectable light list, Add Light and Delete Light, independent settings and artboard gestures; ambient applied once and smooth RGB vector export; scores and hour estimates unchanged |
| 2026-10-16 | minor | 3D lighting: opaque RGB Color for the shared directional light, with neutral ambient, preview/reset controls and smooth vector Revolve shading; scores and hour estimates unchanged |
| 2026-10-17 | minor | Progress log row for the Background Export progress dialog (#2564); headline numbers unchanged. |
| 2026-10-14 | minor | G11: open-path anchor Delete removes adjoining segments without bridging the gap; explicit Remove Anchors keeps its reconnect/refit behavior. Scores and hours unchanged. |
| 2026-10-14 | minor | Document fonts register every explicitly supplied craft-fonts family after the existing Japanese, Arabic and Thai prefix; optional empty input remains supported. Headline scores and estimates are unchanged. |
| 2026-10-14 | minor | Progress log rows for the later merges of 2026-10-14 (#1630–#1875 as listed there); headline numbers unchanged. |
+1
View File
@@ -40,6 +40,7 @@ pub mod pdf;
mod pdfimport;
pub mod pngtext;
pub mod ppi;
pub mod progress;
pub mod psdread;
mod save;
mod screens;
+82
View File
@@ -0,0 +1,82 @@
//! Progress and Cancel of an export running off the UI thread (Background Export), on the shared
//! [`vectorcraft_doc::cancel`] mechanism.
//!
//! The frontend makes a [`Progress`], runs the export inside [`scope`] on its worker and reads the
//! counts from the UI thread to draw them; its Cancel button calls [`Progress::cancel`]. Inside the
//! scope the encoders that work in steps (raster formats: one artboard at a time) report each step
//! through [`vectorcraft_doc::cancel::progress`] and stop at the next check once cancelled; the
//! renderer stops drawing and keeps no half-drawn pattern tile or effect raster. Encoders that
//! make one file in one go report nothing: the frontend shows them as busy and checks
//! [`Progress::cancelled`] itself before writing, so a cancelled export never writes a file.
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use vectorcraft_doc::cancel::{self, CancelToken, ProgressSink};
/// How far an export has got, shared between the worker and the UI thread.
#[derive(Debug, Default)]
pub struct Progress {
token: CancelToken,
done: AtomicU64,
total: AtomicU64,
}
impl Progress {
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
/// `(steps done, steps in all)`; `total` is 0 while the export can't say (one file made in one go).
pub fn counts(&self) -> (u64, u64) {
let total = self.total.load(Ordering::Relaxed);
(self.done.load(Ordering::Relaxed).min(total), total)
}
/// The share of the export done, 0 to 1; `None` while the export can't say.
pub fn fraction(&self) -> Option<f64> {
let (done, total) = self.counts();
(total > 0).then(|| done as f64 / total as f64)
}
/// Ask the export to stop: it writes nothing more, and a render under way stops drawing.
pub fn cancel(&self) {
self.token.cancel();
}
pub fn cancelled(&self) -> bool {
self.token.is_cancelled()
}
}
/// Run `f` with `progress`'s token in effect on this thread and the steps reported to it.
pub fn scope<R>(progress: &Arc<Progress>, f: impl FnOnce() -> R) -> R {
let to = Arc::clone(progress);
let sink: ProgressSink = Rc::new(move |done, total, _| {
to.total.store(total, Ordering::Relaxed);
to.done.store(done, Ordering::Relaxed);
});
cancel::scope(&progress.token, Some(sink), f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_raster_export_counts_its_artboards_and_stops_once_cancelled() {
let mut doc = vectorcraft_doc::Document::new(100.0, 100.0);
let second = doc.artboards[0].clone();
doc.artboards.push(second);
let p = Progress::new();
assert_eq!(p.fraction(), None, "nothing reported yet");
let png = scope(&p, || super::super::encode_all(&doc, "png", &serde_json::json!({"useArtboards": true})));
assert!(png.is_ok(), "{:?}", png.err());
assert_eq!(p.counts(), (1, 2), "the step under way when the last artboard started");
p.cancel();
let r = scope(&p, || super::super::encode_all(&doc, "png", &serde_json::json!({"useArtboards": true})));
assert!(matches!(r, Err(crate::EngineError::Cancelled)), "{:?}", r.err());
assert!(!cancel::is_cancelled(), "the scope ended");
}
}
+52 -1
View File
@@ -6,9 +6,11 @@
//! It needs a thread-safe writer from the host ([`crate::Services::write_shared`], desktop);
//! without one (the web, which downloads) the work runs at once, as with the preference off.
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
use serde_json::{Value, json};
use vectorcraft_engine::cmd::fileio::progress::Progress;
use vectorcraft_engine::file_access::ScopeHandle;
use crate::VectorcraftApp;
@@ -50,9 +52,24 @@ pub struct Job {
pub label: String,
/// The document the job reads (`DocState::uid`), if any.
pub doc: Option<u64>,
/// How far an export has got, and its Cancel ([`crate::export_progress`] shows it).
pub progress: Option<Arc<Progress>>,
/// Continue in Background: the progress dialog no longer shows this job.
pub hidden: bool,
then: Then,
}
impl Job {
pub fn id(&self) -> u64 {
self.id
}
/// Was the job cancelled (it writes nothing more; its result is still on its way)?
pub fn cancelled(&self) -> bool {
self.progress.as_ref().is_some_and(|p| p.cancelled())
}
}
/// The worker and the jobs it has not finished.
#[derive(Default)]
pub struct Background {
@@ -93,6 +110,26 @@ impl Background {
pub fn busy_with(&self, uid: u64) -> bool {
self.jobs.iter().any(|j| j.doc == Some(uid))
}
/// Cancel every export in progress → how many there were.
pub fn cancel_exports(&mut self) -> usize {
let mut n = 0;
for p in self.jobs.iter().filter(|j| !j.cancelled()).filter_map(|j| j.progress.as_ref()) {
p.cancel();
n += 1;
}
n
}
/// Hide the exports in progress from the progress dialog (they go on) → how many there were.
pub fn hide_exports(&mut self) -> usize {
let mut n = 0;
for j in self.jobs.iter_mut().filter(|j| j.progress.is_some() && !j.hidden && !j.cancelled()) {
j.hidden = true;
n += 1;
}
n
}
}
/// Run `work` on a worker thread when `enabled` and the host can write from one, else now; `then`
@@ -106,6 +143,20 @@ pub fn run(
doc: Option<u64>,
work: impl FnOnce(Writer) -> Result<Value, String> + Send + 'static,
then: impl FnOnce(&mut VectorcraftApp, Result<Value, String>) -> Result<Value, String> + 'static,
) -> Result<Value, String> {
run_with_progress(app, enabled, label, doc, None, work, then)
}
/// [`run`] for work that reports to `progress` (an export): the progress dialog shows it while it
/// runs in the background, with Cancel.
pub fn run_with_progress(
app: &mut VectorcraftApp,
enabled: bool,
label: String,
doc: Option<u64>,
progress: Option<Arc<Progress>>,
work: impl FnOnce(Writer) -> Result<Value, String> + Send + 'static,
then: impl FnOnce(&mut VectorcraftApp, Result<Value, String>) -> Result<Value, String> + 'static,
) -> Result<Value, String> {
let mut work: Work = Box::new(work);
let shared = app.services.write_shared.clone().filter(|_| enabled && app.services.download.is_none());
@@ -116,7 +167,7 @@ pub fn run(
Ok(()) => {
let bg = &mut app.background;
bg.next_id += 1;
bg.jobs.push(Job { id, label: label.clone(), doc, then: Box::new(then) });
bg.jobs.push(Job { id, label: label.clone(), doc, progress, hidden: false, then: Box::new(then) });
if label.is_empty() {
return Ok(json!({ "background": true }));
}
+1 -1
View File
@@ -739,7 +739,7 @@ pub fn status_bar(app: &mut VectorcraftApp, ui: &mut Ui) {
.background
.jobs
.iter()
.filter(|j| !j.label.is_empty())
.filter(|j| !j.label.is_empty() && !j.cancelled())
.map(|j| j.label.as_str())
.chain(app.opening.pending.iter().map(|p| p.label.as_str()))
.collect();
+196
View File
@@ -0,0 +1,196 @@
//! The export progress dialog: while an export runs in the background (Background Export) a modal
//! window shows what is being exported, how far it has got (artboard by artboard for raster
//! exports of several artboards; busy for one artboard and for formats made in one go, which
//! report no steps) and two buttons: Cancel (`file.cancelExport`, also
//! Esc) stops it and writes nothing, Continue in Background (`file.exportInBackground`) closes the
//! dialog and leaves the export to the status bar.
//!
//! It opens after [`DELAY`] so a quick export doesn't flash it, and waits while another dialog is
//! open (the overwrite question, an options dialog): never two modals at once.
use serde_json::json;
use crate::dialogs::modal;
use crate::theme::Tokens;
use crate::{VectorcraftApp, widgets};
/// Seconds an export runs before the dialog opens.
pub const DELAY: f64 = 0.4;
/// Where the job a frame first saw is remembered (its id, the time it was first seen).
fn seen_id() -> egui::Id {
egui::Id::new("export-progress-seen")
}
/// What the dialog shows: (label, steps done, steps in all, share done, exports after this one).
fn shown(app: &VectorcraftApp, now: f64, ctx: &egui::Context) -> Option<(String, u64, u64, f32, usize)> {
let jobs: Vec<_> = app.background.jobs.iter().filter(|j| !j.hidden && !j.cancelled()).filter(|j| j.progress.is_some()).collect();
let first = jobs.first()?;
let since = ctx.data_mut(|m| {
let seen = m.get_temp_mut_or_insert_with(seen_id(), || (first.id(), now));
if seen.0 != first.id() {
*seen = (first.id(), now);
}
seen.1
});
if now - since < DELAY {
return None;
}
let (done, total) = first.progress.as_ref().map(|p| p.counts()).unwrap_or_default();
let frac = first.progress.as_ref().and_then(|p| p.fraction()).unwrap_or(0.0) as f32;
Some((first.label.clone(), done, total, frac, jobs.len() - 1))
}
pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
let now = ctx.input(|i| i.time);
let Some((label, done, total, frac, more)) = shown(app, now, ctx) else { return };
if app.ui.dialog.is_some() {
return;
}
let t = Tokens::get(ctx);
let heading = format!("{}…", crate::i18n::msg(&label));
let mut action = None;
modal::show(ctx, &heading, egui::Id::new("export-progress"), -40.0, 20, |ui| {
ui.set_width(360.0);
modal::heading(ui, &heading);
ui.add_space(12.0);
// One step says nothing a spinner doesn't: the bar would sit at 0 % until the file is written.
if total > 1 {
let step = crate::i18n::fmt(tl!("Artboard {n} of {total}"), &[("n", &(done + 1).min(total).to_string()), ("total", &total.to_string())]);
// The count on its own line: drawn over the bar it would straddle the fill's edge.
ui.horizontal(|ui| {
ui.label(egui::RichText::new(step).color(t.text_dim));
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.label(egui::RichText::new(format!("{:.0} %", frac * 100.0)).color(t.text_dim));
});
});
ui.add_space(4.0);
ui.add(egui::ProgressBar::new(frac).desired_width(360.0).desired_height(6.0).fill(t.accent));
} else {
ui.horizontal(|ui| {
ui.add(egui::Spinner::new().size(14.0).color(t.accent));
ui.label(egui::RichText::new(tl!("Encoding and writing the file…")).color(t.text_dim));
});
}
if more > 0 {
ui.add_space(6.0);
let queued = crate::i18n::tn(more as u64, "{n} more export waiting", "{n} more exports waiting");
ui.label(egui::RichText::new(queued).size(11.5).color(t.text_dim));
}
ui.add_space(16.0);
let row = egui::vec2(ui.min_rect().width(), ui.spacing().interact_size.y);
ui.allocate_ui_with_layout(row, egui::Layout::right_to_left(egui::Align::Center), |ui| {
if widgets::secondary_button(ui, "Cancel").clicked() {
action = Some("file.cancelExport");
}
ui.add_space(8.0);
if widgets::secondary_button(ui, "Continue in Background").clicked() {
action = Some("file.exportInBackground");
}
});
});
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
action = Some("file.cancelExport");
}
if let Some(id) = action
&& let Err(e) = app.run(id, json!({}))
{
app.status(e);
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use serde_json::json;
use vectorcraft_engine::Session;
use vectorcraft_engine::cmd::fileio::progress::Progress;
use crate::{Services, VectorcraftApp, background};
/// An app whose background writer waits until `go` is set.
fn app(go: Arc<std::sync::atomic::AtomicBool>) -> VectorcraftApp {
let services = Services {
write_shared: Some(Arc::new(move |_: &str, _: &[u8]| {
while !go.load(std::sync::atomic::Ordering::SeqCst) {
std::thread::sleep(std::time::Duration::from_millis(1));
}
Ok(())
})),
..Default::default()
};
VectorcraftApp::new(Session::new(), services)
}
/// Draws one frame of the dialog at `time` seconds → the texts it drew.
fn frame(app: &mut VectorcraftApp, ctx: &egui::Context, time: f64) -> String {
let mut out = ctx.run_ui(egui::RawInput { time: Some(time), ..Default::default() }, |ui| super::show(app, ui.ctx()));
out.textures_delta.clear();
let mut texts = String::new();
for shape in out.shapes {
if let egui::epaint::Shape::Text(t) = shape.shape {
texts.push_str(t.galley.text());
texts.push('\n');
}
}
texts
}
#[test]
fn opens_after_the_delay_and_cancel_closes_it() {
let go = Arc::new(std::sync::atomic::AtomicBool::new(false));
let mut app = app(go.clone());
let p = Progress::new();
let r = background::run_with_progress(
&mut app,
true,
"Exporting a.png".into(),
None,
Some(p.clone()),
|w| w("/a.png", b"x").map(|()| json!({})),
|_, r| r,
);
assert_eq!(r.unwrap()["background"], true);
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
assert!(!frame(&mut app, &ctx, 0.0).contains("Exporting a.png"), "not before the delay");
frame(&mut app, &ctx, 1.0); // a new window measures itself unseen first
let shown = frame(&mut app, &ctx, 1.1);
assert!(shown.contains("Exporting a.png") && shown.contains("Cancel") && shown.contains("Continue in Background"), "{shown}");
app.run("file.cancelExport", json!({})).unwrap();
assert!(p.cancelled());
assert_eq!(app.ui.status, crate::io::EXPORT_CANCELLED);
assert!(!frame(&mut app, &ctx, 2.0).contains("Exporting a.png"), "a cancelled export isn't shown");
go.store(true, std::sync::atomic::Ordering::SeqCst);
background::wait_all(&mut app);
}
#[test]
fn continue_in_background_hides_it_and_the_export_goes_on() {
let go = Arc::new(std::sync::atomic::AtomicBool::new(false));
let mut app = app(go.clone());
let p = Progress::new();
background::run_with_progress(
&mut app,
true,
"Exporting b.png".into(),
None,
Some(p.clone()),
|w| w("/b.png", b"x").map(|()| json!({})),
|_, r| r,
)
.unwrap();
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
frame(&mut app, &ctx, 0.0);
frame(&mut app, &ctx, 1.0);
assert!(frame(&mut app, &ctx, 1.1).contains("Exporting b.png"));
assert_eq!(app.run("file.exportInBackground", json!({})).unwrap()["hidden"], 1);
assert!(!frame(&mut app, &ctx, 2.0).contains("Exporting b.png"));
assert!(!p.cancelled());
go.store(true, std::sync::atomic::Ordering::SeqCst);
background::wait_all(&mut app);
assert!(app.background.jobs.is_empty());
}
}
+6
View File
@@ -5153,6 +5153,12 @@ theme Appearance Външен вид
Enable Guides for 9-Slice Scaling Включване на водачи за 9-slice мащабиране
Persistent Постоянна
Library Panel Options Опции на панела с библиотека
Artboard {n} of {total} Работна област {n} от {total}
Encoding and writing the file… Кодиране и записване на файла…
@plural {n} more export waiting|{n} more exports waiting Още {n} експортиране в изчакване|Още {n} експортирания в изчакване
Continue in Background Продължаване във фонов режим
Cancel Export Отказ от експортирането
@msg Export cancelled Експортирането е отказано
# Paragraph panel menu › Justification…
Desired Желано
Word Spacing: Разстояние между думите:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5188,6 +5188,12 @@ mark-style Japanese Japonské
@msg too many library panels were opened in this session v této relaci bylo otevřeno příliš mnoho panelů knihoven
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Obraz má {_1} × {_2} pixelů, na jedné straně více než {LARGE_TRACE_SIDE}: vektorizuje se, ale pomaleji. Rychleji se vektorizuje s předvolbou nižší věrnosti nebo menší kopie obrazu.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Obraz byl vektorizován v rozlišení {_1} × {_2} pixelů, zmenšený z {_3} × {_4} (nejvýše {_5} megapixelů).
Artboard {n} of {total} Pracovní plocha {n} z {total}
Encoding and writing the file… Kódování a zápis souboru…
@plural {n} more export waiting|{n} more exports waiting Čeká ještě {n} export|Čekají ještě {n} exporty|Čeká ještě {n} exportů
Continue in Background Pokračovat na pozadí
Cancel Export Zrušit export
@msg Export cancelled Export byl zrušen
# Paragraph panel menu › Justification…
Desired Požadované
Word Spacing: Mezery mezi slovy:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5172,6 +5172,12 @@ swatch Bright Violet Kraftig violet
Typing Indtastning
Persistent Vedvarende
Library Panel Options Indstillinger for bibliotekspanel
Artboard {n} of {total} Tegneflade {n} af {total}
Encoding and writing the file… Koder og skriver filen…
@plural {n} more export waiting|{n} more exports waiting {n} eksport mere venter|{n} eksporter mere venter
Continue in Background Fortsæt i baggrunden
Cancel Export Annullér eksport
@msg Export cancelled Eksport annulleret
# Paragraph panel menu › Justification…
Desired Ønsket
Word Spacing: Ordafstand:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -4763,6 +4763,12 @@ effect Regular Regelmäßig
@msg too many library panels were opened in this session in dieser Sitzung wurden zu viele Bibliotheksbedienfelder geöffnet
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Das Bild hat {_1} × {_2} Pixel, mehr als {LARGE_TRACE_SIDE} auf einer Seite: Es wird nachgezeichnet, aber langsamer. Eine Vorgabe mit geringerer Detailtreue oder eine kleinere Kopie des Bildes geht schneller.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Das Bild wurde mit {_1} × {_2} Pixeln nachgezeichnet, verkleinert von {_3} × {_4} (höchstens {_5} Megapixel).
Artboard {n} of {total} Zeichenfläche {n} von {total}
Encoding and writing the file… Datei wird codiert und geschrieben…
@plural {n} more export waiting|{n} more exports waiting {n} weiterer Export wartet|{n} weitere Exporte warten
Continue in Background Im Hintergrund fortsetzen
Cancel Export Export abbrechen
@msg Export cancelled Export abgebrochen
# Paragraph panel menu › Justification…
Desired Optimal
Word Spacing: Wortabstand:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5140,6 +5140,12 @@ effect Points Σημεία
@msg too many library panels were opened in this session άνοιξαν πάρα πολλοί πίνακες βιβλιοθηκών σε αυτή τη συνεδρία
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Η εικόνα είναι {_1} × {_2} εικονοστοιχεία, πάνω από {LARGE_TRACE_SIDE} σε μία πλευρά: ανιχνεύεται, αλλά πιο αργά. Μια προρύθμιση χαμηλότερης πιστότητας ή ένα μικρότερο αντίγραφο της εικόνας ανιχνεύεται γρηγορότερα.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Η εικόνα ανιχνεύτηκε σε {_1} × {_2} εικονοστοιχεία, σμικρυμένη από {_3} × {_4} (το πολύ {_5} megapixel).
Artboard {n} of {total} Πίνακας σχεδίασης {n} από {total}
Encoding and writing the file… Κωδικοποίηση και εγγραφή του αρχείου…
@plural {n} more export waiting|{n} more exports waiting {n} ακόμη εξαγωγή σε αναμονή|{n} ακόμη εξαγωγές σε αναμονή
Continue in Background Συνέχεια στο παρασκήνιο
Cancel Export Ακύρωση εξαγωγής
@msg Export cancelled Η εξαγωγή ακυρώθηκε
# Paragraph panel menu › Justification…
Desired Επιθυμητό
Word Spacing: Απόσταση λέξεων:
Can't render this file because it contains an unexpected character in line 2006 and column 19.
+6
View File
@@ -5130,6 +5130,12 @@ mark-style Japanese Japonesas
@msg too many library panels were opened in this session se abrieron demasiados paneles de biblioteca en esta sesión
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. La imagen tiene {_1} × {_2} píxeles, más de {LARGE_TRACE_SIDE} en un lado: se calcará, pero más despacio. Un ajuste preestablecido de menor fidelidad o una copia más pequeña de la imagen se calcan más rápido.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). La imagen se calcó a {_1} × {_2} píxeles, reducida desde {_3} × {_4} ({_5} megapíxeles como máximo).
Artboard {n} of {total} Mesa de trabajo {n} de {total}
Encoding and writing the file… Codificando y escribiendo el archivo…
@plural {n} more export waiting|{n} more exports waiting {n} exportación más en espera|{n} exportaciones más en espera
Continue in Background Continuar en segundo plano
Cancel Export Cancelar exportación
@msg Export cancelled Exportación cancelada
# Paragraph panel menu › Justification…
Desired Deseado
Word Spacing: Espaciado entre palabras:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5152,6 +5152,12 @@ mark-style Japanese Japanilainen
@msg too many library panels were opened in this session tässä istunnossa on avattu liian monta kirjastopaneelia
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Kuva on {_1} × {_2} kuvapistettä, yhdeltä sivultaan yli {LARGE_TRACE_SIDE}: se jäljitetään, mutta hitaammin. Pienemmän tarkkuuden esiasetus tai kuvan pienempi kopio jäljittyy nopeammin.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Kuva jäljitettiin kokoon {_1} × {_2} kuvapistettä pienennettynä koosta {_3} × {_4} (enintään {_5} megapikseliä).
Artboard {n} of {total} Piirtoalusta {n}/{total}
Encoding and writing the file… Tiedostoa koodataan ja kirjoitetaan…
@plural {n} more export waiting|{n} more exports waiting {n} vienti odottaa|{n} vientiä odottaa
Continue in Background Jatka taustalla
Cancel Export Peruuta vienti
@msg Export cancelled Vienti peruutettiin
# Paragraph panel menu › Justification…
Desired Haluttu
Word Spacing: Sanaväli:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5187,6 +5187,12 @@ theme Appearance Apparence
@msg too many library panels were opened in this session trop de panneaux de bibliothèque ont été ouverts dans cette session
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. L’image fait {_1} × {_2} pixels, plus de {LARGE_TRACE_SIDE} sur un côté : elle est vectorisée, mais plus lentement. Un paramètre prédéfini moins fidèle ou une copie plus petite de l’image se vectorise plus vite.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). L’image a été vectorisée à {_1} × {_2} pixels, réduite de {_3} × {_4} ({_5} mégapixels au plus).
Artboard {n} of {total} Plan de travail {n} sur {total}
Encoding and writing the file… Encodage et écriture du fichier…
@plural {n} more export waiting|{n} more exports waiting {n} autre exportation en attente|{n} autres exportations en attente
Continue in Background Continuer en arrière-plan
Cancel Export Annuler l’exportation
@msg Export cancelled Exportation annulée
# Paragraph panel menu › Justification…
Desired Optimal
Word Spacing: Espacement des mots :
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5174,6 +5174,12 @@ imageTrace Outline Körvonal
@msg too many library panels were opened in this session ebben a munkamenetben túl sok könyvtárpanel nyílt meg
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. A kép {_1} × {_2} képpont, egyik oldalán több mint {LARGE_TRACE_SIDE}: a vektorizálás megtörténik, de lassabban. Kisebb hűségű előbeállítással vagy a kép kisebb másolatával gyorsabb.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). A kép vektorizálása {_1} × {_2} képponton történt, {_3} × {_4} méretről kicsinyítve (legfeljebb {_5} megapixel).
Artboard {n} of {total} Rajztábla: {n} / {total}
Encoding and writing the file… A fájl kódolása és írása…
@plural {n} more export waiting|{n} more exports waiting Még {n} exportálás várakozik
Continue in Background Folytatás a háttérben
Cancel Export Exportálás megszakítása
@msg Export cancelled Az exportálás megszakítva
# Paragraph panel menu › Justification…
Desired Kívánt
Word Spacing: Szóköz:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5172,6 +5172,12 @@ swatch Bright Violet Violet cerah
Typing Mengetik
Persistent Persisten
Library Panel Options Opsi panel pustaka
Artboard {n} of {total} Artboard {n} dari {total}
Encoding and writing the file… Mengodekan dan menulis berkas…
@plural {n} more export waiting|{n} more exports waiting {n} ekspor lagi menunggu
Continue in Background Lanjutkan di latar belakang
Cancel Export Batalkan ekspor
@msg Export cancelled Ekspor dibatalkan
# Paragraph panel menu › Justification…
Desired Diinginkan
Word Spacing: Spasi Kata:
Can't render this file because it contains an unexpected character in line 3768 and column 19.
+6
View File
@@ -4801,6 +4801,12 @@ lighting Light Luce
@msg too many library panels were opened in this session in questa sessione sono stati aperti troppi pannelli libreria
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. L’immagine è di {_1} × {_2} pixel, più di {LARGE_TRACE_SIDE} su un lato: viene vettorializzata, ma più lentamente. Un predefinito a fedeltà più bassa o una copia più piccola dell’immagine è più veloce.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). L’immagine è stata vettorializzata a {_1} × {_2} pixel, ridotta da {_3} × {_4} (al massimo {_5} megapixel).
Artboard {n} of {total} Tavola da disegno {n} di {total}
Encoding and writing the file… Codifica e scrittura del file…
@plural {n} more export waiting|{n} more exports waiting {n} altra esportazione in attesa|{n} altre esportazioni in attesa
Continue in Background Continua in background
Cancel Export Annulla esportazione
@msg Export cancelled Esportazione annullata
# Paragraph panel menu › Justification…
Desired Desiderato
Word Spacing: Spaziatura parole:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -4841,6 +4841,12 @@ lighting Light ライト
@msg too many library panels were opened in this session このセッションで開いたライブラリパネルが多すぎます
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 画像は {_1} × {_2} ピクセルで、一辺が {LARGE_TRACE_SIDE} を超えています。トレースはできますが、時間がかかります。忠実度の低いプリセットや画像の小さいコピーを使うと速くなります。
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 画像は {_3} × {_4} から縮小した {_1} × {_2} ピクセルでトレースされました (最大 {_5} メガピクセル)。
Artboard {n} of {total} アートボード {n} / {total}
Encoding and writing the file… ファイルをエンコードして書き込み中…
@plural {n} more export waiting|{n} more exports waiting 待機中の書き出し: あと {n} 件
Continue in Background バックグラウンドで続行
Cancel Export 書き出しをキャンセル
@msg Export cancelled 書き出しをキャンセルしました
# Paragraph panel menu › Justification…
Desired 最適
Word Spacing: 単語間隔:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -4764,6 +4764,12 @@ lighting Light 광원
@msg too many library panels were opened in this session 이 세션에서 라이브러리 패널을 너무 많이 열었습니다
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 이미지가 {_1} × {_2}픽셀로 한 변이 {LARGE_TRACE_SIDE}을 넘습니다. 추적은 되지만 더 느립니다. 충실도가 낮은 사전 설정이나 이미지의 작은 사본을 사용하면 더 빠릅니다.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 이미지를 {_3} × {_4}에서 축소한 {_1} × {_2}픽셀로 추적했습니다(최대 {_5}메가픽셀).
Artboard {n} of {total} 아트보드 {n} / {total}
Encoding and writing the file… 파일을 인코딩하고 쓰는 중…
@plural {n} more export waiting|{n} more exports waiting 대기 중인 내보내기 {n}개 더
Continue in Background 백그라운드에서 계속
Cancel Export 내보내기 취소
@msg Export cancelled 내보내기를 취소했습니다
# Paragraph panel menu › Justification…
Desired 희망
Word Spacing: 단어 간격:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6 -1
View File
@@ -5215,7 +5215,12 @@ swatch Bright Violet Felviolet
@msg too many library panels were opened in this session er zijn in deze sessie te veel bibliotheekpanelen geopend
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. De afbeelding is {_1} × {_2} pixels, meer dan {LARGE_TRACE_SIDE} aan één zijde: ze wordt getraceerd, maar langzamer. Een voorinstelling met minder detail of een kleinere kopie van de afbeelding traceert sneller.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). De afbeelding is getraceerd op {_1} × {_2} pixels, verkleind van {_3} × {_4} (maximaal {_5} megapixels).
Artboard {n} of {total} Tekengebied {n} van {total}
Encoding and writing the file… Bestand coderen en schrijven…
@plural {n} more export waiting|{n} more exports waiting Nog {n} export in de wachtrij|Nog {n} exports in de wachtrij
Continue in Background Doorgaan op achtergrond
Cancel Export Export annuleren
@msg Export cancelled Export geannuleerd
# Paragraph panel menu › Justification…
Desired Gewenst
Word Spacing: Woordafstand:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5040,6 +5040,12 @@ mark-style Japanese Japońskie
@msg too many library panels were opened in this session w tej sesji otwarto zbyt wiele paneli bibliotek
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Obraz ma {_1} × {_2} pikseli, ponad {LARGE_TRACE_SIDE} na jednym boku: zostanie obrysowany, ale wolniej. Ustawienie wstępne o niższej wierności lub mniejsza kopia obrazu obrysuje się szybciej.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Obraz obrysowano w rozdzielczości {_1} × {_2} pikseli, po zmniejszeniu z {_3} × {_4} (najwyżej {_5} megapikseli).
Artboard {n} of {total} Obszar kompozycji {n} z {total}
Encoding and writing the file… Kodowanie i zapisywanie pliku…
@plural {n} more export waiting|{n} more exports waiting Czeka jeszcze {n} eksport|Czekają jeszcze {n} eksporty|Czeka jeszcze {n} eksportów
Continue in Background Kontynuuj w tle
Cancel Export Anuluj eksport
@msg Export cancelled Eksport anulowany
# Paragraph panel menu › Justification…
Desired Optymalne
Word Spacing: Odstępy między wyrazami:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5105,6 +5105,12 @@ mark-style Japanese Japonesas
@msg too many library panels were opened in this session foram abertos painéis de biblioteca demais nesta sessão
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. A imagem tem {_1} × {_2} pixels, mais de {LARGE_TRACE_SIDE} em um lado: ela é traçada, mas mais devagar. Uma predefinição de menor fidelidade ou uma cópia menor da imagem traça mais rápido.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). A imagem foi traçada em {_1} × {_2} pixels, reduzida de {_3} × {_4} (no máximo {_5} megapixels).
Artboard {n} of {total} Mesa de Trabalho {n} de {total}
Encoding and writing the file… Codificando e gravando o arquivo…
@plural {n} more export waiting|{n} more exports waiting Mais {n} exportação aguardando|Mais {n} exportações aguardando
Continue in Background Continuar em Segundo Plano
Cancel Export Cancelar Exportação
@msg Export cancelled Exportação cancelada
# Paragraph panel menu › Justification…
Desired Desejado
Word Spacing: Espaçamento entre Palavras:
Can't render this file because it contains an unexpected character in line 6 and column 47.
+6
View File
@@ -4797,6 +4797,12 @@ lighting Light Свет
@msg too many library panels were opened in this session в этом сеансе открыто слишком много панелей библиотек
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Изображение {_1} × {_2} пикселей, больше {LARGE_TRACE_SIDE} по одной стороне: трассировка выполняется, но медленнее. Стиль с меньшей точностью или уменьшенная копия изображения трассируются быстрее.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Изображение трассировано в размере {_1} × {_2} пикселей, уменьшенное с {_3} × {_4} (не более {_5} мегапикселей).
Artboard {n} of {total} Монтажная область {n} из {total}
Encoding and writing the file… Кодирование и запись файла…
@plural {n} more export waiting|{n} more exports waiting Ещё {n} экспорт в очереди|Ещё {n} экспорта в очереди|Ещё {n} экспортов в очереди
Continue in Background Продолжить в фоне
Cancel Export Отменить экспорт
@msg Export cancelled Экспорт отменён
# Paragraph panel menu › Justification…
Desired Желательно
Word Spacing: Интервал между словами:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -5144,6 +5144,12 @@ theme Appearance Utseende
@msg too many library panels were opened in this session för många bibliotekspaneler har öppnats i den här sessionen
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Bilden är {_1} × {_2} pixlar, mer än {LARGE_TRACE_SIDE} på en sida: den vektoriseras, men långsammare. En förinställning med lägre återgivning eller en mindre kopia av bilden går snabbare.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Bilden vektoriserades vid {_1} × {_2} pixlar, nedskalad från {_3} × {_4} (högst {_5} megapixlar).
Artboard {n} of {total} Rityta {n} av {total}
Encoding and writing the file… Kodar och skriver filen…
@plural {n} more export waiting|{n} more exports waiting {n} export till väntar|{n} exporter till väntar
Continue in Background Fortsätt i bakgrunden
Cancel Export Avbryt export
@msg Export cancelled Exporten avbröts
# Paragraph panel menu › Justification…
Desired Önskat
Word Spacing: Ordavstånd:
Can't render this file because it contains an unexpected character in line 5 and column 25.
+6
View File
@@ -4781,6 +4781,12 @@ lighting Light Світло
@msg too many library panels were opened in this session у цьому сеансі відкрито забагато панелей бібліотек
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Зображення {_1} × {_2} пікселів, понад {LARGE_TRACE_SIDE} з одного боку: трасування виконується, але повільніше. Стиль із нижчою точністю або менша копія зображення трасуються швидше.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Зображення трасовано в розмірі {_1} × {_2} пікселів, зменшене з {_3} × {_4} (щонайбільше {_5} мегапікселів).
Artboard {n} of {total} Монтажна область {n} з {total}
Encoding and writing the file… Кодування та запис файлу…
@plural {n} more export waiting|{n} more exports waiting Ще {n} експорт в очікуванні|Ще {n} експорти в очікуванні|Ще {n} експортів в очікуванні
Continue in Background Продовжити у фоні
Cancel Export Скасувати експорт
@msg Export cancelled Експорт скасовано
# Paragraph panel menu › Justification…
Desired Бажане
Word Spacing: Інтервал між словами:
Can't render this file because it contains an unexpected character in line 725 and column 40.
+6
View File
@@ -4781,6 +4781,12 @@ theme Appearance Giao diện
@msg too many library panels were opened in this session đã mở quá nhiều bảng thư viện trong phiên này
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Ảnh có kích thước {_1} × {_2} điểm ảnh, hơn {LARGE_TRACE_SIDE} ở một cạnh: ảnh vẫn được dò, nhưng chậm hơn. Một thiết lập sẵn có độ trung thực thấp hơn hoặc một bản sao nhỏ hơn của ảnh sẽ dò nhanh hơn.
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Ảnh đã được dò ở {_1} × {_2} điểm ảnh, thu nhỏ từ {_3} × {_4} (tối đa {_5} megapixel).
Artboard {n} of {total} Bảng vẽ {n} / {total}
Encoding and writing the file… Đang mã hóa và ghi tệp…
@plural {n} more export waiting|{n} more exports waiting Còn {n} lượt xuất đang chờ
Continue in Background Tiếp tục trong nền
Cancel Export Hủy xuất
@msg Export cancelled Đã hủy xuất
# Paragraph panel menu › Justification…
Desired Mong muốn
Word Spacing: Khoảng cách từ:
Can't render this file because it contains an unexpected character in line 3948 and column 10.
+6 -1
View File
@@ -5023,7 +5023,12 @@ lighting Light 光源
@msg only http, https and mailto URLs open in the browser, not “{url}” 浏览器中只会打开 http、https 和 mailto 的 URL,不会打开 “{url}”
@msg {id} opens another app: only the person at the keyboard can run it {id} 会打开其他应用程序:只有使用键盘的人才能运行它
@msg “{name}” is not a file “{name}” 不是文件
Artboard {n} of {total} 画板 {n} / {total}
Encoding and writing the file… 正在编码并写入文件…
@plural {n} more export waiting|{n} more exports waiting 另有 {n} 个导出等待中
Continue in Background 在后台继续
Cancel Export 取消导出
@msg Export cancelled 已取消导出
# Paragraph panel menu › Justification…
Desired 所需
Word Spacing: 字间距:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+6
View File
@@ -4077,6 +4077,12 @@ lighting Light 光源
Enable Guides for 9-Slice Scaling 啟用 9-slice 縮放參考線
Persistent 持久
Library Panel Options 資料庫面板選項
Artboard {n} of {total} 工作區域 {n} / {total}
Encoding and writing the file… 正在編碼並寫入檔案…
@plural {n} more export waiting|{n} more exports waiting 另有 {n} 個匯出等待中
Continue in Background 在背景繼續
Cancel Export 取消匯出
@msg Export cancelled 已取消匯出
# Paragraph panel menu › Justification…
Desired 所需
Word Spacing: 字間距:
Can't render this file because it contains an unexpected character in line 6 and column 47.
+42 -8
View File
@@ -3,7 +3,9 @@
use serde_json::{Value, json};
use vectorcraft_doc::SavedView;
use vectorcraft_doc::cancel;
use vectorcraft_engine::EngineError;
use vectorcraft_engine::cmd::fileio::progress::{self, Progress};
use vectorcraft_engine::cmd::fileio::{self, Format, SAVE_FORMATS, SaveMode, SavePlan, TEMPLATE_FORMATS};
use crate::background::{self, Writer};
@@ -675,6 +677,25 @@ pub fn recent_files(app: &VectorcraftApp) -> &[String] {
&r[..r.len().min(app.session.prefs.recent_files_count as usize)]
}
/// The status once an export was cancelled.
pub const EXPORT_CANCELLED: &str = "Export cancelled";
/// File → Cancel Export (the progress dialog's Cancel): every export running in the background
/// stops and writes nothing more → `{cancelled: n}`.
pub fn cancel_exports(app: &mut VectorcraftApp) -> Value {
let n = app.background.cancel_exports();
if n > 0 {
app.status(EXPORT_CANCELLED);
}
json!({ "cancelled": n })
}
/// The progress dialog's Continue in Background: the exports go on, shown in the status bar only
/// → `{hidden: n}`.
pub fn hide_exports(app: &mut VectorcraftApp) -> Value {
json!({ "hidden": app.background.hide_exports() })
}
/// Export the active document in `format` (default: the path's extension, else PNG) with the
/// `document.export` options in `params` (artboard, range, useArtboards, selectedOnly, ppi, SVG
/// options…): every file it writes (one per artboard, linked images) goes next to `path`. The
@@ -704,18 +725,31 @@ pub fn export(app: &mut VectorcraftApp, format: Option<&str>, path: Option<Strin
// Background Export: encoded and written from this snapshot while editing goes on.
let label = format!("Exporting {}", fileio::file_name(&path));
let (params, target) = (params.clone(), path.clone());
// The progress dialog's counts and Cancel: a cancelled export stops drawing and never starts
// writing.
let progress = Progress::new();
let (reporting, asked) = (progress.clone(), progress.clone());
let work = move |write: Writer| {
let enc = fileio::encode_all(&doc, f.id, &params).map_err(|e| e.to_string())?;
let files = write_encoded(write, &doc, &path, &enc)?;
let mut out = json!({ "path": files.first().unwrap_or(&path), "warnings": enc.warnings });
if files.len() > 1 {
out["files"] = json!(files);
}
Ok(out)
progress::scope(&reporting, || {
cancel::check().map_err(|e| e.to_string())?;
let enc = fileio::encode_all(&doc, f.id, &params).map_err(|e| e.to_string())?;
cancel::check().map_err(|e| e.to_string())?;
let files = write_encoded(write, &doc, &path, &enc)?;
let mut out = json!({ "path": files.first().unwrap_or(&path), "warnings": enc.warnings });
if files.len() > 1 {
out["files"] = json!(files);
}
Ok(out)
})
};
let enabled = app.session.prefs.background_export;
let failed = target.clone();
let mut r = background::run(app, enabled, label, None, work, move |app, r| {
let mut r = background::run_with_progress(app, enabled, label, None, Some(progress), work, move |app, r| {
// A file written before the Cancel arrived is reported as written.
if r.is_err() && asked.cancelled() {
app.status(EXPORT_CANCELLED);
return Ok(json!({ "cancelled": true }));
}
let r = r.inspect_err(|e| report_write_error(app, true, &failed, e))?;
let what = match r["files"].as_array() {
Some(files) => format!("{} files", files.len()),
+2
View File
@@ -25,6 +25,7 @@ pub mod cursors;
pub mod dialogs;
pub mod dock;
mod edit_toolbar;
pub mod export_progress;
pub mod find_font;
pub mod floating;
pub mod font_menu;
@@ -1440,6 +1441,7 @@ impl VectorcraftApp {
dock::floating_panel(self, &ctx);
floating::show(self, &ctx);
dialogs::show(self, &ctx);
export_progress::show(self, &ctx);
palette::show(self, &ctx);
if self.custom_titlebar {
titlebar::resize_zones(ui);
+15
View File
@@ -747,6 +747,18 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
("file.openRecent29", "Open Recent File 29", "", "{}"),
("file.openRecent30", "Open Recent File 30", "", "{}"),
("file.reveal", "Show in Folder", "", "{} show the document's file in the system file manager (desktop) → {path}"),
(
"file.cancelExport",
"Cancel Export",
"",
"{} stop every export running in the background (Background Export): an export stops between artboards and writes no file once cancelled → {cancelled: n}",
),
(
"file.exportInBackground",
"Continue in Background",
"",
"{} close the export progress dialog; the exports go on, shown in the status bar → {hidden: n}",
),
(
"ui.dxfOptionsDialog",
"DXF Options Dialog",
@@ -1101,6 +1113,8 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
"file.newFromTemplate" if p.get("dataBase64").is_none() => io::new_from_template(app, s("path")),
"file.revert" if p.get("confirmed").and_then(Value::as_bool) != Some(true) => io::ask_revert(app),
"file.reveal" => io::reveal(app),
"file.cancelExport" => Ok(io::cancel_exports(app)),
"file.exportInBackground" => Ok(io::hide_exports(app)),
id if id.starts_with("file.openRecent") => match recent_slot(app, id).cloned() {
Some(path) => io::open_reporting(app, &path),
None => Err("no such recent file".into()),
@@ -2225,6 +2239,7 @@ pub fn enabled(app: &VectorcraftApp, id: &str) -> bool {
"type.bold" | "type.italic" => crate::panels::character::text_style(app).is_some(),
id if crate::panels::paragraph::ALIGN_COMMANDS.iter().any(|c| c.0 == id) => crate::panels::character::text_style(app).is_some(),
"file.reveal" => app.services.reveal.is_some() && app.session.active().is_some_and(|d| d.path.is_some()),
"file.cancelExport" | "file.exportInBackground" => app.background.jobs.iter().any(|j| j.progress.is_some() && !j.cancelled()),
"file.place"
| "file.export.svg"
| "file.export.png"
+28
View File
@@ -121,6 +121,34 @@ fn exports_run_in_the_background_and_the_preference_turns_both_off() {
assert!(app.background.jobs.is_empty());
}
#[test]
fn a_cancelled_export_writes_nothing() {
let (gate, writing) = (Gate::default(), Gate::default());
let files = Files::default();
let (f, g, w) = (files.clone(), gate.clone(), writing.clone());
let services = Services {
write_shared: Some(Arc::new(move |p: &str, b: &[u8]| {
w.open();
g.wait();
f.lock().unwrap().push((p.to_string(), b.to_vec()));
Ok(())
})),
..Default::default()
};
let mut app = VectorcraftApp::new(Session::new(), services);
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
// The first export holds the worker at the gate, past its last check: it still writes.
io::export(&mut app, Some("svg"), Some("/out/first.svg".into()), &json!({})).unwrap();
writing.wait();
io::export(&mut app, Some("png"), Some("/out/second.png".into()), &json!({})).unwrap();
assert_eq!(app.run("file.cancelExport", json!({})).unwrap()["cancelled"], 2);
assert_eq!(app.run("file.cancelExport", json!({})).unwrap()["cancelled"], 0, "nothing left to cancel");
gate.open();
background::wait_all(&mut app);
assert_eq!(written(&files), ["/out/first.svg"]);
assert_eq!(app.ui.status, io::EXPORT_CANCELLED);
}
#[test]
fn quitting_waits_for_background_saves() {
let gate = Gate::default();
+3 -1
View File
@@ -1,6 +1,6 @@
# Gaps
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged; transparency grid visibility saved in native documents, #1968; G6: MCP cancellation, progress notifications and busy answers during long exports, #2165, #2171, #2172; EPS editing data: legacy mesh corners, vector opacity masks and compound member paint retained; raster page comparison filters minification without relaxing limits; scores and hours unchanged; correction: quick Image Trace presets leave the panel as it was, the Image Trace button opens it; batch exporting, #1935; G2: Effect › Sketch › Halftone Pattern; Photoshop filters 30/57, 27 remaining (22–38 h); G5: Symbol Options Export Type (Graphic / Movie Clip); G1: Smart Guides line extension, #2120; G16: Brazilian Portuguese catalog complete under the tests, #1914; Localization 71% → 74%, hours 55–90 → 50–85; G6: image variables landed, estimate 8–14 → 6–12 h; Warp Options controls verified by focused checks and original-image review; estimates unchanged; existing-guide Escape cancellation validated 2026-10-14; scores and hours unchanged; open-path anchor Delete keeps surviving runs separate; estimates unchanged; Artboard tab-switch follow-up historically validated on `a0671777`; scores and hours unchanged; Artboard clean active-tab close/Delete follow-up validated 2026-10-15; G13: Object › Intertwine landed, #1763; no entry closed, estimates unchanged; MCP `add_text` exposes the existing `vertical` option for point, area and path type; horizontal remains the default; scores and hours unchanged; Vertical fullwidth question and exclamation marks keep their nominal glyph upright when the font has no vertical alternate; scores and hours unchanged.; G1: Curvature curve geometry, #1236 in part; Width-point finite-arithmetic follow-up validated; scores and hours unchanged; Image Trace adjustment discovery; G9: legacy `.ai` of version 7 saved with type as text and hidden objects kept, legacy type read, #868; estimate unchanged; Revolve: automatic smooth shading and default-on Cap with continuous rims; later 2026-10-14: G8 untrusted files, #1852, #1862–#1873; G11 anchor X/Y/W/H, #1824, Snap to Grid over Snap to Pixel, #1816, redo during a drag, #1719, Dim Images, #1683, failed-save dialog, #1685; gaps noted for reporters: G1 Warp Options for Effect › Warp, #1760, Color Picker Tab order, #1692, key anchor, #1636; G7 custom toolbars, #1759, workspace panel widths, #1753; G11 Shape Builder gaps between closed shapes, #1691, interior anchor delete; G13 Intertwine, #1763, gradient mesh from an image, #1676, Image Trace radial gradients, #1849; G12 duplicated line removed; no entry closed, estimates unchanged; verified PngSuite downloads, #1729; synthetic control-input budgets, #1709; 2026-10-14 fixes: G11 anchor Align and Distribute, #1636, Delete and selection, #1674, #1666, #1743, #1686, Roughen and Scribble, #1643, #1648; G8 file and input hardening, #1776–#1783, #1786, #1807; G10 Wayland cursors and the Windows title bar, unconfirmed, #1645, #1758; no entry closed, estimates unchanged; later 2026-10-13 fixes, #1570, #1578, #1590, #1613, #1615, #1616, #1620 in part, #1602 in part; no entry closed, estimates unchanged; TIFF is available in Export for Screens and Asset Export with shared format settings; scores and hours unchanged; G1/M11: Artboard deletion and history selection normalization; history regressions and full workspace CI pass; scores and hours unchanged; Character styles retain explicit Auto leading, propagate resets and preserve local leading overrides; scores and hours unchanged; Width Point Edit: Shift-double-click enables adjoining adjustment; plain double-click keeps it off; scores and hours unchanged; G12: Identify Objects By acts, #394; ~16 → ~15 prefs still inert; G12: Appearance of Black › Printing / Exporting acts, #394; ~16 → ~15 prefs still inert; control transport deadlines, #1726; G1: Average and Join in one step with a corner or smooth choice added as missing (it was listed as done in ui-parity.md); Join after Average, #1533; guide objects, #1534; Keyboard Shortcuts, #1539; G9 and G11 fixes, #1528, #1530, #1544, #1553, #1512, #1537; estimates unchanged; Direct Selection anchor precedence, #1508; dialog slider rails, #1483; template layers in Outline view, #1486; Tabs panel stop drags, #1458; type that does not fit its frame is reported, #1471; 3D on outlined type, #1481, Twist range, #1524, twisted walls, #1525; print-size images, #1517; French catalog, #1511; estimates unchanged; G1: Split Into Grid options, #1462, Transform Objects and Reflect's angle, #1448 and #1460, Pathfinder on a group, #1450, valueLine truncated
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (G12: Background Export progress dialog with Cancel, #2564; no entry closed, estimates unchanged; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged; transparency grid visibility saved in native documents, #1968; G6: MCP cancellation, progress notifications and busy answers during long exports, #2165, #2171, #2172; EPS editing data: legacy mesh corners, vector opacity masks and compound member paint retained; raster page comparison filters minification without relaxing limits; scores and hours unchanged; correction: quick Image Trace presets leave the panel as it was, the Image Trace button opens it; batch exporting, #1935; G2: Effect › Sketch › Halftone Pattern; Photoshop filters 30/57, 27 remaining (22–38 h); G5: Symbol Options Export Type (Graphic / Movie Clip); G1: Smart Guides line extension, #2120; G16: Brazilian Portuguese catalog complete under the tests, #1914; Localization 71% → 74%, hours 55–90 → 50–85; G6: image variables landed, estimate 8–14 → 6–12 h; Warp Options controls verified by focused checks and original-image review; estimates unchanged; existing-guide Escape cancellation validated 2026-10-14; scores and hours unchanged; open-path anchor Delete keeps surviving runs separate; estimates unchanged; Artboard tab-switch follow-up historically validated on `a0671777`; scores and hours unchanged; Artboard clean active-tab close/Delete follow-up validated 2026-10-15; G13: Object › Intertwine landed, #1763; no entry closed, estimates unchanged; MCP `add_text` exposes the existing `vertical` option for point, area and path type; horizontal remains the default; scores and hours unchanged; Vertical fullwidth question and exclamation marks keep their nominal glyph upright when the font has no vertical alternate; scores and hours unchanged.; G1: Curvature curve geometry, #1236 in part; Width-point finite-arithmetic follow-up validated; scores and hours unchanged; Image Trace adjustment discovery; G9: legacy `.ai` of version 7 saved with type as text and hidden objects kept, legacy type read, #868; estimate unchanged; Revolve: automatic smooth shading and default-on Cap with continuous rims; later 2026-10-14: G8 untrusted files, #1852, #1862–#1873; G11 anchor X/Y/W/H, #1824, Snap to Grid over Snap to Pixel, #1816, redo during a drag, #1719, Dim Images, #1683, failed-save dialog, #1685; gaps noted for reporters: G1 Warp Options for Effect › Warp, #1760, Color Picker Tab order, #1692, key anchor, #1636; G7 custom toolbars, #1759, workspace panel widths, #1753; G11 Shape Builder gaps between closed shapes, #1691, interior anchor delete; G13 Intertwine, #1763, gradient mesh from an image, #1676, Image Trace radial gradients, #1849; G12 duplicated line removed; no entry closed, estimates unchanged; verified PngSuite downloads, #1729; synthetic control-input budgets, #1709; 2026-10-14 fixes: G11 anchor Align and Distribute, #1636, Delete and selection, #1674, #1666, #1743, #1686, Roughen and Scribble, #1643, #1648; G8 file and input hardening, #1776–#1783, #1786, #1807; G10 Wayland cursors and the Windows title bar, unconfirmed, #1645, #1758; no entry closed, estimates unchanged; later 2026-10-13 fixes, #1570, #1578, #1590, #1613, #1615, #1616, #1620 in part, #1602 in part; no entry closed, estimates unchanged; TIFF is available in Export for Screens and Asset Export with shared format settings; scores and hours unchanged; G1/M11: Artboard deletion and history selection normalization; history regressions and full workspace CI pass; scores and hours unchanged; Character styles retain explicit Auto leading, propagate resets and preserve local leading overrides; scores and hours unchanged; Width Point Edit: Shift-double-click enables adjoining adjustment; plain double-click keeps it off; scores and hours unchanged; G12: Identify Objects By acts, #394; ~16 → ~15 prefs still inert; G12: Appearance of Black › Printing / Exporting acts, #394; ~16 → ~15 prefs still inert; control transport deadlines, #1726; G1: Average and Join in one step with a corner or smooth choice added as missing (it was listed as done in ui-parity.md); Join after Average, #1533; guide objects, #1534; Keyboard Shortcuts, #1539; G9 and G11 fixes, #1528, #1530, #1544, #1553, #1512, #1537; estimates unchanged; Direct Selection anchor precedence, #1508; dialog slider rails, #1483; template layers in Outline view, #1486; Tabs panel stop drags, #1458; type that does not fit its frame is reported, #1471; 3D on outlined type, #1481, Twist range, #1524, twisted walls, #1525; print-size images, #1517; French catalog, #1511; estimates unchanged; G1: Split Into Grid options, #Line truncated
Every known shortfall against Illustrator, one entry each, **ranked by how much it stops a professional from
switching**. This is the work list: unless you were given a task, pick the highest-ranked gap you can make
@@ -202,6 +202,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
## G12 Preferences and panels that don't act yet
- **Done (2026-10-17):** Background Export shows its progress in a dialog with Cancel and Continue in Background (#2564), on the shared cancel token (#2546); a cancelled export writes no file. Save As, Export for Screens and Export Selection don't show it yet. Estimate unchanged.
- **Done:** quick Image Trace presets trace at once and leave the panel as it was; the Image Trace button (Control bar, Properties) opens the controls with Threshold and Advanced (Paths, Corners, Noise), as the public documentation describes (<https://helpx.adobe.com/illustrator/using/image-trace-results-optimization.html>). Other context-specific Properties gaps remain.
- **Missing:** ~14 Preferences options stored but not acted on (#394: Open
@@ -349,6 +350,7 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall
| Date | Change | Summary |
|---|---|---|
| 2026-10-17 | minor | Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged. Windows native canvas checks and screenshots reviewed in PR #2643. |
| 2026-10-17 | minor | G12: Background Export progress dialog with Cancel and Continue in Background (#2564); no entry closed, estimates unchanged |
| 2026-10-16 | minor | Native documents restore transparency grid visibility (#1968); save/open regression covers on/off, old files and SVG; scores and hours unchanged (estimated) |
| 2026-10-16 | minor | G6: MCP cancellation, progress notifications and a busy answer during long exports (#2165, #2171, #2172); no entry closed, estimates unchanged |
| 2026-10-16 | minor | G11: PDF export of a CMYK document reports its RGB colours and non-CMYK images, with a count, in the export warnings (#2162); no entry closed, estimates unchanged |
+3 -1
View File
@@ -1,6 +1,6 @@
# UI and interaction parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged; Artboard Options' X and Y with a reference point, #1876; scores unchanged; library panels: one per library, dockable and tabbable, with Persistent, #2603; the Selection tool threads text from the out port, #2572 in part; scores unchanged; Group Selection picks and moves one path of a compound path, #2441 in part; the Move dialog opens on the last move and its last checkboxes; scores unchanged; transparency grid visibility saved in native documents, #1968; Live Corners radius up to the neighbouring cuts, #2332; Image Trace quick presets: wording corrected to the shipped behaviour, the Image Trace button opens the controls; batch exporting, #1935; document window scroll bars, #2322; Anchor Point tool: a click on a handle end retracts that handle only, #2267; scores unchanged; Smart Guides: the dragged end of a straight segment keeps to its extension at any angle, #2120; Warp Options controls verified by focused checks and original-image review; estimates unchanged; existing-guide Escape cancellation validated 2026-10-14; scores and hours unchanged; open-path anchor Delete keeps surviving runs separate; estimates unchanged; Artboard tab-switch follow-up historically validated on `a0671777`; scores and hours unchanged; Artboard clean active-tab close/Delete follow-up validated 2026-10-15; Curvature curve geometry, #1236 in part; Width-point finite-arithmetic follow-up validated; scores and hours unchanged; Image Trace adjustment discovery; later 2026-10-14 merges: macOS save sheet Format menu back to missing, #1855, #866 reopened; anchor X/Y/W/H in the Transform panel, Properties and Control bar, #1824; Snap to Grid over Snap to Pixel, #1816; toolbar labels, columns and the All Tools drawer, #1751; Actions panel selection, #1629 in part; scores unchanged; 2026-10-14 merges: anchor Align and Distribute, #1636; Delete on closed paths and whole objects, #1674; selection inside isolation, #1666; Escape in a Direct Selection drag and while typing, #1743, #1686; Pen clicks under 3 px, #1663; [ and ] on more tools, #1661 in part; fields commit on click away, #1787; command search keys, #1757; a guide's position in the Transform panel is a convenience with no parity claim, #1659; scores unchanged; intersect Smart Guides for drawn points and dragged anchors, #1602 in part; a ruler guide's position in the Transform panel, #1597 in part; Symbol Options before New Symbol, #1560; tool flyout widths, #1616; Pathfinder Trim, Merge and Crop strokes, #1570; scores unchanged; G1/M11: Artboard deletion and history selection normalization; history regressions and full workspace CI pass; scores and hours unchanged; Width Point Edit: Shift-double-click enables adjoining adjustment; plain double-click keeps it off; scores and hours unchanged; per-corner radius fields with a link toggle, split from #1594; Join merges anchors lying on one another, #1533; correction: Average and Join with a corner or smooth choice is missing, not done; guide objects take the guide colour and style and Lock Guides, #1534; Keyboard Shortcuts lists commands outside the menus, #1539; round corners next to curves and the Smooth tool's reach, #1512; Make Compound Path on a group, #1537; dialog slider rails, #1483; template layers stay in Preview in Outline view, #1486; Direct Selection takes the selected object's anchor where anchors coincide, #1508; Tabs panel stop drags, #1458; Split Into Grid dialog, #1462; Transform Objects and Reflect's angle, #1448 and #1460; Pathfinder panel on a group, #1450; value fields: readable selection, #1465 in part, and a focused field follows its value, #1457; scores unchanged; Transform dialogs have a live Preview and step with the arrow keys, #1412; transform tools, dialogs and Move act on direct-selected anchors, #1408; the bounding box hides during a corner drag, #1229; scores unchanged; dialogs focus their first field on every open, #1367, and a first field that starts greyed out once it is enabled, #1395; scores unchanged; Rectangular Grid and Polar Grid click dialogs take the skew, frame, compound path and Fill Grid options, #1377 in part, score unchanged; Live Corners: a Direct Selection click on a widget selects its corner, #1239; custom ruler origin, #1212; Artboard tool clicks fit the topmost editable object in one undo step (#1227); scores unchanged; Pathfinder single-result source names and SVG IDs retained, #1293; DXF control-point SPLINE closure read, #1299 follow-up; Document Setup: Edit Artboards closes the modal after applying valid settings; pointer-click regressions; scores and hours unchanged; Artboards: Escape Line truncated
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-17 · **Change:** minor (Background Export progress dialog with Cancel, #2564; scores unchanged; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged; Artboard Options' X and Y with a reference point, #1876; scores unchanged; library panels: one per library, dockable and tabbable, with Persistent, #2603; the Selection tool threads text from the out port, #2572 in part; scores unchanged; Group Selection picks and moves one path of a compound path, #2441 in part; the Move dialog opens on the last move and its last checkboxes; scores unchanged; transparency grid visibility saved in native documents, #1968; Live Corners radius up to the neighbouring cuts, #2332; Image Trace quick presets: wording corrected to the shipped behaviour, the Image Trace button opens the controls; batch exporting, #1935; document window scroll bars, #2322; Anchor Point tool: a click on a handle end retracts that handle only, #2267; scores unchanged; Smart Guides: the dragged end of a straight segment keeps to its extension at any angle, #2120; Warp Options controls verified by focused checks and original-image review; estimates unchanged; existing-guide Escape cancellation validated 2026-10-14; scores and hours unchanged; open-path anchor Delete keeps surviving runs separate; estimates unchanged; Artboard tab-switch follow-up historically validated on `a0671777`; scores and hours unchanged; Artboard clean active-tab close/Delete follow-up validated 2026-10-15; Curvature curve geometry, #1236 in part; Width-point finite-arithmetic follow-up validated; scores and hours unchanged; Image Trace adjustment discovery; later 2026-10-14 merges: macOS save sheet Format menu back to missing, #1855, #866 reopened; anchor X/Y/W/H in the Transform panel, Properties and Control bar, #1824; Snap to Grid over Snap to Pixel, #1816; toolbar labels, columns and the All Tools drawer, #1751; Actions panel selection, #1629 in part; scores unchanged; 2026-10-14 merges: anchor Align and Distribute, #1636; Delete on closed paths and whole objects, #1674; selection inside isolation, #1666; Escape in a Direct Selection drag and while typing, #1743, #1686; Pen clicks under 3 px, #1663; [ and ] on more tools, #1661 in part; fields commit on click away, #1787; command search keys, #1757; a guide's position in the Transform panel is a convenience with no parity claim, #1659; scores unchanged; intersect Smart Guides for drawn points and dragged anchors, #1602 in part; a ruler guide's position in the Transform panel, #1597 in part; Symbol Options before New Symbol, #1560; tool flyout widths, #1616; Pathfinder Trim, Merge and Crop strokes, #1570; scores unchanged; G1/M11: Artboard deletion and history selection normalization; history regressions and full workspace CI pass; scores and hours unchanged; Width Point Edit: Shift-double-click enables adjoining adjustment; plain double-click keeps it off; scores and hours unchanged; per-corner radius fields with a link toggle, split from #1594; Join merges anchors lying on one another, #1533; correction: Average and Join with a corner or smooth choice is missing, not done; guide objects take the guide colour and style and Lock Guides, #1534; Keyboard Shortcuts lists commands outside the menus, #1539; round corners next to curves and the Smooth tool's reach, #1512; Make Compound Path on a group, #1537; dialog slider rails, #1483; template layers stay in Preview in Outline view, #1486; Direct Selection takes the selected object's anchor where anchors coincide, #1508; Tabs panel stop drags, #1458; Split Into Grid dialog, #1462; Transform Objects and Reflect's angle, #1448 and #1460; Pathfinder panel on a group, #1450; value fields: readable selection, #1465 in part, and a focused field follows its value, #1457; scores unchanged; Transform dialogs have a live Preview and step with the arrow keys, #1412; transform tools, dialogs and Move act on direct-selected anchors, #1408; the bounding box hides during a corner drag, #1229; scores unchanged; dialogs focus their first field on every open, #1367, and a first field that starts greyed out once it is enabled, #1395; scores unchanged; Rectangular Grid and Polar Grid click dialogs take the skew, frame, compound path and Fill Grid options, #1377 in part, score unchanged; Live Corners: a Direct Selection click on a widget selects its corner, #1239; custom ruler origin, #1212; Artboard tool clicks fit the topmost editable object in one undo step (#1227); scores unchanged; Pathfinder single-result source names and SVG IDs retained, #1293; DXF control-point SPLINE closure read, #1299 follow-up; Document Setup: Edit Artboards closes the modal after applying valid settings; pLine truncated
How VectorCraft's tools, handles, snapping and panels behave next to Illustrator's. A vector illustrator's
trust is in the details: where a handle lands, what Shift and Alt do mid-drag, what a smart guide snaps to,
@@ -226,6 +226,7 @@ panel-menu commands such as Break Link to Symbol), so they can be given shortcut
| Blend panel (30.7) | partial | Window › Blend: Make, Spacing, Orientation, Reverse Front to Back, Reverse Spine, Replace Spine, Expand and Release, running the Object › Blend commands; the easing and color controls are missing |
| SVG Interactivity, Retype, Comments, Version History panels | missing | the last two are cloud features (out of scope) |
| Workspaces (save, reset, switch) | done | |
| Background Export: a progress dialog with the file name, the artboard count and a bar (busy for one artboard and for formats made in one go), Cancel (Esc) and Continue in Background; it opens after 0.4 s and never over another dialog. A cancelled export writes no file | done | #2564; on the shared `vectorcraft_doc::cancel` token (#2546), so a cancelled render keeps no half-drawn pattern tile or effect raster. The bar moves between artboards, not within one. Save As, Export for Screens and Export Selection don't show it yet |
| Swatch and graphic style library panels: each library opens in a panel of its own, several at once, that floats, groups, docks and closes like any panel; opening an open library brings its panel forward; Previous / Next Library change the library in place; the panel menu's Persistent reopens the panel at startup with its view and find field (a library loaded from a file is read again, a missing file is skipped with a status-bar note) | done | #2603; panel ids `library:<kind>:<id>`, `ui.libraryPanel {panel, library?, view?, showFind?, persistent?}`; the library panels have no sort option, as before |
| DXF export/import preserves intended curve closure | done | #1299; R13–2018 closed SPLINE bit set/read; an open curve ending at its start stays open; knots and control points unchanged; native CIRCLE/ARC export and CNC preset remain pending |
| macOS save sheet: choose the format from a menu | done | #866; the save panel is VectorCraft's own `NSSavePanel` with its Format menu set before the sheet opens (`apps/vectorcraft/src/mac_save_format.rs`); #1855 had withdrawn the menu that was added after the sheet began, which made Save As, Save a Copy and the first Save show no sheet |
@@ -248,6 +249,7 @@ re-measure of the panels added since. Slider rails show on Medium Dark (#1808, #
|---|---|---|
| 2026-10-17 | minor | Blend spine Anchor Point conversions, selection/stacking priority and Shift regression coverage (#2544); scores and hours unchanged. Windows native canvas checks and screenshots reviewed in PR #2643. |
| 2026-10-17 | minor | Artboard Options has X and Y beside a reference point locator, counted from the ruler origin as the Transform panel's are; a typed X or Y moves the artboard's reference point there and a new Width or Height keeps it in place (#1876); scores unchanged (estimated) |
| 2026-10-17 | minor | Background Export shows a progress dialog with Cancel and Continue in Background (#2564), built on the shared cancel token of #2546; scores and hours unchanged (estimated) |
| 2026-10-17 | minor | Library panels (#2603): each swatch or graphic style library opens in its own dockable, tabbable panel, several at once; the panel menu's Persistent reopens a panel at startup with its view and find field, a library loaded from a file read again from its path; scores unchanged (estimated) |
| 2026-10-17 | minor | Selection tool: clicking the red out port of overflowing area type, then a closed path, empty canvas or a dragged rectangle threads the text there (#2572 in part); Escape cancels. Scores and hours unchanged. |
| 2026-10-17 | minor | Group Selection picks one path of a compound path (the outer shape or a hole) and moves it on its own; a second click adds the compound path (#2441, in part) |