Commit Graph
2291 Commits
Author SHA1 Message Date
aiongg c124e0ebcf Integration: auto-size tests that keep the top edge name the top-centre reference point (#180 x next's centre default) 2026-10-12 20:00:34 +00:00
skylar taylor-barrick 17cf5b4e91 test(recovery): make failed republishing fixtures deterministic
Force actual failed recovery publication at the reserved destination so privileged runners exercise the intended retention path. Keep the normal writer, publication order and existing assertions; enable these fixtures across platforms.

Validation: all six local gates and the FreeBSD root VM workspace build/tests.

PR #627.
2026-10-12 13:57:37 -06:00
aiongg 38bdc19232 Merge #180: text frame auto-size grows and shrinks frames to fit their text
text-autosize 60551322.

Conflict: crates/doc/src/item.rs: next's reference-point doc and default auto_size_ref 4 (centre, as IDML leaves it) plus the branch's minimum-size and No Line Breaks fields
Conflict: crates/engine/src/lib.rs: autosize pass before next's record_undo_step on the success path; bump_revision for next's global revisions
Conflict: crates/engine/src/cmd/interchange.rs: next's grep_style_warnings and .indd comment plus the branch's autosize::apply on import
Conflict: crates/engine/src/cmd/object.rs: branch's textFrameOptions params doc with next's firstBaseline values
Conflict: ROADMAP.md: progress log both
Conflict: docs/gaps.md: next's optical kerning wording with the branch's auto-size note on #180
2026-10-12 19:57:02 +00:00
aiongg 4e7b33607e Pages panel: double-clicking a parent shows that parent; parents are identified by id
- layout.parents.edit takes `parent` (id, full name, or a prefix only one
  parent has) and asks the canvas to fit that parent's spread; turning
  editing on without one shows the first parent. The result names the
  parent shown.
- Commands resolve parents by id, then full name, then a unique prefix.
  Unknown or ambiguous names are errors, so a typo no longer clears a
  page's parent; null or "[None]" clears it.
- Pages panel: only the row of the parent the canvas shows is selected;
  rows, drag payloads and the Apply Parent menu carry the parent id.
  Parent rows show rendered thumbnails of the parent spread, cached by
  document revision like page thumbnails.
- Delete All Guides on a parent acts on the parent the canvas shows.

Fixes #624.
2026-10-12 19:49:59 +00:00
hasan-sdaif d8d66a2757 Complete the Arabic (العربية) catalog: every missing key translated
ar.rs covered 1,456 of the interface strings; the newer catalogs (it, ja,
pt-br, uk) had since grown to a 1,690-key union. This adds the 238 keys
Arabic was missing, in the same clean-room Modern Standard Arabic and
InDesign-style vocabulary the file already uses (كائن مرسّى، مسار مغلق،
خطوة وتكرار، الفحص المسبق، دمج البيانات، الكائن الأصل…):

- the whole menu-path family (نص/…، كائن/…، جدول/…، نافذة/…) — Type on a
  Path, Track Changes, Story Direction, Transform Again, Pathfinder…
- the special-character and white-space inventory (شرطة كاملة، مسافة
  شعرية، محرف نهاية الفقرة، علامات الاقتباس المستقيمة…) and their
  symbols (رمز حقوق النشر، رمز العلامة التجارية…)
- data merge (سجل، سجلات في الصفحة، تحديد مصدر بيانات…), EPUB/HTML/XML/
  IDML exports, proof setups and colour-blindness previews, anchored
  objects, parent pages, slug and bleed fields, quick apply, preflight.

Same table, same lookups — Arabic now covers the union of every
language's keys, matching Japanese's completeness (1,694 keys).
2026-10-12 19:47:15 +00:00
aiongg 774ecf4fa5 Integration: book chapter-number test closes its chapters before Update Numbering (#341 x #615 open-chapter refusal) 2026-10-12 19:46:34 +00:00
aiongg 527e5cbc0c Merge main: atomic desktop and CLI exports, staged book updates, recovery checkpoint retention, exit recovery
upstream/main c3859c82 (#614 e198eb5d, #615 9509b2bc, #616 8e151a2f, #617 c3859c82).

Conflict: ROADMAP.md: header keeps next's change list plus orderly native exit recovery; progress log both
Conflict: apps/designcraft-cli/src/main.rs: next's case-insensitive .jpg/.jpeg check with main's write_atomic
Conflict: apps/designcraft/src/main.rs: on_exit keeps next's startup.presented() (not an Option) and adds preserve_documents_on_exit; next's discard_marked_text and main's preserve_documents_on_exit both; Services write uses write_atomic and keeps next's clipboard_text; tests both
Conflict: crates/engine/src/cmd/book.rs: main's ChapterBatch paginate with next's chapter-number resolution and {pages, chapters} result and doc
Conflict: crates/engine/src/cmd/file.rs: revert takes main's discard_document ordering without the revision + 1 (next's DocState::new hands out a fresh revision)
Conflict: crates/engine/src/recovery.rs: main's save_tracked, write_entry and open (st.bump_revision() for next's global revisions); next's reopen-twice test assertions kept
Conflict: docs/gaps.md, docs/target-app-parity.md: headers combined; next's Language, Books and Numbering lines plus main's book update safety line
2026-10-12 19:46:34 +00:00
LosminekandClaude Opus 5.5 2c0ca990b8 i18n(cs): Quit DesignCraft
Czech for the app-menu entry added on main since this PR was opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:41:25 +02:00
Losminek a91c720526 Merge remote-tracking branch 'upstream/main' into cs-pr 2026-10-12 21:37:51 +02:00
aiongg 84158e36d3 Document tabs: long names are shortened so the close button stays visible
A tab is at most 260 px wide. A longer document name ends in an ellipsis
(cut at a grapheme boundary, RTL names included), the dirty marker and
zoom stay readable, and the full name shows in the tab's tooltip. Tabs
and their close buttons carry accessible labels.

Fixes #603
2026-10-12 19:32:28 +00:00
aiongg 30ba47211e Text frames: Balance Columns evens out the last frame's columns (#609)
In the frame a story ends in, Balance Columns lowers the bottom of the
columns after the last explicit column break as far as the text still
fits, reusing the bounded search that balances columns above spanning
paragraphs. Frames the text runs on from fill normally. Text Frame
Options gets a Balance Columns checkbox.
2026-10-12 19:18:45 +00:00
aiongg 4be988f335 Integration: format 2026-10-12 18:57:40 +00:00
aiongg 203870ed64 Merge #591: Double-click a frame handle to fit the frame to its content; Fit Frame to Content fits text frames
Conflict: crates/engine/src/cmd/object.rs: object.fit's doc keeps next's text and adds the `axis` clause; test modules from both sides
Conflict: crates/ui-egui/src/canvas.rs: kept next's input code (it sends the second press as Down with clicks: 2) and dropped the PR's release-time DoubleClick; the PR's UI test stays
Conflict: crates/tools/src/select.rs: the handle double-click joins next's second-press preamble, after the port checks and before editing text and the frame/content toggle (Down or DoubleClick with click_count 2 on a handle runs object.fit along fitting_axis); the DoubleClick arm stays empty; module doc from both
Conflict: crates/tools/src/tests.rs, ROADMAP.md: both sides
2026-10-12 18:56:35 +00:00
aiongg 605513228a Text frames: auto-size grows and shrinks frames to fit their text
Height Only, Width Only, Height and Width and Keep Proportions frames fit
their text after every undoable command (same undo step) and after IDML
import, around the reference point, with minimum height/width and No Line
Breaks. Text Frame Options gains an Auto-Size section; IDML reads and writes
the minimum and no-line-break attributes. Applies to unthreaded frames and
the last frame of a thread; vertical frames and type on a path are left as
they are. (#180)
2026-10-12 18:55:57 +00:00
aiongg 3b295ceed0 Integration: drop #402's JSON-parser overflow test (it tests serde_json, not Place) 2026-10-12 18:50:15 +00:00
aiongg f6a03984d4 Merge #402: Place: an explicit x, y, spread or width puts the image in a new frame
Conflict: crates/engine/src/cmd/file.rs: the spec keeps next's pdfCrop boxes and loadCursor with the PR's width bound and placement precedence; the PR validates `width` earlier, so next's later want_w line goes; next's loadCursor branch stays
2026-10-12 18:50:08 +00:00
aiongg 796e9d713d Integration: the Eyedropper matches the clicked frame where no image pixel shows; sampling skips clipped-out pixels and hidden states (#572, #561)
color.sample takes `matchFrom`: with no opaque image pixel under the point (an empty part of an image frame, a transparent pixel), it applies that object's attributes as object.matchAttributes does, in the same command; the tool passes the object under the pointer. sample_item and the tool walk shown_children(), so only a multi-state object's active state is sampled, and sample_item skips points outside the graphic's clipping path. object.matchAttributes's body is a function both commands share.
2026-10-12 18:47:51 +00:00
aiongg 20a14d95f0 Merge #572: Eyedropper: sample a placed image's colour into the selected text or objects
Conflict: crates/engine/src/cmd/style.rs: object.color keeps next's apply_color, spec and enabled check (#84); takes the PR's color.sample (with next's enabled check), image_color_at and sample_item; drops the PR's color_swatch, color_items and has_text_or_selection; explicit `id`/`ids` win over a text selection in apply_color; the PR's tests follow next's caret behaviour (a caret takes the sampled colour for the next typing)
Conflict: crates/tools/src/tests.rs: both sides; the eyedropper test's Asset and Graphic literals gain next's pdf_crop, pdf_box, clip and wrap fields
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, ROADMAP.md: both sides
2026-10-12 18:43:58 +00:00
aiongg f11097c3f8 Merge #608: UI: spring-loaded zoom (Cmd+Space / Cmd+Alt+Space)
Conflict: crates/engine/src/tooling.rs: every with_ctx caller (IME preedit, commit, end, caret) takes the PR's `|s, cx| s.tool.…` form; pointer keeps next's end_composition before dispatch and tool_key its composing() early return
Conflict: crates/ui-egui/src/canvas.rs: the cursor block takes `space` from navigation_space, then the zoom branch, then `(space && !cmd) || alt_text`; the spring-zoom pointer events carry next's `clicks`; the PR's tests name their button helper `press` (next's tests have a `primary`) and compare cursors with what cursors::show sets for the engine cursor (next paints or rasterizes cursors per platform)
Conflict: ROADMAP.md, docs/target-app-parity.md, docs/ui-parity.md: status lines list both sides; progress and change-log rows keep both
2026-10-12 18:36:04 +00:00
aiongg 0d1fa3bf43 Merge #607: MCP: reconnect closed sockets before sending the next request 2026-10-12 18:29:52 +00:00
aiongg a680f2c937 Merge #606: Styles: selection capture accepts deleted-swatch fills 2026-10-12 18:29:52 +00:00
aiongg 3f6f8453ca Merge #577: fix(render): A group's gradient feather fades the group, on screen and in PDF
Conflict: crates/doc/src/item.rs: both tests (next's rotated group bounds, the PR's feather bounds)
Conflict: ROADMAP.md: both progress lines
2026-10-12 18:29:39 +00:00
moppeeerandClaude Opus 5.5 f25cae4780 feat(edit): Paste vector art from other apps as editable paths
Illustrator, VectorCraft, Figma and Inkscape put copied objects on the
system clipboard as SVG markup. Pasting it now creates editable paths, as
InDesign does with Illustrator art: fills, strokes (weight, caps, joins,
dashes) and opacity come through as unnamed colours, groups stay groups,
text comes in as outlines, CSS pixels become points (0.75 pt/px) and the
art is centred in the view. One undo step; garbage is refused.

- engine: edit.pasteSvg {svg, spread?, at?}
- canvas: Ctrl/Cmd+V with SVG on the clipboard (not while typing)
- Edit > Paste with nothing copied here asks for the system clipboard
- control channel: ui.paste {text}

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:23:47 +02:00
aiongg 8e212fb611 Merge #255 (update): fix(ui): Compact the Advanced object Control panel into aligned rows
The update rebases the compact panel next has (already inside the control bar's scroll area) and adds accessibility labels and the progress line.
Conflict: crates/ui-egui/src/panels/mod.rs: next's swatch_list with the PR's swatch_picker returning the chip's response; next's swatch-list test discards it
Conflict: crates/ui-egui/src/chrome.rs: kept next's control-bar tests (they find the Fill chip by its group)
Conflict: crates/ui-egui/src/{lib.rs,object_control.rs}: rebased duplicates; kept next's side, then took the PR's labels
Conflict: ROADMAP.md: both progress lines
2026-10-12 18:23:46 +00:00
aiongg c490660ced Merge #342 (update): feat(ui): Lay out Numbering & Section Options like InDesign's
Conflict: crates/engine/src/cmd/layout.rs: Document Setup keeps next's refusal of an out-of-range start page; layout.section's spec keeps next's styles (kanji) with the PR's 1–99999 bound; the section body takes the PR's SectionEdit, whose start number goes through next's start_number check; tests keep next's section_start_numbers_are_bounded with the PR's one-undo-step test (the PR's start_numbers_are_bounded expects Document Setup to clamp, which next refuses, so it is left out)
Conflict: crates/doc/src/lib.rs: kept next's iterative saturating page_number; dropped the PR's second MAX_PAGE_NUMBER (next has it in page.rs)
Conflict: crates/ui-egui/src/dialogs.rs: next already leaves Enter and Escape to an open popup; kept next's side and added the PR's Style-menu key test
Conflict: crates/engine/src/cmd/mod.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs}: rebased duplicates; kept next's side
2026-10-12 18:21:59 +00:00
aiongg 9d1a60785c Merge #537 (update): Engine: report the selected text; remember recently used fonts
Conflict: crates/engine/src/cmd/text.rs: kept next's selection_attrs (typing format, `mixed`) and took the PR's selected_text_preview for the selected text
2026-10-12 18:18:37 +00:00
aiongg ade7db75cb Merge #575 (update): Effects panel: the level row, Isolate Blending and Knockout Group
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, panels/properties.rs: rebased duplicate of the PR code next has; kept next's side and took the new pasted-into-frame fix
Conflict: ROADMAP.md: dropped the rebased duplicate progress line
2026-10-12 18:18:10 +00:00
aiongg e439d5d4d2 Merge main: preserve live state when persistence fails (#613)
Conflict: crates/engine/src/cmd/file.rs: spec strings keep next's (extension, return value, .indd); Save a Copy adds the extension then rebases data-source paths on a copy; file_save takes main's prepare-then-commit order with next's bump_revision
Conflict: ROADMAP.md: status line lists both changes; progress log keeps both sides
2026-10-12 18:17:47 +00:00
skylar taylor-barrick 8e151a2fd4 fix(recovery): retain recovered checkpoints until save or close
Keep recovered snapshots available through a second crash before autosave. Track checkpoint ownership across folders and restarted IDs; Save, Close and Revert clean only checkpoints owned by that document.

Follow-up to #506 and the retention concern in #380.

PR #616.
2026-10-12 12:15:46 -06:00
skylar taylor-barrick 9509b2bcea fix(book): stage chapter updates before saving
Prepare and stage every chapter before a book update writes files. Preserve imported IDML sources, reject open native chapters and report completed paths after a later write failure.

Follow-up to #485.

PR #615.
2026-10-12 12:12:01 -06:00
skylar taylor-barrick b9048a5b08 fix(save): preserve live state when persistence fails
Preserve document paths, revisions and collection contents when persistence fails. Rebase Save a Copy paths without changing the open document.

Follow-up to #485.

PR #613.
2026-10-12 11:53:46 -06:00
aiongg 3719470140 Integration: format 2026-10-12 17:26:21 +00:00
aiongg 7cc6f6db72 Merge idml-deleted-text (update): deleted text inside nested paragraphs stays deleted; a deleted break doesn't break (#581)
Conflict: crates/idml/src/tests.rs: both sides' tests (#473's SameParaStyleSpacing tests, then the branch's deleted-text tests)
2026-10-12 17:25:31 +00:00
aiongg aef8c39a3b Integration: wrap tests use the top-to-baseline band; a clipping path contour stops at its frame (#384, #561, #589, #557)
an_image_contour_stops_at_its_frame builds its Graphic with next's clip and wrap fields.
a_wrap_object_cutting_a_narrow_frame_leaves_its_sliver_empty and lines_in_band test a line's
band from its top to its baseline. New test: a Detect Edges clipping path overhanging its frame
wraps text (Same As Clipping) only within the frame.
2026-10-12 17:23:45 +00:00
aiongg cb83b6071a Merge contour-wrap (update): a line meets the wrap from its top to its baseline; an image's contour stops at its frame (#384)
Conflict: crates/compose/src/lib.rs: wrap_exclusion keeps next's custom boundary and outline closure, which now yields (outline, clipping frame) and limits the contour to the frame via Contour::within
Conflict: crates/compose/src/lib.rs: contour_path keeps next's (it, kind) form; Same As Clipping (the graphic's clip path) and Bounding Box (shown bounds) return the frame path as the clip, other kinds the frame with no clip
Conflict: crates/compose/src/lib.rs: main loop and estimate_slots keep next's grid and wrap_slot code; wrap_slot drops its desc argument and tests the band from the line top to its baseline (free_slots and the in-band edge search), for both callers
2026-10-12 17:20:50 +00:00
aiongg bfaebb76ee Integration: an explicit SameParaStyleSpacing Ignore survives a native save (#473)
same_para_style_spacing uses deserialize_explicit_value, so Some(None) round-trips through
serde. Test: SameParaStyleSpacing as a Properties element on the based-on Normal style closes
the gap between consecutive headings; SetIgnore keeps the usual spacing.
2026-10-12 17:18:26 +00:00
aiongg dad91f0c74 Merge #473: Honor IDML SameParaStyleSpacing between same-style paragraphs (#449)
Conflict: crates/compose/src/lib.rs: same-style gap replaces the pending space; otherwise next's text_above span space-before rule
Conflict: crates/doc/src/attrs.rs: same_para_style_spacing before the drop-cap fields and their doc
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/idml/src/tests.rs: both sides' tests
2026-10-12 17:16:10 +00:00
aiongg 3ac3bc90de Merge main (0.7.1): atomic saves, recovery per instance, quit keeps documents when cancelled
Conflict: crates/engine/src/atomic.rs: main's side (the reviewed #485 code supersedes the PR head on next)
Conflict: crates/engine/src/recovery.rs: main's #506 code, with next's write_entry helper kept
Conflict: apps/designcraft/src/profile.rs: main's own_run returning Option (and_then), with next's portable root_with argument
Conflict: crates/ui-egui/src/lib.rs: main's QuitState quit flow (d020b4e8) over the #545 head; next's Find Font alert guard; one import_warning_tests module (next's, with the Find Font test)
Conflict: apps/designcraft/src/native_menu.rs: next's MAC_APP_MENU layout, which already has the dc-quit item running app.quit
Conflict: ROADMAP.md: next's header with the quit change added; next's log entries then main's three
Conflict: docs/target-app-parity.md: main's atomic save, recovery and quit lines
2026-10-12 17:14:07 +00:00
Jeffrey ThayneandClaude Opus 5.5 2d2c6bbc83 Links: placed text files can stay linked (Word, RTF, text)
File > Place of a text file with `link: true`, or with the new
Preferences > File Handling > Create Links When Placing Text Files,
records on the story the file's path, size and hash, and the style map
and style-conflict option used. The Links panel and links.list show
these files OK / Modified / Missing like graphics. links.update imports
a modified file again into the same frames and thread with the saved
style map (Auto Rename's choices are kept, so no new _wrd_ styles). As
in InDesign, edits made in the layout are replaced: the Links panel and
Window > Links > Update Link ask first (Update / Cancel) when a linked
story was edited in the layout, while the links.update command updates
and returns a warning, as InDesign scripting does. links.relink,
links.goTo and links.embed (Unlink) take {story}. Saved in the native
format; IDML writes the text unlinked. Tracked changes import as
accepted, as before. Tests cover place-with-link, Modified/Missing
status, update with the saved style map keeping frames, the
local-edits warning, the confirmation dialog (confirm, cancel, no
dialog for unedited stories), relink, unlink, the preference, and a
native save/load round trip. Closes #597.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 11:08:31 -06:00
moppeeerandClaude Opus 5.5 42a4846ba8 fix(ui): Numbering & Section Options applies in one step and keeps keys for its menus
Review follow-up.

- OK ran layout.section and then layout.chapterNumbering: two undo steps,
  and a chapter start the second command refused (over 99 999) left the
  section applied. `layout.numberingOptions {page, …section, chapter}`
  checks both parts before the document changes and applies them in one
  edit; the window's OK runs it. layout.section and
  layout.chapterNumbering share its parsing.
- Enter or Escape with a Style menu open confirmed or closed the whole
  dialog. Dialogs now leave both keys to an open popup (read before the
  dialog draws, since egui closes a popup on Escape that frame).
- A start page of 4294967295 overflowed page_number (a panic in debug
  builds, page 0 in release). Page numbers saturate; layout.section
  refuses start numbers outside 1-99 999 (MAX_PAGE_NUMBER, as chapter
  numbers) and Document Setup clamps its start page instead of wrapping
  a 64-bit number into 32 bits.

Also rebased on main: the restructured ROADMAP keeps main's text, and the
inventory in docs/target-app-parity.md lists chapter numbering and the
window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:05:51 +02:00
moppeeerandClaude Opus 5.5 73c37fdcca feat(ui): Lay out Numbering & Section Options like InDesign's
Layout > Numbering & Section Options now opens its own window instead of
the generated command form, on the section of the page in view: Start
Section (always on for page 1), Automatic Page Numbering or Start Page
Numbering at, and a Page Numbering group with Section Prefix, Style,
Section Marker and Include Prefix when Numbering Pages; then Document
Chapter Numbering with its style, Automatic Chapter Numbering, Start
Chapter Numbering at, Same as Previous Document in the Book (only in a
book) and the book's name. OK and Cancel sit beside the options, out of
the scrolling body.

OK runs layout.section and layout.chapterNumbering; a refused value
(a prefix over eight characters or with + or a comma, a start number
below 1) keeps the window open and changes nothing. Opening the window
reads the chapter numbering without running a command, so it doesn't
stop a Data Merge preview. New strings are translated (German, French,
Spanish, Japanese, Chinese, Italian).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:05:43 +02:00
aiongg f8d9f3f3a3 IDML: deleted text inside nested paragraphs stays deleted
A paragraph range inside a tracked change takes the change into its character
attributes, so the mark holds for its character ranges however their format is
built.
2026-10-12 17:05:30 +00:00
aiongg 254cc49d1b Text wrap: an image's contour stops at its frame 2026-10-12 17:04:48 +00:00
aiongg 90890e37aa Compose: a deleted break doesn't break
A column, frame or page break character that tracked changes delete, or a
hidden condition hides, no longer sends the next paragraph on. Deleted
paragraphs between a live break and the next paragraph don't stop the break.
Tests cover a deleted paragraph range inside a change, a deleted frame break in
both nestings, and a live break before a deleted paragraph.
2026-10-12 17:02:46 +00:00
aiongg 67ae415506 Text wrap: a line meets the wrap from its top to its baseline 2026-10-12 17:02:08 +00:00
moppeeerandClaude Opus 5.5 2a01b80918 Label the object Control panel's captions and chips for screen readers
Put the compact object groups inside the Control bar's existing sideways
scroll area, and give the painted captions (X:/Y:/W:/H:, icon captions,
Columns) and the Fill/Stroke chips accessible labels so tests and screen
readers find them. The Fill and Stroke chips open with nothing selected,
as before, so a popup opens at a scrolled control.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:18 +02:00
moppeeer 6f75b648da Compact the Advanced object Control panel into aligned rows 2026-10-12 18:29:18 +02:00
moppeeerandClaude Opus 5.5 65ef8a1c70 fix(ui): Keep Enter and Escape in the Save Document Preset popup; saved presets in the engine
Review follow-up. Enter in the Save Document Preset popup created the
document and Escape closed the whole dialog: the dialog footer took
both keys while a popup was open. The dialog now leaves Enter and
Escape to an open popup (read before it draws, as egui closes a popup
on Escape that frame): Enter in the preset name saves the preset,
Escape closes only the popup. Clicking the name field no longer closes
the popup either (menus close on any click; this one only outside), and
the field takes focus when the popup opens.

Saved presets lived only in the UI state, so `file.new {preset: name}`
refused them. They are now engine preferences (saved with prefs.json):
`file.savePreset {name, …the file.new settings}` replaces a preset of
that name and refuses built-in names, `file.deletePreset {name}` removes
one, `file.presets` lists them after the built-in ones (`saved: true`),
and `file.new {preset}` makes documents from them by name. The Saved tab
reads and writes them through those commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:17 +02:00
moppeeerandClaude Opus 5.5 564fc8cd98 feat(ui): Lay out the New Document window like InDesign's
File > New > Document now shows Recent, Saved, Print, Web and Mobile
tabs of page cards (drawn to the preset's proportions; double-click
creates) beside the preset's details: document name, width and height
with arrows, units, orientation, pages, start page #, facing pages,
primary text frame, columns and gutter, and collapsible margins and
bleed and slug per edge with link toggles. Save Document Preset keeps
presets by name; documents made are remembered for the Recent tab.
Small windows stack the details above the presets and scroll; the
layout mirrors for right-to-left languages. New strings go through the
translation tables (Italian, German, French, Spanish, Japanese, Chinese).

file.new takes intent, units, startPage and per-edge bleed and slug.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:17 +02:00
moppeeerandClaude Opus 5.5 c828e1f97c fix(engine): Keep section prefixes to InDesign's rules
A section prefix is at most eight characters and contains no plus or
comma (page references and ranges use them); `layout.section` refuses
others and leaves the section unchanged. Symbols, a footnote style,
no longer number pages. The parameter documentation lists the 01, 001
and 0001 styles, and a test pins the fields the generated dialogs read
from both numbering commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:16 +02:00