Commit Graph
14 Commits
Author SHA1 Message Date
Valentin KleinandClaude Opus 5.5 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>
2026-10-10 19:32:59 -04:00
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>
2026-10-10 18:50:37 -04:00
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>
2026-10-10 18:50:20 -04:00
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>
2026-10-10 17:56:54 -04:00
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>
2026-10-10 17:54:23 -04:00
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>
2026-10-10 17:48:51 -04:00
79b6f33b03 Long footnotes continue onto the next page (#352) (#357)
When the footnotes referenced on a page don't fit below its text, the note
that doesn't fit is split at a line boundary: its first line stays on the
page of its reference (if even that doesn't fit, the reference line moves
to the next page, as before), and the rest continues at the top of the
next page's note area, before that page's own notes, under a full-width
continuation separator. Notes still continuing after the last page get
pages of their own. Endnotes are unchanged.

The docx reader doesn't keep a document's own continuation separator or
continuation notice, so the default line is drawn and no notice.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 17:43:38 -04:00
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>
2026-10-10 17:40:39 -04:00
Valentin KleinandClaude Opus 5.5 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>
2026-10-10 17:10:09 -04:00
81bf9187f2 Wrap long display equations across lines like Word (#326) (#329)
A display equation wider than its column ran off the page. It now breaks
at top-level binary operators and relations (never inside a fraction,
radical, script or matrix), filling each line greedily; a term wider
than the line overflows instead of breaking inside.

- Break before the operator by default, or after it, or repeated on both
  lines, as the document's m:brkBin says; m:brkBinSub picks how a minus
  repeats.
- Continuation lines are indented by m:wrapIndent (one inch by default)
  or set flush right with m:wrapRight.
- Manual breaks (m:brk on a run) start a new line; m:alnAt aligns it at
  an operator of the first line.
- DOCX: m:mathPr in settings.xml and m:brk in math runs are read and
  written back. Documents without them save as before.
- Inline equations, numbered equations and m:jc alignment are unchanged.

Tests: layout (a long sum wraps within the column with indented
continuation lines; after/repeat modes; manual breaks and alnAt; short
equations stay on one line; hostile break input) and DOCX round-trip.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 16:37:25 -04:00
1800007463 Windows: use OpenGL when DirectX 12 has no GPU driver (#316) (#325)
Since Windows defaults to DirectX 12 only (#50), PCs whose graphics chip has
no DirectX 12 driver (Intel 4th generation on Windows 11) fall back to WARP,
Microsoft's software renderer, and the app lags. Before eframe creates its
instance, WordCraft now probes DirectX 12 with a short-lived instance: a
hardware adapter that meets eframe's device limits keeps DirectX 12 only;
WARP only enables OpenGL next to DirectX 12 (GPU preferred, WARP as last
resort); no adapter, or only GPUs below the limits, uses OpenGL alone.
WGPU_BACKEND still overrides everything. The choice is logged, and the
decision is a pure function with unit tests.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-10 16:24:16 -04:00
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>
2026-10-10 14:52:08 -04:00
Valentin KleinandClaude Opus 5.5 8622ae8cec Desktop File › Print opens the PDF in the system viewer (#15) (#286)
On desktop, the Print button on File › Print now renders the document
to PDF, writes it to a fresh wordcraft-print-*.pdf in the OS temp
folder and opens it without blocking the window: in Preview on macOS,
and in the default PDF app on Linux/BSD (xdg-open, gio, ...) and
Windows (via the `open` crate, already in the tree). The user prints
from there through the system print dialog. If no viewer can be
started, the status bar says so and the file is removed. Print files
older than an hour are cleaned up off the UI thread at start-up and
after each print.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:34:11 -04:00
Brandon ThomasandClaude Opus 5.5 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>
2026-10-10 14:11:53 -04:00