Commit Graph
1863 Commits
Author SHA1 Message Date
Zach BerryandClaude Sonnet 5.5 f58ec39968 [CC3] table.cellAlign takes a horizontal align
align: left|center|right|justify sets every paragraph of the target cells;
anchor stays the vertical alignment and is optional when align is given.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 20:31:46 -05:00
Ayoze Torres d027f9d866 Spell check docs: state the 100-character limit instead of linking a private constant (#1175) 2026-10-28 01:13:04 +00:00
Ayoze Torres 7c891de450 Spell check: don't check words longer than 100 characters (#1175)
Dictionary::check splits a word at every point looking for compound
parts, so a check costs O(n²) in the word's length under a compounding
dictionary (German, Dutch, …). A 100,000-character "word" took about
17 s per check in release, and spell check runs again on every edit.
suggest() was already capped at 64 characters; check() wasn't.

Words longer than MAX_CHECK_CHARS (100, Hunspell's word length limit)
now pass unchecked.
2026-10-28 01:01:00 +00:00
Harrison Booth b5928a182e Keep the File > New tiles inside the right margin in a narrow window (#1421)
set_max_width(CONTENT_W) widened the page past the margin whenever the window was
narrower than CONTENT_W, so the last tile in each row ran off the screen edge.
2026-10-27 19:50:52 -05:00
Harrison Booth 5896859440 Charts: tickLblPos none hides value-axis labels and unfilled gridlines are not drawn (refs #1366) 2026-10-27 19:31:45 -05:00
Harrison Booth d989389441 fix(format): a slider commits only a move to another shown value
changed() also fires when the slider rounds the value it shows, on focus too. Compare the rounded
values, so keyboard and accessibility edits commit without focus and rounding does not.
2026-10-27 19:31:36 -05:00
Harrison Booth 31efc67f73 test(text): the bullet is the ❑ or the dot the face draws, by glyph 2026-10-27 19:28:48 -05:00
Harrison Booth 8680166081 test(render): the shared shape id also hides a slide shape in the collision test 2026-10-27 19:18:53 -05:00
Harrison Booth 90ce7dcb9b test(format): clear the reflection after each preset, as #1356 reports 2026-10-27 19:18:14 -05:00
Harrison Booth 9d32bc4da9 fix(text): keep private-use bullets in named Unicode symbol fonts; .notdef falls back to a dot
Private-use codes are mapped by code only when no bullet font is named or it is a legacy symbol
font. A bullet that the cascaded face still cannot draw uses the dot instead of .notdef.
2026-10-27 19:17:11 -05:00
Harrison Booth faf4c0ee52 fix(format): Reflection slider with only focus does not re-add the reflection
A reflection slider that had focus and lost it to the None button committed its stale value.
Commit on focus loss only after an edit the user made, and cover it with a kittest.
2026-10-27 19:10:49 -05:00
Zach BerryandClaude Fable 5.1 4c83fb9abe [CCC2] Insert answers say when they edited a master or layout
PowerPoint shows the Slide Master tab while a master or layout is open,
so inserting there is never mistaken for editing a slide. DeckCraft's
insert commands answered the same in both views. Session::execute now
adds editing: {kind, name} (as slide.inspect does) to the answers of
insert.*, shape.insert, shape.freeform, shape.connect and slide.new in
master, layout, handout and notes-master view; answers on slides are
unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-27 18:55:41 -05:00
Zach BerryandClaude Fable 5.1 6a1b8f1e39 [ZZ1] insert.dateTime in the Handout/Notes Master view fills the master's date placeholder
PowerPoint: Header and Footer > Notes and Handouts > Date and time puts a date field in the
date placeholder of the notes and handout masters, and every handout and notes page shows it.
Before, with no text caret the command wrote the current slide's date placeholder (design
.headerFooter) even in those views, so the handout PDF showed nothing. Now it writes the selected
date placeholder, else the master's own, as a field (update) or plain text, answers where:
master, and refuses (changing nothing) when the master has no date placeholder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-27 18:55:41 -05:00
Harrison Booth 1e842137b0 Animations: Darken and Desaturate use PowerPoint's preset ids and HSL shift, and 14 effects get its default durations 2026-10-27 18:53:24 -05:00
Harrison Booth d6f532bb0d PDF export: transparent content pixels take the backdrop colour (fixes #1455)
The content raster's fully transparent pixels were RGB 0,0,0. A viewer that
smooths the image blends colour and mask separately, so the black showed as a
grey hairline around white pictures and white-filled shapes.
2026-10-27 18:52:43 -05:00
Harrison Booth 952e4db95f Merge remote-tracking branch 'origin/main' into dc-fix-reflection
# Conflicts:
#	crates/ui-egui/src/panes.rs
2026-10-27 18:47:18 -05:00
Harrison Booth f4ca20659c Merge remote-tracking branch 'origin/main' into dc-fix-ids-1362
# Conflicts:
#	crates/render/src/lib.rs
2026-10-27 18:43:17 -05:00
Harrison Booth b5257f9446 Merge remote-tracking branch 'origin/main' into dc-fix-bullet-1347
# Conflicts:
#	crates/text/src/lib.rs
2026-10-27 18:41:43 -05:00
Zach BerryandClaude Sonnet 5.5 50b200be7c [HH5] Long English dates follow each English locale's day order and punctuation
PowerPoint formats the datetime types by the run's language: en-GB's long
date is "18 October 2026" and the weekday form "Sunday, 18 October 2026".
We gave every English locale the US order ("October 18, 2026"), and a test
pinned that. datetime2 and datetime4 now put the day first for en-GB, en-AU,
en-NZ, en-IE and en-IN (the locales the numeric date already handled), and
datetime2 also for en-ZA. The punctuation follows PowerPoint on Windows as
checked per locale in review: en-IE writes no comma after the weekday
("Tuesday 27 October 2026"), and en-GB and en-AU put a comma after the month
in datetime3 ("27 October, 2026"). Other languages still have no month names,
so they are refused as before.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:24:46 -05:00
Zach BerryandClaude Sonnet 5.5 48535be970 [JJ1] review.compare says which side each change is on
Each change now carries number (the editor's slide number beside the 0-based
slide) and onlyIn (deck or file; absent for a change in both). Shape details
say (only in the deck) / (only in the file). The docs say review.accept takes
the file's side.

PowerPoint: Compare marks the other file's differences as revisions that
Accept applies and Reject discards, so accepting takes the file's side; kept.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 18:24:31 -05:00
Zach BerryandClaude Sonnet 5.5 7b424a463b [HH9] picture.reset: document and pin what it keeps (frame shape, size, position)
PowerPoint: Reset Picture discards the picture's formatting changes
(corrections, recolor, artistic effect, picture-style effects and outline);
Reset Picture & Size also restores the size. The frame shape set by Change
Shape is not touched. Ours already left the geometry alone (the reported
geometry wipe does not reproduce); effects, outline and crop are picture
formatting that PowerPoint discards too, so they stay reset (declined:
parity). Added the regression test and the command doc.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 18:24:31 -05:00
aiongg 55e5ee56b4 Merge pull request #1434 from Jeremy8776/feat/install-scope-policy
Windows installation policy: DeckCraft
2026-10-27 17:09:15 -04:00
aiongg f2f4dfabc0 ci: use storytold/craft-common-actions at the merged installer-policy commit 2026-10-27 20:51:55 +00:00
Harrison Booth 964f4759c7 pptx: read volume, mute, loop, hide and full screen for media from the timing tree 2026-10-27 15:28:52 -05:00
Harrison Booth 110d46daae Docs: address review notes (command count 328, Linux paste qualifier, remaining #77 mentions) 2026-10-27 14:36:54 -05:00
Harrison Booth b003dde823 Docs: refresh gaps and roadmap against merged PRs
Remove the duplicate header lines in gaps.md, ROADMAP.md, ui-parity.md and
localization-parity.md. Drop gap entries that landed: Morph outline alignment
(#67) and animation rewind (#77). Record that PR #75 was closed unmerged so
#60 stays open, and that #53 is closed with Windows image paste tracked in
#1414. Note Reuse Slides (#1103) and Compare reject (#850). Command count 323.
2026-10-27 14:23:51 -05:00
Jeremy 8cb3365596 fix(installer): check the exact architecture-specific machine folder
The pre-signing check matched any folder named Program Files, so it rejected
a valid MSI when Windows resolves Program Files elsewhere, accepted the 64-bit
root for an x86 package and accepted a different app name. Build the expected
folder from the package architecture's resolved root and the policy name.
2026-10-27 19:08:41 +00:00
aiongg 88c2ceff5f Merge pull request #1461 from Silvertree2010/perf/export-speed
Speed up PDF export by reusing equal slide backdrops
2026-10-27 13:42:02 -04:00
NetterSilverandClaude Opus 5.5 2f4a6d906a Speed up PDF export by reusing equal slide backdrops
PDF export rasterises every slide as a backdrop and a content layer and
hands both to the writer. Profiling (gdb stack sampling) showed most of
the main thread outside rendering going to per-pixel work on those
rasters: compositing the backdrop onto white (not vectorised), the
writer hashing every backdrop to deduplicate it, and the straight-alpha
conversion scanning every content pixel.

- Composite the backdrop with saturating adds and skip 16-pixel blocks
  that are already opaque; skip blocks with no partly transparent pixel
  in the straight-alpha conversion. Same formulas, same bytes.
- Keep the last opaque backdrops (up to 32 MiB of pixels) and hand the
  writer the same image again when a slide renders an identical
  backdrop. The writer stored equal backdrops once already; now it also
  skips hashing and compressing the copies. Output is byte-identical.

deckcraft-cli bench, export .pdf step, 15 interleaved runs each on a
16-thread Ryzen (A/A noise +0.9 %):
- sample x4 (32 slides): median 531 -> 322 ms (-39 %), min 529 -> 317 ms
- same deck, every slide a different background: 557 -> 441 ms (-21 %)
- sample (8 slides): 149 -> 103 ms (-31 %)
Exported PDFs are byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:39:31 +01:00
NetterSilverandClaude Opus 5.5 53e183495b Time PDF export over all bench runs
`deckcraft-cli bench` capped the "export .pdf" step at three runs while
its help promises the median of N runs for every step. Use --runs for
it too, so a PDF export benchmark can take enough samples to beat noise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:43:29 +01:00
Jeremy 8445d98e24 fix(installer): resolve the wizard scope and folder correctly
Real msiexec runs (per-user and all-users, silent and wizard) found two defects
that the metadata fixtures cannot see:

- "Only for me" published ALLUSERS=2, so FindRelatedProducts treated the run as
  per-machine and skipped the existing per-user copy. An interactive upgrade
  left two registered products and uninstall left files behind. The page now
  leaves ALLUSERS unset for a per-user choice.
- Windows Installer resolves Program Files once, for the context it started in,
  so choosing "Everyone" in the wizard installed into the user profile with a
  machine-wide registration. The wizard now sets the new-install folder itself
  after the choice (Program Files, Program Files (x86) for 32-bit, or the
  per-user Programs folder). Silent installs are unchanged.

check-install-policy.ps1 now fails if either regresses.
2026-10-27 15:32:16 +00:00
aiongg 2c9edcc394 refactor(ui): use craft-ui's ComboBox for every dropdown (#1457)
* ui: use craft_ui::ComboBox so dropdown menus grow back (egui#5225); repin craft-libs

* chore(deps): craft-libs 60d60d48 (dropdown fixes)

* chore(deps): craft-libs 6af63481 (dropdown fixes)

* chore(deps): craft-libs 4d7b82f7 (dropdown fixes)

* chore(deps): craft-libs 92d392cf (#387 merged)

* chore(xtask): pdf-deps expects craft-libs 92d392cf
2026-10-27 10:26:51 -04:00
NaseqandClaude Opus 5.5 feecee0a30 Slide show tests: check the pending preview and the one-render gate directly (#964)
A harness runs frames until no repaint is asked for, so the preview had
already landed when its first assertion ran. One raw frame now shows the
preview pending and one render started, and the paging test pins a pending
job and checks a page turn starts no other render.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:13:44 +04:30
NaseqandClaude Opus 5.5 356195ba33 Slide show: render the Presenter View's next-slide preview off the UI thread (#964)
Turning the page with Presenter View on re-rendered the next-slide preview
synchronously, single-threaded, on the UI thread. The preview now renders
on a worker thread and arrives on a later frame; the web build (no
threads), or a worker that dies, renders it inline. At most one render runs:
paging faster than it asks for the newest preview once it is done, and a
finished one no longer wanted is dropped. Job and texture are keyed by the
presentation as well as the slide, so a preview rendered before an edit is
rendered again. While a preview is on its way the box stays empty rather
than saying "End of slide show".

Rebased onto the show module split: show/presenter.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:53:57 +04:30
NaseqandClaude Opus 5.5 b1645b006e Render: skip shapes whose outline is not finite or far larger than any screen (#1165)
An ellipse at the EMU limit, compounding group scales or custom-geometry
guides could reach vello's flattener with an outline billions of pixels
long; it sizes its buffer by that length and the allocation aborts the
process. geometry::drawable() rejects a shape with a non-finite path
point, then measures the outline's control box (which always holds the
curve, unlike the tight bounding box when its extremum overflows) unioned
with the frame; past 1e7 device pixels the shape is skipped with a warning.

Rebased onto the render module split: the guard now lives in geometry.rs
and renderer.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:12:07 +04:30
Jeremy 428c8809ea fix(installer): harden install-policy checks and packaging-lint workflow 2026-10-27 12:00:56 +00:00
Jeremy abee4d7522 fix(installer): address scope and ARM64 review feedback 2026-10-27 12:00:56 +00:00
Jeremy 4d9b325d35 feat(installer): default to a per-user ArtCraft folder 2026-10-27 12:00:56 +00:00
FaabyyandClaude b9842d0b82 Slide show: Set Up Slide Show can keep the mouse cursor visible (#1445)
A full-screen show hides a still pointer after 2.5 s, which makes decks
with clickable, branching choices hard to use. Set Up Slide Show now has
Keep mouse cursor visible (`show.keepCursor {on?}`): the show then keeps
the normal pointer, and the pointing hand over links and actions, while
links still follow. It is a user preference kept in ui.json, since PPTX
has no place for it; off by default, Reading View unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-27 10:50:26 +00:00
NetterSilverandClaude Haiku 5.5 cd2e780432 Reject '+' sign in slide range numbers
Found while testing crates/engine/src/cmd/file.rs:390-400 (parse_slide_range)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 09:19:49 +01:00
neoandClaude Opus 5.5 20553865cc Fonts: a variable font's named instances answer to their Windows family names
Documents name non-RIBBI weights by their Windows family ("Montserrat ExtraBold" / Regular).
The bundled Montserrat is variable, so its instances had no Windows names; the installed static
files that do carry them were skipped as already present, and the lookup fell back to Inter
Regular without reporting the font missing. Each named instance other than Regular, Italic,
Bold and Bold Italic now also answers to "<family> <weight>" with a Regular or Italic style,
as Windows lists them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 00:10:58 -07:00
Dominic Anaeto d8961ebc1e P0.2a: finish file output after stdout closes 2026-10-27 02:24:42 -04:00
Harrison Booth 9ad147b310 Format Shape Effects: drawn Shadow, Glow and Soft Edges preset tiles, and a shadow Size slider 2026-10-26 21:51:54 -05:00
Harrison Booth 6fa873dcfc feat(ui-egui): Scale Height/Width and a From origin in Format Shape's Size & Properties
Scale is measured from the size the tab first showed, like the Size and Position
dialog, and runs shape.sizePosition (honouring Lock aspect ratio). From switches
Horizontal/Vertical between the top-left corner and the centre. The lock checkbox
used a fresh id every frame so it never held; it now keeps its state.
2026-10-26 21:18:44 -05:00
aiongg ee875abffa Merge pull request #1433 from aiongg/layout
refactor: shared module layout (craft-contrib#20)
2026-10-26 21:30:28 -04:00
skylar taylor-barrick 020e53e7a0 Merge pull request #1429 from storytold/fix/nextest-0.9.150
ci: require nextest 0.9.150
2026-10-26 17:35:27 -06:00
Harrison Booth 65826295cc fix(text): draw Unicode symbol-font bullets with the fallback chain, not a dot (#1347)
A buFont named like Noto Sans Symbols was treated as a legacy symbol font, so its
bullet characters mapped to a generic dot. Only Wingdings and Symbol map by code now;
the bullet's own face is chosen by the usual cascade instead of a fixed Inter fallback.
2026-10-26 18:20:23 -05:00
Harrison Booth 8c8ab9561b fix(render): animation state never applies to layout and master shapes sharing a slide shape id (fixes #1362) 2026-10-26 18:20:19 -05:00
62ea604394 Animations: the Add Animation menu scrolls when it is taller than the window (fixes #1370)
Every effect in one column is taller than a 1440p screen, and the popup
did not scroll, so the last entries could not be reached. Cap the menu at
the window height minus the title bar and ribbon, and scroll inside it.

Co-Authored-By: Grok 4.7 <noreply@x.ai>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 23:48:25 +01:00
Harrison Booth fa0a3e9dee Duplicate: count the names inside groups when numbering copies 2026-10-26 17:40:21 -05:00