mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-26 11:27:10 -06:00
sonar-fix/enforce-https
519
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9cf3b6862f |
Customize Keyboard dialog (#368) (#378)
Tools > Customize Keyboard (tools.customizeKeyboard): pick a category and a command, see its keys, press a combination to see which command uses it, then Assign / Remove / Reset All. Also reachable from File > Options (Keyboard shortcuts: Customize...) and command search. - engine: KeyMap (assigned key -> command, removed built-in keys), consulted before the registry's built-in shortcuts; keys compared in one canonical form. Saved maps read leniently: junk entries and unknown commands are dropped, never failing the rest of the preferences. - tools.customizeKeyboard: with params (assign/remove/reset/command/key) it only changes or reports the map; without params it opens the dialog. - ui: key dispatch and menu/tooltip shortcut text use the user map; the map persists in ui.json; more keys (Q, F1-F12, 4/6/7, Insert) can be bound. - i18n strings in every catalog; docs/ui-parity, gaps #24, ROADMAP log. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
41bbaf51bf |
i18n: add Russian (ru) interface translation (#300)
* I18N.et: add Estonian interface translation * I18N.et: record the verified headless fork push step * i18n: send interface text that skipped translation through the catalog A test-only pseudo-language wraps every catalog lookup in ⟦…⟧ marks; a new audit test lays the app out in it (every tab, File page, dialog and pane, the right-click menu, and a hover and a click on every ribbon control, including the Table and Equation tabs) and fails on any visible text outside the marks. The document is drawn as an image, so only interface text is checked; document text, font and style names, shortcuts, icon lettering, contributor handles and command error messages are allowed. What it found, now translated in every language that has the strings: - Right-click menu items (Cut, Paste, Font…, Paragraph…, Link…, New Comment). - Paragraph dialog: the alignment choices showed code values (`left`); the label now sits before the dropdown. - Table Design › Table Style Options checkboxes. - Table Layout › Alignment tooltips showed code values (`topLeft`). - Design › Fonts: the theme's name is translated, its font names are not. - `pt` units, the Insert › Table grid label, the default watermark text, the font dialog's preview sample, and the untitled document's name. - Contributors and Models dialogs: headings, sort and name choices, summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n: add Russian (ru) interface translation - ru.tsv: 1,068 entries covering every interface string, written clean-room from the English labels and reviewed by a native speaker. `ru`, `ru-RU`, `ru_RU.UTF-8` and other regions resolve to it; File > Options picks it by hand. - Built-in style names (Normal, Heading 2, TOC 3, Strong…) show in the interface language in the Styles gallery, the Styles pane and the Style Inspector. Display only: documents, commands and saved files keep the English names, and styles the author made keep theirs. - Rendered previews use the interface language: the Styles gallery samples (`АаБбВвГг`) and the Design tab's style-set tiles. - Catalogs gain a `preview` context for sample text that must fit a small tile (`Title` is «Заголовок» as a style but «Пример» in the tiles); it falls back to the plain entry, and unknown contexts are still rejected. - Tests: locale detection and saved preference, full coverage, Cyrillic glyphs in the bundled interface fonts, style-name display, catalog contexts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(ru): translate everything the interface audit finds Adds 356 Russian entries: the equation gallery (categories, templates and built-in equations), equation options, themes, watermark presets, paper sizes, table styles, greetings, outline levels, the strings #313 routes through the catalog, and the new AutoSave messages. The two rows #305 made obsolete (📂 Browse…, ➕ New comment) are gone. The interface audit now also fails when a string it sees translated has no Russian entry, so Russian stays complete as the interface grows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * Draw Table and Eraser: draw tables and split or merge cells with a pen (#303) Insert › Tables › Draw Table and Table Layout › Draw › Draw Table / Eraser. table.draw takes a pen stroke in page points: a rectangle outside a table inserts a one-cell table of that size at the paragraph under its start; a straight vertical or horizontal line inside a table splits the cells it crosses (new grid column or row; untouched cells span it). table.eraser merges the two cells beside the border nearest a point. Each stroke is one undo step. In the app the buttons toggle pen and eraser modes with a live preview, a crosshair with the tool's icon, and Esc to stop; canvas clicks don't move the caret while a tool is on. Splitting through part of a vertically merged cell and erasing beside one are refused with a clear error. Catalog 384/430 -> 387/430. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Draw tab: pen, pencil and highlighter ink, stroke eraser and Hide Ink (#307) Ink strokes are floating freeform shapes: a new Freeform geometry (paths in shape-local coordinates, opacity, and the pen that drew it) on InlineObject::Shape with ShapeKind::Freeform. draw.stroke inserts one anchored to the paragraph under the first point (one undo step; points capped per stroke, strokes capped per page, NaN dropped); draw.erase / draw.eraser with a point deletes the stroke under it; draw.pen, draw.pencil, draw.highlighter, draw.eraser and draw.select set the Draw tab's tool in the session view state; review.hideInk toggles showing ink on screen. The canvas draws a live stroke while a pen is dragged and commits it on release; the eraser deletes strokes it passes over (one undo step per drag); Esc or Select goes back to selecting. Draw tab buttons show the tool in use, with colour and thickness menus; Review gets an Ink group with Hide Ink. Ink renders with round caps and joins on screen and in PDF; highlighters are translucent and behind the text. DOCX writes freeforms as wps:wsp with a:custGeom (moveTo/lnTo) in a wp:anchor and reads them back, along with simple custom-geometry freeforms from other files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #315 review fixes: eraser undo test, sanitized tap dots, custGeom path cap, ink docs - draw.eraser with a point erases through draw.erase: test that it is one undo step (undo/redo) and marks the document dirty. - Render and PDF: a single-point stroke's dot is drawn at the sanitized point, not the raw first one. - DOCX custGeom reading stops once MAX_PATHS paths (subpaths included) are collected, across a:path elements. - docs/file-format-parity.md: ink is saved as custom geometry, not InkML, so Word shows it as a freeform. - widgets test: theme::apply takes an Appearance (#317). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: send interface text that skipped translation through the catalog A test-only pseudo-language wraps every catalog lookup in ⟦…⟧ marks; a new audit test lays the app out in it (every tab, File page, dialog and pane, the right-click menu, and a hover and a click on every ribbon control, including the Table and Equation tabs) and fails on any visible text outside the marks. The document is drawn as an image, so only interface text is checked; document text, font and style names, shortcuts, icon lettering, contributor handles and command error messages are allowed. What it found, now translated in every language that has the strings: - Right-click menu items (Cut, Paste, Font…, Paragraph…, Link…, New Comment). - Paragraph dialog: the alignment choices showed code values (`left`); the label now sits before the dropdown. - Table Design › Table Style Options checkboxes. - Table Layout › Alignment tooltips showed code values (`topLeft`). - Design › Fonts: the theme's name is translated, its font names are not. - `pt` units, the Insert › Table grid label, the default watermark text, the font dialog's preview sample, and the untitled document's name. - Contributors and Models dialogs: headings, sort and name choices, summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n audit: start every ribbon click from a fresh app; translate the table style preview The sweep pressed Escape after each click, and in an equation Escape leaves it, so the Equation tab vanished after its first control and the rest of its menus (Convert, Justification, …) were never opened. Each control now gets a fresh app set up the same way. The narrower allowance for short text (only icon lettering and initials) also catches short words. It found the sample table in the Table Style dialog (Mon, Tue, North, Total, …), now translated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * #313: catalog rows for the newly translated interface text Rows in all eight catalogs for the strings #313 now sends through the catalog (cell alignment tooltips, credits columns and summary, theme names, context-menu items, table picker, pt suffix, Document1, the Font dialog sample) and for the Table Style preview's sample table, which the untranslated-text audit flagged after main's table style editor landed. The audit runs headless (no host services: no file pickers or speech) in about 20 s, so it stays enabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n audit: click the ribbon's bottom row too The sweep only clicked controls centred between y = 52 and 125, which took in the tab row and left out each group's bottom row (Equation › Convert and Justification among them). The band is now taken from the layout: below the tab row and above the document area. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n audit: lay the app out wide enough that no ribbon tab overflows At 1440 pt the Equation tab ran past the window, so its last controls (Justification among them) sat behind the ribbon's scroll arrow and were never clicked. The audit window is now 2560 pt wide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n: add Russian (ru) interface translation - ru.tsv: 1,068 entries covering every interface string, written clean-room from the English labels and reviewed by a native speaker. `ru`, `ru-RU`, `ru_RU.UTF-8` and other regions resolve to it; File > Options picks it by hand. - Built-in style names (Normal, Heading 2, TOC 3, Strong…) show in the interface language in the Styles gallery, the Styles pane and the Style Inspector. Display only: documents, commands and saved files keep the English names, and styles the author made keep theirs. - Rendered previews use the interface language: the Styles gallery samples (`АаБбВвГг`) and the Design tab's style-set tiles. - Catalogs gain a `preview` context for sample text that must fit a small tile (`Title` is «Заголовок» as a style but «Пример» in the tiles); it falls back to the plain entry, and unknown contexts are still rejected. - Tests: locale detection and saved preference, full coverage, Cyrillic glyphs in the bundled interface fonts, style-name display, catalog contexts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(ru): translate everything the interface audit finds Adds 356 Russian entries: the equation gallery (categories, templates and built-in equations), equation options, themes, watermark presets, paper sizes, table styles, greetings, outline levels, the strings #313 routes through the catalog, and the new AutoSave messages. The two rows #305 made obsolete (📂 Browse…, ➕ New comment) are gone. The interface audit now also fails when a string it sees translated has no Russian entry, so Russian stays complete as the interface grows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n(ru): native-speaker review corrections Add Note, Move Past Citation, equation display/inline, accents, stacks, operators, Column Selection, Reading Highlight, ASAP and Tools, as reviewed; the Accent gallery button wraps onto two lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n(ru): translate what the improved audit and today's main add The audit now opens every ribbon menu (bottom rows and the Equation tab's last controls included), which surfaced Equation › Convert and Justification, and the Table Style dialog's sample table. Also covers password protection, Manage Styles, the clipboard pane, Shape Effects and Asian typography from main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n: translate the Table Layout 'Draw Table' ribbon label in every catalog #308's two-line ribbon label had no catalog rows; #300's Russian audit (ru covers everything the interface looks up) found it. Rows in all ten catalogs keep et == es and ru covering zh-hans. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: Borders and Shading line widths through the catalog ({n} pt) #313's untranslated-text audit flagged main's new dialog (#327). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * land-294: Estonian rows for main's newer dialogs Define New Multilevel List and Track Changes Options (#342), rotation (#332), Tabs and Borders and Shading (#327), Columns, Symbol and Field (#335): et keys equal es again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n audit: run on demand (#[ignore]) until its rare failure under load is understood It failed once in ~46 runs on a heavily loaded machine and passed 35 straight reruns, so CI shouldn't depend on it yet. Run it with --ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(ru): restore the review corrections a merge reverted; narrow and hide labels A merge of older copies of this branch's commits put back the pre-review wording of 20 entries (Add Note, Tools, the equation accents and operators, Column Selection, Reading Highlight, ASAP, …) and dropped six that are still in use (Equation › Convert, Centered as Group, the hyphenation menu's ✓ None). They're back as reviewed. Also: 1/4 Em Space → «Узкий пробел», and the Draw tab's Hide Ink button reads «Скрыть». Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * i18n(ru): restore the reviewed wording a merge rewrote The same merge reworded 24 reviewed entries (password protection, Shape Effects, Asian typography, the clipboard pane, the table style sample); they're back as a native speaker reviewed them. Clipboard Pane keeps «Область буфера обмена», like the other panes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po --------- Co-authored-by: Henno Täht <henno.taht@gmail.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: vangel76 <vangel1976@googlemail.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
adcbf52611 |
Move paragraphs, promote/demote, Go Back and Alt+X like Word (#343) (#351)
- para.moveUp / para.moveDown (Alt+Shift+Up/Down, Ctrl+Shift+Up/Down on macOS): the paragraphs the selection touches swap with their neighbour in the same story or cell, keeping style and list membership; selection follows; one undo step; refused at the container edges, next to a table and across a section break. - para.promote / para.demote (Alt+Shift+Left/Right, Ctrl+Shift+Left/Right on macOS): heading level up/down (Heading 1..9), promoted body text takes the level of the heading before it, list items change level like Shift+Tab/Tab. - edit.goBack (Shift+F5): cycles the caret through the last four edit places. - text.toggleUnicode (Alt+X; unbound on macOS): hex code <-> character, undoable. The canvas no longer types the key's letter after an Alt shortcut ran. - Catalog rows, translations in every interface catalog, typing/UI parity docs, tests. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
39ab3b5433 |
Field codes like Word's field keys (#339) (#349)
Show field codes instead of results with View > Field Codes (Alt+F9) or
per field with Toggle Field Codes (Shift+F9); a field showing its code is
drawn as { CODE } on light grey. Edit a field's code in a small popup
(double-click a field showing its code, right-click > Edit Field..., or
fields.setCode), and Ctrl+F9 asks for a new field's code. F9 updates
fields and shows the selected ones' results again.
New commands: fields.unlink (Ctrl+Shift+F9) replaces fields with their
text, fields.lock / fields.unlock (Ctrl+F11 / Ctrl+Shift+F11) keep a
result through updates (already saved as w:fldLock), fields.next /
fields.previous (F11 / Shift+F11) select the next or previous field, and
fields.selected reports the fields in the selection. Range fields
(citations) can be locked, unlinked, edited and stepped through too.
The right-click menu gains Update Field, Edit Field... and Toggle Field
Codes when the selection holds a field. Strings are translated in every
catalog; parity catalog, ui-parity, gaps and roadmap updated.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
eb068d3823 |
Add Word's common keyboard shortcuts (#330) (#338)
Bind Word's documented default shortcuts that were missing to existing commands, plus a few small new commands: Reset Paragraph Formatting (Ctrl+Q), Reset Character Formatting (Ctrl+Space, which used to clear all formatting), em dash, copyright, registered, trademark and ellipsis, DATE / TIME / PAGE fields (Alt+Shift+D/T/P), Print Layout / Outline / Draft / Split views, Word Count (Ctrl+Shift+G), Bookmark, Alt+F7, Ctrl+Page Up/Down find browsing, Shift+F12 / Ctrl+F12 / Ctrl+Shift+F12 / Ctrl+F2 / Ctrl+F4, Mark Index Entry, Mark Citation and the mail merge keys. Where macOS claims Word's key (Cmd+Q quits, Cmd+Space is Spotlight, Cmd+Shift+G is Find Previous, Option+letter types symbols), the binding follows Word for Mac or is left off there. F4 Repeat, Q and F2 now reach the registry from the keyboard, and an Alt shortcut no longer also types its key's character. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
6129bfeee5 |
Docs: collapse duplicate rows left by parallel merges (#372)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
2c8439b24c |
i18n: add Turkish (tr) interface translation (#494)
* chore(lints): satisfy nonminimal_bool on Rust 1.96 Clippy Four boolean expressions rewritten into their equivalent minimal forms (De Morgan / is_none_or) so `cargo xtask ci` passes `clippy -D warnings` on current stable. No behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(tr): Turkish interface (Türkçe) - crates/ui-egui/src/i18n/tr.tsv: complete catalog, all 1,307 keys of es.tsv, written clean-room from the plain meaning of the English labels; placeholders, escapes and "…" kept. A noun after a number stays singular in Turkish, so the context-free format needs no plural forms. - Registry entry `tr` / "Türkçe": tr-TR, tr-CY and tr_*.UTF-8 locales resolve by the generic prefix match; saved preference and English fallback use the existing machinery. - Command search folds case the Turkish way (İ→i, I→ı) for translated labels and locations, while English labels and ASCII command ids keep their existing Unicode case-insensitive matching ("italik" finds "İtalik", "INSERT.TABLE" still finds insert.table). - The Font dialog's preview sample is "AaBbYyZz ĞğİıŞş": it has no lowercase i, so the All Caps preview (to_uppercase) gets the Turkish capitals right. - Tests: catalog key and placeholder parity, locale resolution, saved preference, Turkish folding, the sample's capitals, a real egui command-dialog regression, and ÇçĞğİıÖöŞşÜü in the bundled UI fonts. - Docs: README, ROADMAP, localization-parity, control-protocol, new localization-tr.md (terminology, scope); ATTRIBUTION row for tr.tsv. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(paste): an absolute picture path that is absolute on Windows too `/tmp/b.JPG` has no drive, so `Path::is_absolute` is false on Windows and `paste_inserts_clipboard_pixels` failed there; the test uses `C:\tmp\b.JPG` on Windows. Test-only. 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> |
||
|
|
1581f30176 |
Import/export fixes: TXT encodings and list labels, RTF Unicode, ODT styles and cell colours, HTML borders and pre spaces, LaTeX alignment groups (#433–#440) (#482)
- TXT: the engine opens and saves .txt through wordcraft-formats (BOM/unmarked UTF-16 sniffing, Windows-1252 fallback; list labels and a tab on export) instead of its own narrower decoder and body plain text. - RTF: \uN and \ucN are handled in document info, bookmark names and field instructions, not only in body text. - ODT: common paragraph styles (and common parents of automatic styles) give their text formatting, except the style that sets the paragraph kind; table-cell-properties fo:background-color becomes cell shading. - HTML: tables without style or visible borders export without cell borders; white-space:pre paragraphs keep leading/trailing spaces. - LaTeX: brace groups restore the paragraph alignment set inside them. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
5078d9dea5 |
Equation fixes: numbering removal, control colour, undo for navigation edits, LaTeX text spaces (#444, #446, #447, #448) (#487)
- equation.number off strips the number from every row; a single row is unwrapped,
several rows stay an equation array (was: only the first row survived).
- equation.move works out AutoCorrect/build-up on a copy; plain navigation no longer
rewrites the equation (keeps imported OMML such as m:ctrlPr colours), and a real
build-up is checkpointed as "Build Up" and marks the document dirty.
- LaTeX tokenizer keeps white space inside \text/\textrm/\mbox/\textnormal/\textbf/\textit
arguments (collapsed to one space), so \text{for all x} stays "for all x".
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
2666031c35 |
Spelling: common words like "desktop" are recognised (#520) (#522)
The English speller only knew the 1990s Moby word list plus a small hard-coded EXTRA array, so everyday modern words (desktop, laptop, download, upload, spreadsheet, database, screenshot, inbox, offline, workplace…) were flagged. Inflection, doubled-consonant and prefix rules also only looked stems up in Moby, so even supplemented words failed in inflected forms (blogging, uploader). - New supplement assets/spelling/en-extra.txt: ~220 lowercase base forms, our own list (MIT OR Apache-2.0), replacing the EXTRA array. - All stem lookups (inflections, doubled consonant, prefixes) consult the dictionary and the supplement; suggestions include supplement words. - Regression tests: common modern words and inflections accepted, misspellings still flagged, "dekstop" suggests "desktop"; the list stays sorted and lowercase. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
5c2fbda5e2 |
Dialogs: switching tabs keeps the window's top edge in place (#507) (#511)
Every dialog was anchored CENTER_CENTER, which egui re-applies each frame, so a tab of a different height split the change between top and bottom and the tab strip jumped. Dialogs are now centred on the frame they open, then anchored CENTER_TOP at that top edge until they close; only the bottom edge moves. egui still keeps the window on screen. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
18e472e3de |
.doc import fixes: piece bold, section kinds, orientation, list overrides, style inheritance, alternate font names (#458–#463) (#484)
Follow [MS-DOC] in the Word 97-2003 reader: - Prm: bit 0 is fComplex; Prm0 isprm in bits 1-7, Prm1 Prc index in bits 1-15 (#458) - sprmSBkc operands 0-4 map to continuous/new column/new page/even/odd (#459) - sprmSBOrientation 1 = portrait, 2 = landscape (#460) - negative sprmPIlfo (0xF802-0xFFFF) references the negated LFO index (#461) - StdfBase: istdBase shares the word with stk and is zero-based; the whole base chain is applied, bounded and cycle-safe (#462) - SttbfFfn entries advance by cchData, covering the optional xszAlt (#463) One regression test per issue, built in code from the spec. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
1d4f741f23 |
Citations: eight more bibliography styles (#383) (#388)
Citation and bibliography styles are now data: a CiteStyle table entry per style (in-text form, author name format, ordering, entry templates for books and journal articles). Adds Harvard (Anglia), ISO 690 author-date and numerical, Turabian, GB/T 7714, GOST (name sort and title sort) and SIST02 next to APA, MLA, Chicago and IEEE. Numbered styles count in order of first citation (GOST: in its sorted order) and renumber when a citation is inserted. Word's style names and style-sheet file names select the matching style. The References > Style button is now a menu listing every style with the current one checked; its label shows the current style. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
51e927028a |
Options: interface size setting (#475) (#480)
File › Options › General gets an Interface size choice (80–200 %), kept in
ui.json and applied as egui's zoom factor, so it multiplies the display
scale the system reports instead of replacing it. Junk saved values read
as 100 % and out-of-range ones are clamped. Agents use ui.interfaceSize
{"percent"}. Document zoom (view.zoom) is untouched; egui's keyboard zoom
stays off, so Word shortcuts never change the interface size.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5528eff2ac |
Mail merge: SKIPIF, NEXT, IF in preview, header/footer fields (#427, #428, #429, #430) (#478)
Merge fields are now evaluated in document order with a record cursor, shared by Preview Results and Finish & Merge: - SKIPIF drops the merged copy when its condition holds (#427). - NEXT/NEXTIF move later fields to the next record; the next copy starts after it, and records past the end are blank (#428). - IF rules on merge fields preview their true/false text (#429). - Header and footer stories are previewed and merged; with merge fields in them each letter becomes its own section with its own copies (#430). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
aa7b41d8ef |
Groups keep rotated members' orientation; group resize; ink erase after rotation (#441, #442, #443, #445) (#474)
- Group keeps each member's own turn (and composes a merged group's turn into its members); the group box covers the members' turned bounds and the new group starts unturned (#441). - Size (picture.size) resizes a selected group, scaling its members through the group's child space like Move or Resize (#442). - Ungroup decomposes a turned group: each member's centre is turned about the group's centre and its turn becomes its own within the group's (#443). - The eraser tests the point turned back into the stroke's unturned frame, so turned ink is erased where it is drawn (#445). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5e84270e60 |
Hyperlinks cover only their own text (#413) (#449)
Linking a whole paragraph also linked its paragraph mark, and Enter copied the link at the split into the new paragraph's mark, so everything typed in the paragraphs Enter made (above or below) became the link, and hovering anywhere near the end of the text showed the link's tooltip. - doc: a paragraph mark never takes a hyperlink (format_range, split_off) - engine: typing at either end of a link isn't linked; inside it is (Word) - ui: hover tooltip and Ctrl+click only on the linked text itself Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e4b7d155f1 |
Bump version to 0.5.0; add Linux riscv64 release build (#394)
- release.yml: new `linux-riscv64` job ported from GridCraft. Cross-compiles wordcraft and wordcraft-cli on ubuntu-24.04 with riscv64 libs from ports.ubuntu.com (riscv64 variants of the Linux job's -dev packages), packages a tar.gz, and smoke-tests the CLI under QEMU. The draft-release job needs it, so its tar.gz is uploaded and covered by SHA256SUMS. - packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR support (as in GridCraft). - README and docs/releasing.md list the riscv64 tarball. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
972df1e0c7 |
Track Changes: formatting revisions (w:rPrChange/w:pPrChange) (#41) (#399)
Formatting changes are tracked like insertions and deletions: - Model: runs and paragraph marks carry the formatting before a tracked change (CharProps::fmt_change), paragraphs their old properties (ParaProps::fmt_change) and a list numbering change; tables, rows, cells and sections their old properties. - DOCX: w:rPrChange (runs and paragraph marks), w:pPrChange, w:numberingChange, w:tblPrChange, w:trPrChange, w:tcPrChange and w:sectPrChange are read and written back, each last in its parent (ECMA-376 17.13.5). Nested changes are ignored; ids are renumbered. - Recording: with Track Changes and Track Formatting on, Session::run compares the paragraphs a command changed with the document before it, so every formatting command records without per-command code. An author's later changes keep the formatting before the first one; formatting set back to the original stops being a change. - Accept/Reject (at the caret, selection, all) keep or restore the formatting; Next/Previous and the Reviewing Pane list format changes with a "Formatted: Bold, Size: 14" description. - Markup: change bars beside formatted lines and "Formatted: ..." balloons in the markup area, per Track Changes Options. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4615cef878 |
Rotated OLE objects keep their turn when saving DOCX (#333 follow-up to #332) (#370)
#333 writes OLE objects back from their kept markup, resized to the object's current size, but #332's rotation and flips weren't carried into that markup: a turned or flipped OLE object came back unturned (DrawingML) or with its old turn (VML). The VML shape's style now gets the object's rotation and flip, and a DrawingML picture's a:xfrm gets rot/flipH/flipV and its size, with the drawing's wp:effectExtent covering the rotated bounds like other drawings (added when missing). Inline VML shapes now read their rotation and flips too, so the turn survives a WordCraft round trip. Charts and diagrams can't be turned, so their frame needs nothing new. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
a6b23683c1 |
Font box: type to find a font (#359) (#367)
Typing in the ribbon's or the mini toolbar's font box now lists the
installed families that match, under the field: exact name first, then
names starting with the text, then names containing it, ignoring case
("roman" finds Times New Roman). Up/Down move the highlight, Enter or a
click applies it ("arial" applies Arial), Escape restores the current
font. Text that matches no family is still applied as typed, as Word
allows fonts that aren't installed.
The search is opt-in (widgets::font_combo); the font size box keeps
literal entry. Matches are computed only when the text changes and the
list stays virtualised (#121).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
afb4720644 |
Add Estonian interface translation (#294)
* I18N.et: add Estonian interface translation * I18N.et: record the verified headless fork push step * i18n: send interface text that skipped translation through the catalog A test-only pseudo-language wraps every catalog lookup in ⟦…⟧ marks; a new audit test lays the app out in it (every tab, File page, dialog and pane, the right-click menu, and a hover and a click on every ribbon control, including the Table and Equation tabs) and fails on any visible text outside the marks. The document is drawn as an image, so only interface text is checked; document text, font and style names, shortcuts, icon lettering, contributor handles and command error messages are allowed. What it found, now translated in every language that has the strings: - Right-click menu items (Cut, Paste, Font…, Paragraph…, Link…, New Comment). - Paragraph dialog: the alignment choices showed code values (`left`); the label now sits before the dropdown. - Table Design › Table Style Options checkboxes. - Table Layout › Alignment tooltips showed code values (`topLeft`). - Design › Fonts: the theme's name is translated, its font names are not. - `pt` units, the Insert › Table grid label, the default watermark text, the font dialog's preview sample, and the untitled document's name. - Contributors and Models dialogs: headings, sort and name choices, summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po * Draw Table and Eraser: draw tables and split or merge cells with a pen (#303) Insert › Tables › Draw Table and Table Layout › Draw › Draw Table / Eraser. table.draw takes a pen stroke in page points: a rectangle outside a table inserts a one-cell table of that size at the paragraph under its start; a straight vertical or horizontal line inside a table splits the cells it crosses (new grid column or row; untouched cells span it). table.eraser merges the two cells beside the border nearest a point. Each stroke is one undo step. In the app the buttons toggle pen and eraser modes with a live preview, a crosshair with the tool's icon, and Esc to stop; canvas clicks don't move the caret while a tool is on. Splitting through part of a vertically merged cell and erasing beside one are refused with a clear error. Catalog 384/430 -> 387/430. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Draw tab: pen, pencil and highlighter ink, stroke eraser and Hide Ink (#307) Ink strokes are floating freeform shapes: a new Freeform geometry (paths in shape-local coordinates, opacity, and the pen that drew it) on InlineObject::Shape with ShapeKind::Freeform. draw.stroke inserts one anchored to the paragraph under the first point (one undo step; points capped per stroke, strokes capped per page, NaN dropped); draw.erase / draw.eraser with a point deletes the stroke under it; draw.pen, draw.pencil, draw.highlighter, draw.eraser and draw.select set the Draw tab's tool in the session view state; review.hideInk toggles showing ink on screen. The canvas draws a live stroke while a pen is dragged and commits it on release; the eraser deletes strokes it passes over (one undo step per drag); Esc or Select goes back to selecting. Draw tab buttons show the tool in use, with colour and thickness menus; Review gets an Ink group with Hide Ink. Ink renders with round caps and joins on screen and in PDF; highlighters are translucent and behind the text. DOCX writes freeforms as wps:wsp with a:custGeom (moveTo/lnTo) in a wp:anchor and reads them back, along with simple custom-geometry freeforms from other files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #315 review fixes: eraser undo test, sanitized tap dots, custGeom path cap, ink docs - draw.eraser with a point erases through draw.erase: test that it is one undo step (undo/redo) and marks the document dirty. - Render and PDF: a single-point stroke's dot is drawn at the sanitized point, not the raw first one. - DOCX custGeom reading stops once MAX_PATHS paths (subpaths included) are collected, across a:path elements. - docs/file-format-parity.md: ink is saved as custom geometry, not InkML, so Word shows it as a freeform. - widgets test: theme::apply takes an Appearance (#317). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #313: catalog rows for the newly translated interface text Rows in all eight catalogs for the strings #313 now sends through the catalog (cell alignment tooltips, credits columns and summary, theme names, context-menu items, table picker, pt suffix, Document1, the Font dialog sample) and for the Table Style preview's sample table, which the untranslated-text audit flagged after main's table style editor landed. The audit runs headless (no host services: no file pickers or speech) in about 20 s, so it stays enabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: Borders and Shading line widths through the catalog ({n} pt) #313's untranslated-text audit flagged main's new dialog (#327). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * land-294: Estonian rows for main's newer dialogs Define New Multilevel List and Track Changes Options (#342), rotation (#332), Tabs and Borders and Shading (#327), Columns, Symbol and Field (#335): et keys equal es again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n audit: run on demand (#[ignore]) until its rare failure under load is understood It failed once in ~46 runs on a heavily loaded machine and passed 35 straight reruns, so CI shouldn't depend on it yet. Run it with --ignored. 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: vangel76 <vangel1976@googlemail.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
e71e2d1c52 |
Draw tab: draw with pen, pencil and highlighter, erase ink, and hide ink (#315)
* Draw Table and Eraser: draw tables and split or merge cells with a pen (#303) Insert › Tables › Draw Table and Table Layout › Draw › Draw Table / Eraser. table.draw takes a pen stroke in page points: a rectangle outside a table inserts a one-cell table of that size at the paragraph under its start; a straight vertical or horizontal line inside a table splits the cells it crosses (new grid column or row; untouched cells span it). table.eraser merges the two cells beside the border nearest a point. Each stroke is one undo step. In the app the buttons toggle pen and eraser modes with a live preview, a crosshair with the tool's icon, and Esc to stop; canvas clicks don't move the caret while a tool is on. Splitting through part of a vertically merged cell and erasing beside one are refused with a clear error. Catalog 384/430 -> 387/430. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Draw tab: pen, pencil and highlighter ink, stroke eraser and Hide Ink (#307) Ink strokes are floating freeform shapes: a new Freeform geometry (paths in shape-local coordinates, opacity, and the pen that drew it) on InlineObject::Shape with ShapeKind::Freeform. draw.stroke inserts one anchored to the paragraph under the first point (one undo step; points capped per stroke, strokes capped per page, NaN dropped); draw.erase / draw.eraser with a point deletes the stroke under it; draw.pen, draw.pencil, draw.highlighter, draw.eraser and draw.select set the Draw tab's tool in the session view state; review.hideInk toggles showing ink on screen. The canvas draws a live stroke while a pen is dragged and commits it on release; the eraser deletes strokes it passes over (one undo step per drag); Esc or Select goes back to selecting. Draw tab buttons show the tool in use, with colour and thickness menus; Review gets an Ink group with Hide Ink. Ink renders with round caps and joins on screen and in PDF; highlighters are translucent and behind the text. DOCX writes freeforms as wps:wsp with a:custGeom (moveTo/lnTo) in a wp:anchor and reads them back, along with simple custom-geometry freeforms from other files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #315 review fixes: eraser undo test, sanitized tap dots, custGeom path cap, ink docs - draw.eraser with a point erases through draw.erase: test that it is one undo step (undo/redo) and marks the document dirty. - Render and PDF: a single-point stroke's dot is drawn at the sanitized point, not the raw first one. - DOCX custGeom reading stops once MAX_PATHS paths (subpaths included) are collected, across a:path elements. - docs/file-format-parity.md: ink is saved as custom geometry, not InkML, so Word shows it as a freeform. - widgets test: theme::apply takes an Appearance (#317). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Draw tab: pen, pencil and highlighter ink, stroke eraser and Hide Ink (#307) Ink strokes are floating freeform shapes: a new Freeform geometry (paths in shape-local coordinates, opacity, and the pen that drew it) on InlineObject::Shape with ShapeKind::Freeform. draw.stroke inserts one anchored to the paragraph under the first point (one undo step; points capped per stroke, strokes capped per page, NaN dropped); draw.erase / draw.eraser with a point deletes the stroke under it; draw.pen, draw.pencil, draw.highlighter, draw.eraser and draw.select set the Draw tab's tool in the session view state; review.hideInk toggles showing ink on screen. The canvas draws a live stroke while a pen is dragged and commits it on release; the eraser deletes strokes it passes over (one undo step per drag); Esc or Select goes back to selecting. Draw tab buttons show the tool in use, with colour and thickness menus; Review gets an Ink group with Hide Ink. Ink renders with round caps and joins on screen and in PDF; highlighters are translucent and behind the text. DOCX writes freeforms as wps:wsp with a:custGeom (moveTo/lnTo) in a wp:anchor and reads them back, along with simple custom-geometry freeforms from other files. 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> |
||
|
|
0e2e4cde80 |
Draw tables and split or merge cells with a pen and eraser (#308)
* Draw Table and Eraser: draw tables and split or merge cells with a pen (#303) Insert › Tables › Draw Table and Table Layout › Draw › Draw Table / Eraser. table.draw takes a pen stroke in page points: a rectangle outside a table inserts a one-cell table of that size at the paragraph under its start; a straight vertical or horizontal line inside a table splits the cells it crosses (new grid column or row; untouched cells span it). table.eraser merges the two cells beside the border nearest a point. Each stroke is one undo step. In the app the buttons toggle pen and eraser modes with a live preview, a crosshair with the tool's icon, and Esc to stop; canvas clicks don't move the caret while a tool is on. Splitting through part of a vertically merged cell and erasing beside one are refused with a clear error. Catalog 384/430 -> 387/430. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Draw Table and Eraser: draw tables and split or merge cells with a pen (#303) Insert › Tables › Draw Table and Table Layout › Draw › Draw Table / Eraser. table.draw takes a pen stroke in page points: a rectangle outside a table inserts a one-cell table of that size at the paragraph under its start; a straight vertical or horizontal line inside a table splits the cells it crosses (new grid column or row; untouched cells span it). table.eraser merges the two cells beside the border nearest a point. Each stroke is one undo step. In the app the buttons toggle pen and eraser modes with a live preview, a crosshair with the tool's icon, and Esc to stop; canvas clicks don't move the caret while a tool is on. Splitting through part of a vertically merged cell and erasing beside one are refused with a clear error. Catalog 384/430 -> 387/430. 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> |
||
|
|
15f2f01475 |
Tabs and Borders and Shading dialogs (#327)
* Add Tabs and Borders and Shading dialogs (#320) Tabs: lists the paragraph's tab stops with position, alignment and leader, Set / Clear / Clear All and the default interval. Opens from the Paragraph dialog's Tabs… button, by double-clicking a tab marker on the ruler, or para.tabs without params. OK is one para.tabs call, which now takes set / clear / clearAll / default (clearing a style's stop records a clear stop over it). Borders and Shading: Borders (None / Box / Shadow / 3-D / Custom, style, colour, width, paragraph or text, preview with clickable sides), Page Border (same, whole document or this section) and Shading (fill, paragraph or text) tabs. Opens from Home › Paragraph › Borders › Borders and Shading… and Design › Page Borders. OK runs only the changed parts as one undo step. para.borders and design.pageBorders take exact "sides" (and design.pageBorders a style and applyTo). Shadow and 3-D are drawn as heavier sides because the model has no border shadow flag; shading patterns are omitted because the model keeps a solid fill only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Columns, Symbol and Field dialogs (#321) Layout > Columns > More Columns... opens a Columns dialog: One/Two/Three/ Left/Right presets, number of columns, per-column width and spacing, Equal column width, Line between, a page preview and Apply to (whole document, this section, this point forward). OK is one layout.columns call, which now takes unequal widths and an apply target (forward adds a continuous section break first). Insert > Symbol > More Symbols... opens a Symbol dialog: font picker, Unicode subset list that jumps through a grid of only the characters the font has (drawn in that font), recently used symbols, a hex character code, and a Special Characters tab. insert.symbol takes a font for the symbol alone; typing after it goes on in the text's font. The ribbon's Symbol gallery shows recently used symbols first. Insert > Quick Parts > Field... opens a Field dialog: categories and the fields WordCraft computes, date pictures, number formats, bookmark / sequence / merge field names, preserve formatting, a live field code and a Field Codes view to type the code directly; OK runs insert.field. Also: date pictures read correctly when switches follow them, and am/pm and seconds work in date and time pictures. Strings in every catalog; gaps #7 and ui-parity updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #321: Field dialog descriptions in our own words (clean room) Reword the one-line field descriptions and the empty-selection prompt so none reads like Word's; translations keep their meaning under the new keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #320: test that a default-tab-only para.tabs change undoes and redoes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Columns, Symbol and Field dialogs (#321) Layout > Columns > More Columns... opens a Columns dialog: One/Two/Three/ Left/Right presets, number of columns, per-column width and spacing, Equal column width, Line between, a page preview and Apply to (whole document, this section, this point forward). OK is one layout.columns call, which now takes unequal widths and an apply target (forward adds a continuous section break first). Insert > Symbol > More Symbols... opens a Symbol dialog: font picker, Unicode subset list that jumps through a grid of only the characters the font has (drawn in that font), recently used symbols, a hex character code, and a Special Characters tab. insert.symbol takes a font for the symbol alone; typing after it goes on in the text's font. The ribbon's Symbol gallery shows recently used symbols first. Insert > Quick Parts > Field... opens a Field dialog: categories and the fields WordCraft computes, date pictures, number formats, bookmark / sequence / merge field names, preserve formatting, a live field code and a Field Codes view to type the code directly; OK runs insert.field. Also: date pictures read correctly when switches follow them, and am/pm and seconds work in date and time pictures. Strings in every catalog; gaps #7 and ui-parity updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: #340's rotation round-trip test builds an Image with #333's ole field Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Tabs and Borders and Shading dialogs (#320) Tabs: lists the paragraph's tab stops with position, alignment and leader, Set / Clear / Clear All and the default interval. Opens from the Paragraph dialog's Tabs… button, by double-clicking a tab marker on the ruler, or para.tabs without params. OK is one para.tabs call, which now takes set / clear / clearAll / default (clearing a style's stop records a clear stop over it). Borders and Shading: Borders (None / Box / Shadow / 3-D / Custom, style, colour, width, paragraph or text, preview with clickable sides), Page Border (same, whole document or this section) and Shading (fill, paragraph or text) tabs. Opens from Home › Paragraph › Borders › Borders and Shading… and Design › Page Borders. OK runs only the changed parts as one undo step. para.borders and design.pageBorders take exact "sides" (and design.pageBorders a style and applyTo). Shadow and 3-D are drawn as heavier sides because the model has no border shadow flag; shading patterns are omitted because the model keeps a solid fill only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * cargo fmt after merging main --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
8204c5cb49 |
Columns, Symbol and Field dialogs (#335)
* Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Columns, Symbol and Field dialogs (#321) Layout > Columns > More Columns... opens a Columns dialog: One/Two/Three/ Left/Right presets, number of columns, per-column width and spacing, Equal column width, Line between, a page preview and Apply to (whole document, this section, this point forward). OK is one layout.columns call, which now takes unequal widths and an apply target (forward adds a continuous section break first). Insert > Symbol > More Symbols... opens a Symbol dialog: font picker, Unicode subset list that jumps through a grid of only the characters the font has (drawn in that font), recently used symbols, a hex character code, and a Special Characters tab. insert.symbol takes a font for the symbol alone; typing after it goes on in the text's font. The ribbon's Symbol gallery shows recently used symbols first. Insert > Quick Parts > Field... opens a Field dialog: categories and the fields WordCraft computes, date pictures, number formats, bookmark / sequence / merge field names, preserve formatting, a live field code and a Field Codes view to type the code directly; OK runs insert.field. Also: date pictures read correctly when switches follow them, and am/pm and seconds work in date and time pictures. Strings in every catalog; gaps #7 and ui-parity updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #321: Field dialog descriptions in our own words (clean room) Reword the one-line field descriptions and the empty-selection prompt so none reads like Word's; translations keep their meaning under the new keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Columns, Symbol and Field dialogs (#321) Layout > Columns > More Columns... opens a Columns dialog: One/Two/Three/ Left/Right presets, number of columns, per-column width and spacing, Equal column width, Line between, a page preview and Apply to (whole document, this section, this point forward). OK is one layout.columns call, which now takes unequal widths and an apply target (forward adds a continuous section break first). Insert > Symbol > More Symbols... opens a Symbol dialog: font picker, Unicode subset list that jumps through a grid of only the characters the font has (drawn in that font), recently used symbols, a hex character code, and a Special Characters tab. insert.symbol takes a font for the symbol alone; typing after it goes on in the text's font. The ribbon's Symbol gallery shows recently used symbols first. Insert > Quick Parts > Field... opens a Field dialog: categories and the fields WordCraft computes, date pictures, number formats, bookmark / sequence / merge field names, preserve formatting, a live field code and a Field Codes view to type the code directly; OK runs insert.field. Also: date pictures read correctly when switches follow them, and am/pm and seconds work in date and time pictures. Strings in every catalog; gaps #7 and ui-parity updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: #340's rotation round-trip test builds an Image with #333's ole field 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> |
||
|
|
a7c809e63b |
Charts, SmartArt and OLE objects are no longer lost when you save a .docx (#333)
* Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep charts, SmartArt and OLE objects when saving DOCX (#319) Charts and SmartArt diagrams were drawn since #292 but the writer skipped them, and OLE objects kept only their picture, so opening and saving a document silently dropped them. The reader now keeps each object's own markup (the a:graphic of a chart or diagram, the whole w:object of an OLE object) on the model object, and every part it reaches through relationships (chart part, embedded workbook, colour and style parts; diagram data, layout, quick style, colours and drawing; OLE embedding and picture) as opaque bytes in Document::passthrough, with their content types and relationships in a manifest, as the VBA project already is. The writer emits the object with fresh relationship ids pointing at the re-added parts, keeping each part's own relationship ids and content types. A chart or diagram gets its frame from the object's current size and position; an OLE object gets its new size written into its VML shape. A part whose name the writer uses itself is renamed, and an object pasted more than once gets its own copies of every part (sharing past a size budget). Part counts, relationship counts, markup size and copy bytes are all capped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: #340's rotation round-trip test builds an Image with #333's ole field 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> |
||
|
|
79b6f33b03 |
Long footnotes continue onto the next page (#352) (#357)
When the footnotes referenced on a page don't fit below its text, the note that doesn't fit is split at a line boundary: its first line stays on the page of its reference (if even that doesn't fit, the reference line moves to the next page, as before), and the rest continues at the top of the next page's note area, before that page's own notes, under a full-width continuation separator. Notes still continuing after the last page get pages of their own. Endnotes are unchanged. The docx reader doesn't keep a document's own continuation separator or continuation notice, so the default line is drawn and no notice. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
1d7a54f883 |
Define New Multilevel List and Track Changes Options dialogs (#342)
* Define New Multilevel List and Track Changes Options dialogs (#328) Home > Paragraph > Multilevel List > Define New Multilevel List edits all nine levels with a live preview: number text and style, start, restart after a level, linked paragraph style, alignment, aligned-at and text indent, what follows the number with an optional tab stop, and the number's font. OK runs the new list.define command (list.get reads a definition back). List levels gain a restart-after level and a tab stop, which the counters and layout honour and .docx reads and writes (lvlRestart, num tab); number alignment now places the label. Review > Tracking's launcher opens Track Changes Options: show comments, ink, insertions and deletions, formatting; balloon mode; insertion and deletion marks and colours; changed-line bars and their colour; track formatting. They go through review.trackingOptions, are saved per user with the interface preferences, and the page drawing honours the marks, colours, hidden deletions, change bars and inline mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Parity checklist regenerated after merging main into #342 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> |
||
|
|
bd10795306 |
Free rotation and flips for pictures, shapes and text boxes (#332) (#340)
Drawings carry an angle and horizontal/vertical flips on their placement (Float::rot, flip_h, flip_v), read and written as DrawingML a:xfrm rot, flipH and flipV for pictures, shapes, text boxes and groups; the written effect extent covers the rotated bounds and reading takes that overhang back out. Layout draws them turned about their centre (screen and PDF), square wrap and inline lines keep clear of the rotated bounds, and hit testing follows the turned shape. arrange.rotate now turns the frame (90 degrees, flips) instead of rewriting pixels; arrange.rotation sets an exact angle. The canvas frame has a rotation handle (Shift snaps to 15 degrees) and turned frames resize along their own axes; Picture Format and Shape Format get a Rotation box and a Rotate menu. Text inside a rotated text box stays upright for now. Groups turn and flip as a whole (wpg:grpSpPr a:xfrm): members keep their own turn inside the group's, are carried round its centre, and a group's text boxes move with it. Shape effects are drawn inside the turn; a shadow's direction follows DrawingML rotWithShape (kept on the model, true when absent; Word's presets write 0, so their shadows keep their page direction). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
81bf9187f2 |
Wrap long display equations across lines like Word (#326) (#329)
A display equation wider than its column ran off the page. It now breaks at top-level binary operators and relations (never inside a fraction, radical, script or matrix), filling each line greedily; a term wider than the line overflows instead of breaking inside. - Break before the operator by default, or after it, or repeated on both lines, as the document's m:brkBin says; m:brkBinSub picks how a minus repeats. - Continuation lines are indented by m:wrapIndent (one inch by default) or set flush right with m:wrapRight. - Manual breaks (m:brk on a run) start a new line; m:alnAt aligns it at an operator of the first line. - DOCX: m:mathPr in settings.xml and m:brk in math runs are read and written back. Documents without them save as before. - Inline equations, numbered equations and m:jc alignment are unchanged. Tests: layout (a long sum wraps within the column with indented continuation lines; after/repeat modes; manual breaks and alnAt; short equations stay on one line; hostile break input) and DOCX round-trip. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
9bfdbee0b7 |
System interface theme follows OS changes again, and Dark page no longer darkens the interface (#317)
* System interface theme keeps following the OS; Dark page leaves the interface alone (#311, #312) With Interface theme set to System, every frame resolved the OS appearance to Light or Dark and passed that to egui's set_theme. egui then sent SetTheme(Light/Dark) to the window, which on macOS sets an explicit NSAppearance; winit ignores appearance changes while one is set, so later OS switches never reached the app. Both palettes are now installed as egui's light and dark styles (with the same spacing and text styles), and System leaves egui's preference on System with a light fallback, so egui picks the matching style from the OS appearance it reports and the window keeps following the OS. Manual Light and Dark still pin the window. Dark page (View > Switch Modes, Options > Dark page) also forced the interface dark; it now only changes how pages are drawn and the interface follows the Interface theme setting alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Theme: update #314's test to the new theme::apply(ctx, Appearance) signature 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> |
||
|
|
1800007463 |
Windows: use OpenGL when DirectX 12 has no GPU driver (#316) (#325)
Since Windows defaults to DirectX 12 only (#50), PCs whose graphics chip has no DirectX 12 driver (Intel 4th generation on Windows 11) fall back to WARP, Microsoft's software renderer, and the app lags. Before eframe creates its instance, WordCraft now probes DirectX 12 with a short-lived instance: a hardware adapter that meets eframe's device limits keeps DirectX 12 only; WARP only enables OpenGL next to DirectX 12 (GPU preferred, WARP as last resort); no adapter, or only GPUs below the limits, uses OpenGL alone. WGPU_BACKEND still overrides everything. The choice is logged, and the decision is a pure function with unit tests. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
29e978d6d8 |
Re-land #264, #263, #270, #271, #267, #280: clipboard pane, table styles, Manage Styles, Asian Typography, Group, Shape Effects (#323)
The original squash merges of these six PRs were empty. Integrated and tested together on current main. Co-authored-by: Valentin Klein <vangel1976@googlemail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4a9078b912 |
Grey out the AutoSave switch, with the reason, where AutoSave can't save (#196, #176) (#302)
AutoSave writes only a file saved in this session, in a format that keeps everything (.docx, .docm, .dotx, .dotm, .odt, .rtf, .json), and never in the browser, where saving is a download. The title-bar switch still showed on for a saved .md file (#196) and AutoSave looked available in the web app (#176), so edits stayed unsaved with no explanation. WordApp::autosave_block() now says why AutoSave can't cover the document (browser, never saved, a format that can't keep everything, opened but not saved here). The switch is greyed out with that reason as its tooltip, and clicking it offers Save As (desktop) so saving as .docx turns AutoSave on. In the browser, File > Options' AutoSave checkbox is disabled with the same explanation. file.autosave (scripts, MCP, the switch) now sets the app's AutoSave and returns the reason as an error when asked to turn it on where it can't save; turning it off always works. New strings in every catalog. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
08e8d4ade0 |
Table sizing: Height/Width boxes, AutoFit to contents and a Table Properties dialog (#287)
* Table sizing: Height/Width boxes, real AutoFit Contents, Table Properties dialog (#44) - Table Layout > Cell Size gets Height and Width boxes (inches) for the caret cell's row and column; each edit runs table.rowHeight / table.columnWidth, a drag is one Undo. - AutoFit Contents now measures every column's narrowest (longest word) and widest (unwrapped text) content with the layout's text shaping, shares the text width the way Word does, and writes the widths into the table grid and cell widths. - Table Properties opens a dialog (table width, alignment, indent; row height and rule, break across pages, header row; column width; cell width and vertical alignment). OK applies only what changed as one table.properties step; with settings the command still works headlessly, and without them it reports the current values. - table.columnWidth clears the table's preferred width so the column keeps the new size; table.rowHeight takes an optional exact rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Progress docs: Table Properties dialog and AutoFit Contents landed (#44) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Table sizing: saturating column-span sum in sync_cell_widths Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: one region_text (main's) after #287 met the landed table-style code 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> |
||
|
|
4a75c57f58 |
Comment balloons edit in place, and the ruler drags page margins (#167) (#289)
Clicking a comment balloon in the markup area selects it like Word: its text becomes editable in place, with Reply, Resolve/Reopen and Delete, and replies are shown (and editable) under the comment they answer. Each edit is written back through a new review.editComment command, one undo step per editing session; the Comments pane uses the same path (it used to write the text without an undo step) and gains a Reply button. The margin edges on the horizontal ruler (left/right) and the vertical ruler (top/bottom) can be dragged to set the section's margins through layout.margins, one undo step per drag, snapped to 1/16 inch and clamped so at least an inch of text remains. Indent markers keep priority where they overlap an edge. Setting margins by number no longer switches off mirrored margins; only a preset decides that. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8622ae8cec |
Desktop File › Print opens the PDF in the system viewer (#15) (#286)
On desktop, the Print button on File › Print now renders the document to PDF, writes it to a fresh wordcraft-print-*.pdf in the OS temp folder and opens it without blocking the window: in Preview on macOS, and in the default PDF app on Linux/BSD (xdg-open, gio, ...) and Windows (via the `open` crate, already in the tree). The user prints from there through the system print dialog. If no viewer can be started, the status bar says so and the file is removed. Print files older than an hour are cleaned up off the UI thread at start-up and after each print. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb31860917 |
Progress docs: target-app parity, gaps, alpha gate, readiness by audience (#277)
Progress docs per craftrules standards/progress-docs.md: target-app parity, gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and feature, format, layout, hardware, UI and localization parity docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
15f5ad274e |
Column Selection: Alt+drag selects a block of text (#237)
select.column (Mod+Shift+F8) selects the same x range on a run of lines, from two positions, two page points (Alt+drag), or by toggling column mode where the arrow keys extend the block. Copy/Cut give one line per row, Delete/Backspace remove only the block, character formatting and Change Case apply per row, typing/paste replace the block. Any ordinary caret move drops it. F8 keys now reach their shortcuts in the UI. 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> |
||
|
|
e71c2b6c5b |
Style Inspector: styles.inspector pane, styles.inspect query and per-level clearing (#236)
styles.inspector shows/hides the Style Inspector pane and returns the paragraph style, character style and the direct formatting that differs from each; styles.inspect is the pure query; styles.inspectorClear resets one level (paragraphStyle, paragraphFormatting, characterStyle, characterFormatting) as a single undo step. The pane opens from the Styles pane, with a clear button per level. Parity floor raised to 87%. 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> |
||
|
|
8bc4e6c999 |
Paste Special: paste the clipboard as formatted text, RTF, HTML or unformatted text (edit.pasteSpecial) (#235)
New edit.pasteSpecial command ({"as"?, "text"?, "html"?, "rtf"?}). Without "as" it
lists the clipboard's formats and asks the front end for the dialog; with "as" it pastes in
that format. HTML/RTF go through the wordcraft-formats importers, with their lists, styles and
images merged into the document under fresh ids. Respects Track Changes (now also inside pasted
tables) and caps payloads at 16 MB. UI: Paste Special dialog (radio list + result hint),
Mod+Alt+V and Paste menu entry; strings in all four catalogs. Parity 355/405, floor 87.5%.
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>
|
||
|
|
9c3ad84d33 |
Advanced Find: every match, Reading Highlight, search within a selection (#234)
Home › Editing › Find › Advanced Find (edit.advancedFind) opens the Find
and Replace dialog. With params it returns every match in the body, or
only inside the selection ("in": "selection"), and "highlight": true
turns on Reading Highlight, which marks all matches on the page and
follows edits until it's turned off. The ribbon's Find button becomes a
menu with Find, Advanced Find and Go To; the Find dialog gets a Reading
Highlight toggle. Parity 355/405.
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>
|
||
|
|
d8f71959d3 |
Create and modify your own table styles, saved in the .docx (#146) (#256)
New Table Style and Modify Table Style (Table Design > Table Styles) make real table styles in the document's style sheet: name, based on, and formatting for the whole table, the header row and banded rows (borders, fill, bold, font colour). The table at the caret takes the new style, it shows in the gallery, and other tools that read table styles by name (pandoc's custom-style, for one) see it. - engine: table.newStyle / table.modifyStyle with documented params (regions take borders, fill, bold, italic, colour, size, font; bandSize; para); table.style only accepts table styles now. - doc/layout: table styles gain header-row and row-band cell borders, row-band character formatting and rows per band, applied by layout. - docx: tblStyleRowBandSize and firstRow/band1Horz tcBorders and rPr are read and written, so custom styles round-trip. - ui: a compact dialog from the Styles menu next to the gallery; table style tiles redraw when a style changes. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
4c4dc14a54 |
Reject All removes paragraph breaks inserted with Track Changes on (#229) (#244)
Enter under Track Changes already recorded the new paragraph mark as an insertion, but accepting or rejecting only cleared that flag, so Reject All left the paragraphs split. Rejecting an inserted mark (or accepting a deleted one) now joins the paragraph with the next one again; Accept All, Reject All, Accept/Reject at the caret or over a selection, Next/Previous Change and the Reviewing Pane all see paragraph marks. Backspace at a paragraph start and Delete at a paragraph end now record a tracked deletion of the mark (or remove a mark the same author inserted) instead of only moving the caret; tracked deletions across paragraphs mark the paragraph marks too. DOCX reads and writes paragraph-mark revisions (w:ins / w:del in the mark's w:rPr), and a tracked mark is drawn in its author's colour when formatting marks are shown. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
cc64f3df2d |
Add a System interface theme that follows the OS appearance (#115) (#249)
The interface theme is now a three-way choice: Use system setting, Light or Dark, in File > Options > General and in a new Interface Theme menu in View > Dark Mode. System follows the light/dark appearance egui reports (winit on macOS, Windows and Linux; prefers-color-scheme on the web) at launch and live, and falls back to light when the OS reports none. egui's own theme is now pinned to ours, so an OS change no longer swaps in egui's unstyled style. Saved preferences migrate: the old "dark" switch becomes Dark or Light and is never written again. Light stays the default for new installs. New ui.theme command (light/dark/system); ui.dark still sets Light/Dark. The dark page (View > Switch Modes) is unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6565a0f0ce |
Headless: file.setAuthor takes a name; review.trackChanges lists its value param (#90) (#224)
file.setAuthor now documents {"name": string} in the command list, trims the
name, strips control characters, caps it at 255 characters and refuses a blank
name. wordcraft-cli run and headless mcp take --author NAME. review.trackChanges
lists {"value"?: bool} so scripts find the explicit, idempotent form.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
5d86dec250 |
Right-to-left and Persian text support (bidi, shaping, RTL paragraphs, DOCX) (#207)
* feat(doc,docx): complex-script run properties and RTL OOXML round-trip Model the formatting Word applies to Persian, Arabic and Hebrew text: cs, font_cs, size_cs, bold_cs, italic_cs and lang_bidi on CharProps, resolved with Word's fallbacks (ResolvedChar::complex). Size, bold and italic pair with their complex-script values so a run's size or bold also covers its Persian characters. Add doc::bidi script helpers, and keep ZWNJ and Arabic marks inside words for word selection. DOCX: read and write w:rFonts/@w:cs, w:szCs, w:bCs, w:iCs, w:cs and w:lang/@w:bidi in schema order; stop using the cs font as the Latin font. Tests round-trip Persian text with ZWNJ, digits and mixed Latin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(fonts): directional shaping and Persian font fallback Add shape_run to shape a run in a known bidi direction (Arabic joining, mirrored brackets). Prefer Persian-capable fonts (Vazirmatn, Noto Naskh/ Sans Arabic…) for right-to-left fallback, pick bold/italic fallback faces, and map common Persian document fonts (B Nazanin, B Lotus, B Titr, IRANSans…) to open substitutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(layout): Unicode Bidirectional Algorithm and right-to-left paragraphs Run UAX #9 per paragraph (unicode-bidi), shape each level run in its direction, keep marks and ZWNJ with their letter and a word in one fallback face. After line breaking, apply rules L1/L2 per line and give each cluster a visual box; right-to-left paragraphs are laid out from their start edge and mirrored, so indents, tabs, alignment, list labels, drop caps, floats and borders sit on the right. Caret, hit testing and selection use visual geometry (split selections, caret at bidi boundaries, DocLayout::visual_step for arrow keys). Display items carry glyph-to-text ranges, which the PDF writer now uses. Plain left-to-right lines are unchanged. No hyphenation of RTL words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(engine,ui): paragraph direction commands and RTL editing Add para.ltr / para.rtl (Word's text direction buttons) that change only the reading order, and make the alignment buttons visual in right-to-left paragraphs (para.align also takes start/end). Arrow keys move visually in bidirectional text, Ctrl+arrows follow reading order, and Bold/Italic/ Size/Font cover complex-script text. Ribbon buttons with code-drawn icons, a mirrored ruler for RTL paragraphs, translations, catalog, parity and roadmap updates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(contributors): add Saeed Azarehgar to people.toml Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(engine): para.align with an explicit value sets it, without toggling Only the alignment buttons toggle back to the start edge when pressed again. para.align (used by the Paragraph dialog, scripts and agents) now sets the requested alignment, as seen on the page, in each selected paragraph's own direction. Previously pressing OK in the dialog with Center or Right selected reset the paragraph to the start edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(ui): Direction option in the Paragraph dialog Add Word's Direction (Right-to-left / Left-to-right) to the Paragraph dialog's General section. The dialog now shows alignment and Left/Right indents as seen on the page, mapping them to the paragraph's logical start/end values on OK, so an unchanged OK no longer flips a right-to-left paragraph. OK logic moved to apply_paragraph, with tests; ja/zh translations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(layout): allow hanging trailing spaces in the RTL display test A wrapped right-to-left line's trailing spaces hang past its end edge (the left margin), as left-to-right lines hang them past the right. The test failed whenever the loaded fallback fonts made a line end there; it now checks only visible glyphs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
10eb8798cd |
Equations: Word (OMML) import, layout and save, plus an equation editor like Word's (#191)
* M5.5: Word equations (OMML) import, lay out and save like Word Equations were flattened to plain text on import. Now OMML is read into a math tree (fractions, scripts, radicals, n-ary operators, delimiters, functions, limits, accents, bars, boxes, equation arrays, matrices, phantoms), laid out with the OpenType MATH table (Cambria Math when installed, else STIX Two Math and other open math fonts), drawn to screen and PDF, and written back as the original OMML. Display equations sit on their own centred line. insert.equation parses the linear format into structure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M5.5: equation editor like Word's — Equation tab, in-place editing, # numbers Insert › Equation now opens an equation for in-place editing, with the Equation tab: ready-made equations, Unicode/LaTeX input and conversion (professional ↔ linear), Normal Text, eight symbol sets, and the eleven structure galleries (fraction, script, radical, integral, large operator, bracket, function, accent, limit and log, operator, matrix) with tiles rendered by the math engine. Typing builds up like Word (a/b, x^2, √, ∑… then space), Math AutoCorrect turns \alpha, \sqrt… into symbols, Tab moves between empty slots, arrows/Backspace work through structures, and the right-click menu has structure commands (fraction type, radical degree, limit position, matrix rows/columns, remove brackets…). A trailing #(n) numbers a display equation with the number at the right margin; # alone numbers it automatically. DOCX output keeps numbers Word-compatible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: equation editor strings in Spanish, Brazilian Portuguese and Ukrainian The catalogs that landed on main after #191 was opened lacked the Equation tab and equation command labels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Equations: our own names and order for the built-in equations Clean room: the ready-made equation list used another product's gallery entry names and order. Same formulas (and ids), with our own descriptive labels, grouped by subject (geometry, algebra, calculus, trigonometry, probability). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ROADMAP: equations row matches the landed equation editor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fmt after merge 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> |
||
|
|
e4456efb84 |
Text boxes and floating objects: editing, drag/resize, wrapping, overflow, footnotes (#46)
* fix text boxes: type into a new box, click in and out, Escape leaves it Insert › Text Box left the caret in the body after the box and clicks inside a box never reached its story, so its text could not be edited. - insert.textBox puts the caret in the new box (when anchored in a top-level body paragraph, the only place layout shows box text today). - Layout emits a hit-test-only Placed::TextBox area; story_at prefers a box under the point (body text wins over boxes behind it) and ignores box lines outside their box. - Canvas: click enters a box, clicking outside goes back to the body (not while editing a header/footer); double-click in a box selects a word there. - Escape in a box puts the caret just after it (Document::text_box_anchor). - Editing a box doesn't dim the body or show "Editing header/footer". - Tests: engine (caret in box, typing, undo, table cell unchanged), layout (story_at inside/outside/behind), doc (anchor lookup). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix pasted text boxes sharing the original's text A copied fragment only carried the text box's part id, so a pasted box showed the original's story: editing either changed both, edits made after copying leaked into the paste, and pasting into another document (or Insert › Text from File) pointed at whatever part had that id there, e.g. a header. - Fragment carries copies of the text box stories it shows (nested boxes too). - insert_fragment gives every pasted box a new story of its own; a box whose story can't be found keeps none rather than showing an unrelated part. Nesting is depth-limited and one paste creates at most 4096 stories. - Insert › Text from File uses Document::body_fragment, which brings the file's text boxes along. - Tests: doc (own story, copy-time snapshot, other document with clashing ids, box in a table, fragment without parts, self-nested box), engine (copy/paste/type/undo through commands). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * word count includes text boxes, footnotes and endnotes (Word's default) The status bar and Word Count dialog counted only the body, so words typed into text boxes (and notes) were missing. - Document::counted_stories / word_count_including_notes: the body plus the text boxes, footnotes and endnotes it actually shows (nested too); orphaned stories (deleted or cut boxes), headers, footers and comments don't count. - Session::count_notes (default on) with Session::word_count for the status bar; review.wordCount takes {"includeTextBoxes"?: bool} and reports it. - Word Count dialog: "Include text boxes, footnotes and endnotes" checkbox. - Document::word_count stays body-only (docx Words property, NUMWORDS, stats). - Tests: doc (used vs orphaned stories, nesting, self-nested box), engine (default on, toggle sticks, deleting a box drops its words). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * canvas: select, drag to move and resize pictures, shapes and text boxes Click a picture or shape (or a text box's border) to select it: a frame with eight handles. Drag it to move it, drag a handle to resize it (pictures keep their proportions from a corner, Shift toggles), arrows nudge a floating one (Ctrl/Alt: 1 pt), Escape cancels a drag. While a text box's text is edited its frame shows dashed with handles. Typing or Enter with a text box selected goes into it. Reusable pieces, no per-kind code: - layout: Placed::Object, one hit area for every picture/shape/text box (replaces the text-box-only item); DocLayout::object_at / object / text_box / find_object (page-hinted, no whole-document scans per frame). - engine: arrange.bounds {width,height,x,y,page} (floating objects keep their anchors on the same page; inline ones float where dropped; another page re-anchors to the nearest line) and arrange.nudge; objects::min_size shared with the UI. - ui: frame.rs, a document-agnostic transform frame (handles, hit testing, drag/resize maths, painting); objects.rs wires it to document objects. - geom: Rect::expand. control: ui.press / ui.release for half-way drags. Rendering: nothing is laid out or rasterised while dragging. The preview is the object's own pixels from the cached page texture (moves, picture resizes) or a light outline (text box/shape resizes); the drop is one command, one relayout, one undo step. Tests: frame maths, layout hit areas, engine move/resize/nudge across anchors and pages, hostile values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * moving an object anchors it to the paragraph it's dropped on, so text wraps A floating object only pushes aside text from its anchor paragraph down, and a move kept the old anchor: drag a text box above its paragraph and the text there ran straight under it. - arrange.bounds now anchors the object to the paragraph under its top edge (the last one starting at or above it on that page) and positions it relative to that paragraph's column and top, as Word does: the text it lands on wraps, and it moves with that text. On a page where no paragraph starts it anchors to the nearest line, positioned on the page. - layout: Placed::Object / ObjectHit carry the paragraph origin that column- and paragraph-relative offsets start from. - engine: edit_obj / edit_float change an object at a position (with_obj uses it). - Test: a box dropped over an earlier paragraph anchors there and the lines beside it stop short of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * text boxes hide text that doesn't fit, as in Word Text past a text box's bottom spilled out over the page below it. - layout: fit_box keeps what fits in a box: whole lines that fit (a line that only partly fits is hidden too) and other items starting inside; the first line always stays so even a tiny box shows something. Done in layout, so the canvas, PNG and PDF agree and hidden text can't be clicked; no renderer changes. Reusable for anything laid out into a fixed height. - BOX_INSET_X / BOX_INSET_Y name the text box internal margins (were 7.2/3.6 literals). - Test: overflow hidden, every shown line inside the box, a tall box shows everything, a minimum-size box shows its first line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * square wrap flows text on both sides of a floating object Text only used the wider side of a floating picture, shape or text box; Word's Square wrap fills both sides when there's room. - para: row_spans gives the spans of a row around the objects in its way (each at least 0.5" wide, else the line goes below); a row cut in two is two Lines sharing top and height, the second marked `beside`. Everything per line (alignment and justification per side, hit testing, caret, selection, drawing, PDF) works unchanged; a row is as tall as its tallest part. - layout: a row stays on one page; line numbers count rows, not parts. - Exclusions that don't overlap a line horizontally no longer narrow it. - Test: text both sides of a mid-column box (same row, left then right, hittable), a too-narrow gap stays empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * drop a deleted or cut text box's text from the document Deleting or cutting a text box left its story in Document::parts: never shown or saved to .docx, but listed by document.inspect and kept in memory. - doc: prune_text_boxes removes the text box stories no box shows (nested ones too); free without text boxes, one paragraph pass otherwise. Session runs it after every editing command. Undo snapshots and the clipboard hold their own copies, so undo and cut/paste are unaffected. - doc: reachable() walks the stories objects lead to; counted_stories (word count) and prune_text_boxes share it, and it walks blocks directly instead of building paragraph paths. - Tests: orphaned and nested-orphan boxes go, shown ones (body, nested, in a header) stay; delete then undo, cut then paste. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * word count's include-text-boxes setting survives a restart The Word Count dialog's "Include text boxes, footnotes and endnotes" was a session field, so it reset to on every launch. - engine: Prefs, the editing preferences the front end saves between runs (count_notes moves there; Session::prefs is the one source of truth). - ui: SavedPrefs pairs UiState with the engine Prefs; WordApp::saved_prefs / restore_prefs. UI fields stay at the top level of ui.json, so existing files still load (the new `editing` section defaults). - wordcraft app: saves and restores SavedPrefs instead of UiState alone. - Tests: an old prefs file loads with Word's default; the setting round-trips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * text boxes and floating objects outside the body; footnotes in text boxes Text boxes in table cells, headers, footers, footnotes and other text boxes showed an empty frame (or nothing), and floating pictures and shapes there weren't drawn. Footnotes inserted inside a text box were never numbered or placed. - layout: place_objects, one routine for the pictures, shapes and text boxes in a paragraph's lines (floating ones drawn, every one's area, text boxes' text), used by body paragraphs and by layout_box (cells, headers, footers, notes, box contents). Floats are positioned against an AnchorFrame (column, paragraph, margins, page); headers and footers pass where the page is, so page/margin-anchored objects land right (a footer is laid out again only when it has floating objects); elsewhere they're placed in their container. Nested boxes show MAX_TEXT_BOX_DEPTH (doc) levels deep. - Placed::Object / ObjectHit carry their story; DocLayout::object(&Pos), object lookups include headers and footers, header_footer_text_box_at. A part's lines are looked up in headers and footers too (caret, typing). - Footnotes: numbered in reading order with text boxes where they are (Document::objects_in_reading_order); a box's footnotes go on the page of its line (Document::notes_in_text_box), sharing the body's reservation. - engine: insert.textBox always puts the caret in the new box; disabled inside a text box (as in Word). - canvas: click into a header/footer's text boxes while editing it; leaving a box returns to where it is; body dimming computed once per frame and used for both the render and its cache key. objects: only body objects are selectable, only body paragraphs' objects movable; frames off the body show without handles. - Tests: boxes in header (inline and page-placed), footer, cell and note show text and take the caret; footnotes in a box numbered and placed in order; a box in a table cell takes the caret and its text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * word count: a selected object counts the whole document, in the dialog too With a picture, shape or text box selected the status bar showed the document's total but Review > Word Count counted the selection (0 words). - engine: cmd::objects::object_selection, "the selection is exactly one object"; review.wordCount counts the document then. The UI's objects::selected now uses it (one definition). - Test: an object selection counts the document; a text selection itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * review: bound nested text box expansion; tidy-ups Blocker: laying out a text box lays out the boxes inside it, which could fan out unboundedly (a box whose shapes show itself, or chains of boxes each showing the next many times) - 30 shapes made 1.7M layout items. Footnote numbering's walk fanned out the same way. - doc: BoxBudget, one bound for both: a box isn't expanded inside itself, nesting stops at MAX_TEXT_BOX_DEPTH, an outermost box expands at most 64 boxes inside it (so one hostile box can't starve the next page's header boxes) and a pass at most 20,000. - layout: Ctx carries a BoxBudget for the whole layout; place_objects asks it before laying out a box's text. DocLayout::text_boxes reports how many were. - doc: walk_objects (objects_in_reading_order, notes_in_text_box) uses it too. - Tests (crafted documents): a box showing itself 30 times lays out once; a five-level chain fanning out 30 ways stays within the budget, for layout and for the walk; a box inside a box still shows its text. Weakening the budget makes them fail (20,000 boxes / 600,001 visits). Tidy-ups: - para: row spans in a VecDeque (pop_front, not remove(0)). - fit_box: a text box's text area excludes both the top and bottom margins. - theme: Tokens::handle / handle_shadow for the frame handles (light, dark); the drag preview's opacity is a named constant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * box budget: no overall cap; bound the .docx writer too; tests An audit of the previous commit found: - The 20,000-box overall cap starved ordinary long documents: one budget per layout, spent by body boxes first, then one per page for header boxes (two for footers with floats), so a long document's header boxes went blank on every page. It wasn't needed: only nesting grows exponentially, and MAX_NESTED caps that per outermost box, keeping the work linear. Removed. - The .docx writer still expanded a shape's story only depth-limited (a box showing itself 30 times saved as ~28,000 nested copies, ~7 MB zipped). It now uses the same BoxBudget, and only for text box parts. - Layout expanded a shape's story whatever its part kind (a shape pointing at a header showed the header's text); now text box parts only, as the walk does. The story's blocks are cloned only once the budget agrees. - Translations of "Count words in text boxes and notes" said footnotes only; now footnotes and endnotes, in each catalog's own terms. - Tests: no timing assert or leftovers; a long document with 400 boxes and a header box shows all of them on every page; notes_in_text_box follows nested boxes once; saving a self-showing box stays small (fails at 7 MB without the bound). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Arrange: nudging or dragging an aligned float keeps it in place first main (#136) reads w:align into Float.h_align/v_align, which overrides the offset; the PR's nudge only changed the offset and drag only reset the anchors. Nudge now converts an aligned axis into a column/paragraph offset that keeps the object where it is, and a drag clears the alignment. Test included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fonts: a lookup that races another thread's load of the same family no longer falls back FontDb::face fell back to Source Sans 3 when its load_cataloged added nothing, which happens when another thread loaded the family between the miss and the load. word::resolve memoises that, so the wrong font stuck for the process; it made layout tests on main flaky (justified_lines_shrink_spaces_in_word_2013_mode, space_shrinking_is_only_for_justified_text failed 6 of 15 runs on origin/main). Look again after loading whatever it returns. Regression test races 8 threads on fresh databases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Layout tests: text box and two-sided wrap tests measure what they mean square_wrap_flows_text_on_both_sides compared xs.last() (the end of a trailing space, which may hang past the edge) with the edge; compare the last non-space cluster's right edge. text_box_hides_text_that_does_not_fit compared a tall box's lines with another document's line count; compare with its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Weeb Labs <weeblabs@VFIEVOX3.Router> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |