Commit Graph
387 Commits
Author SHA1 Message Date
aiongg fbfd0b2fe9 Merge gpu-startup: recovered documents survive restarts, the watchdog only restarts a hung adapter, software adapters last, the skip list as an argument
Conflicts: designcraft main.rs ui() (#366's macOS marked-text discard, then the startup watch's leave);
engine recovery.rs (the branch's rewrite-then-discard with next's bump_revision).
2026-10-10 21:28:17 +00:00
aiongg aa743eee88 Merge kanji-page-numbers: Kanji page numbers
Conflicts: engine layout.rs and notes.rs params docs (next's lists plus kanji).
2026-10-10 21:27:19 +00:00
aiongg 158f366af8 Startup: restarts keep recovered documents, a busy UI never counts as a GPU hang, software renderers last
- Recovery: file.recovery.open moves each entry to the reopened document's uid
  (written before the old one is removed), so recovered documents stay on disk
  until saved or closed, also when the app restarts on another adapter or
  stops before its first recovery save.
- First-frame watch: a late first frame is logged and noted in the status bar.
  The adapter counts as hanging only when the UI thread has been stuck outside
  the app's code (logic/ui mark entry and exit) with no progress for 60 s while
  the window isn't known to be minimized, occluded or unfocused. The watch asks
  for a repaint on each look, so an idle UI ends it. VectorCraft restarts on
  the late frame alone, which a held-back compositor or a long compose can set
  off.
- Software renderers (WARP, llvmpipe) are passed over while another backend is
  left; once no hardware adapter of any backend could show the window, the app
  starts again with them allowed, once.
- A restart clears gpu.json's backend entry just before exec or spawn and puts
  it back when starting again fails. Backends a restart left out are no longer
  recorded as failed.
- The watch ends a hung process with TerminateProcess on Windows.
- The skip list travels as the restarted app's --gpu-skip= argument instead of
  an environment variable, so processes the app starts don't inherit it.
2026-10-10 21:26:51 +00:00
aiongg ee529362d6 Merge rtl-master-sides: right-to-left binding puts parent page items on the right side
Conflict: idml tests.rs test modules (both).
2026-10-10 21:26:39 +00:00
aiongg d32134d337 Merge wrap-placed-graphic: text wrap set on a placed graphic wraps text
Conflicts: compose lib.rs imports (both; Composer unused), idml tests.rs (both test modules), ui-egui
panels/mod.rs (next's ruler origin with the branch's graphic wrap for Direct Selection).
2026-10-10 21:26:25 +00:00
aiongg cdd32a5066 Layout: right-to-left binding puts parent page items on the right side
A right-to-left bound spread lists its right page first, parent spreads
included. The parent page shown behind a document page was picked by list
index (first = left), so every page of an imported right-to-left document
showed the other side's parent items. Pick it by position instead: the
leftmost parent page for a left page, the rightmost for a right page.

New parent spreads in a right-to-left document list their pages right
first, and changing the binding reorders existing parent spreads, so IDML
export writes them in binding order. Spread bleed on the canvas and in
spread PDF export takes the outer edges by position as well.
2026-10-10 21:24:02 +00:00
aiongg 720165a709 Merge layers-drag: group members move with their group, no-op drops record nothing, locked layers need Cmd 2026-10-10 21:23:20 +00:00
aiongg c28387eaf9 Sections: Kanji page numbers
Kanji numbering style (一, 二, 三, …, written digit by digit: 10 is 一〇)
for sections, footnotes, endnotes and lists. IDML PageNumberStyle and
FootnoteNumberingStyle read and write Kanji and the leading-zero styles;
the list format "一, 二, 三, 四..." maps to it.
2026-10-10 21:23:01 +00:00
aiongg 7f2b5cfa68 Layout: text wrap set on a placed graphic wraps text
A placed graphic carries its own text wrap (Graphic.wrap). IDML import
reads TextWrapPreference on the Image/PDF element and export writes it
back there. Layout treats it as an obstacle around the part of the
graphic its frame shows, plus the offsets, and also collects wraps of
items inside groups. object.textWrap acts on the graphic when the
selection is the frame's content, and the Text Wrap panel shows its wrap.
2026-10-10 21:23:00 +00:00
aiongg b84a58391f Layers: group members move with their group; no-op reorders leave history alone; Cmd for locked layers
- object.setLayer moves a group member's top-level group (and its members)
  and rejects an unknown or missing layer; object.reorder sets the layer on
  moved groups' members too.
- object.reorder returns without editing when the order and layers would
  not change, so no undo step is recorded.
- Layers panel: locked and hidden layers take object and selection drops
  only with Cmd/Ctrl held; the selection square drops the selected
  members' top-level groups.
2026-10-10 21:22:57 +00:00
aiongg c403cae4c7 Merge #83 update (feat/layout-parity f386a98d): Em Box Height first baseline offset
Conflicts: fonts fontdb.rs (the branch's em box with its from-BASE flag beside next's ICF cache); idml
tests.rs (the branch's copies of tests already on next, and the mojikumi test #129 replaced, dropped;
the Em Box Height test kept). German entry for Em Box Height.
2026-10-10 21:16:13 +00:00
aiongg f386a98d7c Layout: Em Box Height first baseline offset
The first baseline sits the em box top below the frame's top inset: the
font's BASE em box (idtp, else ideo + 1 em), else 0.88 em, for the
largest size on the first line. IDML FirstBaselineOffset="EmboxHeight"
imports and exports as itself; the footnote options list it and the
frame and footnote option commands take emboxHeight.
2026-10-10 21:04:33 +00:00
aiongg 754d09ac2d Merge table-cell-strokes: the style test names the [Black] swatch 2026-10-10 20:38:00 +00:00
aiongg 43d6a5264d Tables: the style test names the [Black] swatch, which style strokes now check 2026-10-10 20:37:55 +00:00
aiongg 23da490a42 Merge table-cell-strokes: cell edge strokes in the Stroke panel and Cell Options, with gap colour and tint (#370)
Conflicts: ui-egui dialogs.rs (next's numberingSection arm and the branch's cellOptions arm; the branch's
copies of the dialog test helpers already on next dropped, its cell options test kept); idml tests.rs and
the i18n tables appended at the end on both sides (both kept; the branch's Gap Tint: and Tint: rows that
next already had dropped).
2026-10-10 20:30:54 +00:00
aiongg cce6f986c5 Tables: cell and table style strokes take type, gap colour and gap tint
style.cell.create/edit stroke and style.table.create/edit border use the
table.setCell stroke parser: type, gapColor (alias gapSwatch) and gapTint, with
the same validation. A bad value is an error and changes nothing.
2026-10-10 20:25:40 +00:00
aiongg e33cb52248 Merge layers-drag: drag layers and objects to reorder them in the Layers panel (#371) 2026-10-10 20:07:20 +00:00
aiongg 1b9125ceea Layers: drag layers and objects to reorder them
- object.reorder {ids, above|below: id | index, layer?}: restacks sibling
  objects in front of or behind a target, or at an index counted from the
  top of a layer, moving them to that layer. Group members stay in their
  group. Bad input is an error and leaves the document unchanged.
- layer.move rejects a missing id or an out-of-range index.
- Layers panel: drag a layer row to reorder layers, an object row to
  restack it or move it to another layer, and a filled selection square
  onto a layer to move the selection there; a line or box shows the drop.
  Groups expand to list their members. Layers list top (frontmost) first,
  matching the stacking order.
2026-10-10 20:06:34 +00:00
aiongg 20d4178c43 Tables: cell edge gap colour and tint, all stroke types on cell edges, inner horizontal/vertical edge choice
CellStroke and cell/table style edge attributes carry gap colour and gap tint
(IDML ...EdgeStrokeGapColor/GapTint, ...BorderStrokeGapColor/GapTint). The table
renderer and PDF export draw every stroke type on cell edges, with the gap colour
under dashes, dots and stripes.

table.setCell validates stroke values, takes gapColor/gapTint and an edges list
(top/left/bottom/right are the target range's outer sides; innerHorizontal and
innerVertical the lines between its rows and columns). table.getCellStroke reports
the shown values of the chosen edges, null where they differ.
2026-10-10 20:04:57 +00:00
aiongg 6d30b39a41 Merge #369: copied objects paste on the spread in view
Conflict in DesignApp::run: the spread is added after the system clipboard step from #84.
2026-10-10 18:48:47 +00:00
noah1400andClaude Opus 5.5 dfdc650318 Paste: copied objects land on the spread in view (#348)
Paste and Paste in Place always put the objects on the first spread,
whatever page was showing. They now go to the spread in view, or to
the one a caller names with `spread`. With facing pages the objects
keep their distance from the spine, so they stay on their side of the
spread, also on a first or last page that sits alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:08:43 +02:00
aiongg b7efb71c05 Merge feat/ruler-zero-point: the page-origin ruler test sets the page origin 2026-10-10 16:58:28 +00:00
aiongg d59687bf96 Rulers: the page-origin ruler test sets the page origin before it reads the pieces
The loop above ends on the spine origin, which has a single ruler piece.
2026-10-10 16:58:24 +00:00
aiongg a4ac6b039c Merge #343 update: Tabs commands return the stored list; tab lists from files are sanitized
Conflict: crates/idml/src/tests.rs: both tests (next's CJK settings and ruby round trips, the branch's hostile tab list import)
2026-10-10 16:44:40 +00:00
aiongg 0f6f96ae6d Merge feat/cjk-typography-ui: ruby, kenten, shatai, auto tate-chu-yoko, rotate roman, roman word break, grid references and the CJK style dialog panes
Conflict: ROADMAP.md: next's FONT1-3 lines with the branch's CJK1 line
Conflict: docs/cjk.md: the branch's rows, with next's aki below and Japanese composer text kept in the leading model row
Conflict: crates/fonts/src/fontdb.rs: both fields (family/style aliases and the ICF cache)
Conflict: crates/compose/src/ruby.rs: the branch's ruby module; its PlacedGlyph (and kenten.rs's) carry next's rendered_char
Conflict: crates/compose/src/lib.rs: modules both; rtl and para_block both; the branch's grid placement (gyoudori, grid references) replaces next's snap, its paragraph-gyoudori span uses next's line_metrics with mark leading and #330's aki below advance; a wrap push moves the line by whole grid lines and its grid end with it; next's trimmed spaces and drop cap, then the branch's ruby and kenten annotation
Conflict: crates/compose/src/shape.rs: next's pieces loop and StyleRuns with the branch's auto tate-chu-yoko split (after marks join their base) and fit, and Upright mode in every shape_segment call; next's label fallback passes the mode on
Conflict: crates/compose/src/tests.rs: both sets of tests appended at the end
Conflict: crates/idml/src/export.rs: next's metadata and text variable writers, then the branch's CJK settings writers
Conflict: crates/idml/src/tests.rs: both tests
Conflict: crates/ui-egui/src/dialogs.rs: the branch's Ruby dialog default section (next's duplicate characterStyleOptions default dropped); next's section arms with the branch's style_cjk::section_ui
2026-10-10 16:42:01 +00:00
aiongg 23b6ce4cc1 Merge feat/ime: IME composition (#322)
Conflict: crates/ui-egui/src/lib.rs: next's missing-fonts test; the branch's side repeated control_bar_shows_its_second_row (next's newer copy stays) and key_names_sent_as_text_are_dropped, whose IME version replaces next's copy in place
2026-10-10 16:30:09 +00:00
aiongg 15167058b9 Merge fix/idml-missing-spread: a spread missing from the package is reported, and part names match leniently
Conflict: crates/engine/src/cmd/file.rs: next's file.open params (InDesign .indd/.indt) with the branch's package-parts warnings
Conflict: crates/engine/src/cmd/interchange.rs: next's file.openIdml params (InDesign files) with the branch's warnings list; import_report reads the branch's Imported report, then next's resolve_pdf_crops; open_idml keeps next's .indd conversion and title, then takes import_report's warnings after the conversion's; next's comment on not saving over the .idml or .indd
2026-10-10 16:29:16 +00:00
aiongg c93664943b Merge feat/ruler-zero-point: a document zero point and ruler origin you can drag, reset and lock
Conflict: crates/idml/src/tests.rs: both sides' tests
2026-10-10 16:28:07 +00:00
aiongg 65a6a0ba7e Merge feat/style-sections-cjk: CJK sections in Paragraph and Character Style Options
Conflict: crates/engine/src/cmd/style.rs: both params notes in the paragraph style edit spec (startAt null, kinsoku null); create_para with next's set_json_over, continue_numbering and the branch's explicit_default_kinsoku; edit_para calls both helpers; both tests
Conflict: crates/ui-egui/src/dialogs.rs: next's section arms (advanced to bullets) and the branch's CJK section arm; next's paragraph helpers and paragraph_local before the branch's section_list (cjk flag, scrolling list; doc comment stays removed as on next)
The branch's "Lines:" row in the shared i18n table is dropped: next already has the key (drop caps).
2026-10-10 16:27:26 +00:00
aiongg 989373114b Tabs: tab lists from files are sanitized like the commands check them 2026-10-10 16:26:56 +00:00
aiongg 2667484d64 Merge feat/style-sections: Paragraph Style Options gains the remaining sections
Conflict: crates/engine/src/cmd/style.rs: next's create_para attrs (set_json_over) followed by the branch's continue_numbering
Conflict: crates/ui-egui/src/dialogs.rs: the branch's paragraph section helpers and sections before section_list (whose doc comment stays removed as on next); its tests, without its copy of paragraph_style_options_tabs_section_adds_a_stop_on_its_ruler (next has it from #343)
Conflict: crates/ui-egui/src/i18n.rs, i18n/it.rs, i18n/ja.rs: both blocks; the branch's [Default] rows dropped (next has the key from New Document)
2026-10-10 16:22:08 +00:00
aiongg f7e17acfd3 Tabs: the commands return the tab list as stored
The Tabs commands check the list (TabStop::checked_list) before they write it
and return that list, with the index of the stop they set in it, so the result
matches what the paragraph or style holds.
2026-10-10 16:21:34 +00:00
aiongg 03697c53f2 Merge #343 update: tab lists checked through paragraph attributes and styles
Conflict: crates/doc/src/attrs.rs: next's TEXT_COLOR and the PR's tab-stop limits and TabStop checks
2026-10-10 16:20:39 +00:00
aiongg c3c24a0be8 Merge fix/idml-interchange: $ID/ font names, placed PDF page and crop, packaged IDML links (#338, #339, #340)
Conflict: ROADMAP.md: next's IDML interchange line with the branch's sentence on placed PDFs, $ID/ font names and packaged links appended; next's INDD line kept
Conflict: crates/engine/src/tests_idml.rs: next's drop cap test and the branch's two placed PDF tests
Conflict: crates/fonts/src/fontdb.rs: next's plausible/measured_top/typo_ascent and the branch's plain_family; next's canonical_family lookups, with plain_family in place of without_format_suffix in style_traits, face (two) and has_family; the branch's has_exact_family dropped (has_family uses canonical_family)
Conflict: crates/idml/src/import.rs: next's char_attrs (tab-split family and composite font names), falling back to names::font_family_in
2026-10-10 16:20:17 +00:00
aiongg 4a6fef0ba1 Merge #325 update: popup Enter/Escape guard, presets as engine commands
Conflict: ROADMAP.md: the PR's New Document line (file.savePreset, file.deletePreset), next's Numbering & Section Options and chapter numbering lines
2026-10-10 16:19:02 +00:00
aiongg d241a22f80 Merge #83 update: drop cap fixes
Drop cap style through IDML as a Dropcap nested style, spaces after the cap, one-line caps, nested styles after the cap, own nested-style lists clearing an inherited drop cap style (cells and notes too), cleared styles round-tripping, tabs in right-to-left drop caps.
Conflict: ROADMAP.md: next's INDD, Interface language and Show CJK Features lines (the PR's main-merge resolution, already on next)
Conflict: crates/compose/src/lib.rs: next's warichu placement followed by the trimmed trailing spaces
Conflict: crates/compose/src/tests.rs: next's side; the PR's side repeats helpers and tests next already has
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side, with the PR's drop_caps_import_and_round_trip and its new drop_cap_fixture and nested-style clearing tests in place of next's older drop cap test
2026-10-10 16:18:49 +00:00
aiongg 64cc973df8 Tabs: style tab lists go through the same check as paragraph tab lists
The style path of the Tabs commands writes its list through
ParaAttrs::set_json_over, the same call format_paras makes for
paragraphs, so TabStop::checked_list sees every list a Tabs command
writes.
2026-10-10 16:15:02 +00:00
aiongg e20183033f Rulers: the two guides from the corner are one undo step
guide.add takes orientation: both with point: [x, y] and adds a
horizontal guide through y and a vertical guide through x in one edit.
Cmd-drag from the ruler corner uses it.
2026-10-10 16:05:50 +00:00
aiongg 6dda095396 Engine: a cancelled gesture puts back the revision it began at
Cancelling a drag, a preview or an IME composition restores the
document, its selection and now its revision. Revisions come from one
counter, so the numbers a cancelled preview used are never handed out
again and caches keyed by (uid, revision) never show a cancelled
preview.
2026-10-10 16:05:46 +00:00
aiongg 1276181cde Text: IME composition in place, commit as one step (#322)
The Type tool shows an input method's marked text in the story as a
preview of text.insert, underlined (the converting clause twice), with
the candidate window at the caret. The commit is one text.insert and one
undo step; a cancelled composition leaves the document as it was. Keys,
shortcuts, the clipboard and Undo wait while the IME composes; a click,
a tool or document switch, or any journaled command keeps the marked
text as typed. On macOS the app tells the input context to drop marked
text the tool kept.

With a split window, only the pane last clicked takes keyboard events
(both panes saw them, so typing went in twice).

The web build drops only real key names from text events, and nothing
while its text input has the keyboard, so autocompleted words survive.

The control channel's ui.ime, the headless MCP backend's ui.ime and the
MCP ime tool send IME events.
2026-10-10 16:05:36 +00:00
aiongg c846b92388 Merge feat/cjk-typography into feat/cjk-typography-ui 2026-10-10 16:03:53 +00:00
aiongg 4c4dedaa93 Ruby: clears kenten on the same side, stays with the kana it overhangs, overprints in Overprint Preview 2026-10-10 16:02:52 +00:00
aiongg d9bc53d7f8 Ruby: placement, spacing, font, size, overhang, scaling and colour settings with JLReq layout and IDML 2026-10-10 15:56:16 +00:00
aiongg 289c4a6aa4 IDML: a placed PDF keeps its crop choice
The placed PDF's asset stores its Crop to choice (crop, art, trim, bleed,
media, or the content bounds with visible or all layers) and where that
box sits on the page. The graphic spans the box: the screen, PDF export,
rasterised exports and clipping-path tracing draw only that part of the
page, so a larger frame doesn't reveal the bleed.

IDML export writes the choice as PDFCrop, with GraphicBounds spanning the
box. Import reads PDFCrop back; the engine finds the box on the PDF page
after import (and after relink or update) and maps it onto GraphicBounds,
or gives a graphic without bounds the box's size. Documents saved without
a choice load with the crop box. The Place PDF dialog offers the content
bounds too, and links.list reports the choice.
2026-10-10 15:52:40 +00:00
aiongg 31a58a8501 CJK: kenten settings, shatai, auto tate-chu-yoko, rotate roman, roman word break and grid references 2026-10-10 15:50:32 +00:00
aiongg 7636af73e4 Drop caps: the cap style goes through IDML as a Dropcap nested style
IDML has no drop cap style attribute. Import reads the nested style list's leading "through 1 Dropcap" entry as the drop cap style; export writes the drop cap style as that entry. The drop cap style counts as that entry when composing, so nested styles after it start after the drop cap.
2026-10-10 15:48:58 +00:00
aiongg ade9eb6e69 Rulers: Spread, Page or Spine origin; Cmd-drag the corner for guides
Preferences > Units & Increments > Origin sets DocSettings.rulerOrigin
(document.preferences {rulerOrigin: spread|page|spine}, IDML
RulerOrigin). Rulers and the X/Y fields (Control, Properties, Info,
transform.set) measure from that origin plus the zero point; with a page
origin the horizontal ruler restarts on each page and an object measures
from the page it is on.

Cmd-drag (Ctrl) from the ruler corner adds a horizontal and a vertical
spread guide through the drop point. The live preview while dragging the
zero point is kept on the pasteboard like the committed value.
Translations for Origin, Spine and Lock/Unlock Zero Point.
2026-10-10 15:41:54 +00:00
aiongg 5551cf9a25 Merge upstream main into feat/text-editing-and-frames
The layout-parity files (ROADMAP, compose lib/tests, engine text, fonts fontdb, idml import/tests, canvas) resolve as in the merge of main into feat/layout-parity.
Conflict: ROADMAP.md: as feat/layout-parity's merge
Conflict: crates/compose/src/lib.rs: as feat/layout-parity's merge; this branch's trimmed trailing spaces follow main's warichu::place and come before the drop cap splice
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: as feat/layout-parity's merge; this branch's TypingFormat/typing_format and main's warichu_cmd
Conflict: crates/fonts/src/fontdb.rs: this branch's styles/traits_of/linked_style over style_traits; style_traits falls back to the family without main's format suffix (exact_style_traits)
Conflict: crates/idml/src/import.rs, crates/idml/src/tests.rs, crates/ui-egui/src/canvas.rs: as feat/layout-parity's merge
Conflict: crates/ui-egui/src/control.rs: main's page_index and automation_contract_tests, then this branch's tests module
Conflict: crates/ui-egui/src/lib.rs: this branch's ClipboardFn and main's Inbox of ImportedFile
Conflict: crates/ui-egui/src/menus.rs: main's Quick Apply tests, then this branch's copy and paste keys test
2026-10-10 15:36:43 +00:00
aiongg cd23a5fbbf Tabs: tab stops set through paragraph attributes are checked like the Tabs commands 2026-10-10 15:35:05 +00:00
aiongg 7f23a5e05b Merge upstream main into feat/layout-parity
Conflict: ROADMAP.md: this branch's Text engine, IDML interchange and Right-to-left lines; main's FID2, PDF export and Interface language lines
Conflict: crates/compose/src/lib.rs: list labels as main's number_label/bullet_label/empty-paragraph arms, kept in this branch's list_label form that marks label glyphs; main's layout_line call (ends_para, forced_mid) and warichu::place, then the drop cap splice; rule above uses main's first-line column/end_x span with this branch's rule_color; caret(): drop-cap branch, then main's stacked-row metrics
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: type.para doc lists the drop cap fields and main's rule fields
Conflict: crates/fonts/src/fontdb.rs: both (plausible/measured_top/typo_ascent and without_format_suffix)
Conflict: crates/idml/src/import.rs: main's table style regions, borders and alternating fill/stroke attrs (this branch's alt_fills helper dropped, unused); underline/strikethrough colour from main with this branch's tint(); frame_options takes the object-style chain's TextFramePreference elements, the frame's column rule colour resolved after it
Conflict: crates/idml/src/tests.rs: main's tests, plus this branch's added tests and helpers
Conflict: crates/ui-egui/src/canvas.rs: main's compose::highlight_quads, then this branch's drop-cap highlight
2026-10-10 15:34:23 +00:00