Commit Graph
566 Commits
Author SHA1 Message Date
AxelandClaude Opus 5.5 0e85e9e5ec Esperanto as a text language (#1142) (#1204)
Esperanto in Character › Language (panel, Properties, style options),
mapped to the BCP 47 tag eo, with English-style typographer's quotes.
IDML keeps the name as written ($ID/Esperanto). Not hyphenated yet:
morpheme-based hyphenation follows in #1201.


Claude-Session: https://claude.ai/code/session_01Y9j7XJDCmPc8UZLs9cTxtu

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 13:16:42 +01: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
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
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 cf0c6971d6 doc: repair parent based_on links in one graph walk (#2244) 2026-11-03 21:29:58 -05: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 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
Tex Jernigan e1910529a7 Frames with a nested image: hit inside the frame, take a placed graphic; replacing keeps the crop; open on a usable layer (#2226)
* Frames holding pasted-in images are hit inside the frame, take a placed graphic; documents open on a usable layer

A frame with items pasted into it (how a document from InDesign keeps a cropped photo) was hit
through its children like a group, so the whole uncropped image counted: a click on the empty
page beside such a photo selected it, and nothing could be deselected there. It is now hit by
its own area, as it is drawn clipped. Such a frame holding only graphics also takes a placed or
dropped graphic (Item::takes_graphic), which fills it as an empty or graphic frame is filled.

A document opened with new objects going to its top layer even when that layer was hidden and
locked (a dieline), so a placed graphic showed as an empty frame outline. It now opens on the
topmost layer that is shown and unlocked (Document::working_layer).

* Place: a graphic replacing the one a frame shows keeps the frame's crop and zoom

Placing or dropping into a frame that shows a graphic (in it, or as the one graphic pasted into
it) filled the frame afresh, so the crop and zoom chosen for the old picture were lost. The new
graphic now covers the old one's area, centred on it: an edited copy of the same picture lands
exactly where the old one was.

* Move the replace-keeps-crop and open-on-a-usable-layer changes to their own PRs

Review asked for them to be checked against reference app behaviour on their own. This PR keeps
the frame hit area and Item::takes_graphic. Reverts 8ea0bc16 and drops Document::working_layer.

* Move Document::working_layer and its test to #2267
2026-11-03 17:21:35 -05:00
Tex Jernigan ae5be94865 Layers: a document opens on its topmost shown, unlocked layer (#2267)
A document opened with new objects going to its top layer even when that layer was hidden and
locked (a dieline), so a placed graphic showed as an empty frame outline. Document::working_layer
picks the topmost layer that is shown and unlocked (the top layer when there is none); DocState::new
and the fallback after the active layer is deleted use it.
2026-11-03 17:15:53 -05:00
aiongg 8b0d264875 Merge pull request #1856 2026-11-03 20:24:26 +00:00
aiongg 6df8d6d934 Apply review fixes
- crates/doc/src/vars.rs
2026-11-03 19:03:59 +00:00
aiongg 7892952fe6 Merge pull request #1222 2026-11-03 18:36:57 +00:00
aiongg ee5ea72aea Merge pull request #1857 from Silvertree2010/fix/h2736-iso-date-parser-accepts-any-char
Reject ISO timestamps without ':' between hour and minute
2026-11-03 12:58:13 -05:00
Dylan M. Taylor 74eab18d16 Assets: index placed files by content so importing many graphics stays linear (#2181) 2026-11-02 22:51:17 -05:00
makesomethingshit 5c364f9897 #1620: Port parent resizing to current layout modules 2026-11-01 15:18:55 +09:00
Brandon Thomas faa2bf5089 Merge storytold/main into PR #1239
# Conflicts:
#	crates/doc/src/xref.rs
2026-10-31 01:00:56 -04:00
Brandon Thomas 8ecbd44c7e Merge pull request #2058 from Silvertree2010/fix/h4112-cross-reference-format-a-inside
Skip quoted attribute values when finding the end of an xref tag
2026-10-31 01:00:17 -04:00
texjer 06d29fe3a6 Parents: single-sided pages in a spread show the parent page in their place 2026-10-31 00:04:41 -04:00
aiongg 4b29760ffd Merge track 6
Conflicts: dialogs.rs dialog widths (both kept); i18n/*.rs adjacent rows (both kept).
2026-10-30 23:57:22 +00:00
aiongg 0979d0b722 Merge track 4 (pages, tables)
Conflicts: dialogs/tests.rs and i18n/*.rs: adjacent additions, both kept.
2026-10-30 23:57:01 +00:00
aiongg aae929eb97 Merge track 3 2026-10-30 23:56:48 +00:00
aiongg 35697cb807 Merge PR #1255: TOC separator and style notation
crates/idml/src/tests.rs: kept the PR's TOC tests, dropped the duplicate copy from #1249
crates/engine/src/tests/idml.rs: main's createBookmarks plus the PR's right-indent separator
crates/ui-egui/src/dialogs.rs: main's labelled_by fields plus the PR's special-character menu
crates/ui-egui/src/i18n/*.rs: kept both added rows
2026-10-30 23:26:42 +00:00
aiongg 450b3ae963 Merge PR #1679: Convert Text to Table and Table to Text
crates/engine/src/cmd/table.rs: both export lists.
crates/engine/src/cmd/table/structure.rs: #1676's Insert Table validation, #1679's MAX_CONVERTED_CELLS.
crates/ui-egui/src/dialogs.rs, dialogs/tests.rs: kept #1676's Insert Table dialog, Insert Pages and #1679's Convert dialogs and tests.
crates/ui-egui/src/menus/tables.rs, tests.rs, ui_commands.rs: flat Convert Cell items; Convert dialogs in the menu.
crates/ui-egui/src/i18n/*.rs: kept both sides' keys.
2026-10-30 23:25:57 +00:00
aiongg 89ef0e3d81 Merge PR #1606: Paragraph Shading and Border pages
crates/ui-egui/src/panels/properties.rs, properties/object.rs: main's split module kept; preview_row and paint_corner_shape exported for the shading corner menus
crates/ui-egui/src/panels/properties/tests.rs: both sides' tests kept
crates/ui-egui/src/dialogs/tests.rs: main's tests kept; the border test uses the new corner labels; the shading layout test added
crates/ui-egui/src/i18n/*.rs: union of keys without duplicates
crates/ui-egui/src/dialogs.rs: the corner shape face uses corner_shape_button (no hard-coded colour in the dialog)
2026-10-30 23:17:40 +00:00
aiongg 0e4cb1f294 Merge PR #1451: Effects blend modes for Drop Shadow, Inner Shadow and Outer Glow
crates/ui-egui/src/effects_dialog.rs: kept both the angle dial tests (main) and the blend mode test (PR); the stray 'The dialog's body.' doc line moved back onto show.
2026-10-30 23:16:03 +00:00
NetterSilverandClaude Haiku 5.5 3fec4d32d8 Skip quoted attribute values when finding the end of an xref tag
Found while testing crates/doc/src/xref.rs:85-91 (expand)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 22:52:52 +01:00
moppeeer 3711ac05ba Merge remote-tracking branch 'origin/main' into effect-blend-modes
# Conflicts:
#	crates/render/src/fx.rs
2026-10-30 21:57:48 +01:00
aiongg 92327dcc4c Merge track b: swatches, canvas, tools and tables PRs
Conflicts: engine/src/tests.rs and i18n/*.rs: adjacent additions from both sides, both kept.
2026-10-30 20:49:48 +00:00
aiongg 4638b19387 Merge PR #1257: TOC: generate and refresh PDF bookmarks
crates/ui-egui/src/dialogs/tests.rs: kept HEAD, appended #1257's new test
2026-10-30 19:46:49 +00:00
aiongg 52ea6806df Merge PR #1496: Find/Change: Change Format, with a character or paragraph style
crates/ui-egui/src/dialogs/tests.rs: kept HEAD, appended #1496's new test
crates/ui-egui/src/i18n/*.rs: kept both sides' rows (unique keys)
2026-10-30 19:45:28 +00:00
aiongg 4834f41b03 Merge PR #1166: Native files: preserve automatic Ruby, Kenten and list-tab overrides 2026-10-30 19:44:36 +00:00
aiongg 19a8a7ae66 Merge PR #1463: Paragraph rules: Type, Gap Color and Tint, Keep In Frame
crates/ui-egui/src/dialogs/tests.rs: kept both sides' appended tests
2026-10-30 19:44:13 +00:00
Claude 239ac1bbb2 Cross-references: saved text counts as generated only on an exact match
An imported cross-reference's text is regenerated only when it is exactly what its format
generates for its destination (Document::drop_generated_xref_text, once the destinations are
resolved); "Page 7, revised" is an edit and is kept, as is the text of one whose destination is
gone. The loose in-order match (matches_format) is gone. Page numbers are recognised by the
instance's AssociatedTextVariable (a cross-reference page number variable, or InDesign's name
for it when the file doesn't define it) rather than its Name, and text inside tracked-change
wrappers counts as shown (insertions in, deletions out). Export writes generated text with its
page numbers as the live variable too, so it reads back as generated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
2026-10-30 17:02:17 +00:00
Claude d48b650320 Merge storytold/main into xref-edited-text
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa

# Conflicts:
#	ROADMAP.md
2026-10-30 16:36:59 +00:00
Brandon Thomas 226b2c3c03 Merge storytold/main into PR #1985 2026-10-29 21:53:38 -04:00
Brandon Thomas 211619e949 Merge pull request #1935 from Silvertree2010/fix/1883-bug-report-designcraft-error-mes
Open documents whose items share an id
2026-10-29 21:53:07 -04:00
Brandon Thomas cddf074cc4 Merge pull request #1868 from Hamza0101/fix/table-allocation-cap
Tables: a shape a table cannot hold is clamped, not allocated (#1583)
2026-10-29 21:51:53 -04:00
Brandon ThomasandClaude Opus 5.5 84801932f2 Renumbering duplicate ids stops at the top of the id range instead of overflowing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 21:39:23 -04:00
moppeeerandClaude Opus 5.5 d42333fb9d Story: para_at's doc comment back on para_at
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:10:58 +01:00
moppeeer e16e0c4d61 Merge remote-tracking branch 'origin/main' into paragraph-rule-types
# Conflicts:
#	crates/compose/src/lib.rs
#	crates/doc/src/attrs.rs
#	crates/idml/src/export.rs
#	crates/idml/src/import.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/i18n.rs
2026-10-29 12:08:24 +01:00
moppeeer c4479a1152 Merge remote-tracking branch 'origin/main' into find-change-format
# Conflicts:
#	crates/engine/src/cmd/find.rs
#	crates/engine/src/cmd/style.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/icons.rs
2026-10-29 12:07:04 +01:00
moppeeer 165d8c65ac Merge remote-tracking branch 'origin/main' into paragraph-shading-indesign
# Conflicts:
#	ROADMAP.md
#	crates/doc/src/attrs.rs
#	crates/idml/src/export.rs
#	crates/idml/src/import.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/panels/properties.rs
2026-10-29 11:50:25 +01:00
moppeeer 35c96ee866 Merge remote-tracking branch 'origin/main' into table-convert-dialogs
# Conflicts:
#	crates/doc/src/table.rs
#	crates/engine/src/cmd/table.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/i18n.rs
#	crates/ui-egui/src/menus.rs
2026-10-29 11:48:24 +01:00
moppeeer 8e42d71af1 Merge remote-tracking branch 'origin/main' into codex/preserve-cjk-auto-overrides
# Conflicts:
#	crates/doc/src/attrs.rs
#	crates/format/src/lib.rs
2026-10-29 11:44:35 +01:00
moppeeer 94dad76ac1 Merge remote-tracking branch 'origin/main' into codex/toc-right-indent-separator
# Conflicts:
#	crates/idml/src/import.rs
#	crates/ui-egui/src/dialogs.rs
#	crates/ui-egui/src/i18n.rs
2026-10-29 11:44:26 +01:00
moppeeer c0b4746c8d Merge remote-tracking branch 'origin/main' into codex/toc-pdf-bookmarks
# Conflicts:
#	crates/engine/src/cmd/style.rs
#	crates/idml/src/export.rs
#	crates/idml/src/import.rs
#	crates/ui-egui/src/dialogs.rs
2026-10-29 11:44:22 +01:00
moppeeer b6fec896f9 Merge remote-tracking branch 'origin/main' into effect-blend-modes
# Conflicts:
#	crates/doc/src/item.rs
#	crates/idml/src/export.rs
#	crates/idml/src/import.rs
#	crates/ui-egui/src/effects_dialog.rs
2026-10-29 11:42:14 +01:00
VoiceLessQ 30a0f08698 Story: copy a paragraph's format for all new returns at once (#1588)
insert_with_raw gave each return in the inserted text its own
Vec::insert of the paragraph's format, and each insert moves every
format after it. A ParaFormat is 2,888 bytes, so the time grew with
the square of the returns: Story::with_text took 2.2 s for 10,000
returns, 15.8 s for 20,000 and 90 s for 40,000. Placing a plain-text
file goes through it. The copies now go in with one splice.
2026-10-29 00:08:22 -02:00
Claude 11f4364705 Merge storytold/main (v0.14.0) into xref-edited-text
The IDML import and export of edited cross-reference text move to import/story.rs and
export/story.rs with upstream's split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgGsJkVe5GYG9qK6VFdECa
2026-10-28 18:09:43 +00:00