diff --git a/crates/ui-egui/src/dialogs/command.rs b/crates/ui-egui/src/dialogs/command.rs index 3f591ccd30..6656b45bf5 100644 --- a/crates/ui-egui/src/dialogs/command.rs +++ b/crates/ui-egui/src/dialogs/command.rs @@ -629,6 +629,43 @@ mod tests { assert_eq!(offset(&mut h), -5.0); } + /// In a document in picas, Text Wrap Options › Offset reads a bare number as the other length + /// fields in picas do: in points with Preferences › Units › Numbers Without Units Are Points on + /// (the default), in picas with it off. A typed unit is read as typed either way. + #[test] + fn text_wrap_offset_in_picas_follows_numbers_without_units_are_points() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 400, "height": 400})).unwrap(); + app.run("document.setUnits", json!({"units": "picas"})).unwrap(); + let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap(); + app.run("select.set", json!({"ids": [id]})).unwrap(); + app.run("object.textWrap.make", json!({})).unwrap(); + let mut fonts = false; + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1100.0, 900.0)).build_ui_state( + move |ui, app: &mut VectorcraftApp| { + if !std::mem::replace(&mut fonts, true) { + crate::theme::install_fonts(ui.ctx()); + return; + } + crate::dialogs::show(app, ui.ctx()); + }, + app, + ); + let apply = |h: &mut egui_kittest::Harness<'_, VectorcraftApp>, text: &str| { + crate::menus::invoke(h.state_mut(), "object.textWrap.options", json!({})); + h.run_steps(3); + enter_offset(h, text); + assert!(h.state().ui.dialog.is_none(), "{text}: OK applied it"); + h.state_mut().session.execute("object.textWrap.options", &json!({})).unwrap()["offset"].as_f64().unwrap() + }; + assert_eq!(apply(&mut h, "10"), 10.0, "on by default: a bare number is in points"); + assert_eq!(apply(&mut h, "2p6"), 30.0, "picas and points as typed"); + assert_eq!(apply(&mut h, "-1in"), -72.0, "a typed unit wins"); + crate::widgets::set_bare_numbers_are_points(&h.ctx, false); + assert_eq!(apply(&mut h, "10"), 120.0, "off: a bare number is in picas"); + assert_eq!(apply(&mut h, "-12 pt"), -12.0, "a typed unit wins"); + } + /// Clicks the dialog's OK button with the pointer, the press and the release in frames of /// their own. fn click_ok(h: &mut egui_kittest::Harness<'_, VectorcraftApp>) { diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 5ae03e1093..6cd911988c 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1286,7 +1286,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur A text wrap object's Offset may be negative as well as positive ([the help page](https://help.adobe.com/archive/en_US/illustrator/cs4/illustrator_cs4_help.pdf#page=307)). A negative Offset (to -1000 pt) shrinks the wrap object by that distance, measured from each edge itself and from the edges of its holes, so lines beside it, above it and below it run that far into it, and an object narrower than twice the distance no longer moves text aside. With Invert Wrap, a negative Offset keeps the text that far inside the object. These are VectorCraft's own rules for the shape of the shrunk object. Text Wrap Options, `object.textWrap.make` and `object.textWrap.options` and the MCP `text_wrap` tool take the negative value, and layout uses it (`crates/text/src/layout/region.rs` tests, `cmd::textwrap::tests::text_wrap_options_negative_offset_reflows_and_round_trips`). In area type of a shape other than a rectangle, each line's whole band, ascent to descent, stays inside the frame: where an edge pinches in within the band, the line ends at the narrowest point, and a line runs beside a hole that starts and ends within its band, not across it. In area type of any shape, a line also stays clear of a text wrap object that reaches into any part of its band, and inside an Invert Wrap object over its whole band (`crates/text/src/layout/region.rs` tests). With Invert Wrap, the spans a line keeps inside a wrap shape of many parts (a comb of 500 teeth) are found by stepping through the line's spans and the shape's spans once for each piece of the band, so the work grows with the number of spans, not with its square (`crates/text/src/layout/region.rs` tests). - Text Wrap Options › Offset is a distance field in the document's units: a bare number is in those units, a typed unit ("12 pt") is read as typed, and OK sends points. An Offset typed outside -1000 to 1000 pt, VectorCraft's own range for the command, or text that doesn't read, is refused: the field flashes and the dialog stays open, whether Enter or a click on OK ends the entry; in every dialog drawn by the shared dialog window, a click on OK no longer confirms it when the distance field it takes the focus from refuses its text (`dialogs::command::tests::text_wrap_offset_field_takes_document_units_and_refuses_values_outside_its_range`). Behavior reference: [the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/enter-values-in-panels-and-dialog-boxes.html). + Text Wrap Options › Offset is a distance field in the document's units: a bare number is in those units, a typed unit ("12 pt") is read as typed, and OK sends points. In a document in picas, a bare number follows Preferences › Units › Numbers Without Units Are Points as the other length fields do: it is in points while that preference is on (the default) and in picas while it is off (`dialogs::command::tests::text_wrap_offset_in_picas_follows_numbers_without_units_are_points`). An Offset typed outside -1000 to 1000 pt, VectorCraft's own range for the command, or text that doesn't read, is refused: the field flashes and the dialog stays open, whether Enter or a click on OK ends the entry; in every dialog drawn by the shared dialog window, a click on OK no longer confirms it when the distance field it takes the focus from refuses its text (`dialogs::command::tests::text_wrap_offset_field_takes_document_units_and_refuses_values_outside_its_range`). Behavior reference: [the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/enter-values-in-panels-and-dialog-boxes.html). The Character panel's Small Caps, Superscript and Subscript buttons and the panel menu's items of the same names turn small caps and the superscript or subscript position on and off for the selected type, or for the text the Type tool has selected (`text.setFormat` or `text.setRangeStyle` `{smallCaps, position}`), in Document Setup's proportions. Turning Superscript on turns Subscript off, and turning Subscript on turns Superscript off. A button or item shows as on when the first selected character (at a caret, the character before it) has its attribute. The Character panel's Anti-aliasing Method dropdown, under Character Rotation, sets how the edges of the selected type objects are drawn as pixels (`text.setFormat {antiAlias}`), for the whole object, with each frame of a thread keeping its own method and graph labels keeping it when the graph is drawn again, on the canvas, in raster exports and when the type is rasterized. VectorCraft defines the methods: Sharp, the default, draws edges as before; None paints a pixel only where the type covers at least half of it; Crisp shows a pixel covered by a share c at `2c - 0.5`, and Strong shows it at `2c`, each kept between 0 and 1. SVG, PDF and EPS export are unchanged. Scores and hours unchanged. The OpenType panel's Stylistic Alternates and Titling Alternates checkboxes turn `salt` and `titl` on and off for the selected type, and its Figure menu lists Default Figure, Tabular Lining, Proportional Lining, Proportional Oldstyle and Tabular Oldstyle; Proportional Lining sets `pnum` and `lnum` and turns `tnum` and `onum` off, Tabular Lining turns `pnum` off and keeps `lnum`, Proportional Oldstyle turns `lnum` off and keeps `pnum`, and Default Figure and Tabular Oldstyle turn `pnum` and `lnum` off. Behavior reference: [Format text with OpenType features](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/format-text-with-opentype-features.html) and [Use swashes, titling alternates, or stylistic alternates](https://helpx.adobe.com/illustrator/desktop/design-with-text/special-characters-glyphs/use-swashes-titling-alternates-or-stylistic-alternates.html) (public documentation). Tests: `panels::opentype::tests`.