mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-28 04:17:06 -06:00
9ddaff2dae35f47e2d4e277de539574db91f25a3
166
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9ddaff2dae |
Import: hostile Markdown and HTML no longer take quadratic time (#355)
A few hundred KB of `*[`, `, `<` (for `>`) and `&` (for `;`). Bracket and destination scans now share a per-paragraph look-ahead budget, tags are searched within 4 KB and entity names within 33 bytes. - HTML `unescape` searched the whole remaining text for `;` after every stray `&`; it now looks only at the first 33 bytes. - The Markdown/HTML-to-document step appended every inline through `insert_text`, which rescans all earlier runs, so a paragraph with thousands of runs took quadratic time on its own. It now appends runs directly and normalises once. Ordinary links, images, tags and entities read as before. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.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> |
||
|
|
2545b170ba |
Tests: the equation-wrap test accepts plain y where no math font is installed (FreeBSD CI) (#348)
The first glyph is math italic 𝑦 only when a font has it; FreeBSD CI has none, so it shapes as plain y. The test is about line breaks and indents, not the glyph. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
81bf9187f2 |
Wrap long display equations across lines like Word (#326) (#329)
A display equation wider than its column ran off the page. It now breaks at top-level binary operators and relations (never inside a fraction, radical, script or matrix), filling each line greedily; a term wider than the line overflows instead of breaking inside. - Break before the operator by default, or after it, or repeated on both lines, as the document's m:brkBin says; m:brkBinSub picks how a minus repeats. - Continuation lines are indented by m:wrapIndent (one inch by default) or set flush right with m:wrapRight. - Manual breaks (m:brk on a run) start a new line; m:alnAt aligns it at an operator of the first line. - DOCX: m:mathPr in settings.xml and m:brk in math runs are read and written back. Documents without them save as before. - Inline equations, numbered equations and m:jc alignment are unchanged. Tests: layout (a long sum wraps within the column with indented continuation lines; after/repeat modes; manual breaks and alnAt; short equations stay on one line; hostile break input) and DOCX round-trip. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
9bfdbee0b7 |
System interface theme follows OS changes again, and Dark page no longer darkens the interface (#317)
* System interface theme keeps following the OS; Dark page leaves the interface alone (#311, #312) With Interface theme set to System, every frame resolved the OS appearance to Light or Dark and passed that to egui's set_theme. egui then sent SetTheme(Light/Dark) to the window, which on macOS sets an explicit NSAppearance; winit ignores appearance changes while one is set, so later OS switches never reached the app. Both palettes are now installed as egui's light and dark styles (with the same spacing and text styles), and System leaves egui's preference on System with a light fallback, so egui picks the matching style from the OS appearance it reports and the window keeps following the OS. Manual Light and Dark still pin the window. Dark page (View > Switch Modes, Options > Dark page) also forced the interface dark; it now only changes how pages are drawn and the interface follows the Interface theme setting alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Theme: update #314's test to the new theme::apply(ctx, Appearance) signature Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
1800007463 |
Windows: use OpenGL when DirectX 12 has no GPU driver (#316) (#325)
Since Windows defaults to DirectX 12 only (#50), PCs whose graphics chip has no DirectX 12 driver (Intel 4th generation on Windows 11) fall back to WARP, Microsoft's software renderer, and the app lags. Before eframe creates its instance, WordCraft now probes DirectX 12 with a short-lived instance: a hardware adapter that meets eframe's device limits keeps DirectX 12 only; WARP only enables OpenGL next to DirectX 12 (GPU preferred, WARP as last resort); no adapter, or only GPUs below the limits, uses OpenGL alone. WGPU_BACKEND still overrides everything. The choice is logged, and the decision is a pure function with unit tests. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
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> |
||
|
|
9dd2450ce2 |
UI: hover and pressed feedback for the drawn icon buttons (follow-up to #305) (#314)
#305 replaced symbols the interface fonts lack with drawn icons, but the new buttons switched state instantly and the pane close button had no pressed state at all. - widgets::drawn_state: the shared look for drawn buttons. Hover fades in over egui's animation time and the pressed state blends in while the pointer is down. Framed buttons take egui's widget visuals (fill, stroke, text colour, expansion) so they match ui.button; frameless ones take the ribbon's hover/pressed tokens, like the ribbon buttons. - widgets::icon_button: a frameless icon button built on it; the panes' close button uses it. - icon_text_button (Editing/Reviewing, Comments, New Comment) uses it too. widgets::tests::drawn_buttons_fade_in_on_hover_and_darken_while_pressed drives both kinds with real pointer events at 60 fps and checks the idle, mid-fade, hovered and pressed fills. 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> |
||
|
|
4a9078b912 |
Grey out the AutoSave switch, with the reason, where AutoSave can't save (#196, #176) (#302)
AutoSave writes only a file saved in this session, in a format that keeps everything (.docx, .docm, .dotx, .dotm, .odt, .rtf, .json), and never in the browser, where saving is a download. The title-bar switch still showed on for a saved .md file (#196) and AutoSave looked available in the web app (#176), so edits stayed unsaved with no explanation. WordApp::autosave_block() now says why AutoSave can't cover the document (browser, never saved, a format that can't keep everything, opened but not saved here). The switch is greyed out with that reason as its tooltip, and clicking it offers Save As (desktop) so saving as .docx turns AutoSave on. In the browser, File > Options' AutoSave checkbox is disabled with the same explanation. file.autosave (scripts, MCP, the switch) now sets the app's AutoSave and returns the reason as an error when asked to turn it on where it can't save; turning it off always works. New strings in every catalog. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
82b31efd67 |
UI: draw icons instead of symbols the interface fonts lack (✕ ✎ 💬 ➕ 📂 ⋯ ➢) (#305)
Several buttons put symbol characters in their text that neither Inter nor egui's emoji fallbacks contain, so they drew as empty boxes: the panes' close button (✕), the title-row Editing/Reviewing (✎) and Comments (💬) buttons, the Comments pane's New comment (➕), File › Open's Browse… (📂), the Equation tab's symbol-set button (⋯) and the ➢ tile in the Bullet Library. - Pane close buttons paint the existing `close` icon, with a Close tooltip. - New `widgets::icon_text_button` paints an icon from icons.rs next to text; Editing/Reviewing (pencil), Comments and New Comment use it. The Editing/Reviewing menu is now an egui Popup on that button. - Browse… drops the emoji; ⋯ becomes …; the ➢ bullet stays a bullet choice and only its menu tile draws the arrowhead. - Catalogs: `📂 Browse…` is renamed `Browse…` (translation without the emoji) and `➕ New comment` is removed in favour of the existing `New Comment`, in every language. theme::tests::interface_symbols_have_glyphs scans the UI sources' string literals for non-letter, non-ASCII characters and checks each against the real interface font setup, with a short commented exception list (equation templates drawn by the math renderer, the ➢ bullet value). 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> |
||
|
|
fc0c11a440 |
Shape Format: Shape Effects — shadow, glow and soft edges (#275) (#280)
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> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
5034dc517f |
Layout > Arrange > Group: group pictures, shapes and text boxes into one object (#267)
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> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
98bd70e117 |
Paragraph: Asian Typography settings, with kinsoku and mid-word Latin wrapping in layout (#269) (#271)
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> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
11a6ad60a5 |
Paste pictures from the system clipboard (screenshots, Copy Image, copied files) (#45) (#272)
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>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
f186dda4d0 |
Manage Styles: list, preview, delete and show or hide styles (#270)
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>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
|
||
|
|
68e6380a98 |
Table styles: every region, a live preview, delete, custom styles first (#146) (#263)
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> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
bf64d17a16 |
Clipboard pane: collect the last 24 copies and cuts and paste any of them again (#264)
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>
Co-authored-by: Brandon Thomas <echelon@gmail.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> |
||
|
|
12a4da3be5 |
Make the floating header text box test independent of installed fonts (#284)
The test put a two-line header 36pt from the top of the page and checked that the body still starts at the 72pt top margin. How tall those two lines are depends on the font the default text resolves to: with the installed Carlito-style fonts they fit, but with only the bundled fallback fonts (as on the FreeBSD CI VM) they end at 72.6pt, so the header correctly pushed the body down and the control check failed. Start the header 18pt from the top instead, which leaves the two lines plenty of room above the margin with any font. The checks are unchanged: the control body starts at the top margin, the floating box changes neither the body start nor the page count, and the same box inline still pushes the body down. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e9a38a88ca |
Pictures: draw WMF and EMF pictures instead of a grey box (#293)
Windows metafiles (WMF, EMF), common for logos, crests and diagrams in older documents, couldn't be decoded and showed as grey boxes, on screen and in PDF. The new crate wordcraft-metafile (layer 1) reads them from the public [MS-WMF] and [MS-EMF] specifications into paths and bitmaps, and places them in a picture's box; render and pdf paint the result as vectors. It covers the drawing records Office pictures use (lines, polygons, curves, rectangles, ellipses, arcs, path brackets), pens and brushes, the mapping modes and world transforms, and bitmaps in DIB form with the usual raster operations. Input is treated as hostile: every read is bounded, and a byte budget caps what one picture may allocate. Not yet: text records (ExtTextOut) and EMF+ records are skipped, so a metafile whose content is mostly text shows only its lines and fills. docxide-pdf bench (365 documents, vs main + #135): the twelve documents with WMF/EMF pictures show them; the pictures are a small part of their pages, so the scores move little (Jaccard passes 208 -> 209, five documents up to 3 SSIM points better, none worse). Co-authored-by: Oliver Zieschang <4963183+naxvog@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
23395e7fc0 |
Tables: autofit by content, and floating tables inside cells (#291)
Word sizes the columns of a table that may follow its content (tblLayout
not fixed) from what is in them; we kept the stored grid as it was:
- A table with no preferred width anywhere (no tblW, no tcW: what
generators write) now gets its columns from their content: each its
widest line if all fit, else shared out between longest word and
widest line, as Word does (case51: a nested table no longer fills its
cell, and the document is two pages like Word's).
- In other autofit tables no column is narrower than its longest word;
the columns with room give up the difference ("ON" no longer breaks
into "O/N" in case91).
Floating tables (w:tblpPr) inside a table cell were laid out in the
text flow. They now stand at their position in the cell and take no
room; the text after them wraps around them, a table that may not
overlap goes below the ones in its way, and the cell grows to hold
them. A row whose lines all fit but whose nested floating table runs
past the page bottom splits there instead of moving to the next page.
Text now flows beside a floating object into gaps of 20pt or more
(was 36pt): Word puts a paragraph beside a floating table in a 21.3pt
gap but not in an 18.6pt one (docxide-pdf case139-148 vary just that).
docxide-pdf bench (365 documents, vs main + #135): Jaccard passes
208 -> 227, SSIM passes 76 -> 86, page counts right 320 -> 324; three
documents slightly worse (case149 -4 SSIM: Word moves the whole floating
table to the next page, we split it; two others -1 or less).
Co-authored-by: Oliver Zieschang <4963183+naxvog@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
8622ae8cec |
Desktop File › Print opens the PDF in the system viewer (#15) (#286)
On desktop, the Print button on File › Print now renders the document to PDF, writes it to a fresh wordcraft-print-*.pdf in the OS temp folder and opens it without blocking the window: in Preview on macOS, and in the default PDF app on Linux/BSD (xdg-open, gio, ...) and Windows (via the `open` crate, already in the tree). The user prints from there through the system print dialog. If no viewer can be started, the status bar says so and the file is removed. Print files older than an hour are cleaned up off the UI thread at start-up and after each print. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6b40846789 |
i18n: translate the remaining untranslated interface strings; test the font fallback cache with legacy names (#276)
* i18n: translate the remaining untranslated interface strings; test the font fallback cache with legacy family names (#233, #239) Follow-ups from integrating #233 and #239: every tl! string now has a row in every catalog, and a test pins that loading a face by its legacy family name drops the fallback cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n: Serbian rows for the newly translated strings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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> |
||
|
|
a99dddcbdc |
Show/Hide ¶: paragraph mark no longer overlaps text in mixed-direction paragraphs (#278)
* Show section breaks with Show/Hide ¶ (#42) With formatting marks on, the last paragraph of a section now ends in a dotted double rule with the break's name centred in it (Section Break (Next Page), (Continuous), (Even Page), (Odd Page)) instead of a plain ¶. The type shown is the start type of the section that follows. The mark is screen-only: PDF export skips it, and print/PNG never turn marks on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Show/Hide ¶: put the paragraph mark past mixed-direction text (#274) The paragraph mark (and the section-break mark) was anchored at the caret position after the paragraph's logically last character. When that text runs against the paragraph's direction (Hebrew ending a left-to-right paragraph, Latin ending a right-to-left one) that position is inside the line, so the mark was drawn on top of a letter. The mark now sits at the line's visual end for the paragraph's direction: right of the rightmost glyph in a left-to-right paragraph, left of the leftmost in a right-to-left one. Pure left-to-right and pure right-to-left lines are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- 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> |
||
|
|
f6a6ded2cc |
Tests no longer depend on the installed fonts; PDF text of field results with ligatures (#261)
On a Linux machine with Carlito and Noto Naskh Arabic installed, four
layout and PDF tests failed on main:
- field_results_are_extractable_text found a real bug: a field result is
laid out as one cluster, and the display list gave each of its glyphs one
character. A ligature (Carlito, the Calibri substitute, joins "ti") took
only its first letter and shifted the rest, so the PDF text read
"Sectio 3.01 fir details3". The layout now keeps each glyph's text range
from shaping, so a ligature carries all its letters. A new test pins this
with bundled Source Sans 3 ("fi", "ffi"), whatever fonts are installed.
- fragmented_hidden_text_lays_out_like_the_visible_text compared visible
text in alternating bold runs with an all-regular paragraph, so it only
passed when the default font's bold happened to break lines the same.
The plain paragraph now has the same bold runs.
- persian_letters_join_and_brackets_mirror counted glyphs, but Noto Naskh
Arabic draws a dotted letter as two glyphs (the dotless form and the
dot). It now compares letters by shaping cluster.
- glyph_runs_carry_their_text_for_pdf_export expected لا as one ligature
glyph; Noto Naskh Arabic draws the lam and the alef separately. The
ligature check now applies when the font forms the ligature.
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> |
||
|
|
c97b568d62 |
Touchpad scrolling follows the fingers and coasts after a flick; mouse wheel scrolls further (#122) (#252)
The document canvas used egui's built-in wheel handling: touchpad deltas lost their first and last events, Wayland compositors leave kinetic scrolling to the app so a flick stopped dead, and a wheel notch scrolled only 40 px. The canvas now scrolls itself (crates/ui-egui/src/scroll.rs): touchpad pixel deltas move the page 1:1 in the same frame; on Linux/BSD a flick keeps coasting with time-based exponential decay, stopped by a click, a key, a wheel notch or the end of the document (macOS, Windows and browsers already send their own momentum); a wheel notch scrolls about three lines (56 px at 100%, gently scaled with zoom) and still eases in. Ctrl+wheel zoom and Shift+wheel sideways scrolling are unchanged. 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> |
||
|
|
7dcfa07c15 |
File dialogs (Open, Save As, Export) no longer freeze the window on Linux (#94) (#246)
* 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> * 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> |
||
|
|
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> |
||
|
|
18d3a39278 |
Chinese interface shows every character instead of boxes on Windows (#248)
* 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> * 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> |
||
|
|
f4a694ecf0 |
Font list offers every installed weight (Light, Medium, SemiBold, Black…), as Word does (#239)
* 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> * 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> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> |
||
|
|
7b8c38fa62 |
Contributors: add my own entry (dkhlapov) (#238)
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9643dcb621 |
Font picker: build only the visible rows, cache font fallbacks (#121, #59) (#233)
Opening the font menu built a row, and so rendered a preview, for every installed family: each preview loads that family's font files, so the menu kept repainting until every font on the system was read into memory (1.1 GB for 305 families here; far more on large collections), which froze the app. The combo list now uses ScrollArea::show_rows, so only rows in view are built. Layout asked FontDb for a fallback face once per character the font lacks, and each lookup sorted every loaded face, so text in a script the font lacks (Thai) slowed down with every font loaded. Fallback lookups are now cached per (character, excluded face) until more faces load: 5000 Thai characters lay out in 5 ms instead of 96 ms with all fonts loaded. Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |