Commit Graph
252 Commits
Author SHA1 Message Date
aiongg fc40ffed2c Merge #475: CLI: --export writes the file type its extension names 2026-10-11 12:23:53 +00:00
aiongg d5a6eca36d Merge #427 update: Text: Optical kerning spaces pairs from their outlines
Conflict: Cargo.lock: next's (the PR's dependency is already on next)
Conflict: ROADMAP.md: next's (the PR's earlier head is already merged)
Conflict: docs/gaps.md: next's (the PR's earlier head is already merged)
Conflict: docs/typography-parity.md: next's, test count 170 -> 172 as in d0120bf6
Conflict: crates/compose/src/optical.rs: next's plus d0120bf6's kernable() dash and fullwidth exclusion and its unit test
Conflict: crates/compose/src/tests.rs: next's plus d0120bf6's optical_kerning_leaves_dash_pairs_alone
2026-10-11 12:19:35 +00:00
noah1400andClaude Opus 5.5 8547a9fca4 CLI: --export writes the file type its extension names (#432)
--export knew .pdf, .epub, .idml and .designcraft and saved a PNG of
the page under every other name: out.html, out.txt, OUT.PDF, and
out.designcraft from `script`. The exit status was 0.

.html and .htm now run file.exportHtml, .rtf and .txt run
file.exportText (the story being edited or of the selected frame), and
extensions match in any case. A name with another extension is an
error before anything runs; one with no extension is still a PNG.
`run` and `script` share one list, and `script` saves a copy for
.designcraft.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:55:05 +02:00
Abdelrehman Fouad d0120bf6a6 Text: Optical kerning leaves dashes and fullwidth forms alone
Two dashes end to end have no ink gap to measure, so -- and the double
em dash opened up by the loosen cap; Chinese sets —— as one continuous
rule. Fullwidth Latin (U+FF21–FF5A) was kernable through its Latin
script and moved CJK text off its em grid. Both are now excluded from
kernable(), with a unit test and a compose test that failed before.
2026-10-11 11:45:29 +02:00
Abdelrehman Fouad d02a220b4e 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 11:39:20 +02:00
aiongg 2fae23fcc6 Merge atomic-save: MCP: exported files replace the target atomically (#436)
Conflict: ROADMAP.md: both progress-log entries, next's newer ones first
Conflict: apps/designcraft/src/gpu.rs: next's side; the branch's test fix targets the startup record tests next replaced
Conflict: apps/designcraft/src/main.rs: next's gpu startup and macOS IME helper; config_dir() dropped for the branch's profile::config_dir(), recovery_dir from profile::recovery_dir()
Conflict: crates/ui-egui/src/canvas.rs: next's guard (menu_open, keyboard_pane already limits keys to the focused pane)
Conflict: crates/ui-egui/src/lib.rs: modules from both sides
2026-10-11 05:16:10 +00:00
aiongg 54520e11e8 Merge canvas-scrollbars: UI: document views have scrollbars, and Alt pans while editing text
Conflicts:
- crates/ui-egui/src/canvas.rs (handle_input): the Alt-hand block comes
  first, then next's zero point and ruler guide drags, which keep their
  menu_open check. The Alt-hand press also waits while a canvas context
  menu is open, like the other canvas presses.
- docs/ui-parity.md: the status line names both live corners and the
  scrollbars.

show() reserves the 10 px strip on the right and bottom only, so the
rulers, the zero-point corner and guide drags keep their positions.
2026-10-11 02:55:53 +00:00
aiongg 607b2f4a34 Merge live-corners: Tools: live corners round a frame's corners by dragging
Conflicts:
- crates/tools/src/lib.rs: Overlay keeps next's ContentGhost and adds
  LiveCornerWidget and LiveCornerDiamond.
- crates/tools/src/select.rs: the module doc keeps next's threading and
  content paragraphs and adds the live-corner one. Drag keeps Place and
  adds Corner; SelectionTool holds both `loaded` and `live`. pointer()
  first ends live-corner editing when the selection changed, then runs
  next's loaded-text-cursor and double-click handling. An empty-canvas
  press clears `live` and keeps next's `content: false` Pending. drag()
  handles Place and Corner. overlays() keeps next's Place marquee and
  content ghost and appends the widget or diamonds.
- crates/ui-egui/src/canvas.rs: the overlay pass keeps next's doc/layout
  for ContentGhost and next's Path drawing, and adds the two live-corner
  arms (the branch's no-op Path arm is dropped). The live-corner render
  test goes before next's fast_harness tests.
- crates/engine/src/cmd/object.rs: next's text_wrap stays; the branch's
  corner_options function follows it.
- crates/engine/src/tests.rs, crates/tools/src/tests.rs: both sides'
  tests kept.
- ROADMAP.md: the live corners progress-log line goes first; the status
  line names it too.

Action::Handled is matched in engine tooling.rs; no other crate matches
Action or Overlay exhaustively.
2026-10-11 02:50:45 +00:00
aiongg eab0ac7f4b UI: document views have scrollbars, and Alt pans while editing text
Each document view (and each split pane) has thin, theme-coloured scrollbars on its right
and bottom edges, outside the rulers and the view. They span the pasteboard: the thumb is
the visible fraction, dragging it pans, clicking the track pages by one view, and they
follow panning and zooming by any other means. Rotated views scroll in screen axes.

With the Type tool editing text, Alt held at the press gives the Hand tool for that drag:
the cursor turns into the hand, the drag pans, and the caret stays. Alt pressed after a
text drag starts still copies the dropped text.
2026-10-11 02:40:00 +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 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 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 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
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 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 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
Brandon ThomasandClaude Opus 5.5 a9124a0517 Release prep: version 0.6.0; Linux riscv64 tar.gz in releases (#398)
- release.yml: new linux-riscv64 job (cross-compiled on ubuntu-24.04 against
  ports.ubuntu.com riscv64 libs, tar.gz only, CLI smoke-tested under QEMU),
  ported from GridCraft; the draft release job needs it, so SHA256SUMS covers it.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
  support, as in GridCraft.
- cargo xtask version set 0.6.0; README, hardware parity and ROADMAP log note
  the new platform.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:33:30 -04:00
aiongg 153fa60054 Merge #388: Show the Pencil stroke while drawing
Conflict: crates/ui-egui/src/canvas.rs draw_tool_overlays: the PR's
Overlay::Path arm (draw_path_overlay) and next's Overlay::ContentGhost
arm both kept; draw_path_overlay sits before draw_content_ghost.
2026-10-10 23:23:48 +00:00
aiongg 0430763918 Merge #325 update: New Document in the progress docs
The PR was rebased onto upstream main; its code commits are unchanged
(range-diff shows only ROADMAP lines moved into the new docs commit), so
next already carries them.

Conflicts: crates/ui-egui/src/{dialogs.rs,i18n.rs,i18n/it.rs,lib.rs}:
next's versions (the old PR code plus next's own dialogs, findFont and
numberingSection work). ROADMAP.md and docs/target-app-parity.md take the
PR's New Document entries.
2026-10-10 23:22:41 +00:00
noah1400andClaude Opus 5.5 4e8575b5c8 Merge main into fix/188-smart-guides-vertical
ROADMAP.md was restructured in #355 and its feature list moved to
docs/target-app-parity.md. The smart guides line this branch reworded
is changed there instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:35:30 +02:00
moppeeerandClaude Opus 5.5 f6e96d2106 fix(ui): Show the Pencil stroke while drawing
The Pencil tool's stroke only appeared once the mouse button was
released. The tool reported the stroke so far as a path overlay, but the
canvas skipped path overlays (they were never drawn), so nothing showed
while drawing. The canvas now draws them: curves flattened to about a
quarter of a screen pixel, dashed when asked. That also brings back the
Smooth and Erase tools' dashed drag previews.

The Pencil's preview was black, lost on a dark pasteboard; it is drawn in
the colour of the layer the path goes on, as InDesign does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:18:59 +02:00
moppeeerandClaude Opus 5.5 543fc41016 docs: New Document in the progress docs
Rebased on the progress-docs restructure (#355): the ROADMAP bullets this
PR added moved to the inventory in docs/target-app-parity.md, and the
ROADMAP progress log gets a line for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:06:58 +02:00
aiongg 17c7bb3fd2 Merge contour-wrap: wrap both sides of an object and around its contour
Combines contour-wrap (wrap side, contour type, multi-segment lines) with
the placed-graphic and nested wraps already on next.

- crates/compose/src/lib.rs: exclusion() and the new graphic_exclusion()
  share wrap_exclusion() (offsets, spine sides resolved per page, contour).
  wrap_obstacles() builds every obstacle through them: the item's own wrap,
  the graphic's wrap around its shown bounds, and children of groups and
  pasted-into frames with their own transform (depth <= 64). Contour type
  Bounding Box follows the shown part of the graphic, other types the frame
  path. wrap_slot() returns all free segments (free_slots) and steps 1 pt
  at a time beside a contour; Jump Object stays in wrap_slot only. The line
  loop keeps grid gyoudori, Jump Object leading steps and grid snapping for
  a line's first segment, and carries the other segments (with the line's
  grid end) to the next lines; estimate_slots() lists every segment through
  wrap_slot(). hit_line() breaks ties between segments by x, used by hit()
  next to the drop-cap lookup.
- crates/compose/src/tests.rs: both sides' tests; the hostile-geometry
  test builds Exclusion with side and contour.
- crates/engine/src/cmd/object.rs: object.textWrap is text_wrap() with
  mode/side/contour (unknown values are errors) and content?, applied to
  the frame's or the graphic's wrap.
- crates/idml/src/import.rs, export.rs: ContourOption/@ContourType is read
  in the shared text_wrap() and written by text_wrap_pref() as a child of
  TextWrapPreference after Properties, so graphic wraps carry it too.
- crates/idml/src/tests.rs: both sides' tests. tests/wrap.rs gains a test
  of a contour, right-side wrap on a placed graphic shown in part.
- crates/ui-egui/src/panels/mod.rs: the Text Wrap panel's side and contour
  combos read the targeted wrap (tw), the graphic's when content is selected.
2026-10-10 21:39:26 +00:00
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 fbda023d7f Layout: wrap both sides of an object and around its contour
Lines beside an object that lets text through on both sides are set in
segments, left then right, and the paragraph runs on from one to the
next. One-sided wraps (left, right, spine sides, largest area) block the
other side. A contour wrap follows the object's outline band by band,
with the offset around it; graphic frames follow their contour type
(bounding box of the graphic, frame path, same as clipping; detected
edges, alpha channel and image paths follow the frame path). The Text
Wrap panel sets the wrap side and contour type through object.textWrap,
and IDML import and export keep ContourOption.
2026-10-10 21:28:03 +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
skylar taylor-barrick c62866443c UI.9: integrate shared panel docking and preserve workspace behavior 2026-10-10 14:42:40 -06:00
aiongg 16bb39e531 Merge gpu-startup: pick the GPU that drives the display, fall back across adapters and backends, and log startup errors (#273, #334) 2026-10-10 20:30:59 +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 279336c445 Startup: pick the GPU that drives the display, restart on the next adapter or backend, and log startup errors
Ported from VectorCraft's start-up fixes (#502, #545, #651, the display-GPU
choice, #806, #964) and reconciled with the backend fallback of #297:

- The app picks the window's adapter itself (eframe's native_adapter_selector,
  apps/designcraft/src/gpu.rs): adapters that can't present never, then
  WGPU_ADAPTER_NAME, hardware before software, native backends before OpenGL,
  the GPU that drives the primary display (Windows EnumDisplayDevices through
  winsafe, Linux /sys/class/drm), the power preference (WGPU_POWER_PREF;
  otherwise power saving on Windows and macOS, the system's order elsewhere),
  then DX12 before Vulkan. Every adapter and the choice are logged.
- wgpu's indirect-call validation is off (WGPU_VALIDATION_INDIRECT_CALL=1 turns
  it back on): its compute shader failed to compile on an Intel Mac and lost
  the Metal device (#334, first error).
- run_native runs under catch_unwind. A wgpu error or a panic in wgpu,
  egui-wgpu or naga during the first frames, or a first frame that doesn't
  reach the screen in 20 s, starts the app again without that adapter
  (DESIGNCRAFT_GPU_SKIP; exec on Unix, a new process on Windows). When no
  adapter of the start's backends is left, it starts again with the next
  backend. Each restart leaves out one more adapter or backend, so they end.
  Adapters without PCI ids (Metal) are keyed by name.
- The backend fallback (gpu/backend.rs, gpu.json) stays for driver faults that
  take the process down. Windows tries DirectX 12, then OpenGL, then Vulkan,
  each in its own instance: Vulkan last because creating its instance loads
  every installed Vulkan driver, and OpenGL kept out of the DX12 instance
  because creating it crashed in AMD's atio6axx.dll (#167).
- main returns an ExitCode and logs why the app stopped to standard error and
  the log file, which is all a Windows start without a console leaves (#273).

README, architecture, gaps, hardware and target-app parity docs and ROADMAP
describe the choice, the restarts and the variables.
2026-10-10 20:26:06 +00:00
aiongg 57d9761c69 Tables: cell strokes in the Stroke panel and Cell Options › Strokes and Fills
With cells selected, or the text cursor in a cell, the Stroke panel edits the
cell edges chosen on a drawn edge proxy: weight, type, colour, tint, gap colour
and gap tint. A click toggles a line, a double-click chooses all outer or all
inner lines, a triple-click chooses or clears all. Table › Cell Options ›
Strokes and Fills… has the same proxy and fields plus the cell fill colour and
tint, and applies the changed values in one undoable step. Translations for
the new strings in every interface language.
2026-10-10 20:16:53 +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 5fae1ac2cc Merge upstream main a127c6d: progress docs (#355); ROADMAP.md takes upstream's rewrite 2026-10-10 18:47:02 +00:00
Brandon ThomasandClaude Opus 5.5 a127c6d5c3 Progress docs: target-app parity, gaps, alpha gate, readiness by audience (#355)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, hardware, UI and localization parity docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:09:17 -04: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 bac5b091ae Merge #330 update: under the Japanese composers a line sits the upper line's leading below it
Conflict: crates/compose/src/lib.rs: next's line_metrics (tops, mark leading, last_line_mark) and baseline grid snap with the branch's (reference, model) and aki_below advance passed to next_baseline; Above keeps next's span space after plus the branch's aki_below
2026-10-10 16:36:22 +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 4014dac6c2 Compose: under the Japanese composers a line sits the upper line's leading below it
Under the Aki Below leading model a line's leading is the space below it, so the
next line's reference point sits the upper line's leading below the upper line's
(InDesign's Japanese-composer output measures this in four corpus documents).
The first line in a frame or column places itself with its own leading; space
before and after adds on top, and the baseline grid snaps the result. The other
leading models advance by the lower line's leading as before.
2026-10-10 16:22:17 +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 30778c14a5 CJK: document kenten, shatai, grid, ruby and ICF status 2026-10-10 16:03:35 +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 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 6286f7c0a5 Merge #336: UI: CJK features behind a preference that follows the interface language
Conflict: ROADMAP.md: next's Right-to-left and Interface language lines (IDML Kashidas, German and Japanese cover every catalog, Ukrainian covers every key) plus the PR's Show CJK Features line
Conflict: crates/ui-egui/src/lib.rs: the PR's cjk_features() before next's opens_as_document (with .indd/.indt and its doc comment)
2026-10-10 13:50:51 +00:00
aiongg 4fd3c0fcae UI: CJK features behind a preference that follows the interface language
Preferences > Type > Show CJK Features (cjkFeatures; unset follows the
interface language: on for Japanese, Chinese and Korean) hides the
CJK-only Type menu items (Tate-Chu-Yoko, Ruby, Kenten, Warichu) and the
Ruby Quick Apply entry. The commands, layout and IDML work either way.
2026-10-10 13:48:07 +00:00
aiongg 1abb74da0f Merge #330: Compose: the CJK leading model and character alignment apply only under the Japanese composers 2026-10-10 13:18:52 +00:00
aiongg 5dc8383a50 Compose: apply the CJK leading model and character alignment only under the Japanese composers
Every IDML root style carries LeadingModelAkiBelow and AlignEmCenter, but only
the Japanese composers (HL Composer J, HL Single J) use them; the Adobe and
World-Ready composers set lines baseline to baseline with every character on
the Roman baseline. Applying them everywhere moved lines down after a size
change and lowered smaller-em glyphs, pushing the last lines of tight frames
(and whole keep-together paragraphs) into overset.

Composer gains Japanese and JapaneseSingleLine, read from and written to IDML;
the composer choice in the UI keeps the kind.
2026-10-10 11:56:45 +00:00
aiongg aadd54a926 Merge upstream main 736acff into next
Upstream main moved 9e4f694 -> 736acff by 10 squashes: #258, #285, #153, #280, #288, #281,
#176, #299, #298, #297. New to next: #258 (datamerge test), #153 (temporary files and release
inputs), #280 (warichu), #176 (PDF image conversion cache), #297 (graphics backend before the
window). Already on next: #285, #288, #281, #299, #298.

Conflict: ROADMAP.md: next's lines; CJK1 takes main's wording (ruby unfinished, warichu set after the line is broken)
Conflict: crates/compose/src/lib.rs: list labels (#298): next's list_label structure; paragraph start / break moves: next's `go` (with #295's sub-columns) under the maintainer's #285 comment; Cursor: next's start/next_page/next_baseline with tops; line placement: #280's warichu::place right after layout_line, before next's trimmed trailing spaces and the drop cap splice (so neither is stacked and the spaces follow the closed-up end_x); caret(): next's drop-cap branch first, then #280's stacked-row metrics
Conflict: crates/compose/src/tests.rs: next's tests kept; #280's tests auto-merged
Conflict: crates/engine/src/cmd/text.rs: both (next's TypingFormat/typing_format, #280's warichu_cmd)
Conflict: crates/idml/src/tests.rs: next's side; #280's warichu round-trip test auto-merged
Conflict: crates/pdf/src/export.rs: #176's content cache and test counter with next's RasterMode (no Exporter `interpolate` field on next, so the maintainer's `mode.interpolate &= self.interpolate` is not carried); test exporter gets next's drawing_items field
Conflict: crates/ui-egui/src/canvas.rs: #280's compose::highlight_quads (its RTL branch equals next's mixed-direction spans) followed by next's drop-cap highlight
Conflict: crates/ui-egui/src/menus.rs: next's formatting_affects_text test kept

Auto-merge duplicates removed: #288's table-style tests and #298's list test in idml tests.rs,
#288's tests in doc styles.rs and #285's docx test (both files equal next's), #281's dialog
tests in dialogs.rs (equals next's) and its menu_button/menu_max_height/clipped_submenu in
menus.rs. contributors/people.toml takes main's (next had a duplicated
[people.emanuelebonaventura] table from the 9e4f694 merge, which broke the ui-egui build
script's TOML parse).

Maintainer edits carried over: #285 break characters and Next Column through one closure
(next's `go`, comment added); #281 viewport-aware menu_button in the app bar and the Paragraph
menu, per-dialog widths clamped to the window (all already on next); #280 warichu after the
last-line rules (layout_line with ends_para/forced_mid) and rules at each warichu row's
baseline (rule_baseline in render and pdf text_rules); #176 CMYK fallback through
lossless(.., mode) and its updated contract tests; #258 test fixes; #153 and #297 as landed.
2026-10-10 08:20:36 +00:00