Fix #4931: native Save As Version is a menu of the versions VectorCraft writes

This commit is contained in:
bflatastic
2026-11-01 01:39:08 +07:00
parent 0014e4e1f0
commit 7ad5ee0dff
28 changed files with 105 additions and 7 deletions
+55 -7
View File
@@ -7,12 +7,13 @@
//! editable), `path`, `format`, and one field per option (agents set them with `ui.dialog.set`).
//! Native and `.ai` files show their save options (VectorCraft Options after Save As): each
//! artboard to a separate file, with `all` (true: every artboard) or `range`, Include Linked Files,
//! Embed ICC Profiles, Create PDF-Compatible File and Use Compression. A `.ai` file's Version comes
//! first: PDF-compatible, or legacy version 7 (`aiVersion: "7"`, a file per artboard), which takes
//! only Transparent Images (`transparentImages`), Hidden Objects (`hiddenObjects`: a hidden layer,
//! omitted or made visible), Text (`outlineText`: editable or outlines) and, with several
//! artboards, a picker of the artboards to save (thumbnails to check, field `boards`, saved as
//! `range`).
//! Embed ICC Profiles, Create PDF-Compatible File and Use Compression. A native file's Version is a
//! menu of the versions VectorCraft writes (`version`, named by the releases that read each). A
//! `.ai` file's Version comes first: PDF-compatible, or legacy version 7 (`aiVersion: "7"`, a file
//! per artboard), which takes only Transparent Images (`transparentImages`), Hidden Objects
//! (`hiddenObjects`: a hidden layer, omitted or made visible), Text (`outlineText`: editable or
//! outlines) and, with several artboards, a picker of the artboards to save (thumbnails to check,
//! field `boards`, saved as `range`).
use std::sync::OnceLock;
@@ -342,6 +343,10 @@ fn option_row(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, o: &Forma
ui.end_row();
return;
}
if o.name == "version" && o.ty == "integer" {
native_version(ui, d, o);
return;
}
if o.name == "transparentImages" {
ui.label(egui::RichText::new(tl!("Transparent Images:")).color(t.text_dim)).on_hover_text(o.description);
let choices = [tl!("Flatten"), tl!("Omit")];
@@ -379,7 +384,9 @@ fn option_row(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, o: &Forma
if o.ty == "boolean" {
ui.label("");
let on = value.as_bool().unwrap_or(false);
if widgets::check_tip(ui, label.trim_end_matches(':'), on, true, o.description) {
// Versions older than compression read only plain files.
let enabled = o.name != "compress" || !uncompressed(d);
if widgets::check_tip(ui, label.trim_end_matches(':'), on && enabled, enabled, o.description) {
d.fields.insert(o.name.into(), json!(!on));
}
ui.end_row();
@@ -412,6 +419,43 @@ fn option_row(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog, o: &Forma
ui.end_row();
}
/// The native versions VectorCraft writes, newest first, each with the first release that reads
/// it (the format version each release tag writes: 2 in 0.1, 3 from 0.2, 4 from 0.8).
const NATIVE_VERSIONS: [(u32, &str); 4] = [(4, "0.8"), (3, "0.2"), (2, "0.1"), (1, "0.1")];
/// A native file's Version (#4931): a menu of the versions VectorCraft writes, named by the
/// releases that read them, so a version it can't write can't be chosen. A version without
/// compression turns Use Compression off.
fn native_version(ui: &mut egui::Ui, d: &mut Dialog, o: &FormatOption) {
let t = Tokens::get(ui.ctx());
ui.label(egui::RichText::new(tl!("Version:")).color(t.text_dim)).on_hover_text(o.description);
let names: Vec<String> = NATIVE_VERSIONS
.iter()
.map(|(n, release)| crate::i18n::fmt(tl!("VectorCraft {release} and later (version {n})"), &[("release", release), ("n", &n.to_string())]))
.collect();
let names: Vec<&str> = names.iter().map(String::as_str).collect();
let at = NATIVE_VERSIONS.iter().position(|(n, _)| *n == native_version_of(d)).unwrap_or(0);
if let Some(i) = widgets::dropdown_names(ui, ("save-option", o.name), names.get(at).copied().unwrap_or_default(), &names, 254.0)
&& let Some((n, _)) = NATIVE_VERSIONS.get(i)
{
d.fields.insert(o.name.into(), json!(n));
if *n < vectorcraft_format::COMPRESSED_SINCE {
d.fields.insert("compress".into(), json!(false));
}
}
ui.end_row();
}
/// The native version the dialog will write (the current one unless chosen).
fn native_version_of(d: &Dialog) -> u32 {
d.fields.get("version").and_then(Value::as_u64).and_then(|v| u32::try_from(v).ok()).unwrap_or(vectorcraft_format::VERSION)
}
/// Is a native file to be saved in a version that can't be compressed?
fn uncompressed(d: &Dialog) -> bool {
native_version_of(d) < vectorcraft_format::COMPRESSED_SINCE
}
/// Web Save As: another format brings its own options and file extension.
fn switch_format(app: &mut VectorcraftApp, d: &mut Dialog, id: &str) {
let (Some(old), Some(new)) = (fileio::format(&d.str("format")), fileio::format(id)) else { return };
@@ -444,6 +488,10 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> DialogResult {
.iter()
.filter_map(|o| d.fields.get(o.name).filter(|v| !v.is_null() && v.as_str() != Some("")).map(|v| (o.name.to_string(), v.clone())))
.collect();
if uncompressed(d) {
// Use Compression shows off there, whatever it held before.
options.remove("compress");
}
if legacy_ai(d) {
// The artboards checked in the picker (all of them: no range).
options.remove("range");
@@ -347,3 +347,27 @@ fn eps_save_as_keeps_page_options_and_writes_eps_without_export_only_switches()
assert!(vectorcraft_eps::native(&saved[0].1).is_some());
assert_eq!(app.session.active().unwrap().format, "eps");
}
/// #4931: a native file's Version is a menu of the versions VectorCraft writes, the current one
/// first and chosen, each named by the releases that read it. An older version without
/// compression saves plain, whatever Use Compression held.
#[test]
fn native_version_is_a_menu_of_the_versions_vectorcraft_writes() {
let listed: Vec<u32> = NATIVE_VERSIONS.iter().map(|(n, _)| *n).collect();
let writable: Vec<u32> = (vectorcraft_format::MIN_VERSION..=vectorcraft_format::VERSION).rev().collect();
assert_eq!(listed, writable, "every version VectorCraft writes, newest first");
let (mut app, written, _) = desktop("art.vectorcraft");
assert_eq!(app.run("file.saveAs", json!({})).unwrap()["pending"], KIND);
let text = crate::tests_labels::painted_text(&mut app, |app, ui| super::super::show(app, ui.ctx()));
assert!(text.contains("VectorCraft 0.8 and later (version 4)"), "{text}");
assert_eq!(native_version_of(dialog(&app)), vectorcraft_format::VERSION);
let d = app.ui.dialog.as_mut().unwrap();
d.fields.insert("version".into(), json!(2));
d.fields.insert("compress".into(), json!(true));
assert!(uncompressed(d));
frame(&mut app, true);
assert!(app.ui.dialog.is_none(), "saved: {}", app.ui.status);
let (_, bytes) = written.borrow()[0].clone();
let head = String::from_utf8_lossy(&bytes[..bytes.len().min(200)]).to_string();
assert!(head.contains("\"version\": 2") || head.contains("\"version\":2"), "{head}");
}
+1
View File
@@ -5926,3 +5926,4 @@ breakText Glyphs Глифи
Set Size of Each Задаване на размер на всеки
@msg select exactly two objects изберете точно два обекта
@msg give `width` or `height` задайте `width` или `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} и по-нови (версия {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5960,3 +5960,4 @@ shape Open Otvoren
Set Size of Each Postavi veličinu svakog
@msg select exactly two objects odaberite tačno dva objekta
@msg give `width` or `height` zadajte `width` ili `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} i novije (verzija {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6033,3 +6033,4 @@ breakText Glyphs Glifs
Set Size of Each Defineix la mida de cadascun
@msg select exactly two objects selecciona exactament dos objectes
@msg give `width` or `height` indica `width` o `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} i posteriors (versió {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6042,3 +6042,4 @@ breakText Glyphs Glyfy
Set Size of Each Nastavit velikost jednotlivě
@msg select exactly two objects vyberte právě dva objekty
@msg give `width` or `height` zadejte `width` nebo `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} a novější (verze {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5940,3 +5940,4 @@ breakText Glyphs Glyffer
Set Size of Each Angiv størrelse for hver
@msg select exactly two objects markér præcis to objekter
@msg give `width` or `height` angiv `width` eller `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} og nyere (version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5628,3 +5628,4 @@ breakText Glyphs Glyphen
Set Size of Each Größe einzeln festlegen
@msg select exactly two objects wählen Sie genau zwei Objekte aus
@msg give `width` or `height` geben Sie `width` oder `height` an
VectorCraft {release} and later (version {n}) VectorCraft {release} und neuer (Version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5995,3 +5995,4 @@ breakText Glyphs Γλύφοι
Set Size of Each Ορισμός μεγέθους καθενός
@msg select exactly two objects επιλέξτε ακριβώς δύο αντικείμενα
@msg give `width` or `height` δώστε `width` ή `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} και νεότερες (έκδοση {n})
Can't render this file because it contains an unexpected character in line 164 and column 5.
+1
View File
@@ -5985,3 +5985,4 @@ breakText Glyphs Glifos
Set Size of Each Definir el tamaño de cada uno
@msg select exactly two objects selecciona exactamente dos objetos
@msg give `width` or `height` indica `width` o `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} y posteriores (versión {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6073,3 +6073,4 @@ breakText Glyphs Merkit
Set Size of Each Aseta kunkin koko
@msg select exactly two objects valitse täsmälleen kaksi objektia
@msg give `width` or `height` anna `width` tai `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} ja uudemmat (versio {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6040,3 +6040,4 @@ breakText Glyphs Glyphes
Set Size of Each Définir la taille de chaque objet
@msg select exactly two objects sélectionnez exactement deux objets
@msg give `width` or `height` indiquez `width` ou `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} et ultérieures (version {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6029,3 +6029,4 @@ breakText Glyphs Glifák
Set Size of Each Egyenkénti méret beállítása
@msg select exactly two objects jelölj ki pontosan két objektumot
@msg give `width` or `height` add meg a `width` vagy a `height` értéket
VectorCraft {release} and later (version {n}) VectorCraft {release} és újabb (verzió: {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5940,3 +5940,4 @@ breakText Glyphs Glif
Set Size of Each Atur ukuran masing-masing
@msg select exactly two objects pilih tepat dua objek
@msg give `width` or `height` berikan `width` atau `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} dan yang lebih baru (versi {n})
Can't render this file because it contains an unexpected character in line 2175 and column 5.
+1
View File
@@ -5662,3 +5662,4 @@ breakText Glyphs Glifi
Set Size of Each Imposta dimensione di ciascuno
@msg select exactly two objects seleziona esattamente due oggetti
@msg give `width` or `height` indica `width` o `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} e successive (versione {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5728,3 +5728,4 @@ breakText Glyphs 字形
Set Size of Each 個別にサイズを設定
@msg select exactly two objects オブジェクトをちょうど 2 つ選択してください
@msg give `width` or `height` `width` または `height` を指定してください
VectorCraft {release} and later (version {n}) VectorCraft {release} 以降 (バージョン {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6032,3 +6032,4 @@ breakText Glyphs გლიფები
Set Size of Each თითოეულის ზომის დაყენება
@msg select exactly two objects მონიშნეთ ზუსტად ორი ობიექტი
@msg give `width` or `height` მიუთითეთ `width` ან `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} და უფრო ახალი (ვერსია {n})
Can't render this file because it is too large.
+1
View File
@@ -5625,3 +5625,4 @@ breakText Glyphs 글리프
Set Size of Each 각각 크기 설정
@msg select exactly two objects 개체를 정확히 두 개 선택하세요
@msg give `width` or `height` `width` 또는 `height`를 지정하세요
VectorCraft {release} and later (version {n}) VectorCraft {release} 이상 (버전 {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5984,3 +5984,4 @@ breakText Glyphs Glyphs
Set Size of Each Formaat van elk instellen
@msg select exactly two objects selecteer precies twee objecten
@msg give `width` or `height` geef `width` of `height` op
VectorCraft {release} and later (version {n}) VectorCraft {release} en nieuwer (versie {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5898,3 +5898,4 @@ breakText Glyphs Glify
Set Size of Each Ustaw rozmiar każdego
@msg select exactly two objects zaznacz dokładnie dwa obiekty
@msg give `width` or `height` podaj `width` lub `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} i nowsze (wersja {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5962,3 +5962,4 @@ breakText Glyphs Glifos
Set Size of Each Definir Tamanho de Cada Um
@msg select exactly two objects selecione exatamente dois objetos
@msg give `width` or `height` informe `width` ou `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} e posteriores (versão {n})
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -6020,3 +6020,4 @@ breakText Glyphs Глифы
Set Size of Each Задать размер каждого
@msg select exactly two objects выделите ровно два объекта
@msg give `width` or `height` укажите `width` или `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} и новее (версия {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -6095,3 +6095,4 @@ breakText Glyphs Glyfer
Set Size of Each Ange storlek för vart och ett
@msg select exactly two objects markera exakt två objekt
@msg give `width` or `height` ange `width` eller `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} och senare (version {n})
Can't render this file because it contains an unexpected character in line 5 and column 25.
+1
View File
@@ -6000,3 +6000,4 @@ breakText Glyphs Glifler
Set Size of Each Her Birinin Boyutunu Ayarla
@msg select exactly two objects tam olarak iki nesne seç
@msg give `width` or `height` `width` veya `height` belirt
VectorCraft {release} and later (version {n}) VectorCraft {release} ve sonrası (sürüm {n})
Can't render this file because it contains an unexpected character in line 5 and column 25.
+1
View File
@@ -5642,3 +5642,4 @@ breakText Glyphs Гліфи
Set Size of Each Задати розмір кожного
@msg select exactly two objects виділіть рівно два об’єкти
@msg give `width` or `height` укажіть `width` або `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} і новіші (версія {n})
Can't render this file because it contains an unexpected character in line 178 and column 5.
+1
View File
@@ -5644,3 +5644,4 @@ breakText Glyphs Glyph
Set Size of Each Đặt kích thước từng cái
@msg select exactly two objects hãy chọn đúng hai đối tượng
@msg give `width` or `height` hãy cho `width` hoặc `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} trở lên (phiên bản {n})
Can't render this file because it contains an unexpected character in line 200 and column 5.
+1
View File
@@ -5884,3 +5884,4 @@ breakText Glyphs 字形
Set Size of Each 分别设置大小
@msg select exactly two objects 请恰好选择两个对象
@msg give `width` or `height` 请提供 `width` 或 `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} 及更高版本 (版本 {n})
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -5681,3 +5681,4 @@ breakText Glyphs 字符
Set Size of Each 個別設定大小
@msg select exactly two objects 請選取正好兩個物件
@msg give `width` or `height` 請提供 `width` 或 `height`
VectorCraft {release} and later (version {n}) VectorCraft {release} 及更新版本 (版本 {n})
Can't render this file because it contains an unexpected character in line 6 and column 47.