mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Merge pull request #5614 from FractalEncrypt/fix/new-doc-units-per-template
New Document: units belong to the chosen preset, not the whole tab
This commit is contained in:
@@ -131,6 +131,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
||||
|
||||
## Progress log
|
||||
|
||||
- 2026-11-04: New Document: the units chosen in Preset Details now belong to the chosen document, as the pane's options are listed for the selected preset; the chosen card shows them, every other Recent and Saved card keeps the units its document or preset was made in, and the built-in tabs still follow the chosen units, so switching between inches and millimetres no longer restyles every recent template. Scores and estimates unchanged.
|
||||
- 2026-11-02: Mouse wheel over a closed font-family field in Character, Properties or Control changes selected text through the family list using saved font filters (excluding search text), one undo step per notch, stopping at the ends (#5253). Scores and estimates unchanged.
|
||||
- 2026-10-31: Pattern libraries: Window › Swatch Libraries › Patterns and the Swatches panel's library menu open Geometric Patterns, a built-in library of eleven pattern swatches (dots, stripes, checks, a grid and shapes); clicking one adds its pattern and swatch to the document, once, and applies it to the active fill or stroke (`swatch.library.add`).
|
||||
- 2026-11-01: Find Nearest Swatch joins the Color Effects add-on (Object › Plug-ins › Color Effects): for each colour of the selection, the closest swatches of the document, a built-in library or a library or colour book the user loaded, with their CIEDE2000 difference; Apply gives each colour its nearest swatch as one undo step, linking global and spot swatches and adding a library's to the document first, so a process colour becomes the closest spot colour (`addon.color.nearestSwatch`, `addon.color.applyNearestSwatch`, #4923).
|
||||
|
||||
@@ -201,3 +201,6 @@ sync_github_name = false
|
||||
|
||||
[people.FrancoJacquet]
|
||||
real_name = "Franco Jacquet"
|
||||
|
||||
[people.FractalEncrypt]
|
||||
sync_github_name = true
|
||||
|
||||
@@ -41,7 +41,8 @@ const PARAMS: [&str; 12] = [
|
||||
"rasterEffectsPpi",
|
||||
"previewMode",
|
||||
];
|
||||
/// The preset the fields were last filled from (its fields as `apply` set them).
|
||||
/// The preset the fields were last filled from, as `apply` set them; a Recent or Saved card keeps
|
||||
/// its own units here, which the units chosen in Preset Details don't change.
|
||||
const APPLIED: &str = "__applied";
|
||||
/// Save Preset's name field is showing.
|
||||
const SAVING: &str = "__saving";
|
||||
@@ -257,21 +258,50 @@ fn presets(app: &VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing = egui::vec2(12.0, 12.0);
|
||||
let (w, h, preset, units) = (d.f64("width", 0.0), d.f64("height", 0.0), d.str("preset"), unit(d));
|
||||
// The fields were last filled from this preset's card; Recent keeps one entry per size
|
||||
// and units, so the units tell two entries of one size apart.
|
||||
let chosen = d
|
||||
.fields
|
||||
.get(APPLIED)
|
||||
.filter(|a| a.get("preset").and_then(Value::as_str) == Some(preset.as_str()))
|
||||
.and_then(Value::as_object)
|
||||
.cloned();
|
||||
for s in &list {
|
||||
// The built-in presets' cards show the chosen orientation (square sizes have none)
|
||||
// and the units chosen in Preset Details; choosing one keeps both. Recent and Saved
|
||||
// show each entry as it was made, so a portrait and a landscape A3 are two cards
|
||||
// (#2860).
|
||||
let mut s = DocSettings { units, ..s.clone() };
|
||||
if cat > 1 && ((w > h && s.height > s.width) || (h > w && s.width > s.height)) {
|
||||
std::mem::swap(&mut s.width, &mut s.height);
|
||||
// The built-in presets' cards show the chosen orientation (square sizes have none);
|
||||
// Recent and Saved show each entry as it was made, so a portrait and a landscape A3
|
||||
// are two cards (#2860).
|
||||
let mut card = s.clone();
|
||||
if cat > 1 && ((w > h && card.height > card.width) || (h > w && card.width > card.height)) {
|
||||
std::mem::swap(&mut card.width, &mut card.height);
|
||||
}
|
||||
let selected = d.fields.contains_key(APPLIED) && s.name == preset && s.width == w && s.height == h;
|
||||
let card = preset_card(ui, &s, selected);
|
||||
if card.clicked() || card.double_clicked() {
|
||||
apply(d, &s);
|
||||
// The built-in presets all share the units chosen in Preset Details.
|
||||
if cat > 1 {
|
||||
card.units = units;
|
||||
}
|
||||
create |= card.double_clicked();
|
||||
let selected = chosen.as_ref().is_some_and(|a| {
|
||||
a.get("preset").and_then(Value::as_str) == Some(card.name.as_str())
|
||||
&& a.get("width").and_then(Value::as_f64) == Some(card.width)
|
||||
&& a.get("height").and_then(Value::as_f64) == Some(card.height)
|
||||
&& (cat > 1 || a.get("units").and_then(Value::as_str) == Some(s.units.label()))
|
||||
});
|
||||
// The chosen card shows the units chosen in Preset Details, which the new document
|
||||
// will have (#2078); the others keep their own, so choosing one document's units
|
||||
// doesn't restyle the whole tab.
|
||||
if selected {
|
||||
card.units = units;
|
||||
}
|
||||
let resp = preset_card(ui, &card, selected);
|
||||
if resp.clicked() || resp.double_clicked() {
|
||||
apply(d, &card);
|
||||
// The card is still the entry it was, whatever units it shows: its own units say
|
||||
// which entry it is, so a chosen card stays chosen after a units change.
|
||||
if cat < 2
|
||||
&& let Some(Value::Object(a)) = d.fields.get_mut(APPLIED)
|
||||
{
|
||||
a.insert("units".into(), json!(s.units.label()));
|
||||
}
|
||||
}
|
||||
create |= resp.double_clicked();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use serde_json::json;
|
||||
use vectorcraft_doc::Unit;
|
||||
|
||||
use super::tests_appearance::{app_with_rect, frame_events, run};
|
||||
use super::tests_appearance::{app_with_rect, click, frame_events, run, text_rect};
|
||||
use super::*;
|
||||
|
||||
/// Every text drawn in the second headless frame of `f` (windows size themselves in the first).
|
||||
@@ -171,3 +171,87 @@ fn new_document_cards_follow_the_chosen_units() {
|
||||
assert!(shows(&t, "288 × 432 px") && !shows(&t, "101.6 × 152.4 mm"), "Postcard in px: {t:?}");
|
||||
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["preset"], json!("Postcard"));
|
||||
}
|
||||
|
||||
/// Choosing units in Preset Details changes the chosen document, not every recent one: each card
|
||||
/// keeps the units its document was made in, so switching between inches and millimetres leaves the
|
||||
/// other templates as they were; choosing another card brings its units back.
|
||||
#[test]
|
||||
fn recent_cards_keep_their_own_units() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
// 8.5 × 11 in, then 210 × 297 mm, which Recent lists first and the dialog opens on.
|
||||
run(&mut app, "file.new", json!({"width": "8.5 in", "height": "11 in", "units": "Inches"}));
|
||||
run(&mut app, "file.new", json!({"width": "210 mm", "height": "297 mm", "units": "Millimeters"}));
|
||||
app.run("file.newDialog", json!({})).unwrap();
|
||||
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["units"], json!("Millimeters"));
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("units".into(), json!("Points"));
|
||||
let t = dialog_texts(&mut app);
|
||||
assert!(shows(&t, "595.276 × 841.89 pt"), "the chosen entry in points: {t:?}");
|
||||
assert!(shows(&t, "8.5 × 11 in"), "the other entry keeps its inches: {t:?}");
|
||||
assert!(!shows(&t, "612 × 792 pt"), "the inches entry isn't turned into points: {t:?}");
|
||||
// Clicking the inches card makes it the chosen one, in its own units.
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut draw = |app: &mut VectorcraftApp, ui: &mut Ui| crate::dialogs::show(app, ui.ctx());
|
||||
frame_events(&ctx, &mut app, vec![], &mut draw); // the window sizes itself here
|
||||
let inches = text_rect(&frame_events(&ctx, &mut app, vec![], &mut draw), "8.5 × 11 in").center();
|
||||
click(&ctx, &mut app, inches, &mut draw);
|
||||
let d = app.ui.dialog.as_ref().unwrap();
|
||||
assert_eq!(d.fields["units"], json!("Inches"));
|
||||
assert_eq!((d.fields["width"].clone(), d.fields["height"].clone()), (json!(612.0), json!(792.0)));
|
||||
}
|
||||
|
||||
/// A saved preset keeps the units it was saved in too, whichever units the dialog is showing.
|
||||
#[test]
|
||||
fn saved_cards_keep_their_own_units() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
run(&mut app, "file.newPresets.save", json!({"name": "A4 mm", "width": "210 mm", "height": "297 mm", "units": "Millimeters"}));
|
||||
app.run("file.newDialog", json!({})).unwrap();
|
||||
let d = app.ui.dialog.as_mut().unwrap();
|
||||
d.fields.insert("category".into(), json!("Saved"));
|
||||
d.fields.insert("units".into(), json!("Points"));
|
||||
let t = dialog_texts(&mut app);
|
||||
assert!(shows(&t, "210 × 297 mm") && !shows(&t, "595.276 × 841.89 pt"), "the saved preset keeps millimetres: {t:?}");
|
||||
}
|
||||
|
||||
/// Clicking the card that is already chosen leaves it chosen, in the units the dialog is showing:
|
||||
/// the entry's own units still say which card it is.
|
||||
#[test]
|
||||
fn clicking_the_chosen_recent_card_keeps_it_chosen() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
run(&mut app, "file.new", json!({"width": "8.5 in", "height": "11 in", "units": "Inches"}));
|
||||
app.run("file.newDialog", json!({})).unwrap();
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("units".into(), json!("Points"));
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut draw = |app: &mut VectorcraftApp, ui: &mut Ui| crate::dialogs::show(app, ui.ctx());
|
||||
frame_events(&ctx, &mut app, vec![], &mut draw); // the window sizes itself here
|
||||
let card = text_rect(&frame_events(&ctx, &mut app, vec![], &mut draw), "612 × 792 pt").center();
|
||||
click(&ctx, &mut app, card, &mut draw);
|
||||
let t = dialog_texts(&mut app);
|
||||
assert!(shows(&t, "612 × 792 pt") && !shows(&t, "8.5 × 11 in"), "the card stays chosen in points: {t:?}");
|
||||
}
|
||||
|
||||
/// Recent keeps one entry per size and units, so two entries can be one size in two units: the
|
||||
/// chosen card is the entry the fields were filled from, not every card of that size.
|
||||
#[test]
|
||||
fn recent_entries_of_one_size_in_two_units_stay_apart() {
|
||||
let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default());
|
||||
// Both are 612 × 792 pt; Recent lists the points one first, which the dialog opens on.
|
||||
run(&mut app, "file.new", json!({"width": "8.5 in", "height": "11 in", "units": "Inches"}));
|
||||
run(&mut app, "file.new", json!({"width": "612 pt", "height": "792 pt", "units": "Points"}));
|
||||
app.run("file.newDialog", json!({})).unwrap();
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("units".into(), json!("Inches"));
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let mut draw = |app: &mut VectorcraftApp, ui: &mut Ui| crate::dialogs::show(app, ui.ctx());
|
||||
frame_events(&ctx, &mut app, vec![], &mut draw); // the window sizes itself here
|
||||
let texts = frame_events(&ctx, &mut app, vec![], &mut draw);
|
||||
let mut cards: Vec<egui::Rect> = texts.iter().filter(|(t, _)| t == "8.5 × 11 in").map(|(_, r)| *r).collect();
|
||||
cards.sort_by(|a, b| a.center().x.total_cmp(&b.center().x));
|
||||
assert_eq!(cards.len(), 2, "both cards read in inches: {texts:?}");
|
||||
// The right-hand card is the inches entry: choosing it leaves the points entry in points.
|
||||
click(&ctx, &mut app, cards[1].center(), &mut draw);
|
||||
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["units"], json!("Inches"));
|
||||
let t = dialog_texts(&mut app);
|
||||
assert!(shows(&t, "612 × 792 pt"), "the points entry keeps its points: {t:?}");
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
# Roadmap: milestones and what's next
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-03 · **Change:** minor (OpenType panel offers font-defined Stylistic Sets; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (New Document's units belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -28,6 +28,7 @@ M7 type: Touch Type moves a right-to-left character along its line and up from i
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen preset; Recent and Saved cards keep the units their document or preset was made in, and the built-in tabs still follow the chosen units (#2078). Scores and estimates unchanged. |
|
||||
| 2026-11-03 | minor | M1: Enclosing Lasso provides whole-object enclosure selection as an add-on with no default shortcut or Basic toolbar slot; estimates unchanged. |
|
||||
| 2026-11-03 | minor | New gradients use CMYK default stops in CMYK documents, including Gradient tool creation. Scores and estimates unchanged. |
|
||||
| 2026-10-30 | minor | M4: G9: `.ai`/EPS editing data: a blend takes the transparency (opacity, blend mode, knockout) in its state block after its record, so its steps knock each other out as the page draws them; a user's file comes in 0.6% from its page instead of 1.3%. Scores and estimates unchanged. |
|
||||
@@ -158,6 +159,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged. |
|
||||
| 2026-11-03 | minor | M7: the OpenType panel offers the selected font's available Stylistic Sets with custom or numbered names; estimates unchanged. |
|
||||
| 2026-11-03 | minor | M1: Enclosing Lasso adds freehand whole-object selection under Object › Plug-ins; estimates unchanged. |
|
||||
| 2026-11-02 | minor | Font-family fields in Character, Properties and Control step selected text with the wheel (#5253), with one undo step per notch; scores and estimates unchanged. |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (Document Tools add-on: Batch Trace Folder, #4921; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (New Document's units belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -23,6 +23,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen preset, as the public page lists the pane's options for the selected preset; the chosen card shows them, every other Recent and Saved card keeps the units its document or preset was made in, and the built-in tabs still follow the chosen units (#2078). Scores and estimates unchanged. |
|
||||
| 2026-11-04 | minor | Document Tools add-on (a VectorCraft addition): Batch Trace Folder under Object › Plug-ins (`addon.document.batchTraceFolder`, #4921); evidence added; scores unchanged. |
|
||||
| 2026-11-04 | minor | Object › Expand turns selected symbol instances into their art as Break Link places it, one level deep, with the Expand dialog's Fill and Stroke reaching that art. Scores and estimates unchanged. |
|
||||
| 2026-11-03 | minor | The OpenType panel offers the selected font's stylistic sets by custom or numbered name, and allows several to be active. Scores and estimates unchanged. |
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (Document Tools add-on: Batch Trace Folder under Object › Plug-ins, #4921; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (New Document's units belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -423,6 +423,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen document, as the pane's options are listed "for the selected preset" ([public source](https://helpx.adobe.com/illustrator/desktop/add-and-import-files/start-a-new-file/create-and-save-custom-document-presets.html)); the chosen card shows them, every other Recent and Saved card keeps the units its document or preset was made in, and the built-in tabs still follow the chosen units (#2078); scores and estimates unchanged |
|
||||
| 2026-11-01 | minor | Object › Image Trace › Batch Trace Folder asks for a source and a destination folder and traces each image into it (#4921); scores and estimates unchanged |
|
||||
| 2026-11-01 | minor | Edit › Copy and Cut take the selected ruler guides, with the objects or alone; pasting puts them on the layer new art goes to, moved as the objects are (alone: where they were), Paste in Place onto the active artboard and Paste on All Artboards onto each (#3226); scores and estimates unchanged |
|
||||
| 2026-11-04 | minor | Area type: Align Top / Center / Bottom / Justify Vertically buttons in the Properties panel (Paragraph section) and the Control panel set its vertical alignment in the frame, as Area Type Options does; turned off for frames with rows or columns and threaded frames (#3759); scores and estimates unchanged |
|
||||
|
||||
Reference in New Issue
Block a user