Commit Graph
45 Commits
Author SHA1 Message Date
Dominik StrebelandClaude Opus 5.5 aa6f45ba2c Text: table text takes the master's other-text style
PowerPoint for Mac lays out a table's text in the master's other-text
style (p:otherStyle), while shapes and text boxes take the presentation's
default text style (p:defaultTextStyle). A synthetic deck with an
otherStyle of 14 pt and a defaultTextStyle of 26 pt, exported as PDF,
draws a table cell at 14 pt and a shape's and a text box's text at 26 pt.
DeckCraft laid cells out through a stand-in shape that wasn't a table, so
they took the default text style: a deck whose two styles differ (18 and
20 pt) drew its table text 2 pt too large and wrapped its cells.

master_list_style sends text in a non-placeholder table to otherStyle,
and Shape::table_cell builds the stand-in every cell layout uses (drawing,
row heights, text placement, the caret and selection in a cell) as a
table. The table shape itself resolves the same way, so the formatting
state of a selected table reports the size its cells draw at.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:49:42 +02:00
Marco Arnulfo 367c3488c5 Text: AutoFormat superscripts ordinals (1st, 22nd) as you type 2026-10-16 02:06:42 +02:00
midasmatterhorn a82f691993 text: a bare normAutofit draws at 100% and an edit stores the fitted scale (#724) 2026-10-15 00:56:41 +03:00
Brandon ThomasandClaude Opus 5.5 b1ca1230e6 Engine: text.delete and text.move are registered once (the newer docs win); a test keeps command ids unique
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:15:17 -04:00
Brandon Thomas 081c9fdc5e Merge the landing branch into land-r7
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	apps/deckcraft-cli/tests/cli.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/text.rs
#	crates/engine/src/lib.rs
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/textures.rs
2026-10-14 15:34:15 -04:00
Brandon ThomasandClaude Opus 5.5 30107bdb31 Fix up #321: drop the empty-body layout_for change main's caret_line already covers
The caret's colour (caret_color) is kept and used at main's caret draw site; the
placeholder-prompt hiding is kept too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:29:48 -04:00
Brandon Thomas bdd9898d6f Merge PR #321 from xc4pr: Text: the caret shows on dark slides and in empty placeholders
# Conflicts:
#	crates/engine/src/cmd/text.rs
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/textures.rs
2026-10-14 15:29:17 -04:00
Brandon ThomasandClaude Opus 5.5 4b6f307ebb Fix up #169: auto RTL lives only in the engine and right-aligns only unaligned text
Drop the layout-time direction detection in crates/text (and its test); the engine's
promote_rtl_if_needed sets align Right only when neither the paragraph nor what it
inherits (list styles, layout, master) resolves an alignment. right_to_left_paragraphs
types its original Arabic text again, after an explicit LTR so the toggle it tests
starts from left-to-right.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:19:02 -04:00
Brandon Thomas 91eb9d8884 Merge the landing branch into land-r6
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/engine/src/tools.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/panes.rs
#	crates/ui-egui/src/ribbon.rs
#	crates/ui-egui/src/status.rs
#	crates/ui-egui/src/textures.rs
#	crates/ui-egui/src/thumbs.rs
2026-10-14 15:14:21 -04:00
Brandon Thomas bd005c4626 Merge PR #169 from Hevarh1: Bidi: auto-detect RTL paragraph direction when typing Kurdish, Arabic and Hebrew 2026-10-14 15:14:09 -04:00
Brandon Thomas b815568fd7 Merge PR #626 from NikitkaRa: Spelling: squiggles in table cells and speaker notes; UI-thread checking on the web
# Conflicts:
#	crates/engine/src/cmd/text.rs
#	crates/ui-egui/src/status.rs
2026-10-14 14:44:48 -04:00
Brandon Thomas eff4c02efa Merge PR #615 from NikitkaRa: Spelling: squiggles while typing, Add to Dictionary, per-run languages, compounds
# Conflicts:
#	crates/engine/src/cmd/text.rs
#	crates/ui-egui/src/canvas.rs
2026-10-14 14:44:12 -04:00
Brandon Thomas b3ec4013e6 Merge PR #230 from pierrevbc: Tables: caret in the edited cell, click-to-place, drag borders to resize
# Conflicts:
#	crates/engine/src/cmd/text.rs
#	crates/engine/src/tests.rs
#	crates/engine/src/tools.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/canvas.rs
2026-10-14 14:41:34 -04:00
Brandon Thomas b590cb0b0b Merge PR #303 from hoblin: deckcraft-cli help explains the CLI to an agent
# Conflicts:
#	apps/deckcraft-cli/src/main.rs
#	crates/engine/src/cmd/design.rs
#	crates/engine/src/cmd/file.rs
#	crates/engine/src/cmd/format.rs
#	crates/engine/src/tests.rs
2026-10-14 14:36:13 -04:00
Brandon ThomasandClaude Opus 5.5 8ee597216d Fix up landed PRs from review
- #178: ToUnicode ranges looked up without indexing
- #465: frame_num gaps are concealed (bounded) even when the SPS forbids them; cut streams keep playing
- #471: control request lines up to 256 MB so picture/media inserts still fit
- #473: a merge that loses its only row or column is removed, with regression tests
- #521: AutoCorrect no longer rewrites real words (cant, wont, im)
- #654: inherit_placeholder_geometry's doc comment back on its function

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:31:01 -04:00
Brandon Thomas 71c3848eff Merge PR #521 from NikitkaRa: Text: AutoCorrect options, case rules and your own entries
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-14 14:24:16 -04:00
Brandon Thomas b3c9cc099c Merge the PPTX writer, notes/handout master, PDF and slide-show PRs integrated on land-r3 (#518 #531 #535 #533 #572 #573 #577 #580 #583 #592 #685 #528 #483 #490 #441 #671 #679 #649 #656 #660 #664 #224)
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/model/src/lib.rs
#	crates/pptx/src/write/mod.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/thumbs.rs
2026-10-14 13:56:41 -04:00
Brandon Thomas 0ed74b684a Merge the SmartArt and dialog PRs integrated on land-r1 (#596 #601 #606 #610 #613 #617 #621 #623 #627 #634 #557 #689 #668)
# Conflicts:
#	crates/engine/src/tests.rs
#	crates/ui-egui/src/dialogs.rs
2026-10-14 13:44:43 -04:00
Brandon Thomas 0f3495e55d Merge PR #512 from NikitkaRa: Home: Replace Fonts dialog and font.replace command
# Conflicts:
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/ribbon.rs
2026-10-14 13:34:06 -04:00
Brandon Thomas e0ec02d62c Merge PR #689 from NikitkaRa: UI: Hyperlink dialog follows the selection
# Conflicts:
#	crates/engine/src/cmd/insert.rs
#	crates/ui-egui/src/dialogs.rs
2026-10-14 13:30:10 -04:00
Brandon Thomas 63c32b89b8 Merge PR #573 from NikitkaRa: Add the Notes Master view (stacked on #572 / #533)
# Conflicts:
#	crates/pptx/src/write/mod.rs
2026-10-14 13:29:52 -04:00
Brandon Thomas 875df7674c Merge PR #572 from NikitkaRa: Add the Handout Master view (stacked on #533)
# Conflicts:
#	crates/engine/src/tests.rs
2026-10-14 13:29:33 -04:00
Brandon Thomas 6af2b0ee21 Merge PR #618 from NikitkaRa: Text: underline an IME composition in a table cell
# Conflicts:
#	crates/render/src/lib.rs
2026-10-14 13:23:32 -04:00
Brandon Thomas 1256ee1022 Merge PR #226 from xmaks82: Text: draw shrink-on-overflow at the scale the file was saved with 2026-10-14 12:57:21 -04:00
Brandon Thomas c57d25e8d3 Merge PR #97 from mikl0s: Commands: an invalid shape id is an error instead of the selection 2026-10-14 12:57:19 -04:00
Nikita Rakitin 8c0147cfa7 UI: Hyperlink dialog follows the selection
Insert Hyperlink opened on https:// with an empty ScreenTip, so OK
replaced a web address, email, slide link or tip. The dialog now
starts from the link it would edit, and leaves actions it cannot
edit in place.
2026-10-14 05:40:06 +03:00
Nikita Rakitin 8bc7e55561 Spelling: squiggles in table cells and notes; UI-thread checking on the web 2026-10-14 02:34:33 +03:00
Nikita RakitinandCursor eb7e346ea1 Text: underline an IME composition in a table cell
The preedit was already stored in the cell. It is now laid out the same
way the cell is drawn, and the editor underlines it in place, thicker
under the part being converted. The caret and the input method's
candidate window sit in that cell. Notes stay an egui text field.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 02:08:14 +03:00
Nikita Rakitin a29e200a4e Spelling: background squiggles, Add to Dictionary, per-run languages, compounds 2026-10-14 02:05:22 +03:00
Nikita Rakitin 443fe300d0 Add the Notes Master view
View ▸ Notes Master edits the notes master on a notes-size page (creating
PowerPoint's default placeholders if the deck has none); its tab toggles
header, date, slide image, body, footer and page number, sets the
background and closes the view. The PPTX writer now writes an edited
notes master as it is, even in a deck without notes. Stacked on #572.
2026-10-14 00:31:14 +03:00
Nikita Rakitin bba398f60f Add the Handout Master view
View ▸ Handout Master opens the handout master (creating one with header,
date, footer and page-number placeholders if the deck has none) on a page
at the notes size, with a dashed preview of where 1-9 slides go. Its
contextual tab toggles the placeholders, sets the background and closes
the view. Stacked on #533, which reads and writes the handout master.
2026-10-14 00:25:38 +03:00
Nikita RakitinandCursor e615188f8b Text: AutoCorrect options, case rules and your own entries
AutoCorrect gains PowerPoint's options: correct TWo INitial CApitals,
capitalize the first letter of sentences and the names of days, fix
accidental cAPS LOCK, and replace 1/2, 1/4, 3/4 with fraction
characters. "word..." becomes "word…", "word," and "word." are corrected
too, and the built-in list grows from 13 to ~70 entries. The case rules
apply only to typing, not pasted text.

New text.autocorrect sets the options and adds or deletes replace
entries (your own win over the built-in list; deleted built-ins stay
deleted) and returns the list. Preferences ▸ AutoCorrect Options… opens
an AutoCorrect dialog with the options and the editable list.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 22:43:32 +03:00
Nikita RakitinandCursor 37bd53c62e Home: Replace Fonts dialog and font.replace command
font.replace {from, to} renames a font family everywhere it is named
explicitly: runs (latin, east Asian, complex script and symbol faces), end
marks, bullet fonts, list styles of shapes, layouts and masters, the master
text styles, the deck default style, notes, tables and the theme fonts, so
placeholders that follow the theme change too. Names compare
case-insensitively, theme references (+mn-lt) are left alone, a replace that
finds nothing adds no undo step, and missing fonts are recomputed.
font.used lists the families the slides draw in, for the dialog's Replace
list.

Home gets a Replace Fonts… button opening the dialog: Replace (fonts in the
deck), With (type or pick from installed fonts), and it stays open with a
confirmation like PowerPoint's. Ribbon small buttons now expose their label
to accessibility, which the UI test uses to click it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 22:20:09 +03:00
MarekSpodBiedry 007741718e Slide: leading tabs in a new slide's body set the outline level (#370) 2026-10-13 17:52:00 +02:00
pierrevbc b5a8642417 Tables: show the caret and text selection in the cell being edited
Editing a table cell outlined the cell but drew no caret or selection,
and Up/Down/Home/End fell back to paragraph moves, because the text
layout used for drawing, hit testing and caret movement only existed
for shapes.

text::text_frame now lays out the edited text as it is drawn and gives
the transform to the slide, for shapes and cells alike: a cell's text is
laid out in its rect (merges honoured) with the cell's margins, anchor
and the table style's look, through the renderer's own cell_body and
cell_rects. layout_for and tools::text_pos use it, and the canvas draws
the caret and selection from it. The cell outline follows merged cells.
2026-10-13 11:28:22 +02:00
Brandon ThomasandClaude Opus 5.5 6334d689d2 Text: Ctrl+arrows, Ctrl+Backspace/Delete and other text keys work like PowerPoint (#268) (#333)
* Text: Ctrl+arrows, Ctrl+Backspace/Delete and the other text keys work like PowerPoint (#268)

Observed black-box in PowerPoint for Windows on synthetic text:
- Word stops (crates/model/src/words.rs): words, punctuation runs, symbol
  runs, tabs, line breaks and each CJK character are tokens; trailing spaces
  join the token before. it's, a-b, 3.14, 1,000 are one word; e.g., a_b and
  x@y.com are not. Grapheme clusters never split.
- Ctrl+Left/Right and Ctrl+Shift+Left/Right move by those stops, across
  paragraphs; with a selection they go on from its start/end. In a
  right-to-left paragraph Left and Right swap.
- Ctrl+Backspace deletes to the previous stop; Ctrl+Delete deletes the rest
  of the word, or spaces plus the next word, then applies PowerPoint's smart
  spacing. With a selection both work from its start.
- Ctrl+Up/Down by paragraph, Ctrl+Home/End to the text's ends.
- End on a wrapped line goes past the trailing space and the caret stays
  drawn at that line's end (TextSel::line_end); End again stays, Home
  returns to the same line.
- Ctrl+]/[ and Ctrl+Shift+>/< change font size (egui's Period/Comma/
  bracket key names now match registry shortcuts).
- Shift+F3 cycles lower -> Title -> UPPER; a caret changes its word.
- Double-click selects the word without trailing spaces; triple-click
  includes the paragraph mark.
- Mac keeps Option for words and Cmd for line/text ends (Session::mac_keys).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* rustfmt

* Canvas: one caret, drawn at a wrapped line's end after End

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 22:09:50 -04:00
Brandon ThomasandClaude Opus 5.5 ea3b1159d5 Korean, Japanese and Chinese: input-method composition and interface text (#101) (#331)
* Text: input method composition as commands, one undo step per composition (#101)

text.compose shows an input method's preedit in place at the insertion point and replaces it on
each update; an empty preedit cancels and restores the text and selection. text.commit replaces
the composition with the result as one undo step. Any other edit, key or click settles an open
composition first. The composition is underlined under the baseline (thicker under the part being
converted), and the caret line is measured for empty placeholders too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* UI: Korean, Japanese and Chinese input and interface text (#101)

The slide turns the input method on while it takes typing, with the candidate window at the
caret, and forwards egui Ime events to text.compose / text.commit, so a Korean keyboard composes
syllables instead of separate jamo. Interface text in scripts the interface fonts lack (Hangul,
Simplified Chinese, Thai...) borrows faces from the font database (installed fonts such as Malgun
Gothic; nothing bundled): file names, titles, notes, outline, sections, comments and typed text.
Ported and widened from WordCraft's #565/#840 fallback. The notes pane keeps text typed before
focus leaves in the same frame (Escape, another slide). Control channel: ui.ime.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 22:03:42 -04:00
xc4pr b97af97a58 Text: the caret shows on dark slides and in empty placeholders
The caret was always stroked black. On a dark slide (the Nocturne theme,
or any dark background with light text) it could not be seen. It is now
drawn in the colour that text typed at the caret takes, and falls back to
the theme token when that text has no fill.

An empty placeholder showed no caret at all: its body holds no paragraph
until something is typed, so the edit layout had no line for the caret to
stand on. The edit layout now treats such a body as one empty paragraph,
and the canvas leaves the placeholder's prompt out while it is being typed
into, so the caret does not sit inside "Click to add title".

Fixes #318.
2026-10-13 00:39:17 +02:00
Yevhenii Hurin 717e855cec deckcraft-cli help explains the CLI to an agent
`deckcraft-cli help` and each subcommand's `--help` say what it does,
with a working example; `--help` never runs the subcommand. `describe`
spells out a command's parameters and what it acts on, `commands` lists
one command per line, and the MCP instructions say what format.* acts on.

[claude-opus-5-5] on behalf of hoblin
2026-10-12 23:41:42 +03:00
Магда М.Г. f2c27cbba1 Text: draw shrink-on-overflow at the scale the file was saved with
PowerPoint draws normAutofit text at its saved fontScale/lnSpcReduction;
we ignored them and only shrank when our own layout overflowed, so saved
decks showed larger text and wider line spacing than PowerPoint, with text
running past placeholders. The layout now starts from the saved scale
(nonsense values ignored) and still shrinks further when the text doesn't
fit. Editing the text resets the saved scale so the new text is fitted
afresh, as PowerPoint refits on edit.
2026-10-12 14:52:34 +02:00
Hevar Hemin f033c76913 Bidi: auto-detect RTL paragraph direction and keep typing caret advancing smoothly
When typing in Kurdish, Arabic or Hebrew in a new document or text shape, default
paragraph direction (props.rtl: None) was resolving to LTR. In an LTR
paragraph, visual reordering pinned newly typed characters and the caret to the
left margin, resetting to the start of the line with every keystroke and jumping on
space characters due to UAX #9 rule L1.

- Add first_strong_is_rtl() in deckcraft-model following UAX #9 rules P2/P3.
- Auto-resolve unassigned paragraph direction to RTL in shape_para layout when the
  paragraph starts with an RTL script, defaulting alignment to Align::Right.
- Auto-promote paragraph to RTL (props.rtl = Some(true), props.align = Some(Align::Right))
  when typing or inserting text starting with an RTL character.
- Add regression tests in deckcraft-model, deckcraft-text, and deckcraft-engine.
2026-10-11 22:28:45 +03:00
Mikkel Georgsen 736dd52b51 Commands: an invalid shape id is an error instead of the selection
A shape id that was present but not a valid id (negative, not an integer,
larger than u32) was treated as absent, so commands such as text.set and
text.edit silently edited the selected shape instead. id_param now tells three
cases apart: absent (the selection fallback is unchanged), valid, and invalid
(an error naming the command). arrange, edit (select), inspect, review, table,
text and the animation painter pick this up.
2026-10-10 22:05:22 +02:00
7f1e152870 Links: Insert Hyperlink with a bare caret inserts the address; the show follows links (#31) (#45)
Three causes, each making links look like they "don't save":

- With the caret at a word boundary (end of text, empty paragraph),
  insert.hyperlink formatted an empty range and changed nothing. It now
  inserts the address (or the slide's title, or `text`) as linked text, as
  PowerPoint does. Typing right after a link no longer extends it.
- The slide show ignored hyperlinks and shape actions. A click on one now
  follows it (ShowState::follow): slides, next/previous/first/last, Last
  Slide Viewed, End Show, and URLs; the pointer turns into a hand over links.
- The desktop app was built without eframe's `links` feature, so
  ctx.open_url did nothing natively (also the ribbon's app page link).
  Enabled as in DesignCraft, EffectCraft and PrintCraft.

Saving was fine: links round-trip through .deckcraft and .pptx.

generated with Claude Code

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 06:23:01 -04:00
Brandon ThomasandClaude Opus 5.5 ae9d525bce Rename SlideCraft to DeckCraft: crates, apps, binaries, app id, file extension (.deckcraft; .slidecraft files still open), packaging, docs; ROADMAP alpha and parity estimates
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:46:40 -04:00
Brandon ThomasandClaude Opus 5.5 6078b68e97 M0: workspace, model, geometry, fonts, text, renderer, engine, MCP and CLI
Clean-room PowerPoint-class presentation engine in pure Rust:
- geom: units, transforms and 150+ re-derived preset shapes with adjust handles
- color: theme slots and colour transforms
- model: presentations, masters, 11 layouts, placeholder inheritance, themes,
  text, tables, charts, transitions, animations, text edit operations
- fonts: font DB with craft-fonts, system fonts and open substitutes
- text: shaping, line breaking, bullets/numbering, alignment, autofit, caret hit tests
- render: vello_cpu slides with fills, gradients, pictures, effects, tables, charts
- format: native .slidecraft (zip + JSON)
- engine: ~200 commands, undo/redo, clipboard, pointer tools, keys, sample deck
- mcp: MCP server (headless or bridged to the app); slidecraft-cli

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:27:20 -04:00