Commit Graph
1028 Commits
Author SHA1 Message Date
Marc-Antoine Girard 6655ba675d UI: fix Select icon polygon rendering (#1193) 2026-10-14 17:58:44 -04:00
Marco Arnulfo 01efd53aea Modify Style picks its font from the font box the ribbon uses (#1187) 2026-10-14 17:58:30 -04:00
Marco ArnulfoandBrandon Thomas b309af4148 Keytips: Alt, J, T and Alt, J, L open the table tabs like Word (#1185)
Table Design and Table Layout were in the keytip tab list inside a table but had no letter, so no badge showed and no key reached them. They now take Word's two-letter badges, JT and JL: J waits for the second letter and narrows the tab badges to the J ones, then the tab's control badges show as on any other tab.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 17:58:18 -04:00
9f7330664b Word forms keep their legacy form fields and rows' skipped grid columns when saved (#1184)
* Word forms keep their legacy form fields and rows' skipped grid columns when saved (part of #1174)

* Tests: field initializers name the new form field

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:58:07 -04:00
Brandon ThomasandClaude Opus 5.5 373df5adf1 CI: recovery pruning test retries a scan that a lock race skipped
failed_pruning_cannot_push_a_record_beyond_the_discovery_limit failed
once in a full workspace run: a record whose lock is briefly held (by a
child another test is spawning, which shares the descriptor until it
execs) is skipped rather than reported, so scan() returned Ok. The test
now retries for up to a second before asserting.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:39:06 -04:00
b3af58602b STYLEREF review follow-ups: headers stay cached, switch labels in our own words (#1286) (#1294)
* #1286: key STYLEREF header caches on their per-page results; STYLEREF N finds a localized heading N

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

* #1286: reword the STYLEREF switch labels in our own words, in every catalog

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

* #1286: drop a stray table row from the ROADMAP progress log

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

* #1286: layout-parity STYLEREF row (carried over the rebase)

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

* vi: STYLEREF switch labels as reworded

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 17:22:36 -04:00
ReesandBrandon Thomas bfacaf3627 fix(layout): preserve legacy table paragraph spacing (#577)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 17:22:17 -04:00
3d8f8144d9 File: recover unsaved work after a crash (#518) (#586)
* M10: retain local crash recovery on current main

* i18n: Backstage Recover in every catalog

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:21:57 -04:00
92c0036d72 Russian proofing: spelling, suggestions, grammar and word division (#894)
* Russian proofing: spelling, suggestions, grammar and word division

Runs tagged ru get Russian tools instead of none:
- spelling against an installed ru_RU Hunspell dictionary (not bundled;
  LibreOffice dict-ru folders searched; KOI8-R and Windows-1251 decoded),
  with ё optional, hyphenated words and solid compounds understood, не with
  adjectives, participles and verbal nouns, prefixed verbs, abbreviations
  with endings and camel case left alone, plus our supplement of modern
  words with their declensions (assets/spelling/ru-extra.txt);
- suggestions tuned for Russian: е/ё, letter groups, common confusions,
  missing spaces, typos and a stem scan;
- grammar rules with Russian messages (repeated words, spaces, sentence
  capitals with Russian abbreviations, likely missing commas before
  clause openers, doubled punctuation);
- Russian word division from the spelling rules, written as code.

* Options: Russian in the dictionaries list (ProofLang::Ru arm)

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

---------

Co-authored-by: Магда М.Г. <mail@mgmagda.ru>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:21:39 -04:00
ReesandBrandon Thomas 248dae4bd1 fix(layout): prevent list labels from inflating line height (#601)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 17:21:20 -04:00
575c5f98df .doc: open password-protected Word 97–2003 files (RC4, RC4 CryptoAPI, XOR) (#1079) (#1087)
docbin decrypts XOR-obfuscated, RC4 and RC4 CryptoAPI files after verifying the
password against the stored verifier; the engine reuses the .docx password
prompt errors. Written from [MS-DOC] and [MS-OFFCRYPTO]; synthetic tests only.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 17:21:08 -04:00
eb54d88ec0 Mail merge: .xls recipients, legacy encodings, Filter and Sort (#778) (#885)
* #778: .xls and legacy-encoding recipient lists; filter and sort recipients

- Recipient lists: legacy Excel 97-2003 .xls (BIFF8 reader on the cfb crate already in the
  tree); Excel 5.0/95 and password-protected .xls refused with a clear message; a CSV named
  .xls reads as text, an HTML one gets an error. .xls added to the picker filters (desktop,
  web, built-in browser) and drop handling.
- Text lists (and plain-text import) detect legacy encodings when not UTF-8/UTF-16: GBK/GB18030,
  Big5, Shift_JIS, EUC-KR, Windows code pages (encoding_rs + chardetng, MIT/Apache); an
  `encoding` param overrides.
- mailings.filterRecipients / mailings.sortRecipients: field, comparison (equal, notEqual,
  less, greater, lessOrEqual, greaterOrEqual, blank, notBlank, contains, notContains), value,
  And/Or joins; sort keys. Preview, Finish & Merge and labels use only the matching records
  in sort order. Edit Recipient List edits every record and keeps the filter.
- Recipient List dialog: Filter and Sort section and a merge-order column; catalog rows;
  strings in every catalog; docs.

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

* i18n: Hungarian and French strings for this change

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

* Review fixes for #885: total order for recipient sort, Bulgarian strings

- compare_cells now ranks numbers (compared numerically) before text (compared
  case-insensitively), so it is a total order; a column mixing 9, 10 and 1a
  could make slice::sort_by panic. Regression test sorts mixed columns.
- Bulgarian catalog: the 24 Filter and Sort strings.

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

* vi: mail merge Filter and Sort strings

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:57:06 -04:00
cf9a4ff7fa STYLEREF fields show each page's result in headers and footers (#775) (#882)
* #775: STYLEREF fields in headers and footers show each page's result

Running headers/footers with STYLEREF (e.g. the current chapter title) are
evaluated per page at layout time (ECMA-376 §17.16.5.59): the page's first
paragraph of the style (\l: last), else the nearest before, else after.
Style names/ids, heading levels (STYLEREF 1), character styles, and the
\n \r \w \s \t \p switches. Body STYLEREF fields update with the other
fields. STYLEREF added to Insert › Quick Parts › Field with its options.

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

* #775: STYLEREF error text in our own words

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

* Review fixes for #882: translate the STYLEREF Field dialog strings

Adds the style picker label, the six STYLEREF switch labels and the
STYLEREF description to all 18 interface catalogs.

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

* STYLEREF: reuse the style index while the body and styles are unchanged

Headers with STYLEREF rebuilt and hashed the body's style index on every
layout pass (echelon's follow-up note on #882). The layout cache now keeps
the index with the body blocks it came from (shared, so an edited block is
a different pointer) and the styles/numbering hash, and rebuilds it only
when either changed.

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

* vi: STYLEREF field strings

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:56:47 -04:00
ReesandBrandon Thomas 8e0f42e4bc fix(layout): match Word's contextual paragraph spacing (#568)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:56:29 -04:00
Valentin KleinandClaude Opus 5.5 f822dcb23c macOS packaging: strip extended attributes before signing and verify the DMG's app strictly (#525) (#527)
hdiutil makehybrid -hfs gave every file and folder in the image a
com.apple.FinderInfo, so WordCraft.app failed codesign --verify --deep
--strict inside the released DMG and after copying it out with ditto.

- Build the DMG with hdiutil create -srcfolder -fs HFS+ -format UDZO
  (retried: attaching a device is flaky on CI runners).
- Clear extended attributes on the bundle before signing.
- After signing the DMG, mount it read-only and strictly verify the app
  inside it and a ditto copy of it (plus spctl when notarizing), so the
  release job fails if this regresses.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:56:10 -04:00
Gert Pellin - GPEandBrandon Thomas 1e4ed377d8 README: install on Gentoo from the ::snakebyte overlay (#16)
* README: install on Gentoo from the ::snakebyte overlay

* Contributors: credit switch87 as Gert Pellin

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:55:59 -04:00
2686e20330 Docs: gaps.md re-audited against main (#1071)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:55:40 -04:00
3e20488c15 Comments: an option to show only the selected text's comment (#1055) (#1066)
* test(engine): drop a needless drop() that clippy 1.97 rejects (drop_non_drop)

* Comments: a click inside a selected balloon moves the caret in its text (#1013)

- The canvas under the markup area also "contains" the pointer, so a press on the balloon counted as a click on the page and left it
- Presses over a balloon card now belong to the card, in both the deselect check and the document click in mouse()
- Test: press, drag and release inside the selected balloon; a click on the page still leaves it

* Comments: an option to show only the selected text's comment (#1055)

- Track Changes Options › Comments: "In the margin" (default, as in Word) or "Only for the selected text"
- The second mode takes comments out of the margin column; the comment under the caret, or the clicked one, floats beside the page, over its edge in a narrow window
- The floating card has its own foreground layer, so presses on it never reach the canvas
- review.trackingOptions takes commentDisplay: margin|selected
- comment_range_at_caret: the comment whose range holds the caret
- Strings in all catalogs; tests for the option, the helper and the card's clicks

* vi: comment display options

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:55:27 -04:00
77da439d0b DOCX: carry unmodelled parts; keep comment ids, style defaults, latent styles, list ids and app props (#1034) (#1060)
* DOCX: merge settings.xml into the original instead of regenerating it (#1034)

A save regenerated word/settings.xml from the model, so every setting the
model doesn't hold was dropped: compatibility options (lost in 18 of 18
real-world Word files), rsids, document variables, proofing state and the
colour scheme mapping.

The reader now keeps the original part when it holds such settings, and
the writer merges into it: the original root and every unowned child stay
byte for byte; owned children follow the model in CT_Settings order; in
w:compat only compatibilityMode is replaced. The privacy options are the
model's since #1062, so they are owned too. Kept children that point at a
relationship (a mail-merge data source) are dropped. Anything unexpected
falls back to the generated part. Files WordCraft wrote itself keep
nothing extra.

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

* DOCX: carry unmodelled parts and keep comment ids, style defaults, latent styles, list ids and app props (#1034)

Builds on the settings.xml merge.

- Parts the package or main document relate to that WordCraft neither
  models nor writes (webSettings, stylesWithEffects, people, add-in task
  panes, the thumbnail, future parts) are carried verbatim with their
  relationships and content types; relationship types the writer
  produces, and any the body refers to by id, are not (HANDLED_RELS).
- commentsIds / commentsExtensible: durable ids and UTC dates are read
  into the model and regenerated against the written paragraph ids.
- w:default on localized default styles, w:latentStyles, lists'
  nsid/tmpl/multiLevelType, and app.xml Template/Company/Manager/
  HyperlinkBase round-trip; counts are not carried, and Company/Manager
  are dropped when the file asks to remove personal information.
- Comment reference marks use the document's "annotation reference"
  style id instead of a hard-coded CommentReference.

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

---------

Co-authored-by: przemek-arch <263159043+przemek-arch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:55:15 -04:00
Brandon ThomasandClaude Opus 5.5 2215e52aa4 CI: park the mini-toolbar scroll test that #1501 and #1069 disagree on
#1069's the_bar_scrolls_under_the_ribbon_not_over_it expects the bar to
slide under the ribbon with a selection scrolled above the document;
#1501 (landed first) anchors the bar to the visible selection only, so
the selection has no anchor there and the test fails on main. Ignored
with the reason until the owner picks the behaviour.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:37:03 -04:00
e1f34a90d6 Proofing: a Dictionaries folder setting, and the dictionary each language found (#1063) (#1084)
File › Options › Proofing gets a Dictionaries folder: a folder of Hunspell
.aff/.dic files searched before the system locations, saved with the settings
and applied at start-up. An app started from Finder or the Dock doesn't see
WORDCRAFT_DICTIONARIES, so this is how it finds a dictionary kept in a folder
of the user's own. Changing it reloads the Polish and Portuguese dictionaries
and checks the text again. The pane lists the dictionary file each language
found, or that none was found, so missing spelling marks are explained.

Agents set it with file.options {"dictionariesFolder": path | "auto"}; a
missing folder or a relative path is refused and changes nothing.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:25:00 -04:00
Todd PedersonandClaude Opus 5.5 b8e46b244d UI: combo boxes join their dropdown arrow (field rounded left, arrow right) (#1083)
* Clippy 1.96: simplify boolean guards, drop a needless drop()

Rust 1.96's clippy flags nonminimal_bool in find_pattern, table_mouse and
table_resize, and drop_non_drop in a ribbon test; `cargo xtask ci` failed at
clippy on main. Same logic, rewritten as clippy suggests.

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

* UI: combo boxes join their dropdown arrow (field rounded left, arrow right)

The font and size boxes looked apart from their arrows: the text field was
rounded on all four corners and the arrow on none, leaving a notch where they
meet. The field now rounds only its left corners (in every widget state,
including focus and hover) and the arrow only its right ones, so the two read
as one control. Applies to every combo drawn by widgets::combo/font_combo:
the ribbon's font, size and outline-level boxes, the mini toolbar, and the
Font and Symbol dialogs.

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

* UI: one divider between a combo's field and its arrow

The field's right border and the arrow's left border stood side by side, a
divider twice as wide as the rest of the outline. The arrow's box is now
painted under the field and reaches one border width beneath it, so the
field's right border is the only line between them (in the field's focus
colour while typing). The test draws with the app's light and dark themes.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:24:40 -04:00
Sazid Al BayazidandBrandon Thomas 3962d397e5 Contributors: add Sazid Al Bayazid (albayazid) to people.toml (#1074)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:24:28 -04:00
3e9dde7799 Docs: encrypted DOCX row, duplicate document-grid rows, dated issue count (#1072)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:24:09 -04:00
a04356933c UI: mini toolbar steps aside for the ribbon (#1069)
* Clippy 1.96: simplify boolean guards, drop a needless drop()

Rust 1.96's clippy flags nonminimal_bool in find_pattern, table_mouse and
table_resize, and drop_non_drop in a ribbon test; `cargo xtask ci` failed at
clippy on main. Same logic, rewritten as clippy suggests.

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

* UI: mini toolbar steps aside for the ribbon

The mini toolbar covered the ribbon's drop-downs (the font size list opened
under it). A press outside the document and the bar (the ribbon, a pane, the
rulers, the status bar) now puts the bar away until the selection changes or
the next press in the document; presses on popups (the bar's own lists, an
open ribbon list over the page) neither hide nor restore it. The bar also
moves from the Tooltip layer to Middle, so every popup and menu draws over
it, as its comment always said.

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

* UI: mini toolbar scrolls under the ribbon, not over it

With text selected, scrolling the selection up toward the ribbon carried the
mini toolbar along on top of the rulers and ribbon. The bar is now clipped to
the document area: it slides under the rulers and ribbon (or the status bar)
with the text and goes once none of it shows. Its area is constrained to the
document for hit testing too, so the hidden part no longer swallows clicks
and drags meant for the ruler or the ribbon underneath.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:23:50 -04:00
gossardlaandBrandon Thomas 896c1bbebf Comments: a click inside a selected balloon moves the caret in its text (#1013) (#1051)
* test(engine): drop a needless drop() that clippy 1.97 rejects (drop_non_drop)

* Comments: a click inside a selected balloon moves the caret in its text (#1013)

- The canvas under the markup area also "contains" the pointer, so a press on the balloon counted as a click on the page and left it
- Presses over a balloon card now belong to the card, in both the deselect check and the document click in mouse()
- Test: press, drag and release inside the selected balloon; a click on the page still leaves it

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:23:31 -04:00
Brandon ThomasandClaude Opus 5.5 a4870128b5 CI: Hebrew font substitution test expects David only on Windows
#1052's test asserted that every Hebrew font falls back to David, but
only the Windows fallback list has it, so it failed on Linux and macOS.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:11:27 -04:00
d2ff87856f DOCX: merge settings.xml into the original instead of regenerating it (#1034) (#1059)
A save regenerated word/settings.xml from the model, so every setting the
model doesn't hold was dropped: compatibility options (lost in 18 of 18
real-world Word files), rsids, document variables, proofing state and the
colour scheme mapping.

The reader now keeps the original part when it holds such settings, and
the writer merges into it: the original root and every unowned child stay
byte for byte; owned children follow the model in CT_Settings order; in
w:compat only compatibilityMode is replaced. The privacy options are the
model's since #1062, so they are owned too. Kept children that point at a
relationship (a mail-merge data source) are dropped. Anything unexpected
falls back to the generated part. Files WordCraft wrote itself keep
nothing extra.

Co-authored-by: przemek-arch <263159043+przemek-arch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:05:06 -04:00
b53fc8ca6e fonts: Add platform-specific Hebrew font support (#1052)
* fonts: Add platform-specific Hebrew font support

Add proper Hebrew font substitution and fallback for Windows, macOS, and Linux:
- Windows: Prioritize David/Miriam (Office) and Segoe UI fonts
- macOS: Prioritize Helvetica and Geeza Pro (system defaults)
- Linux: Use Noto Sans Hebrew and open-source fonts

Fixes Hebrew character display issue (showing rectangles) when editing
text in fonts without Hebrew glyphs by ensuring the system falls back
to Hebrew-capable fonts. Includes platform-optimized font lists in
both document font resolution (word.rs) and RTL text fallback search
(fontdb.rs).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* rustfmt

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

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:04:47 -04:00
f9f8b67c54 feat(ui): implement Ctrl+drag to copy objects on canvas (#1046)
* feat(ui): implement Ctrl+drag to copy objects on canvas

* feat(ui): implement Ctrl+drag to copy objects on canvas and update translations for "Copy to"

* vi: Copy to

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

* rustfmt

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:04:34 -04:00
1f01a13dfc Track Changes: deletions inside a field result are tracked, accepted and saved (#1037) (#1043)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:04:13 -04:00
gossardlaandBrandon Thomas 85fcbabcb1 Ribbon: holding a press no longer scrolls the document (#1019) (#1041)
* test(engine): drop a needless drop() that clippy 1.97 rejects (drop_non_drop)

* Ribbon: a held press no longer scrolls the document (#1019)

- Double-click release paths in the canvas returned before ending the text drag
- The stale drag made any later press drive the edge auto-scroll
- A drag now ends once the button is up, wherever it was released
- Test: header double-click, then a held press on the ribbon

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:03:52 -04:00
e29fbdb0bf Page background: picture and texture fills are drawn and kept on save (#999) (#1036)
* Page background: picture and texture fills are drawn and kept on save (#999)

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

* rustfmt

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 16:03:32 -04:00
Sergiu Târpescu 060a3333b8 Ribbon menu buttons carry their name for accessibility (#1050)
The Breaks, Margins, Orientation, Size, Columns and other drop-down
buttons are custom-painted and never called widget_info, so assistive
tech and automation saw them as unlabelled. Register the tip as the
button's name, as the small buttons already do.

Regression test: the Layout > Breaks menu is reachable and its Page and
Next Page items insert a page break and a section break.
2026-10-14 15:48:44 -04:00
Sazid Al Bayazid 2fd3b556f3 Layout: keep with next moves the heading when the next paragraph moves for widow control (#966) (#1049) 2026-10-14 15:48:32 -04:00
85dd93a2ba Table eraser: borders beside vertically merged cells merge as in Word (#1039) (#1044)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:48:19 -04:00
Marco ArnulfoandBrandon Thomas e486f7c39d DOCX: keep Office 2016 charts (cx:chart) and their data when saving (#1029)
An mc:AlternateContent whose Choice holds a cx:chart is read as a read-only chart drawn from its fallback picture, keeping both branches and every part they reach (chartEx part, style, colours, workbook, picture). Saving writes the AlternateContent back with the chart's current frame on both branches, instead of only the fallback picture.

Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:47:59 -04:00
Marco ArnulfoandBrandon Thomas 68501de224 One Page and the zoom are saved with the document and restored when it is reopened (#1023)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:47:46 -04:00
6ed1877ce6 i18n(cs): complete the Czech catalog (built-in styles, equation gallery) (#978)
* i18n(cs): wording fixes after #387

SmartArt graphic and layout terms consistent with the rest of the
catalog, inline equation, plural-safe print count, grammar terminology
(mluvnice), tab stop type, file-not-found gender, review author label.
Also adds the [people.Losminek] contributor entry.

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

* i18n(cs): complete the Czech catalog (built-in styles, equation gallery)

Adds the 386 keys the Russian and Spanish catalogs have and Czech did
not: built-in style names and numbered families, the equation gallery,
watermarks, paper sizes, table styles, preview tiles and the remaining
ribbon/menu labels. The Czech coverage test now requires every Russian
and Spanish key and checks built-in style names; localization-parity
updated.

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

* i18n(cs): shorter Proofing label

"Kontrola pravopisu a mluvnice" overflows the fixed 170 px Options
pane list into the content. "Kontrola pravopisu" fits and also reads
well as the Review ribbon group name.

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

* cs: cross-reference strings; drop paper-size rows the menu no longer uses

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

---------

Co-authored-by: Losminek <301412321+Losminek@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:47:35 -04:00
482401f3c4 DOCX: a hyperlink with an empty target is no link (#1005) (#1030)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:31:53 -04:00
Marco Arnulfo 4fcf7da693 macOS: Control-click opens the context menu, with its spelling suggestions (#1025) 2026-10-14 15:31:35 -04:00
8196624e83 Caret: Down and Up from a line start beside a table go into it, not past it (#1021)
Down from the start of the line above a table (or Up from the start of the
paragraph after it) skipped the whole table: `DocLayout::vertical` took the
nearest line covering the caret's x, and a cell's lines start a cell margin in
from the table's edge, so the paragraph beyond the table won. Lines between
the caret's paragraph and that line in document order now come first: the
caret goes into the nearest such line's table row, to the cell under it or the
horizontally nearest. Another cell of the caret's own row never counts, so Down
in a table still goes to the cell below. Pinned in `tests_typing.rs` and
`docs/typing-parity.md`.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:31:22 -04:00
e9d5da31d4 Track Changes: rejecting a whole inserted paragraph keeps the next paragraph's style and numbering (#1020)
Reject All (and Accept All of a whole deleted paragraph) joined the next
paragraph into the emptied one, so the next paragraph took the removed
paragraph's properties: a § heading after a rejected list item became a
list item and later § numbers shifted. An emptied paragraph is now removed
whole, as Word does. Found while round-tripping a Word-saved contract.

Co-authored-by: przemek-arch <263159043+przemek-arch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:31:04 -04:00
aedbbc9325 feat(engine): rename documents from the title bar and open account settings from the badge (#1016)
* M10: enable document renaming and account settings

* no-mistakes(review): Allow case-only document renames without overwriting files

* no-mistakes(review): Keep unsaved rename as session file name, not Title

* no-mistakes(review): Keep AutoSave and Recent across renames; Compare clears name

* no-mistakes(document): Document file.rename write-root rule; dedupe rename gap note

* vi: Rename Document strings

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

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:30:52 -04:00
5597351213 #916: Cross-reference opens a dialog (#1003)
* #916: Cross-reference opens a dialog

The ribbon's Cross-reference button ran insert.crossReference with no
target, which only returns the target list, so nothing happened. It now
opens a Cross-reference dialog: reference type (heading, bookmark,
equation, figure, table), what to insert (text, number, page,
above/below) and the item, ending in insert.crossReference. Scripts and
agents still get the target list.

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

* i18n: Cross-reference dialog strings in the audited catalogs (ru, hu, tr, bg)

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

* i18n: Cross-reference dialog strings in pl, it and vi

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

---------

Co-authored-by: justinjohn0306 <babyjjbabyjj549@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:30:32 -04:00
90762b0529 i18n(cs): wording fixes after #387 (#973)
* i18n(cs): wording fixes after #387

SmartArt graphic and layout terms consistent with the rest of the
catalog, inline equation, plural-safe print count, grammar terminology
(mluvnice), tab stop type, file-not-found gender, review author label.
Also adds the [people.Losminek] contributor entry.

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

* i18n(cs): shorter Proofing label

"Kontrola pravopisu a mluvnice" overflows the fixed 170 px Options
pane list into the content. "Kontrola pravopisu" fits and also reads
well as the Review ribbon group name.

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

---------

Co-authored-by: Losminek <301412321+Losminek@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:30:20 -04:00
Marco ArnulfoandBrandon Thomas 6be7ef10fb Ribbon tabs that don't fit move to a » menu instead of under Comments (#958)
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:30:07 -04:00
Marco Arnulfo ee33d71173 Focus hides the ribbon, status bar and panes; Escape brings them back (#1017) 2026-10-14 15:09:32 -04:00
Navid Zaman Khan 163462338e fix(markdown): preserve table cells containing code spans and pipes (#1009) 2026-10-14 15:09:21 -04:00
Yousef Al-Harbi b34a8744d0 Reset table tools on table deletion and preserve Draw Table outside tables (#1006)
When a user deleted a table while Draw Table or Eraser was active, the
table was removed and the contextual Table Layout tab closed, but the
canvas remained trapped in drawing/erasing mode because `table_pen::stop`
was never called.

- UI: In `WordApp::after_command`, stop active table tools if `table.deleteTable`
  runs, or if `TableTool::Erase` is active and the caret is no longer in a
  table cell.
- Parity: Keeps `TableTool::Draw` active outside tables so users can still
  draw new tables from Insert › Tables.
- Lifecycle: Stop active table tools in `WordApp::execute` when the document
  is replaced.
- Tests: Added regression tests in `crates/ui-egui/src/table_pen.rs`
  verifying that table deletion (explicit or via last row) resets the tool.
2026-10-14 15:09:09 -04:00