Commit Graph
4720 Commits
Author SHA1 Message Date
Hamza 3c8a3230ff Copy: the anchored-frame scan skips a copy that keeps no story, and reads each anchored item once
From review: a copied graphic keeps no story, so there is nothing to scan; and anchored_items already lists a group's members, so walking each item again visited them twice through unbounded recursion. A text frame inside an anchored group (as IDML import anchors an InDesign group) is tested.
2026-11-05 16:20:38 +05:00
Hamza 9083bd5adc Copy: a text frame anchored in a copied frame keeps its text
clip_doc kept the stories of the text frames among the copied items, and a text frame anchored in a frame's text (as IDML import makes them) is in its host's story, not among them. Its story was dropped from the clipboard, and the paste gave the anchored frame a new empty story. The stories of text frames anchored in the kept stories, and in theirs, are kept too.
2026-11-05 15:32:23 +05:00
4f3bb5340e Pages: parents and alternate layouts; export and print layouts and versions (#1342)
* Pages: more parents and alternate layouts as columns in the Pages panel

Parents
- layout.parents.duplicate copies a parent spread (pages and items) under the next free prefix.
- layout.parents.options also renames the prefix (1-4 characters, no "-") and the name; basedOn is now optional.
- layout.parents.new validates prefix and name and takes basedOn.
- Pages panel: a "+ New Parent" row adds B, C… in one click. The parents' context menu and the panel menu have New Parent…, Duplicate Parent Spread, Parent Options… and Delete Parent, named after the selected parent, or a submenu of the parents when none is selected. A new Parent Options dialog has Prefix, Name and Based on Parent.

Alternate layouts
- Section.layout marks the section that starts a layout; Document::layouts() lists them.
- layout.createAlternate copies one layout (from), not every page; new layout.alternate.duplicate, .delete and .options (rename, resize).
- Each layout starts a spread of its own; sections now follow their pages when pages are inserted or deleted.
- Pages panel: with more than one layout, each is a column side by side with a header (name, size, ▾ menu: create, duplicate, options, delete) and a + column to add one.

Tests cover the commands' happy and error paths, undo, serde, and the panel's menus and columns.

* Pages: address review of parents and alternate layouts

- Deleting a layout's first page keeps the layout's name when another section lands on the same page.
- A parent's full label (prefix-name) must be unique; parents may still share a prefix.
- Alternate layout names round-trip through IDML (Section AlternateLayout / AlternateLayoutLength).
- The Pages panel's selected parent is per document and no longer saved in ui.json.
- Layout ▸ Parent Options… and Alternate Layout Options… open the Pages panel's dialogs.
- The Pages panel computes the layouts once per frame.

* Export: layouts and versions in one export, with presets; print chosen layouts

- file.exportBatch writes the chosen alternate layouts (a file per layout, or all in one PDF) in several versions at once: PDF with any marks, bleed and standard, PNG or JPEG at a resolution. Each version goes in a folder of its own, and file names come from a template ({document}, {layout}, {version}, {date}). Names are made safe and unique. dryRun lists the files; without a dir the files come back as base64 (web).
- Export presets: file.exportPresets, file.saveExportPreset, file.deleteExportPreset, kept in prefs.json. Built-ins: Print + Screen, Press PDF per Layout, Images per Layout, All Layouts in One PDF.
- file.print takes layouts and separateJobs (a job per layout, titled after it).
- File ▸ Export Layouts and Versions… dialog: preset, layouts, versions (add from templates, duplicate, remove, quick PDF choices or custom marks), name template, and a live list of the files it will write. It opens from a layout column's ▾ menu as "Export Layout…". The desktop asks for a folder; the web downloads each file.
- The Print dialog prints chosen layouts, together or separately; the Export PDF dialog fills the page range from a layout.
- crate::io::create_dir_all keeps folder creation inside the automation write root.

* Export: address review of layouts and versions

- An exported image is capped at 80 million pixels, the limit EPUB page images already use.
- The Print dialog stays open and says why when no layout is chosen.
- Clicking a layout column's header leaves Edit Parents before going to the layout's first page.

* Pages, Export: address maintainer review of layouts and versions

- Sections (and the layouts they start) follow a moved page, as they do inserted and deleted
  ones: moving a page across a layout boundary no longer moves the other pages between layouts.
  Delete and move share `settle_sections`.
- Alternate Layout Options resizes only pages whose size changes: renaming a layout no longer
  forces every page to the first page's size.
- Export file and folder names that are Windows device names (CON, NUL, COM1…) get a leading `_`.
- An export without `dir` refuses past 512 MB of files instead of building them all in memory.
- A file that fails partway through an export to a folder says how many were already written.
- Parent Options and Print keep the dialog open, with what was typed and why, when the engine
  refuses.
- A duplicated layout's default name stays within the 100-character limit.
- rustfmt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Pages: Alternate Layout Options sends the size only when it changed

The dialog starts at the layout's first page's size, so the engine couldn't tell a rename from a
resize to that size. The dialog now leaves out a width or height still at its starting value, and
`layout.alternate.options` resizes every page of the layout when a size is given, as before.
The test moves to the UI, where the size was coming from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 06:02:27 +01:00
a794037761 About: credits tables fit without side-scrolling and their columns resize (#2264)
* About: credits tables fit without side-scrolling and their columns resize

The Contributors table and the Models table were egui Grids inside a
two-way scroll area: they opened wider than the dialog, so they scrolled
sideways, and Company and Model sat almost touching. Both are now
egui_extras tables. Each column opens at the width of its header and widest
cell, the spare width goes to the text columns (Name; Company and Model),
and every column edge can be dragged. Widening a column grows the table
like a spreadsheet, and only then does it scroll sideways; the header stays
put while the rows scroll. Counts and dates are right-aligned and every
cell is vertically centred.

The sorted column stays highlighted and its direction shows on the
toolbar's sort-order button, so headers no longer reserve room for an
arrow. The opening widths come from fit_widths, a pure function with unit
tests that a fitted table fills its room exactly and that only the text
columns give way when room is short.

The About dialog opens 820 points wide, so every column fits at its natural width.

The workspace egui_extras entry, which no crate used, drops its svg feature, so the table
brings in no second SVG renderer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Apply review fixes

- crates/ui-egui/src/about.rs
- crates/ui-egui/src/credits.rs

* Let every credits column be dragged, and refit changed tables

The last column was egui's remainder column, which has no drag handle, so
it could only be resized from the edge before it. It is now an ordinary
column with its own handle.

A table keeps its column widths, so switching to a longer name left the
Name column at its old width and clipped the text. The table now goes
back to the opening fit whenever that fit changes: a longer widest cell
or a resized window. Dragged widths are dropped at that point.

fit_widths could overflow the room when one column hit the minimum,
because the other columns did not take up its share. Columns now give
way in proportion to their width above the minimum.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Refit credits tables on what they measure, not the fitted widths

Comparing the fitted widths missed the case it was meant for. Name is the
only growing column, so a longer name takes its extra width from the
spare room and the fit comes out the same: a dragged Name width stayed,
clipping the longer name.

It could also drop dragged widths by accident. The fit comes from the
available width inside the scroll area, which scrolling can nudge, so
scrolling a widened table could reset it.

The table now compares the natural widths and the clip rect's width,
which scrolling does not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-05 04:33:32 +01:00
Dylan M. Taylor 019a89d96d Pass the Linux signing key to the release workflow (#2328) 2026-11-04 17:44:40 -05:00
Mex b98687c3e1 M5: keep out-and-back cubic segments in striped strokes (#2323)
* M5: preserve out-and-back cubics in striped strokes

A cubic can travel out and back when its endpoints and first control point coincide. Include the second control point in the zero-length guard and cover its offset extent and both stripe bands.

* M5: record striped cubic regression coverage

Record the scoped cubic stroke correction without changing readiness estimates or other progress entries.
2026-11-04 15:36:05 -05:00
Dylan M. Taylor ef6c368615 Linux: let the shared makepkg job build the Arch package (#2322)
package.sh built its own Arch package with nfpm while the shared release
workflow also built one with makepkg, because has-arch defaults to true. Both
wrote designcraft-<version>-linux-<arch>.pkg.tar.zst, the draft release merges
the release-* artifacts last-writer-wins, and 0.17.0 shipped the nfpm copy,
which declared fewer dependencies than the makepkg template.

Drop arch from the formats this script builds and remove the archlinux section
from nfpm.yaml, so the shared action is the single builder. It names the
package after the .desktop bundle id, declares the same provides/conflicts
against the AUR packages, and adds the optdepends nfpm could not express.
2026-11-04 14:46:58 -05:00
Dylan M. Taylor f3bcc886dc Linux packages: require libxkbcommon-x11, which winit dlopens on X11 (#2320)
The binaries load their windowing libraries at run time, and xkbcommon's X11
keyboard module is a separate library from the core one. Nothing declared it,
so a package installed on a system without it crashes before opening a window:

  thread 'main' panicked at xkbcommon-dl-0.4.2/src/x11.rs:59:28:
  Library libxkbcommon-x11.so could not be loaded.

winit's X11 backend cannot fall back, so the dependency is required for deb,
rpm and Arch rather than recommended.
2026-11-04 13:57:08 -05:00
aiongg fb630909c4 Merge pull request #2304 from texjer/feat/finder-drop-pointer
Place: a file dragged in from the Finder fills the frame it was dropped on
2026-11-04 11:19:45 -05:00
aiongg 8b1e20fd8f Apply review fixes
- crates/ui-egui/src/app/input.rs
- crates/ui-egui/src/services.rs
2026-11-04 15:40:44 +00:00
Tex Jernigan 632df6178a Place: a graphic dropped on a frame holding a nested image replaces it (#2303)
Split out of #2073. A frame holding its image as an item pasted into it (how a
document from InDesign keeps a photo) takes a dropped graphic as a graphic
frame does: `canvas::drop_frame` uses `Item::takes_graphic` (#2226).
2026-11-04 10:40:17 -05:00
Hamza Naveed b48a9507b1 Swatches: renaming a swatch renames it on the images it colours (#2306) (#2311)
rename_swatch_refs visited every page item's fill and stroke but not the swatch applied to a placed greyscale or bitmap image (Graphic::fill), framed or in a table cell. Those images kept the old name, found no swatch, and drew in black.
2026-11-04 10:39:14 -05:00
MarekSpodBiedry df9f0656ca Master pages: skip hidden and locked layers when picking items (#2221) (#2292) 2026-11-04 07:09:20 -05:00
aiongg dffef02773 Merge pull request #1755 from Hamza0101/fix/korean-sans-fallback
Fonts: a missing Korean sans face falls back to a sans one (#1692)
2026-11-04 07:07:31 -05:00
MarekSpodBiedry 7215a559e5 Hyphenation: enable the Danish hypher patterns (#2282) (#2293) 2026-11-04 07:01:31 -05:00
Hamza 39ea3513a4 Korean fallback: spell 바탕 right, and choose the label's fallback style once 2026-11-04 12:55:57 +05:00
Dylan M. Taylor a4017a3cda Fonts: bound named instances per file, index axis settings in style strings (#2215)
* fix(fonts): bound named-instance listing and index variable-style settings

* address review: bound inspected named-instance records file-wide
2026-11-03 23:26:17 -05:00
aiongg 5309d7d81a Merge pull request #2291 from aiongg/integration-designcraft-20261104-1
Integration batch integration-designcraft-20261104-1
2026-11-03 23:25:23 -05:00
aiongg d30c2b1e66 Merge pull request #2271 2026-11-04 04:14:13 +00:00
aiongg c3ea317837 Merge pull request #2250 2026-11-04 04:14:12 +00:00
aiongg b1f67ee4e4 Merge pull request #2211 2026-11-04 04:14:12 +00:00
aiongg 6c2ab93b03 Merge pull request #2231 2026-11-04 04:14:12 +00:00
Dylan M. Taylor b46ee47982 pdf: placements of one media asset share one embedded file (#2266) 2026-11-03 23:07:05 -05:00
aiongg a2cc32a8d1 Apply review fixes
- crates/epub/src/tests.rs
2026-11-04 03:50:09 +00:00
aiongg 3326d919bb Apply review fixes
- crates/compose/src/tests.rs
2026-11-04 03:49:15 +00:00
Dylan M. Taylor e2c2266087 warichu: split long runs in one pass instead of trying every length (#2184)
* warichu: split long runs in one pass instead of trying every length

The exact split tries every line length for every start, so its work grew with
the square of the run's length, and a document can set warichu on a run of any
length. Runs longer than 512 glyphs are now split where the running advance
reaches each line's share, keeping the break minimums. The glyphs drawn with the
run find their anchor by binary search instead of a scan per glyph.

* address review: warichu split picks the break closest to the target
2026-11-03 22:32:31 -05:00
Dylan M. Taylor 7faf7029fb fix(pdf): indexed membership in page ranges, optional content and PDF/X scans (#2207) 2026-11-03 22:32:10 -05:00
Dylan M. Taylor 36da81e03b fix(textimport): bound xlsx data sources and make docx and hyphenation parsing linear (#2213) 2026-11-03 22:23:32 -05:00
Dylan M. Taylor 64c956f09e fix(render): index line style groups, stop futile glyph-cache eviction, read PDF page sizes once (#2217) 2026-11-03 22:23:11 -05:00
Dylan M. Taylor c4ed9b2210 fix: write screenshots, signing certificates and benchmark files in private temp folders (#2219) 2026-11-03 22:16:28 -05:00
Dylan M. Taylor bcc74f29c9 fix(app): log message line breaks continue the record instead of starting another (#2220) 2026-11-03 22:16:06 -05:00
texjer 8815ef7350 Place: a file dragged in from the Finder fills the frame it was dropped on
Split out of #2073. winit sends no pointer events during a drag from another
application on macOS, so a Finder drop had no pointer and never found the frame
under it. The host now gives the pointer's place on the screen
(`Services::pointer`, `PointerFn`: the system's points before the UI scale,
from `NSEvent.mouseLocation`), and `take_pending_drops` uses it for the files
that came without a pointer, divided by egui's zoom factor and made relative
to the window.
2026-11-03 21:50:08 -05:00
Dylan M. Taylor cf0c6971d6 doc: repair parent based_on links in one graph walk (#2244) 2026-11-03 21:29:58 -05:00
Dylan M. Taylorandaiongg 9437553fd4 Images: one budget for the nested SVG data images of a parse (#2254)
* images: one nested-SVG byte budget per parse

* Apply review fixes

- crates/images/src/lib.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-03 21:29:36 -05:00
Dylan M. Taylorandaiongg 1a059304f9 PPTX export: table border and paragraph lookups by index, direct charmap lookups (#2256)
* pptx: table border lookups by position, paragraph lines grouped once

* pptx: look a character up in the face's map, don't expand it

* Apply review fixes

- crates/pptx/src/table.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-03 21:29:14 -05:00
Dylan M. Taylorandaiongg 1d752d2f1f Text import: cap style names read from Tagged Text and DOCX files (#2258)
* textimport: cap style names read from files

* Apply review fixes

- crates/textimport/src/tagged.rs

---------

Co-authored-by: aiongg <67543387+aiongg@users.noreply.github.com>
2026-11-03 21:28:52 -05:00
aiongg b18ed2e7ad Merge pull request #1294 from KnottyDyes/squad/place-never-into-line-v2
Place: implicit image placement preserves lines and open paths
2026-11-03 21:17:15 -05:00
KnottyDyesandClaude Opus 5.5 5e8571d11e Geom: test that stray end handles leave a line without area
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:58:37 -07:00
Dylan M. Taylor ae93ea5115 table: refuse to split more than 1024 merged-cell owners at once (#2273) 2026-11-03 20:55:20 -05:00
aiongg 2042bd9698 Merge pull request #1302 from KnottyDyes/squad/package-pdf-soft-effects
PDF: keep hyperlinks on rasterized frames; report package PDF warnings
2026-11-03 20:55:11 -05:00
aiongg c05afc6b44 Apply review fixes
- crates/geom/src/path.rs
2026-11-04 01:54:40 +00:00
KnottyDyesandClaude Opus 5.5 b032aa26e8 PDF: test that link stand-ins add only the link to tagged PDF
The nonprinting stand-in for a rasterized linked frame keeps the frame's
story, alt text and effects for link bounds and text composition. A test
now checks that a tagged PDF of a linked frame differs from the same frame
without the link only by the link annotation: no extra structure elements
or alt text. Note why the stand-in keeps the frame's ItemId.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:20:58 -07:00
KnottyDyesandClaude Opus 5.5 5cd8d99db7 Package: report PDF warnings and keep hyperlinks on rasterized frames
Include the PDF export warnings in the package result and report. Cover
shadow and feather output in packaged PDFs with a synthetic regression test.

Preserve frame and text-range hyperlinks on rasterized frames, including
inside groups, at their original source bounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:20:58 -07:00
KnottyDyesandClaude Opus 5.5 5bd8ada171 Place: lines don't become frames when content is placed
Placing an image or media with no placement parameters used the selected
item as the frame, and so did a click of the loaded place cursor. On a
line that made a zero-height frame that kept its stroke. All three now
skip items that enclose no area (PathData::encloses_area): lines and
paths whose points all lie on one line get a new frame instead. Frames,
and open paths that enclose an area, take the content as before.

An explicit frame, x, y, spread or width behave as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 17:52:04 -07:00
Dylan M. Taylor 4071bd40e6 address review: skip a graphic whose PDF crop is too large to trace 2026-11-04 00:39:05 +00:00
aiongg b17dd017d5 Merge pull request #2287 from con3code/test/mojikumi-one-em-close-up
Mojikumi: test consecutive punctuation under the one-em line-end set too
2026-11-03 19:23:28 -05:00
con3codeandClaude Opus 5.5 3894566812 Mojikumi: test consecutive punctuation under the one-em line-end set too
The close-up test checked the half-em line-end set only; the other Japanese
base set closes up the same pairs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 09:01:20 +09:00
aiongg 823eef9838 Fix mojikumi: middle dot loses its quarter em beside a proportional (#2285)
Fixes #2281.

- crates/doc/src/mojikumi.rs
- crates/doc/tests/autocraft_regression.rs
2026-11-03 18:57:15 -05:00
aiongg fe7db96e11 Merge pull request #2168 from 4waymedia/fix/open-large-stored-assets
Format: a saved document opens whatever the size of its placed images (#2166)
2026-11-03 18:33:36 -05:00
Paul GemignaniandClaude Fable 5.1 50780180e7 Format read_entry's caller (cargo fmt)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_012xiyiD63mAukLtyDQFCQKU
2026-11-03 15:21:13 -08:00