mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-25 19:07:17 -06:00
8a2a8bb60dfd46ddceee26a4aa91aeb5cbe14532
88
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8a2a8bb60d |
Insert > Icons: an original icon library, a searchable picker and Icon Color (#309) (#318)
Adds wordcraft_render::icon_lib, 61 monochrome icons in ten categories
(Arrows, Communication, Office, People, Nature, Weather, Shapes, Symbols,
Technology, Transport). They are original WordCraft artwork: simple
geometric line drawings designed on a 24x24 grid as path data in code, with
no icon files and nothing copied from another icon set.
insert.icon {"id", "color"?, "size"?} renders the chosen icon with vello_cpu
to a transparent PNG at about 300 ppi and inserts it at the caret through the
ordinary picture path, so it saves to .docx and every other format. Without
an id it lists the library (narrowed by query and category) and asks the
front end for the picker. picture.iconColor repaints a one-colour picture
in a new colour and keeps its transparency.
Insert > Illustrations > Icons opens a dialog with a search box, category
chips and a grid of icons drawn live by the egui painter from the same path
data; Insert or a double click places the selection. Picture Format > Adjust
gains an Icon Color menu. New strings are translated in every catalog.
Catalog parity 393/434 -> 394/434 (90.8%).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
a5b17eb3a4 |
Enclose Characters: put a character in a circle, square, triangle or diamond (#301)
* Home › Font › Enclose Characters: circle, square, triangle or diamond around a character (#297) New command format.enclose {"shape": "circle|square|triangle|diamond" | null, "style"?: "shrink|enlarge", "text"?: string} puts one full-width or up to two half-width characters in an enclosure, changes its shape, or (null) takes the text back out. It is stored the way ECMA-376 describes it: an EQ field with the overstrike switch, eq \o\ac(○,字), with the text as its plain-text result. Layout now draws EQ \o fields: the arguments overstruck as one cluster (centred, \al or \ar). An enclosure symbol among them is drawn as a vector shape around the text in the text's colour, so it never depends on the font having ○ □ △ ◇; "shrink text" scales the text into a one-em shape, "enlarge symbol" grows the shape around text at its own size. Screen and PDF both get it through the display list. Imported Word documents with enclosed characters used to show nothing (the field has no result); they now render. .docx: written as Word stores enclosed characters (begin, the code split so the symbol and the text have their own run sizes, end, no result); the reader recovers the style from those sizes. The style lives in the model as a trailing \* enlarge on the code, never written to a file. Home › Font gets an Enclose Characters button that opens a dialog (Style: None / Shrink text / Enlarge symbol, Text, Enclosure list, a drawn preview); scripts with a shape never see it. Strings in every interface catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: keep both sides (enclosures and ruby; tests); regenerate parity checklist --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
3042e5251e |
Phonetic Guide: ruby text (furigana, pinyin) over base text (#296)
* Phonetic Guide: ruby text over base text (#288) Home › Font › Phonetic Guide (format.phonetic) sets small ruby text (furigana, pinyin) over the selected text. The ruby is one inline object anchored at U+FFFC whose plain text is the base, so selection and the caret treat it as one unit and exports read the base text. - Model: InlineObject::Ruby with base, ruby, alignment (ECMA-376 ST_RubyAlign), ruby size, raise, base size, language and the ruby's own formatting. - Layout: the base is drawn in its run's formatting, the ruby above it by alignment (centre, distribute letters/space, left, right); the wider of the two sets the width and the line grows to fit the ruby. Drawn in the shared display list, so screen and PDF both show it. - DOCX: w:ruby read and written with w:rubyPr (rubyAlign, hps, hpsRaise, hpsBaseText, lid), w:rt and w:rubyBase runs with their formatting. Previously only the base text was kept. - Command format.phonetic {"ruby", "align"?, "size"?, "offset"?}: sets, edits or (null/"") removes the ruby, undoable; without "ruby" it opens the dialog and returns the selection's phonetic guide. - UI: Phonetic Guide button in Home › Font and a dialog (base text, ruby text, alignment, offset, size, Remove), strings in every catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Merge fix: keep both sides' tests --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
dba6e66d53 |
Choose which side of an object text wraps on (#364)
* Tight and Through wrapping follow the object's outline (#354) Text now wraps around a Tight or Through object's shape instead of its bounding box. The outline is the object's wrap polygon (wp:wrapPolygon, in the 21600-unit space of its frame) when it has one; otherwise it is derived: a shape's geometry (ellipse, triangle, star, heart... flattened), the convex hull of a picture's opaque pixels (alpha threshold on a coarse grid, at most 64 points), or the rectangle. The outline turns and flips with the object, keeps the left/right and top/bottom distances from text, and is built once per placed object; each line asks it which stretches of its band it covers. Through also lets text into gaps inside the outline that are wide enough. DOCX reads and writes wp:wrapPolygon (with edited) for wrapTight and wrapThrough; a shape without one gets its outline written, other objects their rectangle, since the schema requires a polygon. Square, top and bottom, behind and in front of text are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Choose which side of an object text wraps on (#354) Square, Tight and Through objects now have a wrap side, like Word's "Wrap text" choice: both sides (the default), left only, right only, or the largest side. Left keeps the band to the object's right empty on every line beside it, Right the band to its left, and Largest picks the wider side line by line. It works with contour wrapping and with turned objects, and right-to-left paragraphs mirror it. The setting is Float::wrap_text, read from and written to wrapText on wp:wrapSquare, wp:wrapTight and wp:wrapThrough (previously always written as bothSides). The new arrange.wrapText command {"side": "bothSides|left|right|largest"} sets it on the selected object as one undo step. The ribbon's Wrap Text button is now a menu with the wrap styles and a Wrap Text Sides submenu, translated in every interface language. 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> |
||
|
|
860f4ca260 |
Tight and Through wrapping follow the object's outline (#354) (#360)
Text now wraps around a Tight or Through object's shape instead of its bounding box. The outline is the object's wrap polygon (wp:wrapPolygon, in the 21600-unit space of its frame) when it has one; otherwise it is derived: a shape's geometry (ellipse, triangle, star, heart... flattened), the convex hull of a picture's opaque pixels (alpha threshold on a coarse grid, at most 64 points), or the rectangle. The outline turns and flips with the object, keeps the left/right and top/bottom distances from text, and is built once per placed object; each line asks it which stretches of its band it covers. Through also lets text into gaps inside the outline that are wide enough. DOCX reads and writes wp:wrapPolygon (with edited) for wrapTight and wrapThrough; a shape without one gets its outline written, other objects their rectangle, since the schema requires a polygon. Square, top and bottom, behind and in front of text are unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
34511263a7 |
Customize Ribbon and Quick Access Toolbar (#379) (#384)
* Customize Keyboard dialog (#368) 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> * Customize Ribbon and Quick Access Toolbar (#379) Tools > Customize Ribbon (tools.customizeRibbon): one dialog with two pages. Ribbon: commands by category next to the ribbon's tabs; show or hide and reorder tabs, add custom tabs and custom groups (on built-in or custom tabs) holding any commands, rename, remove, reset. Quick Access Toolbar: add, remove and reorder its commands, reset. - engine: RibbonLayout (tab order and visibility, custom groups, the toolbar's commands). Saved layouts read leniently: junk, duplicates, reserved names and unknown commands are dropped. - tools.customizeRibbon: with params (hide/show, newTab, newGroup, add, remove, rename, move, qatAdd/qatRemove/qatMove, reset, layout) it only changes or reports the layout; without params it opens the dialog. - ui: the tab strip and ribbon follow the layout (custom groups draw the commands' own icons, else a lettered tile); the Quick Access Toolbar shows the user's commands; right-click any ribbon button to add it to (or remove it from) the toolbar or open the dialog; the toolbar's ... button opens a menu of common commands and More Commands... (#376); File > Options has a second Customize button; layout persists in ui.json under `ribbon`. - Open and Print icons drawn in code; i18n strings in every catalog; docs/ui-parity, gaps #24, ROADMAP log, parity checklist. Fixes #376. 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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
4c6dd898c2 |
Tables: Delete Columns never leaves a table with no rows (#397)
Delete Cells removes a cell without shrinking the grid, so a row can be shorter than the grid. Delete Columns then removed that row's only cell, dropped every row left without cells, and kept the now empty table block (`rows: []`), an invalid state that anything indexing the first row would turn into a panic. When no rows are left, remove the table, as deleting the only column already does. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.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> |
||
|
|
e2d8551b7f |
Equation gallery: group multi-letter operands in two templates (#347)
A script or above/below operand takes one letter unless it is grouped, as in Word, so `⟶┴yields` (Yields) put only "y" above the arrow and the n×n Matrix's `a_1n`, `a_m1`, `a_mn` subscripted only "1" and "m". Grouped as `⟶┴(yields)` and `a_(1n)`, `a_(m1)`, `a_(mn)`. A new test fails when any template or built-in equation leaves letters right after a script or limit. Claude-Session: https://claude.ai/code/session_01WtHKQ7wrZm3uBuaG1Ye8po Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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> |
||
|
|
4b450f1b00 |
Open and save password-protected Word documents (#55) (#281)
* Clipboard pane: collect the last 24 copies and cuts and paste any of them again
Copy and Cut now also keep each item (rich fragment plus plain text) in a
session list of up to 24, newest first. Items over ~4 MB (estimated) are
skipped and the list stays under ~24 MB in total; copying the same thing
twice in a row adds it once. The system clipboard is untouched.
New commands: edit.clipboardPane (toggle the pane, also the Clipboard
group's dialog launcher), edit.clipboardItems (list with previews),
edit.pasteClipboardItem {index}, edit.pasteAllClipboard,
edit.deleteClipboardItem {index} and edit.clearClipboard. Pasting goes
through the normal paste path, so it is one undo step and respects Track
Changes. The pane lists the items with a short preview; clicking one pastes
it at the caret, and each has Delete, plus Paste All and Clear All.
Parity: 378 -> 379 of 428 features.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Layout > Arrange > Group: group pictures, shapes and text boxes into one object
Shift+click (or Ctrl+click) adds pictures, shapes and text boxes to the
selection; Group (arrange.group) combines the selected floating objects
into one group object that moves, wraps and resizes as one, with its
members keeping their places and scaling with the group. Ungroup
(arrange.ungroup) splits it back, where the group showed them, and
leaves them selected so Group puts them back together.
- Model: InlineObject::Group with the members' coordinate space (like
DrawingML a:chExt), so resizing the group scales its members.
- Layout draws the members inside the group's frame; hit testing
selects the group; text boxes in a group show their text.
- DOCX writes wpg:wgp with a:chOff/a:chExt and each member's a:xfrm,
and reads Word's groups (including inside mc:AlternateContent and
nested groups, flattened).
- select.addObject makes multi-selection scriptable (pos or Selection
Pane index).
Parity 378 -> 379 of 428 (88.6%); floor raised to 88.5%.
Fixes #265
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Paragraph: Asian Typography settings, with kinsoku and mid-word Latin wrapping in layout (#269)
Paragraphs gain the Asian Typography flags (line-breaking rules, wrapping
Latin text in the middle of a word, hanging punctuation, compressing
punctuation at the start of a line, and automatic space between Asian and
Latin text and between Asian text and numbers). They inherit through styles,
round-trip through .docx pPr, are set by the new para.asianTypography
command and appear on a new Asian Typography tab of the Paragraph dialog.
Layout applies the kinsoku lists (no line starts with closing East Asian
punctuation or ends with opening punctuation), breaks between any East Asian
characters when kinsoku is off, and breaks Latin words anywhere when word
wrap is off. Text without East Asian characters breaks as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Manage Styles: list, preview, delete and show or hide styles
Home › Styles › Manage Styles (styles.manage) opens a dialog from the
Styles pane listing the document's paragraph, character, linked and table
styles, sorted as recommended or alphabetically, with a preview line and a
description (type, formatting it sets, what it is based on). From there:
Modify… and New Style… reuse the existing dialogs and come back, Delete
removes custom styles, and two checkboxes show the style in the Styles
gallery (w:qFormat) or hide it from style lists (w:semiHidden).
styles.manage returns the list for scripts (name, type, builtIn,
inGallery, hidden, basedOn, priority, own formatting). styles.delete now
moves paragraphs, runs and tables that used the style to its base (in
every story), rebases styles built on it and takes a custom linked
character half with it; built-in styles are refused and it is undoable.
New styles.setVisibility {style, gallery?, hidden?} sets the flags, which
round-trip through .docx.
Fixes #266
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Create and modify your own table styles, saved in the .docx (#146)
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>
* Table styles: every region, a live preview, delete, custom styles first (#146)
Follow-up to the custom table styles work: the New/Modify Table Style
dialog now covers every region a table style formats, shows what the
style will look like, and table styles can be deleted.
- engine: table.newStyle / table.modifyStyle take lastRow (total row),
firstColumn, lastColumn and bandedColumns regions with the same props
as the others. New table.deleteStyle removes a custom table style:
built-in ones are refused, styles based on it are re-based on its own
base with its formatting folded in (so they look the same), and tables
using it fall back to Table Grid. Undoable like any command.
- doc/layout: table styles gain fill and cell borders for the first and
last column and total row, and fill, text and borders for column
bands; layout applies them in the standard order (column bands, row
bands, first/last column, header/total row).
- docx: firstCol/lastCol/lastRow/band1Vert shading and cell borders are
read and written.
- ui: the dialog's "Apply formatting to" lists all seven regions and a
small live preview table shows the pending changes; Styles menu gets
Delete Table Style (disabled for built-ins); the gallery shows the
document's own table styles first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Paste pictures from the system clipboard (screenshots, Copy Image, copied files) (#45)
egui's paste event only carries text, so a clipboard holding just a picture
sent no paste at all on Ctrl+V, and the ribbon/context-menu Paste only knew
WordCraft's own copy ("the clipboard is empty").
Desktop: the app reads the clipboard's picture through a new
Services::clipboard_picture (arboard, already in the build via egui-winit):
copied files first, else image pixels. Mod+V whose release arrives without a
paste event, and Paste from the ribbon or menus, insert that picture through
insert.picture (one undo step); text naming copied picture files inserts the
pictures. Pixel sizes are hostile: at most 16,000 px a side and 50 Mpx, the
buffer must match, files at most 200 MB.
Web: a document paste listener reads image files from the paste event when
there's no text and delivers them through the inbox like dropped pictures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Shape Format: Shape Effects — shadow, glow and soft edges (#275)
Shapes and text boxes get an effects model (outer shadow with colour,
transparency, blur, distance and angle; glow with colour, size and
transparency; soft-edge radius), the shape.effects command (presets,
custom values or null per effect, applied to every selected shape,
undoable, hostile numbers clamped), screen and PDF rendering with the
same banded approximation of a blur, DOCX a:effectLst read/write
(outerShdw, glow, softEdge) with a matching wp:effectExtent, and a
contextual Shape Format tab with Shape Fill, Shape Outline and Shape
Effects (Shadow, Glow, Soft Edges submenus) plus Arrange.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Open and save password-protected Word documents (#55)
Opening a password-protected .docx used to fail as a broken zip and showed
a blank document. Encrypted packages (an OLE compound file with
EncryptionInfo + EncryptedPackage) are now detected and decrypted with
ECMA-376 agile encryption, written from the public [MS-OFFCRYPTO] spec:
password key derivation with spinCount, verifier check, data-integrity
HMAC, AES-CBC in 4096-byte segments (AES-128/192/256 with SHA-1/256/384/512
on read; AES-256 + SHA-512, spinCount 100000 on save). Standard (Office
2007) and certificate encryption give a clear "not supported" error.
- docx: crypt module (decrypt, encrypt, is_encrypted, read_with_password),
PasswordRequired / WrongPassword / Encryption errors; hostile files are
bounded (stream caps, spinCount <= 10,000,000, checked lengths).
- engine: file.open/file.save take "password"; file.encrypt
{"password": string|null} sets or removes the save password (pure, so it
never lands in Repeat or recorded macros); a document opened with a
password is saved with it again; file.info reports "encrypted".
Passwords are held in a zeroizing type whose Debug prints ***.
- ui: a password prompt when a user-opened file needs one (scripts get the
error), File > Info > Protect Document with Encrypt with Password (typed
twice) and Remove Password; web downloads are encrypted too.
- deps: aes, sha1, sha2, hmac, base64, getrandom (wasm_js in the browser),
zeroize.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Table styles: Table Grid and Normal Table can't be deleted even when a .docx marks them custom
A .docx can set w:customStyle on any style, which made Word's built-in table styles look custom
and deletable. table.deleteStyle and the ribbon's Delete Table Style now also recognise them by
id and name, so no table is left on a style that's gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Manage Styles: deleting a table style runs Table Design's table style deletion
styles.delete on a table style now calls table_style::delete (#263): its tables take Table Grid,
styles based on it keep their look, and Word's built-in table styles are refused even when a
.docx marks them custom (the Manage Styles list reports them built-in too). Document::restyle no
longer retargets tables' own styles, so there is one place that does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Paste pictures: Mod+Shift+V (Paste Formatting) no longer pastes a clipboard picture
The key-release fallback that pastes the system clipboard's picture treated every Mod+V release as
Paste. It now requires plain Mod+V or the Paste key (no Shift, no Alt), with a unit test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Asian typography: test that kinsoku keeps a manual line break before a closing bracket
Manual line breaks end the line by cluster kind, not by break opportunity, so kinsoku's filter
can't drop one before 」; pin that with a layout test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Encrypted saves: the data-integrity HMAC key is hashSize bytes
MS-OFFCRYPTO §2.3.4.14 makes the HMAC salt as long as the hash (64 bytes for SHA-512); it was
16. Reading already accepted both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: password dialog and File › Info strings in every catalog
Rows for the Password and Encrypt with Password dialogs, the Protect Document section of
File › Info and the password status messages in zh-hans, zh-hant, ja, pt-br, es, uk, sr and
sr-latn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Open and save password-protected Word documents (#55)
Opening a password-protected .docx used to fail as a broken zip and showed
a blank document. Encrypted packages (an OLE compound file with
EncryptionInfo + EncryptedPackage) are now detected and decrypted with
ECMA-376 agile encryption, written from the public [MS-OFFCRYPTO] spec:
password key derivation with spinCount, verifier check, data-integrity
HMAC, AES-CBC in 4096-byte segments (AES-128/192/256 with SHA-1/256/384/512
on read; AES-256 + SHA-512, spinCount 100000 on save). Standard (Office
2007) and certificate encryption give a clear "not supported" error.
- docx: crypt module (decrypt, encrypt, is_encrypted, read_with_password),
PasswordRequired / WrongPassword / Encryption errors; hostile files are
bounded (stream caps, spinCount <= 10,000,000, checked lengths).
- engine: file.open/file.save take "password"; file.encrypt
{"password": string|null} sets or removes the save password (pure, so it
never lands in Repeat or recorded macros); a document opened with a
password is saved with it again; file.info reports "encrypted".
Passwords are held in a zeroizing type whose Debug prints ***.
- ui: a password prompt when a user-opened file needs one (scripts get the
error), File > Info > Protect Document with Encrypt with Password (typed
twice) and Remove Password; web downloads are encrypted too.
- deps: aes, sha1, sha2, hmac, base64, getrandom (wasm_js in the browser),
zeroize.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Reland: catalog coverage 390/431 (90.5%) in ROADMAP and target-app parity
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Manage Styles: mark table styles with ⊞, which the interface fonts have (▦ has no glyph, #305's check)
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>
|
||
|
|
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> |
||
|
|
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> |
||
|
|
c0bbcbac24 |
Charts and SmartArt: draw them instead of dropping them (#292)
A chart or SmartArt diagram in a DOCX was dropped on import: it took no room, so the text after it moved up (five of the six chart documents in docxide-pdf's fixtures came out a page short), and nothing was drawn. They are now an InlineObject::Graphic: it takes its room, floats and wraps like a picture, and draws a list of neutral items (shapes, paths, one-line texts, pictures) that layout scales to the object's box. - Charts (read/chart.rs) are drawn from the values the chart part caches: clustered, stacked and 100% bar and column charts, line, area, pie, doughnut and scatter charts, with title, legend, gridlines, axis labels and Excel number and date formats. - SmartArt (read/diagram.rs) is drawn from the drawing Word stores beside the diagram: preset shapes, theme colours, text and pictures. - Theme colour handling is shared (read/drawing_color.rs). - Each chart or diagram part is read once, only through a relationship of its type, under a per-file budget of items. - Tagged PDF tags them as figures with their alternative text, and the accessibility check reports charts without one. Not yet: charts and diagrams aren't written back when saving a DOCX (they weren't before either), so the editor doesn't let you move or resize them. Radar, stock, 3-D and combination charts draw their first supported chart type only; SmartArt pictures aren't clipped to their shape. docxide-pdf bench (365 documents, vs main + #135): page counts right 320 -> 326 (all five chart documents and one SmartArt document), Jaccard passes 208 -> 215, SSIM passes 76 -> 79; eight documents better, none worse. Co-authored-by: Oliver Zieschang <4963183+naxvog@users.noreply.github.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> |
||
|
|
88ad402581 |
Gridlines: the document's own grid spacing, and table gridlines on by default (#69, follow-up to #243) (#283)
View › Gridlines now draws the drawing grid at the document's own spacing: DOCX keeps it in settings.xml as w:drawingGridHorizontalSpacing and w:drawingGridVerticalSpacing (ECMA-376 §17.15.1.44/45), which WordCraft now reads (clamped) and writes (only when it differs from the default), with a round-trip test. Documents that don't say use the spec's 180 twentieths of a point (1/8 inch) instead of a fixed 0.5 cm; across and down can differ. Table Layout › View Gridlines (table.viewGridlines) is on by default, as in Word, so tables without borders still show their cells. Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> 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> |
||
|
|
da18ae8933 |
File › Info: Title, Author and the other property fields keep what you type, and browser saves advance the save stamps (#260, #262) (#268)
The Info page edited a copy of the document properties that was re-read from the document every frame and only written back when a field lost focus, so each keystroke vanished on the next frame and nothing was ever committed. The fields now commit through file.properties as you type (undoable, one step per visit to a field, marks the document dirty). The web build's Save writes the bytes itself instead of running file.save, so it never stamped the modified time, last-modified-by and revision. Both paths now share Session::stamp_save. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8ac57f0312 |
i18n: add Serbian, both scripts (sr, sr-latn) (#250)
Serbian is officially digraphic — Cyrillic and Latin are both in
everyday use, with Cyrillic the default per BCP 47 when no script is
given. Adds both as separate catalogs, same as the existing
Simplified/Traditional Chinese split handles script rather than
region:
- sr-latn.tsv: the actual translation, written clean-room from the
plain meaning of each English label (never from Microsoft Word's or
another product's Serbian localisation), covering the full existing
catalog (874 entries, same key set as zh-hans.tsv).
- sr.tsv: mechanically transliterated from sr-latn.tsv by a small
script (not committed — a one-off; the mapping is the standard
digraph-aware Serbian Latin→Cyrillic table). Brand/product/format
names (WordCraft, PDF, Discord, Zotero, SmartArt, file extensions…)
and `{placeholders}` are protected from transliteration, same names
that stay in Latin letters in every other catalog. Hand-editing this
file isn't the workflow — change sr-latn.tsv and re-transliterate.
- mod.rs: registers `sr` (Cyrillic) and `sr-latn`. No special-casing
needed in `candidates()` for the script split, unlike Chinese's
region-implies-script fallback — `sr-Latn-RS` already produces
`sr-latn` as a candidate before falling back to plain `sr`, and a
bare `sr`/`sr-RS` (no script tag, the common case) resolves straight
to `sr` since that's the registered default-script code.
- tests.rs: locale-matching coverage for both scripts, full-catalog
parity with the reference language, and bundled-font glyph coverage
for both Cyrillic and Serbian Latin's extended letters (š č ć ž đ),
mirroring the existing Ukrainian/Portuguese tests.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.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> |
||
|
|
19e2e37ca6 |
View › Gridlines shows the drawing grid; Table Layout › View Gridlines outlines cells (#69) (#243)
View › Show › Gridlines only outlined table cells, so with no table on the page it seemed to do nothing. It now draws a light 0.5 cm grid over the page's text area, inside the margins, in Print Layout. Table Layout › View Gridlines gets its own command, table.viewGridlines, with its own view flag, and draws the table cell outlines as before. The ribbon button, keytip and parity catalog point at it. Both are screen-only overlays drawn by the canvas; print, PDF and image exports never show them. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
69eaf9925c |
View tab: Zoom In/Out buttons that step from the shown zoom (#67) (#232)
Zoom In/Out stepped from the stored manual zoom, which goes stale while a fit mode (Page Width, One Page, Multiple Pages) sizes the page: from a 163% Page Width, Zoom In jumped to 110%, i.e. zoomed out. The canvas now keeps view.zoom equal to the shown zoom while a fit mode is on, so Zoom In/Out, the Zoom dialog and view.state all start from what the user sees. The View › Zoom group gains Zoom In / Zoom Out buttons (code-drawn icons; the catalog already lists them there), and the Zoom dialog's slider is logarithmic and wider so a short drag no longer jumps from 100% to 480%. 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> |
||
|
|
40c5d51bf9 |
Mailings: Start Mail Merge and Rules open menus, and Match Fields and Check for Errors show what they found (#259)
* Tests: shapes and pictures can be clicked, resized, dragged and nudged Fixed by #46 but only text boxes were covered. These walk the editor's path for shapes (rectangle, ellipse, star, arrow) and pictures: hit test, select, resize with arrange.bounds, drag to float with Square wrap, nudge, undo. Covers #142 and #82. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Font list offers every weight a family installs, named as Word names them (#219) Fonts were listed and matched only by their typographic family name (name ID 16, e.g. "Roboto"), so a face other than Regular, Bold or Italic (Light, Medium, SemiBold, Black, Condensed...) never appeared in the font list, and a document asking for "Roboto Light" fell back to a substitute. Each face now also carries its legacy family name, the one Word lists and stores in documents: name ID 1 for static fonts ("Source Sans 3 Semibold"), or the family plus the style words other than Regular, Bold and Italic for a variable font's named instances ("Inter Light"). The font list includes these names, has_family and face() resolve them (bold and italic still choose or synthesise within the faces the name covers), and asking for a legacy name loads the whole installed family. The system font scan now also reads fvar, so a variable font's instances are listed before it is loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Absolutely positioned VML text boxes float instead of sitting inline (#149) A legacy VML shape (w:pict > v:shape / v:rect) with position:absolute in its style was read as an inline object, so a tall text box in a header made the header as tall as the box and pushed the body down the page. The reader now maps the VML style to the same float model DrawingML anchors use: left/margin-left and top/margin-top offsets, mso-position-*-relative reference areas, mso-position-horizontal/vertical alignment, mso-wrap-distance-* and w10:wrap (square, tight, through, topAndBottom; none or absent is in front of the text, or behind it at a negative z-index). Shapes without position:absolute stay inline. Saving writes the boxes as DrawingML anchors with the same placement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reject All removes paragraph breaks inserted with Track Changes on (#229) 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> * Table Layout: Text Direction turns cell text (#226) The Text Direction button only flipped a flag that layout and rendering ignored (and docx always wrote it as btLr), so pressing it did nothing visible. Cells now carry a text direction (horizontal, top-to-bottom tbRl, bottom-to-top btLr). The button cycles through them like Word's, for every selected cell. Layout runs turned text along the cell's height: an exact row height sets the line length, otherwise the row grows to fit the unwrapped text. Turned lines are drawn in a turned frame on screen and in PDF, and clicks, caret, and selection follow the turn. docx reads and writes w:textDirection with the matching value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * File dialogs no longer freeze the window on Linux (#94) Open, Save As, Export and Insert/Change Picture used rfd's blocking FileDialog on the UI thread with no parent window. On Linux the xdg-desktop-portal call blocked the event loop until the dialog closed, and the unparented dialog could open behind WordCraft, so the app looked frozen. The desktop app now shows rfd::AsyncFileDialog parented to the window (set_parent with eframe's Frame, no unsafe) and waits for the answer on a background thread, which hands it back through a channel and wakes the UI. ui-egui gains a backend-agnostic Services::file_dialog hook: the app remembers what the dialog was for and finishes it when the answer arrives (open the file, save, export, insert or change the picture, turn AutoSave on). "Save changes?" -> Save on a new document now runs the held-back New/Open/Close only once the later Save As has saved; a cancelled Save As cancels it. Only one file dialog is open at a time; further clicks are ignored until it is answered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Select Recipients opens a recipient list instead of a parameters error (#240) Clicking Mailings › Select Recipients ran mailings.recipients with no data, so the status bar showed "`csv`, `path` or `rows` required" and nothing opened. The button is now a menu: Type a New List… opens a Recipient List dialog (an editable table of fields and entries), and Use an Existing List… opens the file picker for a CSV/TSV/text file (desktop: loaded by path; web: the picked file comes through the inbox and loads as recipients instead of opening as a document). User-run commands that lack their input open a dialog instead of failing: Select Recipients and Edit Recipient List open the Recipient List, Insert Merge Field and Find Recipient open small dialogs of their own. Scripts and agents still get the command's error, never a dialog. mailings.recipients and mailings.editRecipients take an optional `fields` list, so a typed list keeps its column order and rows can be arrays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Chinese interface: embed the Chinese UI font in releases, fall back to an installed one (#241) The release workflow pinned storytold/craft-fonts at abb8331, the commit that added the Japanese fonts. Noto Sans CJK SC came one commit later (8dcdacd), so release builds embedded only the Japanese faces and the Simplified Chinese interface fell back to BIZ UDPGothic, which lacks about 157 simplified-only hanzi (页, 选, 删 …) and drew them as boxes. Document text was unaffected because it uses the system font fallback. - Bump the craft-fonts pin in the release and FreeBSD workflows to 8dcdacd. - With CRAFT_FONTS_REQUIRED, a native build now fails when the craft-fonts manifest has no Jpan or Hans font, so an outdated pin can't ship silently again. - When no embedded face covers the interface language, the UI font families get an installed CJK font (desktop only): a short per-platform list of files in the system font folders (Windows Deng/msyh/simhei/simsun, macOS PingFang/STHeiti, Linux Noto Sans CJK/WenQuanYi), header-checked, size-capped, and the face chosen by coverage (a SC face in a pan-CJK collection), so egui never sees a file it can't parse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add a System interface theme that follows the OS appearance (#115) 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> * Mailings: Start Mail Merge and Rules are menus; Match Fields and Check for Errors show results (#240) Start Mail Merge opens a menu of the document kinds the engine makes (Letters, E-mail Messages, Envelopes, Labels, Directory, Normal Word Document) with the current one checked. mailings.start now rejects kinds it doesn't know and takes `normal`. Rules opens a menu of the merge rules the engine has: Merge Record # and Next Record insert straight away; If…Then…Else… and Skip Record If… open a small dialog for the field, value and texts. Run by the user without a field (or without a rule), mailings.rules opens that dialog; scripts and agents still get the default. Match Fields shows which recipient-list field fills each address part, and Check for Errors lists merge fields the recipient list lacks, each in a dialog. Edit Recipient List is disabled until there is a recipient list. The new strings, and the ones the Recipient List dialogs added, are in every interface catalog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #248: read the installed CJK UI font only when CJK text is shown A build without craft-fonts read a large system CJK font on the first frame even for an English interface. Now it is loaded only for a CJK interface language, or once File > Options shows the language list (names in their own scripts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #247 on #246: Use an Existing List… goes through the non-blocking file dialog #246 removed the desktop's blocking pick_open; the recipient list picker now asks the host's file dialog hook (AfterPick::Recipients → load_recipients), and the desktop dialog offers a Recipient lists filter (csv/tsv/txt). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: translate the recipient list and file dialog strings (#247, #246) 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> |
||
|
|
3684289699 |
Select Recipients lets you type a list or pick a CSV, instead of a parameters error (#247)
* Tests: shapes and pictures can be clicked, resized, dragged and nudged Fixed by #46 but only text boxes were covered. These walk the editor's path for shapes (rectangle, ellipse, star, arrow) and pictures: hit test, select, resize with arrange.bounds, drag to float with Square wrap, nudge, undo. Covers #142 and #82. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Font list offers every weight a family installs, named as Word names them (#219) Fonts were listed and matched only by their typographic family name (name ID 16, e.g. "Roboto"), so a face other than Regular, Bold or Italic (Light, Medium, SemiBold, Black, Condensed...) never appeared in the font list, and a document asking for "Roboto Light" fell back to a substitute. Each face now also carries its legacy family name, the one Word lists and stores in documents: name ID 1 for static fonts ("Source Sans 3 Semibold"), or the family plus the style words other than Regular, Bold and Italic for a variable font's named instances ("Inter Light"). The font list includes these names, has_family and face() resolve them (bold and italic still choose or synthesise within the faces the name covers), and asking for a legacy name loads the whole installed family. The system font scan now also reads fvar, so a variable font's instances are listed before it is loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Absolutely positioned VML text boxes float instead of sitting inline (#149) A legacy VML shape (w:pict > v:shape / v:rect) with position:absolute in its style was read as an inline object, so a tall text box in a header made the header as tall as the box and pushed the body down the page. The reader now maps the VML style to the same float model DrawingML anchors use: left/margin-left and top/margin-top offsets, mso-position-*-relative reference areas, mso-position-horizontal/vertical alignment, mso-wrap-distance-* and w10:wrap (square, tight, through, topAndBottom; none or absent is in front of the text, or behind it at a negative z-index). Shapes without position:absolute stay inline. Saving writes the boxes as DrawingML anchors with the same placement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reject All removes paragraph breaks inserted with Track Changes on (#229) 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> * Table Layout: Text Direction turns cell text (#226) The Text Direction button only flipped a flag that layout and rendering ignored (and docx always wrote it as btLr), so pressing it did nothing visible. Cells now carry a text direction (horizontal, top-to-bottom tbRl, bottom-to-top btLr). The button cycles through them like Word's, for every selected cell. Layout runs turned text along the cell's height: an exact row height sets the line length, otherwise the row grows to fit the unwrapped text. Turned lines are drawn in a turned frame on screen and in PDF, and clicks, caret, and selection follow the turn. docx reads and writes w:textDirection with the matching value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * File dialogs no longer freeze the window on Linux (#94) Open, Save As, Export and Insert/Change Picture used rfd's blocking FileDialog on the UI thread with no parent window. On Linux the xdg-desktop-portal call blocked the event loop until the dialog closed, and the unparented dialog could open behind WordCraft, so the app looked frozen. The desktop app now shows rfd::AsyncFileDialog parented to the window (set_parent with eframe's Frame, no unsafe) and waits for the answer on a background thread, which hands it back through a channel and wakes the UI. ui-egui gains a backend-agnostic Services::file_dialog hook: the app remembers what the dialog was for and finishes it when the answer arrives (open the file, save, export, insert or change the picture, turn AutoSave on). "Save changes?" -> Save on a new document now runs the held-back New/Open/Close only once the later Save As has saved; a cancelled Save As cancels it. Only one file dialog is open at a time; further clicks are ignored until it is answered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Select Recipients opens a recipient list instead of a parameters error (#240) Clicking Mailings › Select Recipients ran mailings.recipients with no data, so the status bar showed "`csv`, `path` or `rows` required" and nothing opened. The button is now a menu: Type a New List… opens a Recipient List dialog (an editable table of fields and entries), and Use an Existing List… opens the file picker for a CSV/TSV/text file (desktop: loaded by path; web: the picked file comes through the inbox and loads as recipients instead of opening as a document). User-run commands that lack their input open a dialog instead of failing: Select Recipients and Edit Recipient List open the Recipient List, Insert Merge Field and Find Recipient open small dialogs of their own. Scripts and agents still get the command's error, never a dialog. mailings.recipients and mailings.editRecipients take an optional `fields` list, so a typed list keeps its column order and rows can be arrays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Chinese interface: embed the Chinese UI font in releases, fall back to an installed one (#241) The release workflow pinned storytold/craft-fonts at abb8331, the commit that added the Japanese fonts. Noto Sans CJK SC came one commit later (8dcdacd), so release builds embedded only the Japanese faces and the Simplified Chinese interface fell back to BIZ UDPGothic, which lacks about 157 simplified-only hanzi (页, 选, 删 …) and drew them as boxes. Document text was unaffected because it uses the system font fallback. - Bump the craft-fonts pin in the release and FreeBSD workflows to 8dcdacd. - With CRAFT_FONTS_REQUIRED, a native build now fails when the craft-fonts manifest has no Jpan or Hans font, so an outdated pin can't ship silently again. - When no embedded face covers the interface language, the UI font families get an installed CJK font (desktop only): a short per-platform list of files in the system font folders (Windows Deng/msyh/simhei/simsun, macOS PingFang/STHeiti, Linux Noto Sans CJK/WenQuanYi), header-checked, size-capped, and the face chosen by coverage (a SC face in a pan-CJK collection), so egui never sees a file it can't parse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add a System interface theme that follows the OS appearance (#115) 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> * #248: read the installed CJK UI font only when CJK text is shown A build without craft-fonts read a large system CJK font on the first frame even for an English interface. Now it is loaded only for a CJK interface language, or once File > Options shows the language list (names in their own scripts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #247 on #246: Use an Existing List… goes through the non-blocking file dialog #246 removed the desktop's blocking pick_open; the recipient list picker now asks the host's file dialog hook (AfterPick::Recipients → load_recipients), and the desktop dialog offers a Recipient lists filter (csv/tsv/txt). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: translate the recipient list and file dialog strings (#247, #246) 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> |
||
|
|
8b49ea7546 |
Table Layout › Text Direction turns the cell's text (#226) (#245)
* Tests: shapes and pictures can be clicked, resized, dragged and nudged Fixed by #46 but only text boxes were covered. These walk the editor's path for shapes (rectangle, ellipse, star, arrow) and pictures: hit test, select, resize with arrange.bounds, drag to float with Square wrap, nudge, undo. Covers #142 and #82. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Font list offers every weight a family installs, named as Word names them (#219) Fonts were listed and matched only by their typographic family name (name ID 16, e.g. "Roboto"), so a face other than Regular, Bold or Italic (Light, Medium, SemiBold, Black, Condensed...) never appeared in the font list, and a document asking for "Roboto Light" fell back to a substitute. Each face now also carries its legacy family name, the one Word lists and stores in documents: name ID 1 for static fonts ("Source Sans 3 Semibold"), or the family plus the style words other than Regular, Bold and Italic for a variable font's named instances ("Inter Light"). The font list includes these names, has_family and face() resolve them (bold and italic still choose or synthesise within the faces the name covers), and asking for a legacy name loads the whole installed family. The system font scan now also reads fvar, so a variable font's instances are listed before it is loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Absolutely positioned VML text boxes float instead of sitting inline (#149) A legacy VML shape (w:pict > v:shape / v:rect) with position:absolute in its style was read as an inline object, so a tall text box in a header made the header as tall as the box and pushed the body down the page. The reader now maps the VML style to the same float model DrawingML anchors use: left/margin-left and top/margin-top offsets, mso-position-*-relative reference areas, mso-position-horizontal/vertical alignment, mso-wrap-distance-* and w10:wrap (square, tight, through, topAndBottom; none or absent is in front of the text, or behind it at a negative z-index). Shapes without position:absolute stay inline. Saving writes the boxes as DrawingML anchors with the same placement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reject All removes paragraph breaks inserted with Track Changes on (#229) 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> * Table Layout: Text Direction turns cell text (#226) The Text Direction button only flipped a flag that layout and rendering ignored (and docx always wrote it as btLr), so pressing it did nothing visible. Cells now carry a text direction (horizontal, top-to-bottom tbRl, bottom-to-top btLr). The button cycles through them like Word's, for every selected cell. Layout runs turned text along the cell's height: an exact row height sets the line length, otherwise the row grows to fit the unwrapped text. Turned lines are drawn in a turned frame on screen and in PDF, and clicks, caret, and selection follow the turn. docx reads and writes w:textDirection with the matching value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Chinese interface: embed the Chinese UI font in releases, fall back to an installed one (#241) The release workflow pinned storytold/craft-fonts at abb8331, the commit that added the Japanese fonts. Noto Sans CJK SC came one commit later (8dcdacd), so release builds embedded only the Japanese faces and the Simplified Chinese interface fell back to BIZ UDPGothic, which lacks about 157 simplified-only hanzi (页, 选, 删 …) and drew them as boxes. Document text was unaffected because it uses the system font fallback. - Bump the craft-fonts pin in the release and FreeBSD workflows to 8dcdacd. - With CRAFT_FONTS_REQUIRED, a native build now fails when the craft-fonts manifest has no Jpan or Hans font, so an outdated pin can't ship silently again. - When no embedded face covers the interface language, the UI font families get an installed CJK font (desktop only): a short per-platform list of files in the system font folders (Windows Deng/msyh/simhei/simsun, macOS PingFang/STHeiti, Linux Noto Sans CJK/WenQuanYi), header-checked, size-capped, and the face chosen by coverage (a SC face in a pan-CJK collection), so egui never sees a file it can't parse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add a System interface theme that follows the OS appearance (#115) 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> * #248: read the installed CJK UI font only when CJK text is shown A build without craft-fonts read a large system CJK font on the first frame even for an English interface. Now it is loaded only for a CJK interface language, or once File > Options shows the language list (names in their own scripts). 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> |
||
|
|
302528d67e |
Web: use the browser clock everywhere on wasm (insert weekday, PDF dates, layout timing, UI timers) — follow-up to #214 (#230)
#214 gave now_iso the browser's clock on wasm; the other clock helpers were still stubs there: Insert Date's weekday was always Thursday, the PDF creation date was left out, and the layout and UI millisecond clocks returned 0, so browser AutoSave's timer never fired, the caret didn't blink and status messages never cleared. The engine's clock is now one now_unix() (std on native, js_sys::Date in the browser, as #214 does) that now_iso and the weekday share; the pdf, layout and ui-egui clocks read js_sys::Date the same way on wasm. Refs #188. Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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> |
||
|
|
68364f75c8 |
Tests: shapes and pictures can be clicked, resized, dragged and nudged (#228)
Fixed by #46 but only text boxes were covered. These walk the editor's path for shapes (rectangle, ellipse, star, arrow) and pictures: hit test, select, resize with arrange.bounds, drag to float with Square wrap, nudge, undo. Covers #142 and #82. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
004286e4b7 |
Cross-references point at real bookmarks, and Update Field refreshes them (#227)
insert.crossReference wrote every field as `REF _Ref \h` with a literal bookmark name and created no bookmark, so the fields resolved to nothing when updated or opened in Word. Now: - Headings, figures, tables and equations get a hidden `_Ref<number>` bookmark around the target (label and number only for show=number), reused by later references with the same extent. - Bookmark targets use the bookmark's own name and show its text, not its name. - references.updateFields refreshes REF (bookmark text) and PAGEREF (bookmark page). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |