Commit Graph
1272 Commits
Author SHA1 Message Date
Nikita RakitinandCursor 5d9f47c81a Clipboard: rich text and pictures for other apps
Copy puts HTML on the pasteboard with the same plain words, so Pages keeps
bold, italic and underline, and a paste of that HTML keeps them here. A
shape with no text copies out as a picture.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:37:49 +03:00
Nikita Rakitin ce3725a5c8 PPTX: literal CR LF and CR in XML read as LF; line feeds in run text read as line breaks 2026-10-14 06:37:15 +03:00
Nikita Rakitin 8bbea22f74 Media: refuse MP4s whose sample tables overrun the file before symphonia reserves memory for them 2026-10-14 06:26:15 +03:00
Nikita RakitinandCursor 26d8bfdd3a UI: Design Effects applies a theme effect scheme
design.effects replaces the theme's format scheme (fills, lines and
effects) with DeckCraft, Soft, Crisp, Lift, Glow or Plain. Colours and
fonts stay. The scheme already in use is not an undo step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:21:07 +03:00
Nikita Rakitin 5115f77f08 Media: damaged audio no longer hangs the demux loop or panics in symphonia 2026-10-14 06:20:10 +03:00
Nikita RakitinandCursor 2f3a525568 UI: Format Shape fill transparency follows the selection
The Fill slider seeded itself at 0% and wrote that when it lost focus, so a
solid fill that was already transparent opened as opaque and could be cleared.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:16:14 +03:00
Nikita Rakitin 800c2008df PPTX: table styles the file defines are kept on save even when no table uses them 2026-10-14 06:15:05 +03:00
Nikita RakitinandCursor d6b9cc9b5e Outline: lay out only the slides in view
Outline view built every slide's title and text editors each frame, so a 2000-slide deck took
about 40 ms a frame in a release build (more with real text). Slides outside the view (with a
margin) now take their last measured height, estimated from their line count until first
shown; the current slide is always laid out so its editor keeps the focus.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:13:10 +03:00
Nikita RakitinandCursor 1e6292306a UI: Format Background picture fill sets transparency and tiling
A picture background can set transparency, tile, offset, scale,
alignment and mirror. A solid fill can set transparency. Apply to All
copies the current slide's background, including a picture, onto every
slide. Unchanged options are not an undo step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 06:08:40 +03:00
Nikita Rakitin c4a9f25754 Charts: a chart frame with no width no longer panics 2026-10-14 05:58:30 +03:00
Nikita RakitinandCursor 256612b232 UI: Trim Media dialog follows the selection
Trim Media opened at zero for start, end and both fades, so OK
cleared a clip that was already trimmed. The fields now start from
the selected audio or video.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:54:32 +03:00
Nikita RakitinandCursor 0fcaabc370 UI: Create New Theme Fonts dialog edits the theme in one step
Design › Fonts › Customize Fonts… opens Create New Theme Fonts.
Empty design.fonts params open the dialog; a name and heading or body
faces apply to the open master in one undo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:45:53 +03:00
Nikita Rakitin 6b0c1db6ed PPTX: the notes master's own placeholders and colour map are kept on save 2026-10-14 05:41:01 +03: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 RakitinandCursor d04df05249 Export: record slide resolution in PNG and JPEG pictures
A default export is 2 pixels per point. Without a resolution, Preview
treats those pixels as 72 dpi and the picture opens at twice the slide's
size. PNG pHYs and JPEG JFIF density now say scale times 72, so the
default is 144 dpi. Screenshots stay untagged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:35:37 +03:00
Nikita RakitinandCursor 65e465a611 UI: Create New Theme Colors dialog edits the theme in one step
Design › Colors › Customize Colors… opens the dialog when design.colors
is called with no name and no colours. Save applies that scheme name and
the twelve theme colours together, as one undo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:24:47 +03:00
Nikita Rakitin f22ff9eb62 Format after merging main 2026-10-14 05:20:38 +03:00
Nikita Rakitin 5398c2397c Merge remote-tracking branch 'origin/main' into m-pptx-chart-workbook
# Conflicts:
#	ROADMAP.md
#	crates/pptx/src/read/chart.rs
#	docs/gaps.md
2026-10-14 05:20:31 +03:00
Nikita RakitinandCursor 3f82866aaf Export: image exports keep the whole slide; partial failures say what was written
The renderer caps a picture at MAX_SIDE (16,000 px) by clipping, so an image export whose
slide × scale passed that (4× of a 4032 pt slide) came out cropped. file.export and file.render
now lower the scale to fit (cmd::file::image_scale). When exporting every slide and one file
can't be written, the error says which slides already were, and slide numbers are checked
before anything is written.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 05:20:06 +03:00
Nikita Rakitin 29c24aa07c UI: Alt Text's decorative checkbox follows the selection
The dialog always opened with Mark as decorative unchecked, so OK
cleared a shape that was already decorative. It now starts checked
when every selected shape is.
2026-10-14 05:19:44 +03:00
Nikita Rakitin ef858b710f Merge Shapes: a text box merges as its letters; a picture keeps its place (#653) 2026-10-14 05:07:18 +03:00
Nikita Rakitin c2e770ab53 Show: Show Media Controls hides the playback bar
The Slide Show checkbox wrote nothing. show.setup now stores
showMediaControls, and the show draws the playback bar and GIF button
only while that setting is on.
2026-10-14 05:07:12 +03:00
Nikita RakitinandCursor a9e7747ea5 Canvas: a two-finger twist rotates the selection
macOS delivers a trackpad rotation as egui's Rotate event. While the
pointer is over the canvas, that twist turns the selected shapes, and
the whole gesture is one undo step. Pinch-zoom and scrolling are unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:55:33 +03:00
Nikita Rakitin 9f5de924ad View: Zoom dialog applies a percent or Fit
The dialog waits for OK. View ▸ Zoom opens it, and the arrow keeps the preset list.
2026-10-14 04:53:21 +03:00
Nikita Rakitin 3ea696dc1a Charts: read, write and draw error bars 2026-10-14 04:48:33 +03:00
Nikita Rakitin 679ce03da4 Show: a first animation set to With/After Previous plays when the slide appears (#631) 2026-10-14 04:47:09 +03:00
Nikita RakitinandCursor 8fde746211 Format: never save a .deckcraft that can't be reopened over a NaN
serde_json writes NaN and infinity as null, which doesn't read back as a number, so one NaN
anywhere in the model (a rotation, position, crop, stroke width…) made the saved file (and its
AutoRecover copy) fail to open as "damaged".

- Writer: presentation.json goes through finite::Finite, a serializer adapter that writes
  non-finite floats as 0.
- Loader: files already written that way open; each null where a number belongs reads as 0
  (inside tagged enums, where serde only reports the enclosing object, candidates are tried
  nearest first and kept only when the parse gets further). Other damage still fails.
- repair() brings shape geometry into range: positions and sizes finite and within ±1e6 pt,
  rotation 0–360, picture crop -10..1, font sizes 1–4000 pt, line widths 0–1584 pt.

Animation timings are u32 and can't carry NaN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:45:32 +03:00
Nikita Rakitin 4a7ad03eb0 Charts: logarithmic value axes 2026-10-14 04:45:26 +03:00
Nikita RakitinandCursor b6aa6ab4e4 UI: Date and Time dialog inserts a format in one step
Insert › Date & Time opens the format list instead of placing a date
immediately. With no format, update flag or language, insert.dateTime
opens the dialog and does not edit. OK applies one undo: a field when
Update automatically is on, or the shown text when it is off.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:41:01 +03:00
Nikita Rakitin aed386e269 Charts: draw, read and write value-axis minor gridlines 2026-10-14 04:39:00 +03:00
Nikita Rakitin f0647e1bd8 Review: previous and next comment
Walk every comment in the deck from the Review tab, and list every slide in the Comments pane.
2026-10-14 04:37:49 +03:00
Nikita RakitinandCursor 22074c4c69 Format: repair degenerate slide sizes on load
repair() brings each slide side into PowerPoint's 72–4032 pt (as Design › Slide Size allows;
it accepted 1–4000 before), and replaces a zero, negative or non-finite size with 16:9; a bad
notes size gets the default. The native reader takes a null, string or missing slide/notes
size as NaN for repair to fix, so such a file opens instead of failing as damaged (NaN and
infinity are saved as null). The canvas fit and slide show fit treat a zero or non-finite side
as 1 pt, so an in-memory bad size can't make layout infinite.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:35:13 +03:00
Nikita Rakitin 2702b48530 Show: show the slide number while typing it 2026-10-14 04:26:02 +03:00
Nikita Rakitin 8a5eec369f Render: skip laying out table cell text that lands wholly off the target 2026-10-14 04:22:37 +03:00
Nikita Rakitin ed20cebed8 Charts: scatter and bubble charts get a value x axis 2026-10-14 04:22:19 +03:00
Nikita Rakitin dfee72e742 Show: play a custom show 2026-10-14 04:19:36 +03:00
Nikita Rakitin 3960ea47cd Charts: 100 % stacked axes count in percent; linked axis formats come from the data 2026-10-14 04:19:16 +03:00
Nikita RakitinandCursor dbffbab59d UI: Edit Photo Album reflows the album in one step
Reopen the Photo Album dialog on the current album and replace those slides
in one undo, with black and white, rotation, brightness, contrast and a theme.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:16:00 +03:00
Nikita Rakitin fd1b0a1965 Charts: draw the axes' titles 2026-10-14 04:12:18 +03:00
Nikita Rakitin f5fd324892 Show: presenter timer pause, reset and notes size 2026-10-14 04:06:50 +03:00
Nikita RakitinandCursor d31ed52bbe Show: presenter view keeps a portrait Next slide inside its column
The Next preview took the column's full width and the slide's aspect for its height, so a
portrait slide (up to 1:56) drew a white slab many times the window's height over the notes,
which were pushed below the window. It is now fitted into the top 60% of the column; 16:9
slides keep the full width as before.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 04:04:09 +03:00
Nikita Rakitin 0b66323765 PPTX: shape text without an anchor sits at the top (or the theme's spDef anchor); write ctr for the model's middle default 2026-10-14 04:03:35 +03:00
Nikita RakitinandCursor 05eb4c611b UI: keep every texture within the GPU's max texture side
Slide show, transition and morph frames, thumbnails, master-view canvas, master/layout
thumbnails, Design Ideas previews, presenter-view preview and video frames all upload through
textures::upload/replace, which shrinks a picture past max_texture_side (egui panicked on one).
Render sizes are fitted to the limit first, so a big screen, extreme DPI or a 1:56 slide
doesn't render a picture the GPU can't hold. The master canvas is cropped like the slide canvas.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 03:57:32 +03:00
Nikita Rakitin 77de43266e Text: shrink on overflow stops at once when even the smallest scale overflows 2026-10-14 03:56:19 +03:00
Nikita Rakitin dac0d054fe Show: See All Slides and zoom
During a show, G opens a thumbnail grid and a click jumps to that slide.
Z then a click zooms the slide to 2×. Presenter view has Black, White,
All slides and Zoom. Esc closes the grid, then the zoom, before it leaves.
2026-10-14 03:53:53 +03:00
Nikita RakitinandCursor ba71a40a39 Canvas: a trackpad swipe turns the page
A sideways flick changes slides when the slide fits the window, and any
flick does so during the show. One gesture turns one page. A zoomed slide
still pans. Pinch-zoom is unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 03:48:39 +03:00
Nikita RakitinandCursor 4575d19ac7 UI: Photo Album dialog inserts pictures as slides
Insert › Images opens Photo Album. insert.photoAlbum adds the pictures
and text boxes as slides in the open presentation, one undo step, with
layouts, frames and captions. Omitting pictures opens the dialog.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 03:43:28 +03:00
Nikita Rakitin 3fd1083468 Shapes: chevron text rectangle as presetShapeDefinitions give it 2026-10-14 03:27:58 +03:00
Nikita RakitinandCursor c583480010 Startup: survive damaged settings, font folders, recovery folders and small texture limits
- ui.json / prefs.json are read through a new settings module: regular files only, 4 MiB
  cap, parse errors logged, values sanitized (a saved zoom of 1e30 aborted start-up,
  1e4 panicked in egui); writes are atomic.
- The canvas and the control protocol clamp stray zooms; the status bar shows the zoom in use.
- The canvas texture is cut to the GPU's max texture side (zoom 400% on a 2048 limit panicked).
- The system font scan opens only regular files of sane size (a FIFO named *.ttf in ~/.fonts
  hung start-up), with depth and entry caps.
- AutoRecover skips non-regular entries and reopens at most 32 per start, newest first.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 03:27:57 +03:00
Nikita Rakitin 111f029112 Shapes: star4 and star5 text rectangles as ECMA-376 defines them 2026-10-14 03:23:17 +03:00