Commit Graph
2794 Commits
Author SHA1 Message Date
Joseph AngladaandClaude Sonnet 5.5 208facfb92 SmartArt: custom colours per item from the Text Pane (#3123)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:47:56 +01:00
entropybeaterandBrian 811a847e86 doc, docx: keep the compound border lines (#5499)
* doc, docx: keep the compound border lines

The nine thin and thick compound lines (thinThickSmallGap to thinThickThinLargeGap, ECMA-376 17.18.2)
were read as a single line and written back as one, on paragraphs, tables, cells and pages. BorderStyle
gains them; they are written back by name and drawn as a single line of the border's width, as before.
RTF export and import carry them too (the importer read four of them as double).

* contributors: add entropybeater

---------

Co-authored-by: Brian <255903314+entropybeater@users.noreply.github.com>
2026-11-05 01:40:16 +01:00
Valentin KleinandClaude Sonnet 5.5 c9ecb1a14b Metafiles: read the picture size from the header instead of parsing the whole file (#5481) (#5493)
metafile_size() parsed the whole metafile, decoding every bitmap and building every path, to
read two numbers at picture insert and replace. A new wordcraft_metafile::size reads the frame
from the EMF header or the placeable WMF header, and falls back to the full parse for every
other file (plain WMF, an EMF without a usable frame, a file with no records), so it returns
what parse would. For an EMF with one 8000x5000 1 bpp bitmap the size now costs well under a
microsecond instead of about 280 ms.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:32:30 +01:00
Valentin KleinandClaude Sonnet 5.5 c38cd8c407 Metafiles: decode DIB bitmaps with the bit depth chosen once per bitmap (#5479) (#5492)
decode_clip matched the bit depth, bounds-checked and (for 16 and 32 bpp) divided per channel
for every pixel. The depth, palette and masks are now turned into a row decoder once per
bitmap: a 256-entry colour table for 1/4/8 bpp, plain channel swaps for 24 bpp and default
32 bpp, and precomputed shifts and scale tables for masked 16/32 bpp. Output is byte for byte
the same; the old per-pixel code stays in the tests as the reference.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:32:25 +01:00
Valentin KleinandClaude Sonnet 5.5 991a21dee6 Metafiles: refuse a bitmap whose side no renderer draws before decoding it (#5480) (#5490)
decode_clip only capped width x height at 40 MP. A 32 x 1,250,000 pixel 1 bpp bitmap (about
5 MB in the file) was decoded to 160 MB of RGBA and kept, then dropped by Item::take_pixels
because its side is over MAX_BITMAP_SIDE, while counting against the parse's 256 MB budget.
decode_clip now returns None when the clipped width or height is over the cap, so crops of a
large bitmap that fit still decode.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:32:20 +01:00
Hamza Naveed cbe6a9d5f7 Pin that a comment id past u32 is refused, not truncated (#3677) (#5273)
* Pin that a comment id past u32 is refused, not truncated (#3677)

`validate_comment_id` refuses an `id` that does not fit a `u32`, so the `as
u32` casts behind it can no longer reach another comment -- but nothing pinned
it, and the casts are still there to be reached if the guard moves.

The ids the test sends are the ones that would alias onto real comments if the
truncation came back: 2^32 truncates to 0 (and the first comment is 0), 2^32 +
id to that comment, 4294967301 to 5 as the report describes, and u64::MAX to
u32::MAX. Each of the four commands that take an id is tried with each, then
the comments are checked to be unchanged and unresolved, and a valid id is
accepted afterwards so the guard is shown to be a range check rather than a
refusal.

* Comment ids: the values past u32 go in the existing invalid-id test, refused by the range check
2026-11-05 01:32:15 +01:00
.CooCoo c419985c54 Tests: the balloon anchor test counts work steps instead of timing (#5608)
anchors_walk_dense_unrelated_markers_in_linear_work compared CPU times of
a few microseconds, so cache and timer noise could push the ratio past its
24x limit on a linear walk (43.52x in a CI run).

wordcraft-doc now counts, in tests only, the characters its paragraph
object lookups walk (objects_before, object_offsets and
objects_with_offsets), through a work::count helper behind the existing
test-support feature. The test asserts that 8x the markers take at most
12x the steps, as the layout linear-time tests do: the walk takes 2001 ->
16001 steps (8.0x), and the object_offsets + object_at walk it replaced
takes 2003001 -> 128024001 (63.9x).
2026-11-05 01:32:10 +01:00
Dmitrii KhlapovandClaude Sonnet 5.5 1c7b5013fa Drop Cap follow-ups: whole selection, script fonts, margin gap, menu keeps options (#4077)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:26:57 +01:00
Dylan M. Taylor 3f555bc85d Pass the Linux signing key to the release workflow (#5614) 2026-11-04 17:44:46 -05:00
Aleksander HelgakerandClaude Opus 5.5 650a97b623 ODT: remove the display settings; one choice for each open case (#5609)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 23:08:09 +01:00
Dmitrii KhlapovandClaude Sonnet 5.5 78d71fa19c Insert Date & Time and date fields use local time, not UTC (#1782)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 22:43:19 +01:00
RatkoRandClaude Opus 5.5 4932017711 Dialogs are modal, as in Word (#4076)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:31:22 +01:00
NetterSilverandClaude Haiku 5.5 0802b4fe70 Layout: the caret on the empty line after a trailing line break follows the paragraph's alignment (#4293)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 21:57:34 +01:00
mmazzieriandClaude Opus 5.5 75fc50fb77 DOCX: picture brightness, contrast and transparency (VML washout, a:lum, a:alphaModFix) (#1961)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:47:44 +01:00
rabis7575andClaude Opus 5.5 1f026078be Format Shape: the Angle field leaves an angle above 359.9° alone (#3959)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:33:52 +01:00
Joseph AngladaandClaude Opus 5.5 bf7715785c Desktop: a window restored onto no monitor opens on screen (#4742)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 21:19:03 +01:00
FredApps 573b929ad6 Merge pull request #5593 from storytold/fix-5559-followups
Fix #5559 follow-ups: generated list prefix, hidden-text objects, turned clipped lines, kept-markup checks
2026-11-04 18:47:52 +01:00
FredApps 5c427807d8 Give a wrapped list its own paragraph when another list field precedes it 2026-11-04 18:17:20 +01:00
FredApps 006d9e4b5b Rebuild a wrapped list as its own field when another list field precedes it
update_generated now keeps what comes before a wrapped list's field, which can be
another list field; rebuild from the converted field's code instead of the
paragraph's first list field, and let index::rebuild_from take that code.
2026-11-04 18:00:11 +01:00
FredApps 8218dea5bd Fix #5559 follow-ups: generated list prefix, hidden-text objects, turned clipped lines, kept-markup checks once per export
- update_generated keeps what precedes a wrapped list's field (r4468529243)
- from_doc keeps objects in hidden text when hidden text is written (r4469018820)
- clipped cell lines in a turned frame are drawn once, clipped, turned (r4469018900)
- kept::while_writing works out reply map and page fingerprint once per export (r4468529227)
- odt_charts fixture declares its namespaces (r4468529259)
- guard test for character styles based on a missing parent (r4469018843, not a bug)
2026-11-04 17:43:46 +01:00
FredApps 92ecb40105 Merge pull request #5559 from alehel/ccr-84d15855-h5i4o2
ODT: full open, edit and save support, lossless on save without edits (gap 19)
2026-11-04 16:28:18 +01:00
jpc7k1andClaude Opus 5.5 63ceaf5b80 File › Print: Return prints, as Word's default Print button does (#4651)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:16:16 +01:00
FredApps 69945e0ccb Merge branch 'main' of https://github.com/storytold/wordcraft into pr-5559
# Conflicts:
#	ROADMAP.md
#	docs/layout-parity.md
2026-11-04 16:08:39 +01:00
pakiatandClaude Opus 5.5 2df2bfc30e Show fresh SEQ, STYLEREF and REF results in PDF export and printing (#5162)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:01:58 +01:00
FredApps 7c6341cf50 ODT: write one style:text-position for raised superscript/subscript text 2026-11-04 15:54:52 +01:00
FredApps 6d22e36196 Merge branch 'main' of https://github.com/storytold/wordcraft into pr-5559
# Conflicts:
#	ROADMAP.md
#	docs/gaps.md
#	docs/layout-parity.md
2026-11-04 15:54:52 +01:00
ReesandClaude Opus 5.5 958867b7e8 Walk Print Markup balloon anchors once (#3614) (#4785)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:51:39 +01:00
Mohamed ElsayedandClaude Opus 5.5 e3b000b650 fix(print): report noPrinters when CUPS discovery finds no destinations (#1826)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:41:20 +01:00
LQRDandClaude Opus 5.5 604ac6ddb2 #641: print N-up sheets and folded booklets (#3916)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:29:12 +01:00
FredApps 3c7aa5df90 Merge branch 'main' of https://github.com/storytold/wordcraft into pr-5559
# Conflicts:
#	crates/formats/src/odt/import.rs
2026-11-04 15:24:27 +01:00
FredApps 87cfbac0ee Merge branch 'main' of https://github.com/storytold/wordcraft into pr-5559
# Conflicts:
#	ROADMAP.md
#	crates/formats/src/odt.rs
#	crates/formats/src/odt/body.rs
#	crates/formats/src/odt/import.rs
#	crates/formats/src/odt/page_parts.rs
#	docs/file-format-parity.md
#	docs/gaps.md
2026-11-04 15:13:22 +01:00
Bryan MarkandClaude Opus 5.5 b2734c28f4 Undo: steps share the style sheet and list definitions (1.2 GB → 21 MB at the limit) (#2694)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:03:13 +01:00
ReesandClaude Opus 5.5 ed231fd027 Walk Print Markup comment objects once (#3614) (#4744)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 14:49:31 +01:00
FredApps 06d699dcb7 ODT: round-5 review fixes 2026-11-04 14:44:19 +01:00
VoiceLessQ 560565cdd7 Audit fixes for 12 issues: import limits, escaping, link schemes, table depth (#3862) 2026-11-04 14:13:36 +01:00
Valentin KleinandClaude Sonnet 5.5 1350f62bf0 #2726: AccessKit focus guard — every tree update carries its focused node (#2742)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 13:59:15 +01:00
FredApps 8b9f726ea7 Merge main (688cce47) into ODT PR 2026-11-04 13:44:24 +01:00
.CooCoo 688cce4731 Read Mode: ink and drag previews follow the Page color, which is kept between entries (#4228) 2026-11-04 13:41:06 +01:00
FredApps b6afa0ba3c Review fixes: kept object names skipped (headers too), self-closed settings, STYLEREF/XE after a leading space, RTL padding, split cell backgrounds, PAGE in a table moved by a page break, written-as-read doc 2026-11-04 13:38:55 +01:00
6ec85141d5 Arabic interface: mirror the remaining label/field dialogs (#5449)
* Arabic interface: mirrored right-to-left window and Arabic UI fonts

Adds the Arabic (`ar`) interface language's code: its catalogs are craft-i18n's
`locales/ar`, so this changes no catalog.

- `ar` is registered in `i18n::LANGUAGES` and `Lang::rtl()` says it is written
  right to left; its translations are used as written (egui's text layout
  orders each line's bidi text itself). A ribbon location reads from the right
  with a leftwards mark.
- `rtl.rs`: the window is mirrored. Containers open in `rtl::root`; columns,
  grids, checkboxes, radio buttons, menus, rows, panels, the dialog tab strip
  and the ribbon's scrolling row follow the language's direction. Title bar,
  status bar, ribbon tabs and groups, File pages (including Print, with the
  settings on the right and a solid scrollbar gutter), dialogs, menus and the
  task panes (their docking edge swaps) are laid out from the right. egui's
  `Grid` panics in a right-aligned layout, so grids go through `rtl::grid`.
- Arabic UI font fallback: the craft-fonts Arabic face, else an installed
  Arabic font, loaded when the interface is Arabic.
- The "Auto (200%)" size label keeps its percent sign inside the isolated
  number.
- Tests: Arabic locale, saved preference and lookup order on fixture catalogs;
  an interface audit (skipped without the craft-i18n Arabic catalog) that lays
  the app out right to left at several widths, checks tab, group, pane, Print
  and Go To positions and that nothing panics.

The Arabic work builds on Abdelhaq El Amraoui's mirrored-interface PR (#737).

Co-Authored-By: Abdelhaq El Amraoui <abdelhaqelamraoui@gmail.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: pin craft-i18n at a commit with the Arabic catalog; review fixes

- craft-i18n.rev and the Flatpak manifest pin 19358491 (craft-i18n main), the
  first commit line that has locales/ar/wordcraft.tsv. The old pin had no
  Arabic catalog, so `ar` was registered but not embedded and two i18n tests
  (the_language_setting_is_a_ui_command_and_persists,
  the_languages_offered_are_the_embedded_ones_of_the_list) failed in CI.
- The Arabic font fallback is requested for any right-to-left interface
  (`Lang::rtl()`), not only after the language picker sets the flag, so an
  automatic or saved Arabic gets the installed Arabic face.
- The file browser, the update window and Reading Mode's toolbar run their
  bodies in `rtl::root`, so their far-side buttons and rows are mirrored.
- A group in a right-to-left ribbon row is measured from the right edge: the
  cursor's left edge is negative infinity there, so its width was NaN and the
  ribbon planner dropped every group, never compacting a narrow Arabic window.
  A narrow window now folds groups into drop-downs.
- The mirrored checkbox and radio marks are labelled by their text, so screen
  readers name them.
- Tests: group width in a right-to-left row; the Arabic interface audit checks
  Reading Mode's toolbar.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: ask for the installed Arabic font separately from the CJK one

A previous commit made every right-to-left interface request the installed CJK
fallback font (`system_cjk`) so that the installed Arabic font would load. That
also made every Arabic launch read a large system CJK font file when no
craft-fonts input is embedded (the Flatpak build has none).

`install_ui_fonts` now passes a separate `system_arabic` flag (`Lang::rtl()`):
the installed Arabic font is read for it, and `system_cjk` is again set only
by a CJK interface or by CJK text on screen. `WordApp::fonts_system_arabic`
remembers what was installed, so a language change reinstalls the fonts.

Tests: the_installed_arabic_font_is_asked_for_by_arabic_alone (the Arabic flag
adds the installed font only when none is embedded, and the CJK request alone
adds no Arabic font). Checked a headless screenshot of the Arabic interface
without craft-fonts: the installed Arabic font draws the labels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Fix the AutoSave switch knob: on is at the right, mirrored in Arabic

The title bar's AutoSave knob was placed with `lead_x(rtl == on, ..)`, which
reverses main's mapping in both directions: left to right it drew the knob at
the left when the switch was on, and right to left at the right. main draws it
at the right when on and at the left when off, so the mirrored interface must
draw it at the left when on: `rtl != on`.

The position is now `autosave_knob_x(rtl, on, track)`, pinned by a test for all
four cases. A headless screenshot of the off switch shows the knob at the left
in English and at the right in Arabic.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: file names and paths in right-to-left lines; kerning row order

Tester feedback on the Arabic interface:

- File > Open's Recent list, the built-in file browser and the title bar drew
  file names and paths raw, from the left edge. In an Arabic line the marks of
  a name ("(نهائي) 2.docx") and the folders of a path with Arabic parts were
  scrambled. Rows now start at the side reading starts from (`rtl::lead_x`),
  names go through `i18n::isolate` (a first-strong isolate, with a left-to-right
  mark before the extension so `2.docx` stays `2.docx`) and paths through
  `i18n::isolate_path` (a left-to-right isolate with a mark after every
  separator, so neighbouring Arabic folders do not swap). Other languages get
  the text untouched; saved and spoken text never carries the marks.
- Font dialog, Kerning row: the dialog's grid is drawn left to right inside a
  right-to-left window, so "Points and above" came after its number; in an
  Arabic interface it now comes first, so the line reads "14 نقطة فأكثر" from the
  right. (The grid's columns themselves still keep their left-to-right order.)

Tests: names_and_paths_are_isolated_in_a_right_to_left_interface.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: mirror through craft_ui::direction and Style::right_to_left

The suite's craft-ui now has the direction helpers (`craft_ui::direction`) and
its egui fork a `Style::right_to_left` that mirrors egui's own chrome. Use them
instead of our parallel wrappers:

- `rtl::sync(ctx)` applies the interface direction every frame the language's
  changes (`direction::apply`): it sets the shared direction state and
  `Style::right_to_left` on every theme, which draws check boxes and radio
  buttons with the mark at the reading start, mirrors submenus, scroll bars,
  title bars and the combo boxes' arrows (the Print page's choice lists, the
  font list) and opens combo menus from the right.
- `rtl::checkbox`, `radio_value`, `radio` and `indeterminate_checkbox` are
  gone: about 200 call sites use plain `ui.checkbox`, `ui.radio_value`, ... and
  egui does the mirroring (and names the control by its text, as a plain widget).
- `lead_x`, `lead_center`, `lead_top`, `start_panel` and `end_panel` delegate to
  `craft_ui::direction`. `root`, `flows`, `island`, `grid`, `menu`, `vertical`,
  `far_side` and the other layout helpers stay: the shared crate has no
  equivalent that fits them.

Visual changes: the combo boxes' drop-down arrows and lists are mirrored in
Arabic; nothing changes in left-to-right languages (checked headless
screenshots of the English main window, Font dialog and Print page).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Recent files and the file browser: full path on hover, long names keep their start

Review feedback:

- Each row of File > Open's Recent list shows the document's full path as its
  tooltip (the path line under the name can be longer than the row).
- A long name in the built-in file browser is laid out in one row, with an
  ellipsis at its end, from the side reading starts from, instead of being
  clipped at the row's edge: in a right-to-left interface the old text anchored
  at the right edge cut the end of an Arabic name and the start of a Latin one.
  The whole name is the row's tooltip when it was shortened.

Checked headless screenshots of the file browser with a long English and a long
Arabic name.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Font combos in a right-to-left row: the arrow joins its field on the left

The ribbon's font name and size boxes are drawn from a field and a separate
arrow box that share one outline: the field is square and the arrow's box is
rounded on the side where the arrow goes, painted a border width under the
field. That assumed the arrow is right of the field. In a right-to-left row
(the Arabic ribbon) the arrow comes after the field on its left, so the field
was square on the wrong side and the arrow box rounded on the side facing the
field: two boxes with a gap-like seam, the arrow looking outside the frame.

`arrow_box_shape(rtl, ..)` mirrors the radii and the underlap, and the field's
square corners are chosen by the row's direction (the nw/sw pair in right to
left). Left-to-right rows are drawn exactly as before (English before/after
crops are identical).

Test: the_arrow_box_is_rounded_away_from_its_field.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Pin craft-i18n 4612850 (merged Arabic WordCraft rows, craft-i18n#76)

The pin and the Flatpak manifest commit move from 1935849 to 4612850, which is on
craft-i18n main and adds the 70 Arabic rows this branch relies on.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Pin craft-i18n cac2cf0 (Arabic number agreement and status-bar rows)

Moves the pin and the Flatpak manifest commit from 4612850 to the current craft-i18n
main, which includes craft-i18n#95 (48bed03) and #81 (ef58ff3).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic: isolate paths shown beside labels; mirror the Print page zoom

File > Info shows Location as its own left-to-right path label (cut short with the full path on hover, not wrapped), and the open-failure, Exported and dictionary-file messages isolate their paths. The Print preview zoom puts minus at the slider's left end and plus at its right in Arabic, as the status bar does.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic: mirror the label/field rows of the Font, Info, Paragraph, Page Setup, Insert Table and Options forms

rtl::Table lays a form out as an egui Grid in a left-to-right interface (same id, columns and spacing, so the output is unchanged) and, where the interface is mirrored, with each row's cells running from the right, every column as wide as its widest cell. File > Info puts Properties at the right and Statistics after it, and the Font dialog's kerning row reads 14 points and above.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Docs: record the mirrored Arabic interface in the roadmap, gaps and localization parity

Progress log, the Arabic language row, gap 11 and the status lines and revision histories of the three docs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Insert Hyperlink, Word Count, Phonetic Guide, New Style, Modify Style, Encrypt, merge rule and Match Fields dialogs read right to left

Their label-and-field rows use rtl::Table, so in a mirrored interface the label is at the right with its field to its left. rtl::Table gains striped() for Match Fields. English renders are pixel-identical (only a caret-blink strip differs in an untouched dialog).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Line Numbers, Hyphenation, Drop Cap, Caption, Cross-reference, Index, Mark Index Entry and Source dialogs read right to left

Their label-and-field rows use rtl::Table (label at the right, field to its left). English renders are pixel-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Picture Size, Split Cells, Convert Text to Table, Footnote and Endnote, Table Properties, Cell Options and Custom Properties dialogs read right to left

Their label-and-field rows use rtl::Table. Picture Size's Height and Width pairs read Height first at the right. English renders are pixel-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Define New Multilevel List, Track Changes Options, content control properties, custom colours and table style dialogs read right to left

Label, field and swatch rows use rtl::Table. English renders are pixel-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Columns widths, Special Characters, Compare, AutoCorrect and About Models tables read right to left

Table columns now start at the right edge (rtl::Table gains top(), min_row_height() and an unset column count). About > Models stays a left-to-right scroll box with its columns listed from the right. English renders are pixel-identical (only the caret blink differs).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: table-of-contents styles, recipient filter and sort, and the ribbon Paragraph group read right to left

rtl::Table now stacks its rows top to bottom whatever way the area around it runs (a ribbon group lays out in a row). English renders are pixel-identical (caret blink and a status toast differ in untouched dialogs). The TOC options and recipient filter/sort rows are converted by pattern and not seen in an image.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Columns preset tiles and Preview label, Macros, Add/Remove arrows, Zoom slider and the Recipient List grid

A preset tile is as wide as its caption and centres it (the long Arabic captions ran into the next tile); the Preview column keeps its width so its label no longer wraps letter by letter; Macros puts the name box and list at the reading start with the buttons beside them; the Add >> and << Remove arrows swap in a mirrored interface so they point the way the items move; the Zoom slider is drawn left to right as in English; the Recipient List data grid scrolls left to right instead of running past the left edge. English renders are pixel-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: the chart type and SmartArt layout galleries list their tiles from the right

The chart type dialog, the Insert SmartArt dialog and the ribbon's SmartArt Layouts gallery use rtl::Table rows, so the first tile sits at the reading start. English renders are pixel-identical.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Take main's panes/host.rs after the merge

The merge kept a use of mirrored() that main's pane-dock fix removed; this branch does not touch the panes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: Columns preset captions are translated in the mirrored tile

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic: one Arabic and one French row in the localization parity table; About > Models columns read from the right

The merge left the Arabic and French rows twice in docs/localization-parity.md; each
is now a single row (main's current French text, the Arabic row with the dialogs
note). About > Models keeps main's fitted table but lists its columns, their
alignments and grow weights reversed when the interface is mirrored, so Company
starts at the reading edge. The credits.rs change comes from tareq's helper merge.

Co-authored-by: tareq <tareq.halaby@gmail.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* About > Models: the mirrored table keeps its own widths and scroll position

The columns are listed in reverse when the interface is mirrored, and egui keeps the
resizable column widths and the scroll offset by id. A language switched at run time
would apply one direction's widths to the other's columns, so the mirrored table uses
its own id.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* Arabic interface: About > Models alignment mirrors as its comment says

The mirrored Models table reversed the per-column right-align flags but
did not negate them, so in Arabic the text columns stayed left-aligned and
the counts right-aligned, the opposite of the comment ("counts line up on
the right (left in RTL)"). Negate after reversing so the text sits at the
reading edge and the counts on the left. Keep this line when touching
models_ui.

* About > Models: a mirrored table that overflows opens at its reading edge

The reversed Arabic table puts Company in the rightmost column, but the
horizontal scroll area started at the left, so when the table was wider
than the dialog (narrow window, widened columns) Company and Model were
offscreen. Stick the scroll area to the right in a mirrored interface.

---------

Co-authored-by: Abdelhaq El Amraoui <abdelhaqelamraoui@gmail.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: email <email@email.com>
Co-authored-by: tareq <tareq.halaby@gmail.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-04 13:36:55 +01:00
midasdfandClaude Opus 5.5 2d6dff96cc Layout: 行頭禁則 lists small kana and the prolonged sound mark (JIS X 4051 §4), with the emergency-break gap documented (#2558)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 13:31:39 +01:00
FredApps d2f504e29a Review fixes: package-wide PBKDF2 budget, CLI keeps the ODF style, turned linked boxes, path close, centred PDF fill, doc status (gap 19) 2026-11-04 12:50:36 +01:00
.CooCoo e847b2e5e3 AutoFormat: a tracked heading or border line replaces another author's formatting change (#4231) 2026-11-04 12:27:08 +01:00
VoiceLessQ fd1c5efe6c Format readers: one border-type table for .doc, one HYPERLINK parser for DOCX, RTF and .doc (#4222) 2026-11-04 12:13:39 +01:00
VoiceLessQ 655b4312d3 DOCX: nil shading paints no fill, border theme colours win (part of #1991) (#4705) 2026-11-04 11:58:06 +01:00
FredApps 773ef21f9f Merge origin/main into the ODT branch (gap 19)
# Conflicts:
#	ROADMAP.md
#	crates/layout/src/tests.rs
#	docs/gaps.md
#	docs/layout-parity.md
2026-11-04 11:57:31 +01:00
FredApps 53bccd5442 ODT: two display styles (Microsoft Word style, LibreOffice style) and review fixes (gap 19)
- odf.preset: word (Microsoft Word style, default) or libreoffice; wordcraft still read as word
- Options, CLI (WORDCRAFT_ODF), docs and ROADMAP follow the two styles
- CodeRabbit: kept groups and story fingerprints follow fill_objects; padding serde default;
  list field depth; literal doubled quote; ASK/SET results not exported; dc:date offsets;
  first_pages order; unique picture names; finite raise clamp; PDF rotated-text guard;
  .ott in the password message; flat element bounded by depth; cell tile fallback;
  ROADMAP and docs reconciled
- Remove clean-room wording from the ODT tests
2026-11-04 11:55:49 +01:00
Aleksander HelgakerandClaude Opus 5.5 ba58e70cc8 Flag document fonts that aren't installed (#4770)
* Gap 4: flag document fonts that aren't installed

The font box (ribbon, mini toolbar, both Font dialog boxes) shows a
warning mark when the current font isn't installed; its hover note
names the font drawn instead. The status bar says "N fonts not
installed" and lists each with the faces drawn instead, plus Add Font….
Agents get `font.missing` and `format.state.fontShownAs`.

Layout records, where it picks a face per text segment, the fonts the
shown text asks for that aren't installed and the faces drawn instead
(ParaLayout::substituted, DocLayout::substituted_fonts), so hidden
text, unused styles and orphaned stories never count; list labels,
field results and East Asian and complex-script text do, and so does a
missing roman font drawn in Cambria. Metric-compatible substitutes and
symbol fonts drawn as Unicode aren't flagged. Bounded for hostile
files: 64 pairs a paragraph, 1024 a document, names kept to 256
characters, 20 rows in the popup.

Ported from alehel/wordcraft#1 onto current main; English strings only
(translations belong in storytold/craft-i18n).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: missing-font review fixes

- Judge a padded font name by the face layout drew for it, and skip blank names.
- Name the face CJK text is drawn in for a missing East Asian font, not Cambria.
- Keep the missing-fonts list per window, so several windows don't rebuild it every frame.
- Expose the font box's warning to screen readers as its description.
- Count missing fonts with craft-i18n plurals (`i18n::tn`).
- One table of metric twins (`fonts::word::METRIC_TWINS`): a missing font is drawn in an
  installed twin first, and the warning reads the same table.
- Find the status-bar item by part of its label in the click test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: warn for a font picked at the caret; drop fonts of hidden list items

- At a collapsed caret the font box warns for a missing font typing will use, also at the end
  of text in another font (it waited for the first letter).
- A list item that shows nothing (#3982) reports no missing font: its number was shaped, and
  its font recorded, before layout dropped it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: say where Add Font… is, and that it needs the font file

The font box's note said "Add Font… installs it": Add Font… opens a file picker at the end of
the list, so it only helps with a font file at hand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: docs say the popup lists 20, and when the font box warns ahead

CodeRabbit review: the status-bar popup lists the first 20 missing fonts, then a count; the font
box also warns at a collapsed caret for a font no shown text uses yet; `fontShownAs` is the
font's substitute, fallback faces aside.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: the Font dialog warns for a missing font over a selection

CodeRabbit review: the dialog's boxes show the fonts OK applies, which no shown text may use
yet (an Asian text font over Latin text, a font typed into the dialog), so they name the
substitute whatever is selected. The ribbon's box over a selection still reads the list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: the Asian font box names the face CJK text gets

CodeRabbit review: the status bar's list is by font name, so for a font Latin text also uses
it named the Latin text's substitute. The Asian text box now always looks up the face layout
draws Chinese, Japanese and Korean text in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: gaps.md status on the current line, missing-font scope and twin wording

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: gaps.md says which missing fonts are flagged and what font.missing lists

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Gap 4: font.missing lists what the current view lays out

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 11:48:48 +01:00
Bryan MarkandClaude Opus 5.5 6f62716f08 Text boxes: a press inside one goes to its text, not to a picture under it (#4240)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 11:31:58 +01:00
alehelandClaude Opus 5.5 56c85834f1 Merge origin/main into the ODT branch (gap 19)
Conflicts kept both sides. Where the two branches met:
- Para.mark: both added it. It stays CharProps (ODT needs it); HTML's
  `<p>&nbsp;</p>` converts its Fmt, and to_doc reads it in one place.
- Arrowheads: the PR's line ends (top left to bottom right) with main's
  arrowhead styles.
- inline_rect: the PR's depth below the baseline with main's rule room.
- Spacing and Cell literals take main's new fields.
- The zip entry guard (#3660) also covers the encrypted ODT paths, which
  parsed a package before it; regression test in tests_more/encryption.rs.
- chunks_exact to as_chunks in odt/frames.rs and odt/path.rs (clippy).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:51:35 +01:00