* feat(edit): remove all links command and context menu (#539)
- Expose 'edit.remove_links' and 'edit.remove_all_links' commands to remove all links across the document or on specified pages.
- Add right-click context menu options for links: Properties, Delete, and Remove all links in both Link tool and Select tool modes.
- Extend automation tool 'links_remove' with optional 'pages' parameter and removal count.
- Add notification feedback in UI for link deletion.
- Mark 'edit.remove-all-links' as shipped in Parity with evidence tests.
- Add unit and integration tests covering automation, engine, and UI undo/redo.
* Remove all links: one command id, catalog rows, link menu only on a link
- Drop the duplicate edit.remove_all_links command (same label as the
existing edit.remove_links, so it showed twice); edit.remove_links now
runs remove_all_links with its toast.
- Add the toast strings (No links to remove, Removed 1 link, Removed {n}
links) to all 20 catalogs.
- The canvas context menu shows the link items only when the right-click
hit a link (LinkView::context, set per right-click), so a link left
selected no longer takes over the comments menu, and the Link tool no
longer replaces the comments menu away from links. Regression test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Restore the PR's links_remove pages test (lost with the workdir conflict)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix: recognize paragraph drafts as unsaved work (Issue #811)
* fix(color): honour the /Lab colour space /WhitePoint (#1203)
The old path fed every Lab value to the bundled ICC transform as if the
space's white point were D50, so a /Lab space with any other /WhitePoint
(e.g. D65 [0.9505 1 1.089]) rendered off by several levels per channel
and a D65 blue came out 45 levels too red.
Map L*a*b* to XYZ in the space's own white coordinates (ISO 32000-2
§8.6.5.4), Bradford-adapt it to D65 and convert to sRGB directly, as
Poppler does. Missing or degenerate white points fall back to a flat
white and hostile components are clamped without panicking.
Add a render regression that checks the five reported flat patches of
the D65 white-point fixture against their CIE sRGB values.
* Lab: map normalised Indexed palette components onto L*/Range; drop unused LAB.icc
An /Indexed palette over Lab passes its entries as byte/255 (manual_scale),
which the new Lab conversion read as raw L*a*b* and drew near black. Map
them onto L* 0..100 and the a*/b* /Range, with a regression test. Record the
patch as hayro-interpret (25) in vendor/README.md, and remove LAB.icc (no
longer referenced) with its ATTRIBUTION, NOTICE and assets README entries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Main gates: rustfmt tests/viewer.rs; a type alias for the refresh-steps array (clippy type_complexity)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat: presentation (.pptx) export (#1137)
- Implement OpenXML PresentationML (.pptx) generator in crates/export/src/pptx.rs:
- Generate [Content_Types].xml, _rels/.rels, core properties, presentation.xml
- Build slide master, blank slide layout, and DrawingML theme
- Render slides per page: largest text block as title shape, remaining paragraphs as body text box with font size, bold, italic, and color formatting
- Embed images with proper DrawingML picture shapes and relationships
- Generate DrawingML table shapes with column grid and span merging
- Wire OfficeFormat::Pptx into crates/engine/src/compare.rs and export_office
- Register export.pptx command and mark Presentation (.pptx) Ready in catalog
- Support pptx in automation doc_export_office tool
- Wire export.pptx into UI commands and file save dialog
- Add unit and integration tests across crates/export, engine, automation, and ui-egui
- Update create.export-pptx parity feature evidence and docs
* pptx export: saturating slide positions, matching cell-border tags, theme ea/cs fonts, package test
- Heights and the running vertical position use clamped/saturating arithmetic, so a hostile
text size or image rectangle (1e300, NaN, inf) can't overflow i64; the item loop uses get().
- The table cells' a:lnR and a:lnT borders were closed with </a:lnL>, which made every slide
with a table malformed XML; they now close with their own tags.
- The theme's major/minor fonts carry the schema-required a:ea and a:cs children.
- New test walks the produced zip entry by entry (sizes, inflation, central directory), checks
every XML part's tags balance, the required parts, content-type overrides, relationship
targets and that no placeholders are used; a hostile-sizes test covers the overflow.
- Test literals gain main's Block/Image rotation and size fields.
- Parity notes say what is still unverified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: KrzysztofC <krzysztofc@localhost-live.lan>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Add 'Replace pages…' action to the Organize Pages toolbar, organize grid thumbnail context menu, and Pages panel context menu to replace selected pages.
- Add ViewAction::ReplacePages triggering replace_pages_dialog()
- Expose 'Replace pages…' button with 'replace' icon on the organize toolbar
- Expose 'Replace pages…' on the organize grid and Pages panel thumbnail context menus
- Update parity evidence for organize.replace-pages
- Add integration tests for toolbar and context menu replace actions in crates/ui-egui/tests/editing.rs
Co-authored-by: KrzysztofC <krzysztofc@localhost-live.lan>
* view: check Shift-Command-G before Command-G for find navigation (#810)
* fix: recognize paragraph drafts as unsaved work (Issue #811)
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* view: check Shift-Command-G before Command-G for find navigation (#810)
* Tests: the find shortcut test waits for find by a deadline
(cherry picked from commit eaf3180bd8ebb353b3d8c5ca7b9ef7548ed55c37)
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* create: lift TIFF decoding buffer limit to allow print-sized images (#665)
By default, the tiff crate limits decoded buffer size to 256 MiB.
Set Decoder::with_limits(Limits::unlimited()) to match PNG decoding
behavior and prevent 'decoder limits exceeded' on large images.
* create: cap the TIFF decode buffer at 2 GiB instead of lifting it entirely (#665)
A few bytes claiming enormous dimensions must still be refused, not allocated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>