Commit Graph
1431 Commits
Author SHA1 Message Date
Marco Arnulfo d384bbc496 Units: Preferences chooses inches or centimetres for the Format pane, the ribbon's size boxes, the Slide Size dialog and the ruler (#1326) 2026-10-24 23:02:45 +02:00
Marco Arnulfo 98ce1b35be Pasted shapes get the next automatic name instead of keeping the original's (fixes #1290) 2026-10-24 22:52:52 +02:00
dotCooCoo ba59df768b Edit Points: a panic after a change of document leaves no point type
The guard put back the remembered point type after a panic even when the
command had made another document active, so the type of a shape in the
first document applied to a shape with the same id in the second. The
guard now puts it back only when the document from before is still active,
and forgets it otherwise.
2026-10-24 13:40:54 -07:00
dotCooCoo 0cffe2ca08 Edit Points: a panic or another document leaves no stale point type
A command that panicked after changing the point type Edit Points remembers
left the new type in place, since the guard put back only the document and
selection. The guard now puts the remembered type back too. Shape ids repeat
across documents, so a change of active document forgets the remembered
type.
2026-10-24 13:19:40 -07:00
dotCooCoo 92ce587cd6 Edit Points: right-click a segment for Add Point, Delete Segment and Open/Close Path
The segment menu in Edit Points offered only Straight Segment and Curved
Segment. It now also has Add Point, which adds a point where the right
click was, Delete Segment, which removes the segment from a closed outline
so that the outline opens there (grayed out on an open outline), and Open
Path, which opens the outline at the segment's start point (Close Path on
an open outline).
`shape.deleteSegment` does the deletion for the CLI and MCP.

The place on a segment that a click picks was found only in steps of 1/32
of the segment, so Add Point and Ctrl-click could add the point as far
as 1/64 of a straight segment's length from the pointer. It is now narrowed
down after that first pass.

Adding or deleting a point now forgets a point type remembered for handle
drags, as opening and closing the outline already did. `shape.addPoint` on
the first point of an open outline no longer splits the closing edge of
another outline later in the same path.
2026-10-24 13:07:42 -07:00
Marco Arnulfo 2e54272415 Show: Ctrl+wheel zooms the slide in and out around the pointer (#1286)
Cmd+wheel on a Mac. Four notches double the zoom, up to 4x; zooming back to the whole slide leaves the zoom. The plain wheel still turns the page, and the trackpad pinch is still not a show gesture.
2026-10-24 21:56:17 +02:00
dotCooCoo a7ab15d942 Edit Points: Undo and Redo bring back the point type remembered with each step
Undo restored the outline but kept the point type that a handle drag with
Shift, Ctrl or Alt, or a Point Type choice, had set, so the next drag
without a modifier applied the undone type again. Each undo step now keeps
the point type remembered with the document it restores, and Undo and Redo
put it back, including a Straight or Corner choice that the handles alone
do not show. A command that fails leaves the remembered type as it was, and
the type applies only to the shape it was chosen on.
2026-10-24 12:33:33 -07:00
NetterSilverandClaude Haiku 5.5 8145cc1bac Treat curly apostrophe as ASCII in spell check
Found while testing crates/engine/src/spell.rs:693 (paragraph_words) and :353 (Dictionary::check)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 19:24:20 +00:00
dotCooCoo a9cafe64fc Docs: Play From and the .potx/.ppsx content types are no longer listed as missing
The Animation Pane row in ui-parity.md said the pane cannot preview from
the selected effect, but its button reads Play From and starts there
(animpane_tests). gaps.md, file-format-parity.md and the parity checklist
said .potx and .ppsx are saved with the .pptx content type, but
deckcraft_pptx::export_as writes the template and slide-show content
types, as a test in crates/pptx/tests/it/roundtrip.rs checks. The
gaps.md entry now covers only the macro-enabled variants. The checklist
row stays partial, and cargo xtask parity leaves the summary unchanged.
2026-10-24 11:58:09 -07:00
dotCooCoo 052afb3efd Status bar: the zoom slider reports percent, and Reading View reports when it is on
The zoom slider's number and range were the natural log of the zoom, so
a screen reader read 0 at 100% and set the zoom in log units. The slider
now runs from 10 to 400 percent on a log scale, and its number is the
percentage its text shows. Reading View reports itself as selected when
the view is Reading View, as the other view buttons do.
2026-10-24 11:12:04 -07:00
dotCooCoo 8f31193cc0 Edit Points: Esc before releasing the mouse button cancels a point or handle drag
Esc during a vertex or handle drag in Edit Points used to leave Edit
Points while the drag went on: the point kept following the pointer and
the release added an undo step. Esc now ends the drag and puts the shape
back as it was at the press, with no undo step, and Edit Points stays on.
Esc without a drag still leaves Edit Points.
2026-10-24 10:52:09 -07:00
Marco Arnulfo 9341ae0616 Shapes: Arrow: Notched Right cuts its notch as deep as presetShapeDefinitions give it, parallel to the head 2026-10-24 19:26:42 +02:00
Marco Arnulfo 9e9e13fc2c Files: saving as Outline/RTF keeps every paragraph of a slide title 2026-10-24 19:11:59 +02:00
Marco Arnulfo 1525dae1bd Files: opening an RTF outline keeps non-breaking hyphens 2026-10-24 19:08:05 +02:00
Marco Arnulfo 53bdcbafef Files: opening a Word RTF outline skips the list bullets and keeps each item's indent 2026-10-24 19:04:10 +02:00
Marco Arnulfo 9830b57fbe Shapes: a speech bubble's wedge mirrors with its tip, at 7..10 twelfths on the far side as presetShapeDefinitions give it 2026-10-24 18:50:57 +02:00
dotCooCoo 00f9df7d8d Edit Points: Shift, Ctrl or Alt while dragging a handle makes the point smooth, straight or corner
A handle drag in Edit Points ignored the modifier keys: the point kept
the type it had. In PowerPoint, Shift, Ctrl or Alt held during the drag
sets the point's type.

Shift held while dragging a point's handle now makes it a smooth point.
Ctrl (Cmd on the Mac) makes it a straight point, and Alt (Option) makes
it a corner point. The handle drag passes that type to shape.moveHandle,
and the point keeps it for the next drag without a modifier, as after
Smooth Point, Straight Point or Corner Point in the right-click menu.
2026-10-24 09:38:54 -07:00
dotCooCoo 68c21778ef Merge main into feat/table-cell-range-select 2026-10-24 09:29:12 -07:00
dotCooCoo 0c0cce3764 Merge main into feat/autoformat-lists 2026-10-24 09:29:11 -07:00
dotCooCoo b8f707165b Status bar: screen readers can name its controls and read the slide counter and status message
The status bar's Fit, Zoom In, Zoom Out, Slide Show, Reading View, Slide
Sorter and Normal buttons and the language name reported no widget info,
the zoom percentage reported only its own text as a label, and the zoom
slider had no name, so a screen reader announced the buttons and the
language without a name. The slide counter and the status message were
painted text with no accessibility node, so a screen reader could not
read them.

Each icon button now reports its tooltip as its name, and the four view
buttons also report whether their view is the one shown. The zoom
percentage is the "Zoom level" button with the percentage as its value,
and the slider is "Zoom" with the percentage as its text value. The
language name is the "Language" button with the language as its value.
The slide counter and the status message are labels with the text they
show.
2026-10-24 08:50:49 -07:00
dotCooCoo 205ca7dfc0 Text: the Columns dialog sends only the fields that changed
With several text boxes selected, the dialog shows the first one's
values. OK sent both Number and Spacing, so changing one of them also
gave every box the first box's value of the other. OK now sends only
the fields that differ from what the dialog showed, and with neither
changed it closes without an edit.
2026-10-24 08:23:17 -07:00
dotCooCoo 7d4bc14c1d Control server: refused connections drain on their own threads
The accepting thread drained each connection it refused as busy for up
to 250 ms before accepting the next, so refused peers that stayed
connected without writing delayed every connection after them. Each
drain now runs on a thread of its own, up to 16 at once; past that, a
refused connection gets the busy reply and is closed without a drain.

connection_limit_refuses_then_frees_slot now uses a 30 s idle timeout:
its first client sends nothing, and under load the 300 ms timeout
closed it before the third client connected.
2026-10-24 08:23:14 -07:00
Dominik Strebel 8236a9441b docs(roadmap): status line names the 2026-10-24 progress-log entry 2026-10-24 17:16:58 +02:00
NetterSilverandClaude Haiku 5.5 61b3108be7 Reject invalid index in animation remove, move, timing and options
Found while testing crates/engine/src/cmd/animation.rs:232-246 (remove); same pattern in each_target :265 and move_anim :250

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 17:06:43 +02:00
Dominik Strebel c15e260794 fix(render): an emphasis tint recolours the fill behind a picture's and an object preview's transparent pixels 2026-10-24 16:48:24 +02:00
NetterSilverandClaude Haiku 5.5 744c01f66f Match style as a whole attribute name in HTML paste
Found while testing crates/engine/src/cmd/richclip.rs:230-242 (attr, used by tag_style)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 14:35:42 +00:00
NetterSilverandClaude Haiku 5.5 35f240e453 Return BadParams for overflowing start in review.spellingChange
Found while testing crates/engine/src/cmd/review.rs:424 (spelling_change)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 13:53:26 +00:00
KataccandClaude Opus 5.5 8bc0afaff5 Test the Language dialog's default with nothing selected
With no text or shape selected, Review › Language must apply to the
whole presentation without choosing it, and Selected text must be
disabled. The existing test still covers switching to Whole
presentation while text is selected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 66e369de26 Doc comments for the language functions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 291725c78e format.languageAll: also mark each text body's own list style
A layout placeholder's a:lstStyle can carry lang/noProof, and
ed::format_all only touched runs and end marks, so such a placeholder
kept its old language. Existing list style levels of shape, table cell
and notes bodies now get the edit too; bodies without one get none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 507fdc3767 Contributors: credit Katacc by GitHub profile name
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:53 +03:00
KataccandClaude Opus 5.5 2d3997d2e3 Review: proofing language for the whole presentation
Review › Language gets "Apply to: Selected text / Whole presentation".
The new format.languageAll command sets lang/noProof on every run in
the deck (slides, groups, table cells, notes, masters, layouts) and on
the master and default text styles, so new text inherits it. It needs
no selection and is one undo step; format.language is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:35 +03:00
dotCooCoo c207d6eb0f Tests: the Notes-button test clicks where the button is laid out, so it passes without Inter
status::tests::a_long_language_name_leaves_the_notes_button_clickable
clicked x 150 for the gap before the status bar's controls and x 200 for
the Notes button. Those positions hold for Inter. With a craft-fonts
checkout that has no fonts/latin-manifest.txt, the interface text is set
in BIZ UDPGothic. Labels set in BIZ UDPGothic are wider than in Inter,
so the Notes button starts at x 149. The first click then toggled the
notes pane and the second toggled it back.

The status bar's Notes and Comments buttons now report widget info with
their names. The test reads the Notes button's rect, clicks midway
between x 132 and its left edge, and then clicks its center.
2026-10-24 06:25:07 -07:00
dotCooCoo e89c824c6d Text: a Columns dialog sets the number of columns and the spacing between them
Home > Columns offered 1, 2 or 3 columns, always 18 pt apart, and Format
Shape > Text Box had the same three buttons. The spacing could not be
seen or changed, and picking a number reset it.

Home > Columns > More Columns... and a Columns... button in Format Shape
> Text Box now open a Columns dialog with Number (1 to 16) and Spacing in
inches, filled in from the text box. OK applies both in one undo step.
A Spacing left as shown keeps the text box's exact value.

format.columns with no fields opens the dialog. A key left out keeps the
text box's own value instead of resetting it to 1 column or 0 pt, and a
count that is not a whole number from 1 to 16, or a spacing that is not
a number, is an error. Before, an out-of-range count was clamped, a
count that was not a whole number meant 1 column, and a spacing that
was not a number meant 0 pt.
2026-10-24 05:57:36 -07:00
aiongg 38d2ade2b7 Merge pull request #1260 from aiongg/r1-batch1
Integration batch 1: 35 contributor PRs (charts, shapes, slides, text editing, dialogs, outline files)
2026-10-24 08:38:28 -04:00
Dominik Strebel a8f1573fba fix(pptx): an object saved as its preview picture keeps the fallback picture's fill 2026-10-24 14:29:30 +02:00
NetterSilverandClaude Haiku 5.5 53eda1e8df Reject multiple leading '#' in Rgba::from_hex
Found while testing crates/color/src/lib.rs:37

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 14:21:11 +02:00
Dominik StrebelandClaude Opus 5.5 aece097096 Render: a picture's fill shows behind its transparent pixels
PowerPoint draws a picture's own fill (p:pic/p:spPr) behind the picture, so
it shows through its transparent pixels: a synthetic deck with one
half-transparent PNG three times (no fill, an orange fill, a yellow fill
with a blue outline), exported as PDF, shows the orange and yellow boxes
behind the image. DeckCraft drew the outline but never the fill.

Old equation objects use this: an OLE object (p:oleObj, Equation.3) has a
fallback picture whose spPr gives it a coloured box behind the equation's
transparent metafile. The reader took only the picture's image as the
object's preview and dropped its fill and line.

- The shape-fill loop moves into Renderer::fill_geometry; a picture and an
  embedded object's preview paint their own explicit fill with it before
  the image (a style fill alone still draws nothing, as before).
- An embedded object without a fill or line of its own takes them from
  its fallback picture's spPr; its frame keeps its own position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 14:07:43 +02:00
dotCooCoo 79c1d578be Control server: a peer refused as busy still reads why, and two tests no longer race
When every connection slot was taken, the accepting thread wrote the busy
reply and dropped the socket. A peer that had already written a line saw a
reset instead of the reason. The busy path now closes the same way a
rejected line does: it sends the FIN and drains the socket for at most
250 ms, or the write timeout when that is shorter.

The drain set its read timeout on the writing handle and read through a
clone of the socket. On Windows, a read timeout set on one handle of a
try_clone pair can fail to apply to reads through the other. On Windows 11
a rejected peer that stayed connected then kept its slot until the idle
timeout (10 minutes by default) instead of the write timeout. The timeout
is now set on the handle that reads.

Two tests failed intermittently. a_pipelined_peer_still_reads_why_its_line_was_rejected
connected 12 peers through 2 slots, and a slot comes back only after the
thread serving the previous peer ends; each peer now has a slot of its own.
blocked_ui_times_out_and_full_queue_is_busy relied on a 50 ms sleep to
order two requests from two connections; it now accepts either order.
2026-10-24 04:59:06 -07:00
dotCooCoo 44d5a0e7b9 Tests: UI tests that render with wgpu take turns, so the Windows test run no longer crashes
Harness::render creates a wgpu device on its first call, and egui_kittest
prefers a CPU adapter. When cargo test runs several of these tests on
parallel threads, the deckcraft-ui-egui test binary can exit with
0xc0000005 (STATUS_ACCESS_VIOLATION), so cargo xtask ci stops at its test
step on Windows without cargo-nextest.

The 16 tests that call render now hold one mutex for their whole run
(crate::gpu_lock::gpu_lock, as in photocraft's testkit), so only one of
them runs at a time.
2026-10-24 04:05:13 -07:00
oracola91 920925abae PDF export keeps only the links the slide show opens
A denylist can't keep up with OS protocol handlers: ms-msdt:, ms-word:
with a share path, ldap: and file:///%5C%5Chost/share still went into
exported PDFs. PDF export now writes a URL link only when safe_url
allows it, the check the slide show already uses on a click: http,
https and mailto. Links between slides are unchanged, and any other
link's text stays on the page without the link.

safe_url moves from deckcraft-anim to deckcraft-model, which both
crates use; deckcraft_anim::safe_url stays as a re-export. Local file:
and relative links are left out for now, as asked in review.
2026-10-24 13:31:06 +03:00
oracola91 274b626007 Test: every link of the unsafe-link test sits on the slide
The last links started below the 540 pt slide. They were still
exported, as zero-height annotations at the page edge, so the test
worked, but only because of that. With all 16 links on the slide the
test no longer depends on how off-page links are handled.
2026-10-24 13:27:00 +03:00
oracola91 afb52aeef3 PDF export also drops search: and search-ms: links
Windows Search's search: and search-ms: links can name a folder on
another machine through crumb=location:, and opening one connects to
that host and sends the user's NTLM credentials. They are now left out
of the PDF like the other network-share links, and the test covers both.
2026-10-24 13:27:00 +03:00
oracola91 8c4907a626 PDF export also drops smb: links
An smb://host/share link is a path to another machine too: opening it
connects to that host (macOS and Linux file managers open these links).
It is now left out of the PDF like the other network-share links, and
the test covers it.
2026-10-24 13:27:00 +03:00
oracola91 8fd1c1716f PDF export drops javascript:, vbscript:, data: and network-share links
A slide hyperlink from an untrusted deck became a PDF link whatever it
pointed at. Script and data links, and links to another machine (UNC
\\host\share, //host/share, file://host/...), are now left out of the
PDF; the text stays. On Windows, opening a network path sends the
user's NTLM credentials to that host.

Web, mail, local file: and relative links are kept. The scheme is read
the way a browser reads it: control characters dropped, leading spaces
trimmed, any case. The slide show already refuses these links
(safe_url), and cadcraft's PDF export drops script and data links.
2026-10-24 13:27:00 +03:00
NetterSilverandClaude Haiku 5.5 fb778030c9 Reject invalid shape ids in ids instead of using the selection
Found while testing crates/engine/src/cmd/mod.rs:ids_param / targets (~line 335-350)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 10:13:35 +00:00
Dylan M. Taylor 7be391a1be fix(pptx): harden import resource budgets, deduplication, and lookup caching (#1283)
* fix(pptx): harden import resource budgets, deduplication, and lookup caching

- Chart sidecars (Finding 2): Enforce an import-wide retained byte budget
  and cache captured sidecars by chart part to prevent memory amplification.
- Content types cache (Finding 6): Cache parsed [Content_Types].xml defaults
  and overrides in Package.ct_cache.
- Text run splitting and font lengths (Finding 8): Bound typeface attribute
  lengths and cap paragraph runs to prevent multiplication on text splitting.
- Inner namespace decls (Finding 15): Use HashSet/HashMap indexing and cap
  inner declarations to 1,000.
- Slide and notes deduplication (Finding 16): Deduplicate slide paths and
  cache parsed notes slide bodies by target.
- Diagram media caching (Finding 22): Cache diagram media payloads in
  imp.media_by_part.
- Master slide deduplication (Finding 28): Deduplicate master paths before
  loading.
- Layout target deduplication (Finding 30): Deduplicate layout targets
  across master slides.
- Chart value axis indexing (Finding 32): Index valAx by axId using a HashMap.
- ChartEx series output budget (Finding 34): Charge series point vectors
  against an aggregate output budget and cap series count.
- ChartEx point allocation bounds (Finding 36): Allocate point vectors
  only to actual point span bounded by budget rather than declared ptCount.
- SmartArt recursion depth (Finding 38): Limit SmartArt recursion depth to 8.

* fix(pptx): address review feedback on sidecar cache, series budget, and inner decls

* fix(pptx): preserve cached sidecar bytes and non-empty category fallback
2026-10-24 06:01:30 -04:00
dotCooCoo e8910cb253 Paste: a table, bullet or slide from another deck keeps its own pictures and sounds
Copy listed the media of pictures, media clips, 3-D models and shape
fills only, and Paste rewrote the ids of pictures, media clips, opaque
previews and shape fills only. Picture fills in table cells and table
backgrounds, picture-filled text runs and picture bullets were left off
the clipboard. In another deck they pointed at a missing picture, or at
that deck's own picture when it used the same media id. A copied slide
lost its transition and animation sounds in the same way.

Paste Special > Picture gave clashing media fresh ids but drew the
shapes with the old ids, so a clashing id drew the open deck's picture.
Review > Compare > Accept Revision of a compared deck's slide copied the
same partial set, and missed the slide background as well.

Copy, Paste, Paste Special > Picture and Accept Revision now find and
rewrite media ids with the media_refs walkers that slide.reuse uses.
2026-10-24 02:48:19 -07:00
aiongg 528af4e503 Integration: a rejected positional revision is not turned into a deletion when a slide is inserted before it 2026-10-24 09:40:33 +00:00
aiongg 202255cbbb Integration: restore chart.rs CRLF line endings 2026-10-24 09:39:13 +00:00