Commit Graph
1485 Commits
Author SHA1 Message Date
aiongg 7e4c75fce9 Merge pr/662: Commands: reject unknown spread values instead of falling back to page 1 (#662)
# Conflicts:
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/guides.rs
#	crates/engine/src/cmd/object.rs
2026-10-12 23:59:28 +00:00
aiongg 605b31c6d6 Merge pr/663: CLI: accept a UTF-8 BOM in scripts and document the syntax in script --help (#663) 2026-10-12 23:56:41 +00:00
aiongg 5b903c036e Merge pr/637: Index: keep level 3 and 4 topics in a run-in index (#637)
# Conflicts:
#	contributors/people.toml
2026-10-12 23:56:37 +00:00
aiongg 14eff698dd Merge pr/639: Fonts: fall back to a font made for Malayalam (#639) 2026-10-12 23:56:26 +00:00
aiongg e7ad004f4d Merge main: mirror gradient midpoints when reversing; preserve leading empty Tagged Text paragraphs 2026-10-12 23:56:21 +00:00
Jason Brashear 91263c912f fix(textimport): preserve leading empty Tagged Text paragraphs
Preserve paragraph breaks after a ParaStyle tag starts the story so leading empty paragraphs and their styles survive Tagged Text import.

Validated individually and after #638 with all six cargo xtask ci gates (1,278 tests passed, four existing tests ignored, 15 WASM compilation checks), six independent paragraph/header/Unicode probes, and an actual export-to-placement command smoke test.

Refs #641
2026-10-12 17:21:52 -06:00
Jason Brashear cc5b4a1f0f fix(color): mirror gradient midpoints when reversing
Move and mirror segment midpoints when reversing gradient stops so reversed gradients preserve color and opacity interpolation.

Validated locally on macOS with all six cargo xtask ci gates (1,277 tests passed, four existing tests ignored, 15 WASM compilation checks), plus independent regressions, undo/redo, native and IDML round trips, and PNG/PDF rendering.

Refs #638
2026-10-12 17:20:54 -06:00
Marco Arnulfo 9e15d5a17e fix(cli): accept a UTF-8 BOM in scripts and document the syntax in script --help (fixes #654) 2026-10-13 00:41:46 +02:00
Marco Arnulfo 3d59dd5d97 fix(cmd): reject unknown spread values instead of falling back to page 1 (part of #651) 2026-10-13 00:38:54 +02:00
aiongg 9487b80220 Integration: format 2026-10-12 22:24:41 +00:00
aiongg b234500e9b Integration (#646): wrap_slot's no-progress check reads next <= b (clippy neg_cmp_op_on_partial_ord) 2026-10-12 22:24:31 +00:00
aiongg 5b01f90baf Merge shaped-text-frames: Text frames: lines follow an oval or polygon frame's shape (#646)
Conflict: crates/compose/src/lib.rs: modules and exports both (outline, optical, parabox, hit_note_with); placement = next's carry/grid/wrap_slot code, entered for outlines too (and the first-word `need`); free_slots starts from the outline's intervals with cut set (1.5 em filter, segments in reading order, reversed for RTL); the branch's free_slot dropped
Conflict: crates/compose/src/lib.rs: next's bands are top..baseline (descenders hang into wraps); a shaped frame's outline holds the descenders too: wrap_slot and free_slots take the line's descent, used only for the outline's intervals (the branch's oval tests check descender corners)
Conflict: crates/compose/src/lib.rs: estimate_slots takes the band (the paragraph's ascent from line_metrics, max 0.8 em, and descent, max 0.25 em, for a shaped frame; next's 0.8 em and no descent otherwise), returns early only without wraps and outline; est_first uses that ascent; wrap_slot's 1 pt step for outlines (and contours) returns None when it makes no progress or is not finite
Conflict: crates/compose/src/tests.rs: tests both
Conflict: ROADMAP.md: logs both
2026-10-12 22:23:22 +00:00
aiongg 1ff2e978b2 Integration (colour-entry x #552): the Tools panel's Fill/Stroke double-click opens the Color Picker with picker_fields (CMYK stays CMYK); the Formatting Affects Text picker test fills the fields the picker writes for a typed colour 2026-10-12 22:17:14 +00:00
aiongg 283f3f5bbc Merge colour-entry: Color Picker and Color panel keep typed values; colours read on a fixed scale (#323)
Conflict: crates/engine/src/cmd/style.rs: object.color params doc and enabled = next's (text?, has_text or selection) + the model form; apply_color = next's text targets and caret typing format + the branch's rounding-based swatch reuse
Conflict: crates/ui-egui/src/dialogs.rs: next's deleteCharacterStyle / swatchOptions arms; colorPicker = the branch's (no-op without edits, model-form colour) with next's `text`
Conflict: crates/ui-egui/src/panels/swatches.rs: double-click opens the picker with picker_fields + next's `text`; spectrum = the branch's model form + next's `text`
Conflict: docs/target-app-parity.md: the branch's Color panel line + next's Threading and Place text lines
Conflict: ROADMAP.md: logs both
2026-10-12 22:17:14 +00:00
aiongg cb141d6a2b Merge image-colour-profiles: Images: CMYK and profiled photos show in their colours
Conflict: ROADMAP.md: logs both
2026-10-12 22:10:50 +00:00
aiongg 116b3b4ec9 Text frames: lines follow an oval or polygon frame's shape (#646) 2026-10-12 22:07:43 +00:00
aiongg 6483a43ba8 Integration (docx-lists x #360 list levels): Word levels set list_level (ilvl + 1) and lvlRestart; parent numbers in a label are ^k level references, written as text only where the model's level numbers differ from Word's (legal labels, unnumbered levels); Start At from a simulated per-level ListCounter; tests nested_levels_and_restarts adjusted, parent_numbers_the_model_lacks_are_text 2026-10-12 22:07:29 +00:00
aiongg 8ce45eaef6 Merge docx-lists: Word import: bullets and numbering from numbering.xml (#626)
Conflict: crates/textimport/src/docx.rs: tests both
Conflict: ROADMAP.md: logs both
2026-10-12 22:04:39 +00:00
aiongg e391002be6 Merge text-stroke-behind: Text: stroke behind fill (#619)
Conflict: crates/render/src/text.rs: the branch's paint_glyphs with next's fill and stroke overprint (overprint_fill / overprint_stroke, an overprinting() Multiply layer around each paint); next's cell_stroke(kind, weight, length); path text strokes don't overprint, as before
Conflict: crates/pdf/src/text.rs: the branch's text_run / paint_outlines / glyph_outlines split with next's skew tan, vertical mark offsets and split_clusters glyph order (#421)
Conflict: crates/engine/src/cmd/paths.rs: next's shatai transform + the branch's stroke_behind_fill key
Conflict: crates/idml/src/tests.rs: tests both
Conflict: docs/typography-parity.md, ROADMAP.md: headers combined, logs both
2026-10-12 22:04:10 +00:00
aiongg 8811669ee0 Merge alt-arrow-kerning: Type: Alt+Left/Right kerns at the caret and tracks a selection (#621)
Conflict: crates/engine/src/cmd/prefs.rs: next's document.preferences params doc + kerningIncrement
Conflict: crates/engine/src/tests.rs: tests both
Conflict: docs/target-app-parity.md: next's UI and Pen lines + the branch's Tools line
Conflict: ROADMAP.md: logs both
2026-10-12 21:58:22 +00:00
aiongg 86848092ed Merge autoflow-columns: Autoflow: one frame per column, as the page's columns are set (#625)
Conflict: crates/engine/src/cmd/place_text.rs: autoflow(d, sid, max_pages, cmd, primary): next's parent-spread refusal and cmd-named errors + the branch's per-column body; callers file.place, text.thread (primary false) and Smart Text Reflow (primary true)
Conflict: crates/engine/src/lib.rs: Smart Text Reflow passes next's "Smart Text Reflow" and primary
Conflict: crates/engine/src/cmd/file.rs: next's file.place params doc with the branch's autoflow wording
Conflict: docs/target-app-parity.md: next's Threading line + the branch's Place text line
Conflict: ROADMAP.md: logs both
2026-10-12 21:54:55 +00:00
aiongg 7f494e4f3f Color Picker: hex and number fields keep typed text; CMYK colours stay CMYK; the page is not dimmed
The hex field keeps its text while focused, commits each time it parses
(#rgb, rrggbb, any case) and shows the colour again when focus leaves. R/G/B
and editable C/M/Y/K fields hold their values as typed. Picking on the field
or by hex keeps a CMYK colour CMYK through the CMYK working space; typed R/G/B
values make it RGB. OK without edits leaves the fill or stroke alone. Dialogs
draw no backdrop, so the page keeps its colours behind them (#323).
2026-10-12 21:53:06 +00:00
aiongg d050223b78 Colour entry: panel number fields keep typed text; colours are read on a fixed scale
The Color panel's C/M/Y/K and R/G/B fields keep the typed number until Enter
or leaving the field, and send {model, ...} colours in 0..1, which object.color
reads without guessing the scale (M 1 is 1 %, R 1 is not pure red). Colours
that round to the same swatch name reuse that swatch instead of adding hidden
twins. The hex parser rejects signs and other non-hex characters (#323).
2026-10-12 21:53:06 +00:00
aiongg 3381b97e31 Merge #629: Complete the Arabic (العربية) catalog: every missing key translated
Conflict: crates/ui-egui/src/i18n/ar.rs: both sides; the PR's 11 keys next already has dropped (Black, Bottom:, Columns:, Cyan, Horizontal:, Left:, Magenta, Right:, Top:, Vertical:, Yellow)
2026-10-12 21:51:40 +00:00
aiongg 2cc95c64a3 Integration (#618 review): differing SVG fill-opacity and stroke-opacity take the fill's for the object with a warning (items have one opacity); test differing_fill_and_stroke_opacity_takes_the_fills_and_warns 2026-10-12 21:49:21 +00:00
aiongg 09e8118b21 Merge #618: Paste vector art from Illustrator, VectorCraft or Figma as editable paths
Conflict: crates/engine/src/cmd/mod.rs: next's file/layout exports + is_svg_markup
Conflict: crates/ui-egui/src/lib.rs: next's logic(); the PR's RequestPaste hook and request_system_paste field dropped (next reads the system clipboard through Services::clipboard_text); run() routes edit.paste with SVG markup and no insertion point to edit.pasteSvg at next's view centre (with_system_clipboard's spread/at)
Conflict: crates/ui-egui/src/menus.rs: next's activate/menu_enabled; pastes_from_system dropped
Conflict: crates/ui-egui/src/canvas.rs: PR's view_centre dropped (next's canvas::view_centre); PR's Event::Paste SVG arm dropped (the paste event reaches run() through edit.paste); tests both, the PR's two UI tests rewritten against run() (paste event in the middle of the view; native-menu Edit > Paste reading SVG from the system clipboard, markup stays text at an insertion point)
Conflict: docs/control-protocol.md: ui.ime and ui.paste rows
Conflict: ROADMAP.md: logs both
2026-10-12 21:47:29 +00:00
aiongg f4e769369c Merge main: fix(macos): make Dock Quit cancelable; test(recovery): make failed republishing fixtures deterministic
Conflict: Cargo.toml: next's winit patch (rust-windowing/winit#4694, Windows mixed-DPI drags) kept; main's skylartaylor/winit patch held back (Cargo takes one patch per crate; both are single commits on v0.30.13 for different platforms, no published commit has both)
Conflict: Cargo.lock: next's winit source; main's ui-egui tempfile dev-dependency taken
Conflict: apps/designcraft/src/main.rs: next's startup; main's macOS with_close_requested_on_terminate block left out (needs main's winit patch); apps/designcraft/Cargo.toml keeps next's (no macOS winit dependency)
Conflict: ROADMAP.md: headers combined, logs both
Conflict: docs/target-app-parity.md: headers combined
2026-10-12 21:40:47 +00:00
aiongg b20ddf87ec Images: CMYK and profiled photos show in their colours
Placed rasters are converted to display sRGB once, at decode time, in one
module (designcraft-images colour):
- embedded ICC profiles in JPEG, PNG, TIFF, WebP and PSD (RGB and grey) are
  applied; sRGB-like profiles leave the pixels exactly as decoded
- CMYK JPEGs (incl. YCCK, Adobe-inverted values), CMYK TIFFs and CMYK PSD
  composites go through their embedded CMYK profile, else the working CMYK
  space, with the colour settings' intent and black-point compensation
- oversized (> 16 MiB), unreadable or mismatched profiles are ignored with a
  log line

The render image cache is rebuilt when the colour settings change. PDF/A
exports of CMYK TIFFs get the same managed RGB as the screen.
2026-10-12 21:30:41 +00:00
aiongg 270dd46b50 Text: stroke behind fill (#619)
A character attribute strokeBehindFill paints a text stroke under the fill
at double width, so its full weight lies outside the letters and they keep
their shape. Screen and PNG rendering, PDF export (stroke as outlines
first, then the filled text, so the text is not duplicated; clipped to the
outside of the glyphs when there is no fill), Create Outlines (outside-
aligned stroke), the Properties panel and Character Style Options.

IDML StrokeAlignment on CharacterStyleRange, CharacterStyle and
ParagraphStyle imports and exports as the attribute (OutsideAlignment =
on, CenterAlignment = off).
2026-10-12 21:06:42 +00:00
Marco Arnulfo de31bd5647 fix(fonts): fall back to a font made for Malayalam (part of #628)
Malayalam took the first installed file mapping it: on macOS Arial Unicode MS, which has no Malayalam shaping, so conjuncts like ക്ഷ fell apart. Fonts made for Malayalam are tried first, loaded on demand through the CJK chain lookup.
2026-10-12 23:03:22 +02:00
aiongg 7515dfeaf5 Word import: bullets and numbering from numbering.xml (#626)
Paragraphs with w:numPr, directly or through their paragraph style, become
bullet or numbered paragraphs: Word's number formats, label text, start
numbers and overrides, level restarts, the text after the label and the
level's indents. Parent levels in a label are written as text. Unreadable or
hostile list definitions leave plain paragraphs.
2026-10-12 20:59:17 +00:00
skylar taylor-barrick 64f0ca8fa6 fix(macos): make Dock Quit cancelable
Route AppKit termination through the existing unsaved-document close transaction using the immutable winit patch. Restore pending prompts from hidden or minimized windows and preserve answers across repeated requests.

Validation: all six local gates, native cancellation/retry/save smoke, and hosted platform checks.

Fixes #544.

PR #623.
2026-10-12 14:52:12 -06:00
webdevtodayjason 98f1340f61 fix(index): keep level 3 and 4 topics in a run-in index 2026-10-12 15:50:26 -05:00
webdevtodayjason f605ca3157 chore(contributors): add Jason Brashear 2026-10-12 15:50:26 -05:00
aiongg 86a0ce2cf7 Type: Alt+Left/Right kerns at the caret and tracks a selection
With the Type tool, Option/Alt+Left/Right with a caret changes the manual kerning of the pair at the caret by the Kerning/Tracking increment (a new document preference, 20/1000 em by default, in Preferences > Units & Increments); with a selection it changes the tracking of the selected text. Cmd (Ctrl on Windows and Linux) multiplies the step by five. A pair without manual kerning starts from 0. The new type.kernStep command does the work, one undo step per press.

Moving by words is Cmd+Left/Right on macOS and Ctrl+Left/Right on Windows and Linux; Option/Alt+Shift+Left/Right still extends the selection by words. Fixes #621.
2026-10-12 20:48:14 +00:00
aiongg cb38862846 Autoflow: one frame per column, as the page's columns are set
Autoflow on Place threads one frame per page column (right to left in a right-to-left story) and adds pages until the story fits; a frame the user drew or selected stays as it is, and later columns of its page are filled when it sits in one. Empty frames autoflow made at the end of the thread are removed. Pages Smart Text Reflow adds get a primary frame with the page's columns, and it removes trailing pages that hold only empty frames of the story. Fixes #625.
2026-10-12 20:39:04 +00:00
aiongg dfd98fca13 Merge parent-pages-panel: Pages panel: double-clicking a parent shows that parent; parent thumbnails (#624)
parent-pages-panel 4e7b3360.

Conflict: crates/engine/src/cmd/layout.rs: branch's layout.parents.edit {on?, parent?} with bump_revision; branch's Result-returning parent_ref (pages.insert and applyParent callers merged clean) next to next's set_margins_columns and parent_spread_index (a stray parent_ref doc line above set_margins_columns dropped); next's test modules plus the branch's parent_tests
Conflict: crates/ui-egui/src/panels/pages.rs: branch's page and parent thumbnails through next's widgets::load_texture
Conflict: ROADMAP.md: header keeps next's change list plus Pages panel parents; the branch's progress line first
2026-10-12 20:11:02 +00:00
aiongg e3f444ad10 Merge #603: document tabs shorten long names so the close button stays visible
doc-tab-overflow 84158e36. Merged clean onto next's chrome.rs.
2026-10-12 20:07:01 +00:00
aiongg e2dd71378e Merge #609: Balance Columns evens out the last frame's columns
balance-columns 30ba4721.

Conflict: crates/compose/src/lib.rs: story-end check (balance_end) before next's deleted-paragraph filler, then prange; next's `go` closure with the branch's band tail on Next Column; next's Cursor::clip replaced by the branch's tail-aware clip (the auto-placed duplicate dropped)
Conflict: crates/compose/src/tests.rs, crates/idml/src/tests.rs: tests both
Conflict: ROADMAP.md, docs/target-app-parity.md: both (auto-size and Balance Columns lines)
2026-10-12 20:06:06 +00:00
aiongg 069fe47b0d Integration: Fit Frame to Content leaves an auto-size text frame as auto-size fitted it (#591 x #180); test fit_frame_to_content_leaves_an_auto_size_frame_as_auto_size_set_it 2026-10-12 20:00:39 +00:00
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 698a87febc Integration: wgpu errors are logged only after the start-up frames, so a failing adapter still starts the app again on the next one (#612 x adapter restart) 2026-10-12 19:50:35 +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
aiongg b32deda339 Merge #612: Windows mixed-DPI drag keeps the window's size; GPU surface up to the adapter's texture limit
win-mixed-dpi 38dad0fb. Cargo.lock: next's lock plus the winit git source and the dpi 0.1.1 it brings (merged clean; cargo metadata --offline leaves it unchanged).

Conflict: apps/designcraft/src/main.rs: next's startup (adapter selection, catch_unwind, apple events) with log_uncaptured_errors at the top of its wgpu_render_state block; request_adapter_texture_size and mod gpu_limits merged clean
Conflict: ROADMAP.md: progress log both
Conflict: docs/hardware-parity.md: header keeps next's change list plus the mixed-DPI note
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
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