Commit Graph
125 Commits
Author SHA1 Message Date
Brandon Thomas 266da52dd9 Merge PR #640 from NikitkaRa: Charts: category axis orientation; horizontal bars list the first category at the bottom
# Conflicts:
#	crates/pptx/src/read/mod.rs
#	crates/pptx/src/write/chart.rs
#	crates/render/src/chart.rs
2026-10-14 13:48:09 -04:00
Brandon Thomas 593f55dfa1 Merge PR #638 from NikitkaRa: Charts: bar widths, column/bar point fills, smoothed lines and chart text colour as the file sets them
# Conflicts:
#	crates/pptx/src/read/chart.rs
#	crates/render/src/chart.rs
2026-10-14 13:47:34 -04:00
Brandon ThomasandClaude Opus 5.5 32a49e8bf6 Fix up merged PRs: a trendline caption in a tiny chart no longer panics
f64::clamp panics when the plot is narrower than the caption's minimum width;
use main's clamp_soft, as the rest of the chart code now does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:47:08 -04:00
Brandon Thomas 8f0640a7b2 Merge PR #603 from NikitkaRa: Render: draw chart trendlines
# Conflicts:
#	crates/render/src/chart.rs
2026-10-14 13:47:08 -04:00
Brandon Thomas b0345cfaf2 Merge PR #602 from NikitkaRa: Charts: polar radar, stock high-low lines and up/down bars, combo sample 2026-10-14 13:42:48 -04:00
Brandon Thomas 82ea49bcf1 Merge PR #598 from NikitkaRa: Charts: keep and draw region map charts 2026-10-14 13:42:45 -04:00
Brandon Thomas 7c46b5b76a Merge PR #594 from NikitkaRa: Charts: multi-level treemaps and sunbursts; inclusive box quartiles 2026-10-14 13:42:41 -04:00
Brandon Thomas 6057715c2a Merge PR #591 from NikitkaRa: Charts: histograms, Pareto and box and whisker; Office 2016 charts save as themselves
# Conflicts:
#	crates/render/src/chart.rs
#	crates/ui-egui/src/ribbon.rs
2026-10-14 13:42:41 -04:00
Brandon Thomas 9479e3b17c Merge PR #537 from NikitkaRa: Charts: draw waterfall, funnel, treemap and sunburst layouts
# Conflicts:
#	crates/model/src/chart.rs
#	crates/render/src/tests.rs
2026-10-14 13:38:34 -04:00
Brandon ThomasandClaude Opus 5.5 edaef792e0 Fix up merged PRs: Edit Points hits select their shape on right click; Hyperlink sound fields in #713's tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:11:36 -04:00
Brandon Thomas 337bd35a31 Merge PR #663 from NikitkaRa: Render: don't lay out table cell text that lands off the slide
# Conflicts:
#	crates/render/src/tests.rs
2026-10-14 13:09:05 -04:00
Brandon Thomas facca31f75 Merge PR #657 from NikitkaRa: Charts: draw axis titles 2026-10-14 13:09:05 -04:00
Brandon Thomas e7a106fcc3 Merge PR #639 from NikitkaRa: Render: cap dash count so a tiny dash on a huge shape can't crash on open 2026-10-14 13:09:03 -04:00
Brandon Thomas 2dcfbdaff4 Merge PR #600 from NikitkaRa: render: 3-D contours 2026-10-14 13:08:59 -04:00
Brandon Thomas d48d66b7f8 Merge PR #597 from NikitkaRa: render: 3-D light rigs and materials, per-side extrusion shading 2026-10-14 13:08:58 -04:00
Brandon Thomas 5d4e08733b Merge PR #595 from NikitkaRa: Render 3-D extrusions: sides under turned cameras (3-D slice 1)
# Conflicts:
#	crates/render/src/tests.rs
2026-10-14 13:08:58 -04:00
Brandon Thomas 4dea355f02 Merge PR #554 from NikitkaRa: Pptx: round-trip comments, links, shows, groups and inherited placeholders 2026-10-14 13:08:53 -04:00
Brandon Thomas 5334442eb5 Merge PR #507 from NikitkaRa: UI: seeded whole-window soak with memory and timing bounds 2026-10-14 13:08:47 -04:00
Brandon Thomas 6f2b41f236 Merge PR #502 from NikitkaRa: Engine: seeded editor soak tests; tiny charts no longer blank the slide
# Conflicts:
#	crates/render/src/tests.rs
2026-10-14 13:08:46 -04:00
Brandon Thomas bce94027ad Merge PR #486 from NikitkaRa: Charts: pie and doughnut data labels use the number format (#324) 2026-10-14 13:08:45 -04:00
Brandon Thomas 215fed001e Merge PR #478 from NikitkaRa: Render: cap RGBA conversion and bound the failed-image cache (#402) 2026-10-14 13:08:44 -04:00
Brandon Thomas 6484091328 Merge PR #476 from NikitkaRa: Render: budget shape path-gradient work on dense outlines (#404) 2026-10-14 13:08:44 -04:00
Brandon Thomas 271822164f Merge PR #437 from NikitkaRa: Metafile: clip EMF and WMF drawing to rectangle regions
# Conflicts:
#	crates/render/src/tests.rs
2026-10-14 13:08:42 -04:00
Brandon Thomas 9fab337cd2 Merge PR #157 from LloydNicholson: Charts: value axes start above zero when the values sit high, as in Office 2026-10-14 12:57:19 -04:00
Brandon Thomas 3635bdc8ba Merge PR #713 from nagasakimark: Slide show: click-triggered animations, per-slide state and hit testing 2026-10-14 12:53:34 -04:00
Claude 887ea1e706 Slide show: click-triggered animations, per-slide state and hit testing
Make the slide show behave like PowerPoint for interactive decks.

- Hit testing resolves the topmost visible shape under the pointer.
  Non-interactive shapes block shapes beneath them; the hand cursor
  shows only over interactive shapes.
- Click-triggered animations (interactive sequences) play on shape
  click, repeat after their last step, and apply in click order so
  cycling "score ring" shapes work.
- Each slide keeps its own progress: returning to a slide through a
  link or Back restores hidden shapes and animation state.
- A shape with a link and an animation follows the link immediately;
  its animation clock only runs while the slide is shown and resumes
  with the remaining time on return.
- With advance-on-click off, background clicks still play animation
  steps but never change slide.
- A click on a playing step completes it at once.

Docs (gaps, animation and slide show parity, roadmap) are updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 17:22:23 +09: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 fd1b0a1965 Charts: draw the axes' titles 2026-10-14 04:12:18 +03:00
Nikita Rakitin 71b02327cf Charts: category axis orientation (maxMin) read, written and drawn; horizontal bars run bottom-up 2026-10-14 03:16:35 +03:00
Nikita Rakitin ca2af8fe30 Render: cap a stroke's dash count so a tiny dash on a huge shape can't abort on open 2026-10-14 03:14:28 +03:00
Nikita Rakitin 8e124d32a8 Charts: clustered bar widths from gap width and overlap as fractions of one bar; schema defaults when absent 2026-10-14 03:09:16 +03:00
Nikita Rakitin cbc6cd0e34 Charts: draw data-point fills on columns and bars, smoothed lines, and the file's chart text colour 2026-10-14 03:03:16 +03:00
Nikita RakitinandCursor c176d42bb4 Charts: polar radar, stock high-low lines and up/down bars, combo sample
Radar and filled radar charts are drawn polar: spokes per category,
polygon gridlines and value labels up the first spoke. Stock charts
draw high-low lines with close dashes, or up/down bars between open
and close, and are saved as c:stockChart (hiLowLines, upDownBars)
instead of a line chart; c:upDownBars is read, and chart.options takes
upDownBars. New stock charts start as high-low-close and new combo
charts as columns with a line.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 01:31:40 +03:00
Nikita Rakitin 768641615a Render: draw chart trendlines
Fit linear, exponential, logarithmic, polynomial, power and moving-average
lines, including forecast, and draw them with the equation and R² label.
2026-10-14 01:29:51 +03:00
Nikita Rakitin ad7af60510 render: 3-D contours 2026-10-14 01:29:23 +03:00
Nikita RakitinandCursor 210df9a3d1 Charts: keep and draw region map charts
Read the regionMap chartEx layout as a RegionMap chart (regions and
their colour values), write the part back as read while unchanged, and
when edited rebuild it with the original geography (projection, culture
and cached boundaries) carried over. With no map data in the repo, the
renderer draws each region as a value-coloured tile with a colour scale
and a note that the map itself is not drawn.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 01:23:54 +03:00
Nikita Rakitin ab6051894d render: 3-D light rigs and materials; extrusion sides lit per side 2026-10-14 01:23:54 +03:00
Nikita Rakitin 27988aaa24 Render 3-D extrusions: sides swept behind the face under turned cameras
sp3d extrusionH (with extrusionClr, srgb or scheme) under a camera that
turns the shape now draws the shape's sides: its outline swept from the
back face to the front along the camera's view of the depth axis, in the
side colour shaded, before the face. camera::project3 projects points
off the shape's plane.
2026-10-14 01:19:18 +03:00
Nikita RakitinandCursor b3420a0b04 Charts: multi-level treemaps and sunbursts; inclusive box quartiles
Read, keep and write every cx:lvl of a chartEx category dimension,
build a category tree from runs of parent labels, and draw treemaps as
nested squarified groups with banners and sunbursts as one ring per
level. Box & whisker honours quartileMethod="inclusive" (QUARTILE.INC)
on import, render, save and the chart.options command.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 01:16:09 +03:00
Nikita RakitinandCursor 15daed6ca4 Charts: histograms, Pareto and box and whisker; Office 2016 charts save as themselves
Histograms and Paretos bin their observations (bin count, bin width or
Scott's rule) and draw as touching columns, a Pareto with its cumulative
line on a percentage axis. Box and whisker charts draw exclusive-quartile
boxes, 1.5 IQR whiskers, means and outliers per category group.

Edited and new Office 2016 charts are written as chartEx parts from the
model (with the plain-chart fallback), so a waterfall stays a waterfall.
The chart menus list all seven types, and chart.options sets bins and
waterfall totals.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-14 01:08:13 +03:00
Nikita Rakitin f9d5a43174 Round-trip comments, links, shows, groups and inherited placeholders
An owned corpus of those element kinds survives open, save and reopen.
Paragraph default run properties, including a link, and action sounds
were dropped on save, so import and export now keep them.
2026-10-13 23:43:03 +03:00
Nikita RakitinandCursor 0d47da07e5 Charts: draw waterfall, funnel, treemap and sunburst layouts
These Office 2016 charts were drawn as plain columns. Now:
- waterfall: bars float from the running total, total points
  (cx:subtotals, now read into Chart.subtotals) stand on the axis and
  reset it, increases/decreases/totals take accents 1-3 with a matching
  legend, and connectors join each bar to the next;
- funnel: centred bars as wide as their value, category labels on the
  left and values inside;
- treemap: squarified tiles in proportion to their value, labelled;
- sunburst: the innermost level as a ring with an open centre.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 23:16:23 +03:00
Nikita RakitinandCursor e9315bc141 UI: seeded whole-window soak with memory and timing bounds
ui_soak_tests.rs drives the app through the egui test harness with seeded
random clicks, drags, keys (plain, Ctrl, Shift), typing and scrolling over the
sample deck. Every ten actions it checks that every document validates, the
selection is in range, undo, journal, thumbnail and texture caches stay
bounded, and no command or render panic was caught; at the end, that input
really reached the editor and the mean frame stays under 250 ms. Two seeds x
150 actions run in CI; DECKCRAFT_UI_SOAK_STEPS/SEED run it long.

Panics swallowed by the guards were invisible to tests: Session now counts
them (panics_caught) and deckcraft_render::panics_caught() counts render
panics drawn as blank. Textures::thumb_count exposes the thumbnail cache size.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 22:09:48 +03:00
Nikita RakitinandCursor 85833cf5f5 Engine: seeded editor soak tests; tiny charts no longer blank the slide
soak_tests.rs drives every non-file command with plausible and hostile
parameters over a ~100-slide deck, checking after each step that the
document validates, the selection is in range, the undo stack is bounded,
undo then redo restores the exact document, and every 100 steps that the
deck saves and reopens as .deckcraft and .pptx. Four seeds x 400 steps run
in CI (under a second); DECKCRAFT_SOAK_STEPS/SEED run it long.

The long soak found that a chart a few points wide panicked in f64::clamp
(label gutter min above max), and the render guard then blanked the whole
slide. chart.rs now uses a non-panicking clamp_soft for the gutters and the
zero line; a render test draws tiny charts next to a shape without the
guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 21:50:23 +03:00
Nikita RakitinandCursor 7d23e4670b Charts: pie and doughnut data labels use the number format (#324)
Pie and doughnut data labels still went through fmt_num, which rounded
anything non-integral to one decimal (999.99 drew as "1000.0"). They now
use Chart::data_label like the other label paths (series format, else
axis format, else General), and fmt_num is gone.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 21:01:43 +03:00
Nikita RakitinandCursor 201ab63c48 Render: cap RGBA conversion and bound the failed-image cache (#402)
decode_at accepted up to 400 million pixels and then called to_rgba8, which
the decoder's allocation limit doesn't cover (a grey image converts to four
times its decoded size), and every picture that failed to decode was kept,
bytes and all, for the life of the process.

- Raster decodes check the RGBA size (512 MiB cap) from the header before
  decoding and again before the conversion.
- The failed-source cache keeps at most 256 entries and 64 MiB of encoded
  bytes, oldest forgotten first; a larger failed input isn't kept, and a hit
  must be the same Arc.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 20:52:20 +03:00
Nikita RakitinandCursor ce878ef74e Render: budget shape path-gradient work on dense outlines (#404)
A shape path gradient tested every raster pixel against every flattened
outline edge, so an outline with tens of thousands of segments cost
billions of tests and stalled rendering. The outline is now simplified
before rasterising so pixels x edges stays under 64M: points closer than
a raster pixel are dropped first, then every k-th point is kept, with
each polygon left closed and at least 8 edges.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 20:49:02 +03:00
NikitaandCursor 4fee02636a Metafile: clip EMF and WMF drawing to rectangle regions
INTERSECTCLIPRECT, EXCLUDECLIPRECT and EXTSELECTCLIPRGN limit what later records paint, including a region made of several rectangles. A rotated map stores the bounds of the clip rectangle.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-13 17:57:34 +03:00
NetterSilver 35312529e1 slide.colorAt: the colour the slide is drawn with at a point (#367)
A read-only command, {slide?, x, y (slide units), scale?}: the slide is rendered and
the pixel at the point is returned as {color: "RRGGBB", alpha, x, y}. This is what the
Eyedropper takes, and what scripts and MCP use to read a colour off a slide. A point
outside the slide, a missing or non-numeric coordinate or an unknown slide is an error.
2026-10-13 16:41:57 +02:00
Brandon ThomasandClaude Opus 5.5 8ee082f257 Render: 3-D shapes' faces are lit even without a bevel
A shape with scene3d and sp3d but no bevelT was drawn in its flat fill
colour. PowerPoint lights the front face from the light rig whether or
not there is a bevel, so a plain 3-D rotated rectangle is lighter than
its fill. Model the face with the same threePt approximation as the
bevel (no rim), for solid fills.

Wild 3-D slides: s8 6.35 -> 4.26, s9 19.74 -> 17.68. Corpus unchanged
except lo tdf114848 s4 2.13 -> 1.94.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 08:16:41 -04:00