Commit Graph
4827 Commits
Author SHA1 Message Date
aiongg 60f2c597a5 macOS: Settings… is in the app menu
The macOS menu bar shows Settings… (app.preferences, Cmd+K) in the application menu after About and leaves it out of Edit. The app menu labels go through the interface language. Windows, Linux and the web keep Edit › Preferences….
2026-10-11 02:34:49 +00:00
aiongg ff34ad3d14 Integration: INDD import follows indd-utils main
The indd dependency tracks indd-utils' main branch; Cargo.lock pins 68308f6f021a58901e82db4659705b8b96939b3b (was 9cf456d9). The API is unchanged: designcraft-engine builds as it was.
2026-10-11 02:33:11 +00:00
aiongg f12b3443a0 Merge #427: Text: Optical kerning spaces pairs from their outlines
Conflicts:
- Cargo.lock: designcraft-compose depends on both unicode-script (#427)
  and unicode-segmentation (next).
- ROADMAP.md: the optical kerning progress-log line goes above next's two
  2026-10-11 lines. Status line keeps next's Last reviewed date and names
  both changes.
- docs/gaps.md, docs/typography-parity.md: same status-line merge.
2026-10-11 02:30:53 +00:00
aiongg edcb3d2036 Merge font-search: Return and Escape in the font menu stay in the menu, never reach the dialog under it
No conflicts; crates/ui-egui/src/panels/mod.rs merged automatically.
2026-10-11 02:25:28 +00:00
KnottyDyes 8518ade582 Fonts: discover Linux user fonts in XDG_DATA_HOME
Linux font discovery ignored XDG_DATA_HOME and always scanned ~/.local/share/fonts.

Use XDG_DATA_HOME/fonts when the base path is absolute, otherwise keep the default. Preserve ~/.fonts and system directories, with environment-independent regression tests for directory selection.
2026-10-10 20:21:31 -06:00
aiongg 4b3dca6fff Integration: fonts listed by the platform keep their name aliases (#362) 2026-10-11 02:21:18 +00:00
aiongg 5e51392ac4 Merge mac-font-activation: macOS fonts that font services and managers activate are listed (#261, #327)
Conflict in ROADMAP.md: kept both 2026-10-11 progress-log lines (New
Document from next, then the font activation line).
2026-10-11 02:20:28 +00:00
aiongg cffff885bb Integration: GREP lookbehind overlay test passes the drop-cap end (#425)
next's overlays() takes the drop cap's end as a fifth argument; the test from #316 calls it with 0, like the other overlay tests.
2026-10-11 02:20:00 +00:00
aiongg 037771057e Merge #316 update: GREP styles with a pattern that can't compile are rejected, and imports warn
Conflicts:
- engine cmd/file.rs, cmd/interchange.rs: kept next's file.open and
  file.openIdml docs (content detection, INDD conversion, package parts)
  and added "GREP styles whose pattern can't compile" to their warnings.
  open_idml keeps next's conversion and import-report warnings and appends
  grep_style_warnings after the font warnings.
- engine cmd/style.rs: style.paragraph.create/edit docs combine next's
  startAt and kinsoku notes with the grepStyles rule. create_para and
  edit_para keep next's set_json_over, continue_numbering and
  explicit_default_kinsoku, then call check_grep_styles. The branch's
  grep_style_error, check_grep_styles and grep_style_warnings follow
  explicit_default_kinsoku. Kept next's delete_tests and
  swatch_options_tests; grep_style_tests goes at the end of the file.
- ui-egui dialogs.rs: kept next's style_section_edit tests and added the
  branch's bad-GREP-pattern test.

confirm_paragraph_style_options, grep_error and the dialog status line
merged without conflicts; next had not changed the OK arm they replace.
2026-10-11 02:19:10 +00:00
aiongg 3bda745a52 Tools: live corners round a frame's corners by dragging
A selected, unlocked rectangle frame at least 40 px on screen shows the
yellow widget near its top-right corner. Clicking it shows a diamond at
each corner. Dragging a diamond along its edge sets the size of all four
corners as one undo step (Shift: that corner only), clamped to half the
shorter side. Alt-click steps that corner's shape; Shift+Alt-click steps
every corner. Escape, a click on empty canvas, another selection or
another tool ends corner editing. Positions follow the frame's transform.

object.cornerOptions takes corners: four {shape, size} entries. Tools
gain Action::Handled and the LiveCornerWidget/LiveCornerDiamond overlays,
drawn by the canvas in the live_corner theme token. Fixes #186.
2026-10-11 02:16:21 +00:00
aiongg cf0ff4a034 Merge group-nested-panic: Objects: group siblings inside a group; refuse mixed levels and spreads
Conflicts in crates/engine/src/cmd/object.rs:
- Helpers: kept next's opt_u64, siblings_mut(d, spread, parent), reorder,
  set_layer_deep and set_layer, then added the branch's GroupPlan,
  group_plan, GROUP_SAME_LEVEL and can_group. The branch's
  siblings_mut(d, &GroupPlan) is dropped; group() calls next's helper as
  siblings_mut(d, plan.spread, &plan.parent).
- Tests: kept next's reorder_tests and the other test modules next added,
  followed by the branch's group_tests module.

group() and ungroup() were unchanged on next, so group() is the branch's
version. cmd/mod.rs (CANT_GROUP_SELECTION, selection_reason) and lib.rs
(execute_unguarded) merged without conflicts.
2026-10-11 02:15:58 +00:00
aiongg c537f1ae46 UI: Return and Escape in the font menu stay in the menu, never reach the dialog under it
Every font field's menu (Control bar, Contextual Task Bar, Properties > Character,
Character and Glyphs panels, Paragraph/Character Style Options, Find/Replace Font)
keeps its search focused and open on a click and filters as you type. In a dialog,
Return picked the highlighted family and also pressed OK, and Escape closed the
menu and cancelled the dialog: the menu now consumes the keys it uses. The
drawn font fields report themselves as combo boxes to screen readers.
2026-10-11 02:10:36 +00:00
aiongg aa6446336b Paragraph Style Options: after a later step fails, OK edits the style it created
Once style.paragraph.create (or edit with a rename) succeeds, the dialog
switches to editing that style, so when export tagging then fails the
dialog stays open with the error and a second OK edits the style instead
of creating another.
2026-10-11 01:58:37 +00:00
aiongg 80b9b1d037 macOS: the window buttons sit centred in the title bar
On macOS the application bar is the window's title bar. AppKit centres
the traffic lights in the standard 28 pt title-bar band and they cannot
be moved without unsafe code, so the bar is 28 pt there: the lights sit
vertically centred in it, and the bar's content starts after them with
the same 8 pt gap the lights keep from the top. The Home button shrinks
to 22 pt to keep a margin in the shorter bar.

The bar's frame margin leaves room for the panel separator, so the
content row is the full bar height and the title and controls share one
centre line on every platform.

Fixes #333.
2026-10-11 01:58:12 +00:00
aiongg ae50689e27 GREP: styles with a pattern that can't compile are rejected, and imports warn
style.paragraph.create, style.paragraph.edit and type.para return the
compile error (bad GREP: ...) for a GREP style pattern that can't compile
and change nothing. Paragraph Style Options shows the error under the
pattern as it is typed, and on OK keeps the dialog open on the GREP Style
section with the command's error.

Opening an IDML or native document keeps such a style and reports a
warning naming the style (or paragraph) and the pattern; composition
keeps skipping it. Adds a lookbehind GREP style test.
2026-10-11 01:51:51 +00:00
aiongg 833c0ec8d6 Fonts: macOS fonts that font services and managers activate are listed
The system font scan also reads the font files CoreText has available
(core-text's collection of all available fonts, safe API), so fonts that
Adobe Fonts, RightFont and other font managers register from their own
folders are cataloged. Files the font folders already hold are read once;
paths that lead to no file are skipped. FontDb::global serves the desktop
app and designcraft-cli alike; the scan stays in the background.

Fixes #261, #327.
2026-10-11 01:50:32 +00:00
aiongg 21a230e426 Merge pdf-effects-wrap: PDF: items with soft effects keep their text wrap 2026-10-11 01:47:49 +00:00
skylar taylor-barrick 16a7365701 Merge pull request #409 from skylartaylor/codex/ui-suite-integration-20261010
Adopt shared panel docking and preserve workspace commands
2026-10-10 19:46:47 -06:00
aiongg c014832572 Objects: group siblings inside a group; refuse mixed levels and spreads
Grouping objects that were not top-level items of the first object's
spread panicked (index out of bounds), through object.group, Group on a
content selection, and states.create. Objects nested at different levels
or on different spreads were silently left out of the new group.

Objects that share a spread and a parent group now group into a nested
group in that parent, keeping their stacking order and position. Objects
on different spreads or at different levels return an error and the
document is unchanged, as do objects inside a multi-state object. Group
is disabled in the menu for a selection it can't group; a call that
names its ids still runs whatever is selected.

Fixes #412
2026-10-11 01:46:19 +00:00
aiongg 814102ed35 Layout: items with soft effects keep their text wrap
PDF export replaces objects with soft effects by images of their
appearance. The image item carried no text wrap, so text recomposed
for the export ran under the object. Each rasterized object with a
wrap now stays in the export copy as a nonprinting stand-in that keeps
the wrap of the frame, its placed graphic and its grouped items, with
its text, form field, button and media removed.
2026-10-11 01:39:19 +00:00
Abdelrehman Fouad 62faa8eee2 Text: Optical kerning spaces pairs from their outlines
Optical kerning was treated exactly like Metrics: the font's kern pairs
and nothing else, so text set with Optical in InDesign came out wider,
rewrapped and went overset in tightly fitted frames.

Now the font's pairs are turned off for Optical text and each pair is
spaced from its outlines (crates/compose/src/optical.rs): every glyph's
ink is sampled into 28 bands across the em, the pair's mean and smallest
ink gap over the bands both glyphs ink are compared with the font's
stem-to-stem gap (the pair nn, or HH then oo), and the pair moves 60% of
the way towards it, keeping 30% of that gap and moving at most -0.12 or
+0.06 em. Latin, Greek and Cyrillic letters, digits and Western
punctuation take part; spaces, marks, missing glyphs, right-to-left
runs, upright and tate-chu-yoko glyphs and pairs across a fallback font
keep their font spacing. Profiles and references are cached, bounded.

Tests: AV, To and r. close up and nn stays; HH closes up under Optical
but not Metrics (fails on main); every change on a pangram stays within
the bounds and spaces keep their width; profile, gap, adjustment and
character-class unit tests.

Docs: typography parity Kerning row and remaining effort, gap 4,
ROADMAP milestone 6 and progress log.

Fixes #181.
2026-10-11 03:25:01 +02:00
aiongg 2d67dc8737 Merge #83 update: Em Box Height follows the font's typo box or cap height
# Conflicts:
#	crates/fonts/src/vertical.rs
2026-10-11 01:15:03 +00:00
aiongg 0b72584465 Layout: Em Box Height follows the font's typo box or cap height
A font's em box is its BASE em box; else it tops at the OS/2 typo
ascender when the typo ascender and descender span exactly one em; else
it is centred on half the cap height (OS/2 sCapHeight, else the H
glyph's top), 0.5 em + cap / 2 above the baseline; else 0.88 em. The Em
Box Height first baseline, vertical text and declared_em_box all use
this one em box; declared_em_box is None only for the 0.88 em fallback.
2026-10-11 01:12:08 +00:00
aiongg 16a17604df Merge #360 update: span columns in a one-column frame add no span space
# Conflicts:
#	crates/compose/src/lib.rs
2026-10-11 01:11:47 +00:00
aiongg 91a01a6774 Compose: span columns in a one-column frame add no span space 2026-10-11 01:09:28 +00:00
aiongg e3bf0e745c Merge #413: Fonts: a pan-CJK font's family name decides its font menu group 2026-10-11 01:02:11 +00:00
aiongg f9985611bc Merge #411: Undo: a command that runs another is one undo step 2026-10-11 01:02:10 +00:00
con3codeandClaude Opus 5.5 65f0b37920 Fonts: system_fonts_cataloged builds on wasm
`cfg!` doesn't remove the expression, and `cataloged` only exists off
wasm, so `cargo xtask wasm` failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 10:00:17 +09:00
aiongg ef65f39b93 Integration: FontDb::system_fonts_cataloged builds on wasm (#394) 2026-10-11 00:53:49 +00:00
skylar taylor-barrick 2bdb0ea01d UI.9: recover saved docking metadata and declare frontend MSRV 2026-10-10 18:52:20 -06:00
con3codeandClaude Opus 5.5 52ffb3c68a Fonts: a pan-CJK font's family name decides its font menu group
A font of a pan-CJK family lists the code pages of every language it
covers. With no `meta` languages and no CJK family name, the first group
in menu order won, so a Simplified Chinese face such as "… Noto Sans CJK
SC" was listed under Japanese.

When a font lists several CJK code pages, the region tag in its family
name (JP; SC, CN, GB; TC, HK, TW, MO, HC; KR — a whole word in capitals)
now decides, if the font lists that language. Fonts with one CJK code
page, or none, are grouped as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013phQ3ekq6uGBEWD6FjFYG2
2026-10-11 09:50:51 +09:00
aiongg 54b9a4d314 Merge mojikumi-base: CJK: custom mojikumi tables without a base set apply their rules
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-11 00:47:10 +00:00
aiongg 11631cde12 CJK: custom mojikumi tables without a base set apply their rules 2026-10-11 00:42:47 +00:00
aiongg 12ea53f10e Merge #404: SVG: a font family named in any case finds the installed font 2026-10-11 00:40:54 +00:00
sanyamsingh001andCodex 79601ed48d docs: avoid unrelated roadmap changes
Co-Authored-By: Codex <codex@openai.com>
2026-10-11 10:35:11 +10:00
aiongg f1b4b0cf49 Merge #394 update: UI: CJK interface text from installed fonts, on the Latin baseline
# Conflicts:
#	crates/ui-egui/src/theme.rs
2026-10-11 00:35:02 +00:00
noah1400andClaude Opus 5.5 ad173006f7 Undo: a command that runs another is one undo step (#406)
Cut, Duplicate, Paste in Place, the Arrange commands and pasting text
run a second command inside themselves, and both recorded an undo
step: the second Undo did nothing. Only the outer command records now.
A command that fails after changing the document records its step
too; a script that stopped at a bad step left changes that could not
be undone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:34:43 +02:00
aiongg d666f0e312 Merge #393 update: UI: no crash on textures past the GPU limit
# Conflicts:
#	crates/ui-egui/src/canvas.rs
2026-10-11 00:32:52 +00:00
aiongg ee0b462446 Merge #309 update: Snap: smart guides beat the baseline grid; a box centres between two others 2026-10-11 00:32:23 +00:00
aiongg 0946f5931d Merge #305 update: Preserve explicit nullable text defaults when reopening documents
# Conflicts:
#	ROADMAP.md
2026-10-11 00:32:22 +00:00
aiongg ce144a614a Merge remote-tracking branch 'upstream/main' into next
# Conflicts:
#	ROADMAP.md
2026-10-11 00:30:35 +00:00
skylar taylor-barrick a77bf8bff5 UI.9: reconcile upstream before shared UI landing 2026-10-10 18:00:07 -06:00
aiongg ecdb9b2dc2 Integration: rustfmt after merging #389-#392, indd 8 and 9 2026-10-10 23:52:24 +00:00
aiongg 9d717ea417 Merge cjk-run-baseline: CJK: smaller runs align to the line's em box centre
Conflicts:
- crates/fonts/src/fontdb.rs, vertical.rs: next's em cache
  ((top, bottom), declared) with FontFace::declared_em_box and the ICF
  cache/icf_box kept; the branch's base_em_box accessor dropped (same
  value). em_box's fallback chain takes the branch's let em form.
- crates/compose/src/lib.rs: next's cjk_icf_box and the branch's
  alignment_em_box, which reads declared_em_box.
- crates/compose/src/tests.rs: both tests. next applies character
  alignment only under the Japanese composers (5dc8383a), so the branch's
  smaller_cjk_run_aligns_to_the_line_em_box_centre runs under japanese();
  next's cjk_em_center_alignment_moves_small_characters measures centres
  on the alignment em box (declared, else 0.88/-0.12 em).
2026-10-10 23:49:04 +00:00
aiongg 778a270f48 Merge smallcap-tounicode: PDF: small caps and substituted figures keep their text
Conflicts:
- crates/pdf/src/text.rs run_text: the branch's two generated_text
  branches first, then #392's kashida branch (no text), then the cmap
  fallback for other inserted glyphs.
- crates/compose/src/lib.rs: next's kashida PlacedGlyph (with dx) gets
  generated_text: None.
- crates/compose/src/shape.rs hyphen_after: next's rendered_char/moji
  resets and generated_text = None.
- crates/compose/src/ruby.rs: next's ruby module (#363); the branch's
  edit to the old ruby set() has nothing to apply to.
- crates/pdf/src/tests.rs: tests from both.

Also, so the merge compiles: next's ruby (ruby.rs annotate) and kenten
(kenten.rs shape_mark) PlacedGlyph literals take generated_text: None;
they map back through the font like other inserted glyphs. Kanji page
numbers, composite-font note numbers and fallback-face label segments
go through shape_segment's replacement and list labels through
prepend_label, so they carry their generated text.
2026-10-10 23:47:37 +00:00
aiongg 8806a223fa Integration: shatai glyphs in right-to-left lines draw inside the line span (#392)
next's shatai path draws a slanted glyph on its own through tagged_run,
which opens a Span; inside #392's right-to-left line span that nested
marked content and krilla panicked ("can't start marked content twice")
in tagged exports. While a line span is open, the glyph is drawn with
run like the line's other runs. Test:
shatai_glyphs_in_right_to_left_lines_stay_in_the_line_span (panicked
before).
2026-10-10 23:46:28 +00:00
aiongg 93924a00b3 Merge pdf-rtl-text: PDF: right-to-left text extracts in reading order
No conflicts.
2026-10-10 23:45:02 +00:00
aiongg a386c73d82 Integration: PDF crop box is part of an asset's identity; clippings keep anchored graphics (#391)
Asset::same_file compares pdf_crop (#362) with type, page and bytes: one
PDF page shown with two crop boxes keeps two assets, so add_asset,
adopt_asset, insert_asset (IDML/INDD import) and the load/save merge
never point a placement at another crop. Test in
identical_files_share_one_asset.

The copy clipping (edit.rs clip_doc) keeps the assets used_assets finds
in it, so graphics anchored in copied text, graphic table cells (#379),
notes and media posters keep their files; it collected only graphics on
the copied items before. Test:
copied_text_frames_keep_the_graphics_anchored_in_their_text.
2026-10-10 23:44:15 +00:00
aiongg cfd57cb3ca Merge asset-dedupe: Assets: one asset per image, and saves leave out unused ones
Conflicts:
- crates/engine/src/cmd/{datamerge/fill.rs, file.rs, mathexpr.rs,
  media.rs, table.rs}: the branch's add_asset calls, with next's Asset
  fields (pdf_crop, pdf_box) through ..Default::default(); file.place
  keeps next's PdfCrop-aware asset (crop_pdf) and adds it with add_asset;
  the data merge graphic keeps next's wrap field.
- crates/format/src/lib.rs: load runs next's upgrade(doc, version), then
  merge_duplicate_assets (zip and legacy JSON); tests from both, with the
  round-trip test placing its asset (saves drop unused ones).
- crates/idml/src/import.rs graphic(): the branch's linked_assets reuse and
  insert_asset, with next's PDF page and PdfCrop on the asset and the
  graphic's text wrap (#389 integration) in the shared graphic closure.
  linked_assets is keyed by (path, page, crop), so placements of one PDF
  showing different pages or crop boxes keep separate assets.

Also, so the merge compiles: Asset/Graphic literals in the branch's tests
(crates/doc/src/assets.rs, format, engine links.rs) take next's pdf_crop,
pdf_box and wrap fields.
2026-10-10 23:41:30 +00:00
aiongg 27312c1cf9 Integration: feathers inherit from object styles; merge closes its functions (#390)
The merge of idml-feathers left overlay() in crates/idml/src/import.rs and
imports_and_round_trips_text_wrap_side_and_contour_type in tests.rs
without their closing braces (both sides added code at the same place);
this closes them.

Test: feathers_come_from_the_object_style_unless_its_category_turns_them_off
(gradient and directional feathers come from the style through
with_style; EnableGradientFeather="false" in
ObjectStyleObjectEffectsCategorySettings drops the style's gradient
feather; the item's own Applied="false" wins).
2026-10-10 23:38:21 +00:00