Drop cap style through IDML as a Dropcap nested style, spaces after the cap, one-line caps, nested styles after the cap, own nested-style lists clearing an inherited drop cap style (cells and notes too), cleared styles round-tripping, tabs in right-to-left drop caps.
Conflict: ROADMAP.md: next's INDD, Interface language and Show CJK Features lines (the PR's main-merge resolution, already on next)
Conflict: crates/compose/src/lib.rs: next's warichu placement followed by the trimmed trailing spaces
Conflict: crates/compose/src/tests.rs: next's side; the PR's side repeats helpers and tests next already has
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side, with the PR's drop_caps_import_and_round_trip and its new drop_cap_fixture and nested-style clearing tests in place of next's older drop cap test
next already holds both parents of the PR's main merge (dc18c104 and main 92649ffd); the conflicts come from the two different resolutions of the same pair.
Conflict: ROADMAP.md: next's IDML, INDD and Interface language lines; the PR's PDF export line, which keeps main's Export PDF options dialog sentence that next had dropped
Conflict: crates/compose/src/tests.rs: next's side (tracked_lines and the spacing/GREP tests already sit elsewhere in next's file)
Conflict: crates/fonts/src/fontdb.rs: next's canonical_family lookup in exact_style_traits (#126)
Conflict: crates/idml/src/import.rs: next's range_format
Conflict: crates/idml/src/tests.rs: next's side; the PR's block repeats tests next already has
Test that the drop cap style counts as a leading "through 1 Dropcap" nested style, and describe the IDML form in ROADMAP. The previous drop cap commit also makes the cap reach down the text's leading rather than to where line N is set.
A one-line drop cap keeps its characters' own point size when it is smaller than the text (verse numbers), and tabs inside a left-to-right drop cap advance to the paragraph's tab stops.
IDML has no drop cap style attribute. Import reads the nested style list's leading "through 1 Dropcap" entry as the drop cap style; export writes the drop cap style as that entry. The drop cap style counts as that entry when composing, so nested styles after it start after the drop cap.
Every conflicted file resolves as in the merge of main into feat/text-editing-and-frames (this branch carries #83 and #84 up to "Merge #83 into feat/text-editing-and-frames").
Conflict: ROADMAP.md, crates/compose/src/lib.rs, crates/engine/src/cmd/text.rs, crates/fonts/src/fontdb.rs, crates/idml/src/import.rs, crates/idml/src/tests.rs, crates/ui-egui/src/canvas.rs, crates/ui-egui/src/control.rs, crates/ui-egui/src/lib.rs: as feat/text-editing-and-frames's merge, without that branch's later copy and paste keys commit
Conflict: crates/compose/src/tests.rs: both sides' tests (this branch's kerning and kenten tests, main's Spanish hyphenation test)
Conflict: ROADMAP.md: this branch's Text engine, IDML interchange and Right-to-left lines; main's FID2, PDF export and Interface language lines
Conflict: crates/compose/src/lib.rs: list labels as main's number_label/bullet_label/empty-paragraph arms, kept in this branch's list_label form that marks label glyphs; main's layout_line call (ends_para, forced_mid) and warichu::place, then the drop cap splice; rule above uses main's first-line column/end_x span with this branch's rule_color; caret(): drop-cap branch, then main's stacked-row metrics
Conflict: crates/compose/src/tests.rs: both sides' tests
Conflict: crates/engine/src/cmd/text.rs: type.para doc lists the drop cap fields and main's rule fields
Conflict: crates/fonts/src/fontdb.rs: both (plausible/measured_top/typo_ascent and without_format_suffix)
Conflict: crates/idml/src/import.rs: main's table style regions, borders and alternating fill/stroke attrs (this branch's alt_fills helper dropped, unused); underline/strikethrough colour from main with this branch's tint(); frame_options takes the object-style chain's TextFramePreference elements, the frame's column rule colour resolved after it
Conflict: crates/idml/src/tests.rs: main's tests, plus this branch's added tests and helpers
Conflict: crates/ui-egui/src/canvas.rs: main's compose::highlight_quads, then this branch's drop-cap highlight
Conflict: ROADMAP.md: kept both entries (New Document, then Numbering & Section Options).
Conflict: crates/ui-egui/src/dialogs.rs: width match keeps "newDocument" => 960.0 and adds "numberingSection" => 560.0, dropping the PR's "newDocument" if is_rtl => 380.0; tests keep next's helper block and add only the PR's numbering_and_section_options_keep_their_actions_in_view.
Conflict: crates/ui-egui/src/i18n.rs: kept both TABLE tail blocks (File › New › Document, then Layout › Numbering & Section Options).
Conflict: crates/ui-egui/src/i18n/it.rs: kept both tail blocks.
Review follow-up. Enter in the Save Document Preset popup created the
document and Escape closed the whole dialog: the dialog footer took
both keys while a popup was open. The dialog now leaves Enter and
Escape to an open popup (read before it draws, as egui closes a popup
on Escape that frame): Enter in the preset name saves the preset,
Escape closes only the popup. Clicking the name field no longer closes
the popup either (menus close on any click; this one only outside), and
the field takes focus when the popup opens.
Saved presets lived only in the UI state, so `file.new {preset: name}`
refused them. They are now engine preferences (saved with prefs.json):
`file.savePreset {name, …the file.new settings}` replaces a preset of
that name and refuses built-in names, `file.deletePreset {name}` removes
one, `file.presets` lists them after the built-in ones (`saved: true`),
and `file.new {preset}` makes documents from them by name. The Saved tab
reads and writes them through those commands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: crates/ui-egui/src/lib.rs: both modules kept, mod new_document before mod object_control
Conflict: crates/ui-egui/src/dialogs.rs: the PR's translated ok_label plus next's findFont arm, translated the same way ("Replace All"); cancel_label is a match: newDocument "Close", findFont "Done", else "Cancel"
Conflict: crates/ui-egui/src/i18n/it.rs: both blocks kept (next's machine-translated and Tabs rows, then the PR's File › New › Document rows)
Conflict: ROADMAP.md: both lines kept (next's IDML1 line, then the Tabs panel line)
Conflict: crates/engine/src/cmd/mod.rs: both spec lists kept (thread::specs, then tabs::specs)
Conflict: crates/ui-egui/src/dialogs.rs: next's delete_paragraph_style and the PR's style_tabs both kept, without the section_list doc comment that next removed; in the tests the PR's copies of draw, ruled_paragraph, undo_steps, the rule tests, command_app, the generic command tests and the text frame options test duplicated next's identical ones and were dropped, keeping only the PR's new Tabs section test
Conflict: crates/ui-egui/src/i18n/it.rs: both blocks kept (next's machine-translated rows, then the Tabs rows)
Conflict: crates/ui-egui/src/i18n/uk.rs: both blocks kept (next's machine-translated rows, then the Tabs rows)
Layout > Numbering & Section Options now opens its own window instead of
the generated command form, on the section of the page in view: Start
Section (always on for page 1), Automatic Page Numbering or Start Page
Numbering at, and a Page Numbering group with Section Prefix, Style,
Section Marker and Include Prefix when Numbering Pages; then Document
Chapter Numbering with its style, Automatic Chapter Numbering, Start
Chapter Numbering at, Same as Previous Document in the Book (only in a
book) and the book's name. OK and Cancel sit beside the options, out of
the scrolling body.
OK runs layout.section and layout.chapterNumbering; a refused value
(a prefix over eight characters or with + or a comma, a start number
below 1) keeps the window open and changes nothing. Opening the window
reads the chapter numbering without running a command, so it doesn't
stop a Data Merge preview. New strings are translated (German, French,
Spanish, Japanese, Chinese, Italian).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: ROADMAP.md: next's Right-to-left and Interface language lines (IDML Kashidas, German and Japanese cover every catalog, Ukrainian covers every key) plus the PR's Show CJK Features line
Conflict: crates/ui-egui/src/lib.rs: the PR's cjk_features() before next's opens_as_document (with .indd/.indt and its doc comment)
Preferences > Type > Show CJK Features (cjkFeatures; unset follows the
interface language: on for Japanese, Chinese and Korean) hides the
CJK-only Type menu items (Tate-Chu-Yoko, Ruby, Kenten, Warichu) and the
Ruby Quick Apply entry. The commands, layout and IDML work either way.
A document's chapter number now has a style (1, I, i, A, a, 01, 001,
0001) and a source, as in Numbering & Section Options > Document
Chapter Numbering: Automatic Chapter Numbering (one more than the
previous document in the book; 1 first), Start Chapter Numbering at,
or Same as Previous Document in the Book.
`layout.chapterNumbering {style?, start?, source?}` sets them (undoable)
and, with no parameters, reports them with the open book that holds the
document. The book's Update Numbering (`book.paginate`) resolves chapter
numbers in book order and reports them. Chapter Number variables and
cross-reference chapter numbers use the style.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
File > New > Document now shows Recent, Saved, Print, Web and Mobile
tabs of page cards (drawn to the preset's proportions; double-click
creates) beside the preset's details: document name, width and height
with arrows, units, orientation, pages, start page #, facing pages,
primary text frame, columns and gutter, and collapsible margins and
bleed and slug per edge with link toggles. Save Document Preset keeps
presets by name; documents made are remembered for the Recent tab.
Small windows stack the details above the presets and scroll; the
layout mirrors for right-to-left languages. New strings go through the
translation tables (Italian, German, French, Spanish, Japanese, Chinese).
file.new takes intent, units, startPage and per-edge bleed and slug.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict: crates/tools/src/snap.rs: first_on_axis: a guide or margin in reach competes with the baseline grid through #84's nearer(); otherwise #309's smart-guide passes run and the baseline grid comes last. #84's nearer_of_margin_and_baseline_wins and #309's tests pass.
A German table (crates/ui-egui/src/i18n/de.rs) covers every key of the shared,
Japanese, Arabic, Brazilian Portuguese, Italian and Ukrainian catalogs (1,697
rows; before, 164 strings were German). The shared table's German column stays
the fallback for keys added after it. Tests check placeholders, padding, colons
and ellipses against the English source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the vertical axis the baseline grid was tried before smart guides.
It snaps while hidden, and with lines every 12 pt and a box's top,
centre and bottom each reaching 4 pt either side, one of them is nearly
always in the zone. It took almost every vertical move and drew nothing,
so object alignment and equal spacing hardly ever showed on y. The
baseline pass now runs after the smart guide passes.
Smart spacing also only matched a gap between two other boxes. A box
dragged between two neighbours now snaps to where both of its gaps are
equal, and both gaps are marked.
Fixes#188
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5fQBTFb4hhKXsCFYitZ1P
* PDF export: Export Adobe PDF options dialog with remembered settings
File > Export PDF... now opens an options dialog (General / Compression /
Marks and Bleeds / Advanced) that exposes only the parameters the engine's
file.exportPdf already supports: PDF standard, image compression, flattener
preset, spreads, document bleed, crop/bleed/page-info marks with weight and
offset, tagged PDF, page range, and the title. Choosing a preset fills the
dependent fields; editing any field switches the preset to Custom.
The last-used settings persist in ui.json (UiState.pdfExport) and are reused
across exports and sessions. Programmatic callers that pass explicit params
(path, options) still export directly without the dialog; cancelling the save
picker writes nothing.
Adds English and ar/pt-br strings, unit tests for the settings serde, the
dialog defaults and preset mapping, the open/confirm flow (stub writer), and
the menu dispatch, plus a ROADMAP note.
* PDF export: rename dialog title to "Export PDF"
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Upstream main moved 9e4f694 -> 736acff by 10 squashes: #258, #285, #153, #280, #288, #281,
#176, #299, #298, #297. New to next: #258 (datamerge test), #153 (temporary files and release
inputs), #280 (warichu), #176 (PDF image conversion cache), #297 (graphics backend before the
window). Already on next: #285, #288, #281, #299, #298.
Conflict: ROADMAP.md: next's lines; CJK1 takes main's wording (ruby unfinished, warichu set after the line is broken)
Conflict: crates/compose/src/lib.rs: list labels (#298): next's list_label structure; paragraph start / break moves: next's `go` (with #295's sub-columns) under the maintainer's #285 comment; Cursor: next's start/next_page/next_baseline with tops; line placement: #280's warichu::place right after layout_line, before next's trimmed trailing spaces and the drop cap splice (so neither is stacked and the spaces follow the closed-up end_x); caret(): next's drop-cap branch first, then #280's stacked-row metrics
Conflict: crates/compose/src/tests.rs: next's tests kept; #280's tests auto-merged
Conflict: crates/engine/src/cmd/text.rs: both (next's TypingFormat/typing_format, #280's warichu_cmd)
Conflict: crates/idml/src/tests.rs: next's side; #280's warichu round-trip test auto-merged
Conflict: crates/pdf/src/export.rs: #176's content cache and test counter with next's RasterMode (no Exporter `interpolate` field on next, so the maintainer's `mode.interpolate &= self.interpolate` is not carried); test exporter gets next's drawing_items field
Conflict: crates/ui-egui/src/canvas.rs: #280's compose::highlight_quads (its RTL branch equals next's mixed-direction spans) followed by next's drop-cap highlight
Conflict: crates/ui-egui/src/menus.rs: next's formatting_affects_text test kept
Auto-merge duplicates removed: #288's table-style tests and #298's list test in idml tests.rs,
#288's tests in doc styles.rs and #285's docx test (both files equal next's), #281's dialog
tests in dialogs.rs (equals next's) and its menu_button/menu_max_height/clipped_submenu in
menus.rs. contributors/people.toml takes main's (next had a duplicated
[people.emanuelebonaventura] table from the 9e4f694 merge, which broke the ui-egui build
script's TOML parse).
Maintainer edits carried over: #285 break characters and Next Column through one closure
(next's `go`, comment added); #281 viewport-aware menu_button in the app bar and the Paragraph
menu, per-dialog widths clamped to the window (all already on next); #280 warichu after the
last-line rules (layout_line with ends_para/forced_mid) and rules at each warichu row's
baseline (rule_baseline in render and pdf text_rules); #176 CMYK fallback through
lossless(.., mode) and its updated contract tests; #258 test fixes; #153 and #297 as landed.
* Desktop: pick the graphics backend before the window exists; DirectX 12 on Windows
On an AMD hybrid-graphics laptop (Radeon RX 6800M beside an integrated
Radeon, with two versions of amdvlk64.dll loaded into one process) the
app died a few seconds after launch with an access violation inside
AMD's Vulkan driver at the first swapchain present. Nothing reached the
log: a fault inside a driver is a native crash the engine's panic guard
never sees. wgpu's default backend set (PRIMARY | GL) enumerates Vulkan
first, so every start on that machine went down the same path, while
WGPU_BACKEND=dx12 and WGPU_BACKEND=gl ran fine and the headless CPU
renderer was never affected.
The desktop app now chooses the backend before creating the window
(apps/designcraft/src/gpu.rs): DirectX 12 first on Windows, then Vulkan,
then OpenGL; Vulkan then OpenGL on Linux; Metal on macOS. OpenGL stays
in the set as the in-process fallback when the chosen backend has no
adapter. WGPU_BACKEND still overrides everything and turns the fallback
off.
Start-up fallback: gpu.json in the settings directory records the
backend being tried until the third frame begins (the first has been
presented by then) or the app exits normally. A record left behind means
that backend never showed a frame, so the next start skips it, tries the
next candidate and says so in the status bar. The list starts over when
every candidate has failed or the app version changes;
DESIGNCRAFT_NO_PREFS records nothing. The adapter, backend and driver
version are logged at start-up for bug reports.
Verified on the affected machine: a default start runs on DirectX 12; a
simulated crashed DX12 start moved to Vulkan, which faulted for real,
and the start after that came up on OpenGL with the status line. Nine
unit tests cover the chooser and the record; cargo xtask ci passes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Merge origin/main; on Windows OpenGL isn't added to the DX12 or Vulkan instance (#167)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Set warichu as smaller lines inside the parent line.
Type › Warichu stacks the selected run after the line is broken, closes up the rest of the line, and round-trips the IDML warichu properties. The line break itself still sees the full-size run.
* Keep clicks, the caret, and Up/Down on each warichu row.
The glyphs were already stacked inside the parent line, but hit testing, the caret, and vertical movement still used that parent line. Break minimums, row widths, spacing, and tab leaders now follow the small lines, and underlines sit on the small baseline.
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: add Italian (it) UI translation
Adds an Italian interface catalog (crates/ui-egui/src/i18n/it.rs) covering every
key of the shared table and of the Arabic table (1,430 strings), written from the
English source using ordinary Italian desktop-publishing vocabulary.
Registers "Italiano" in Edit > Interface Language, wires it into tr(), and extends
the i18n and menu tests (lookup, no duplicates, full key coverage, translated menu
titles, language switch frames).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* contributors: add emanuelebonaventura (display name insanityxoff)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Text frames: column rules draw between columns on screen and in PDF
A frame with Column Rule on gets a bar centred in each gutter, inside the
insets, broken around paragraphs that span columns; right-to-left and
vertical frames included. object.textFrameOptions takes columnRuleWeight
and columnRuleColor (unknown swatches are an error) and an inset array
whose null sides stay; document.inspect reports the rule.
* Text Frame Options: Column Rules fields; OK changes only edited fields
The dialog shows the selected frame's options, with an inset field per
side, and sends only what the user changed, so unequal insets survive.
The rule weight is read in points.
* Column rules: tint, horizontal offset and top/bottom insets; IDML import and export
Text Frame Options gains Tint %, Top Inset, Bottom Inset and Horizontal
Offset for the rule, and object.textFrameOptions and document.inspect
take and report them. IDML reads the ColumnRule attributes of
TextFramePreference on frames and object styles and writes them when a
rule is set.
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Landed: #119#294#144#199#248#222#223. #119#144#199#248#223 were
already on next; #222 (Spanish hyphenation) and #294 (Ukrainian catalog
test) are new here and come in whole. Each squash equals its landed PR
head (fetched to refs/remotes/pr-landed/N).
Conflict: contributors/people.toml: next's side (keeps emanuelebonaventura between moppeeer and thaynej)
Conflict: crates/doc/src/styles.rs: next's side (next's cell/table style tests)
Conflict: crates/pdf/src/export.rs: next's side in both hunks (no Exporter `interpolate` field on next; `let i = mode.interpolate` kept once)
Conflict: crates/ui-egui/src/dialogs.rs: confirm: next's `paragraphRules` arm; basic_character_formats: upstream's side (maintainer's font menu, see below)
Conflict: crates/ui-egui/src/i18n.rs: next's translated "Tint:" row
Conflict: crates/ui-egui/src/lib.rs: next's side (keeps ClipboardFn)
Conflict: crates/ui-egui/src/widgets.rs: next's side (next's numeric field grid test)
Maintainer edits in the landed PR heads:
- #119 (bfe02c9): inbox and PDF page dialog imports go through open_file; import_file uses opens_as_document. Already on next.
- #144 (fa5b942): paragraph_style_options reads a cloned doc; already on next. Basic Character Formats' Font Family is a ComboBox over font_menu_body (blank row clears a sparse family, "—" when unset). Taken from upstream in place of next's font_combo + "×" button.
- #199 (7afa9b7): one Properties test module with both tests. Already on next.
- #248 (856a432): people.toml keeps moppeeer and thaynej. Already on next.
- #222 (ac9b68d): ROADMAP Language line combines #199's "Properties ▸ Character" with #222's Spanish hyphenation note. Comes in with #222.
- #223 (c3d8a07): `mode.interpolate &= self.interpolate` and the decode check in lossless. The decode check is on next; the interpolate line is not, because next has no Exporter `interpolate` field and RasterMode::for_standard already turns interpolation off for every standard, PDF/A included.
* Paragraph rules: a partial ruleAbove/ruleBelow edit keeps the other rule fields; Rule Above honours Text width
* Paragraph Rules: dialog for the selected paragraphs and a Paragraph Style Options section
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- An RGB image with no ICC profile of its own was written as DeviceRGB
under the CMYK output intent, and the export only warned. In PDF/X-4
it now carries the sRGB profile (assets/icc/sRGB-v2-magic.icc, ICC
v2.1, CC0). JPEGs stay passed through. Untagged PNG, GIF and WebP,
and the decoded TIFF, BMP and PSD fallback, go in as RGB with the
profile. A re-encoded JPEG keeps the source's RGB profile or gets
sRGB. Grey images and images with their own profile are unchanged.
- Every image constructor asked for interpolation. PDF/X-4 and PDF/A
exports now write images without it, which also removes the
ImageInterpolation error that stopped PDF/A exports with a placed
image. Plain exports keep it.
- make_pdfx4 writes pdf:Trapped False into the XMP, matching
/Trapped/False in the document information.
- check_pdfx4 reports an image that asks for interpolation.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Text set in Spanish was not hyphenated at all. It now uses Javier
Bezos's Liang patterns, hyph-es.tex 5.0 from hyph-utf8 under MIT,
through the hypher crate 0.1.8 with only its alloc and spanish
features. The full feature, which embeds 48 languages under several
licences, stays off.
- hyphen::Lang names the hyphenator for a run: English, or a hypher
language. Lang::for_language maps a language name or locale code.
- word_breaks_in and hyphen_points_in take the language. word_breaks
and hyphen_points stay as the English entry points.
- Composition hyphenates a non-English run whose language has
patterns and skips the rest. The word cache key includes the
language.
- NOTICE carries the Bezos copyright line and the MIT text.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* UK1: add Ukrainian interface translation
Translate existing interface catalogs and wire Ukrainian menu selection, contextual publishing labels and grammatical counters. Validate persisted selection, untouched document data, placeholder/key coverage and bundled Cyrillic glyphs.
Co-Authored-By: Codex <noreply@openai.com>
* i18n uk: translate the open and place alert titles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The rows share one fixed height that preserves their composed total. Merged rows and rows that are not laid out are refused, and the table stays unchanged.
* UI: right-clicking a ruler picks that ruler's units, and the vertical ruler measures in the vertical units (#133)
* UI: the Properties panel's Character section sets the text's language, from the same list as the Character panel (#130)
Conflict: crates/idml/src/import.rs: next's text_frame_options(&[&El]) object-style chain with #274's column rule fields; #274's frame_options takes the prefs list and looks up ColumnRuleStrokeColor through Prefs; the frame site resolves the rule colour's swatch after building options from the chain (the chain borrows the importer)
Conflict: crates/idml/src/tests.rs: tests only; kept both
Conflict: crates/compose/src/tests.rs: tests only; kept both
Conflict: crates/pdf/src/tests.rs: tests only; kept both
Text Frame Options gains Tint %, Top Inset, Bottom Inset and Horizontal
Offset for the rule, and object.textFrameOptions and document.inspect
take and report them. IDML reads the ColumnRule attributes of
TextFramePreference on frames and object styles and writes them when a
rule is set.
The dialog shows the selected frame's options, with an inset field per
side, and sends only what the user changed, so unequal insets survive.
The rule weight is read in points.
Conflict: ROADMAP.md: kept next's IDML1 line and #263's Paragraph Rules line
Conflict: crates/compose/src/lib.rs: Rule Above uses #263's first line and Column/Text width with #83's rule_color() for colour and tint
Conflict: crates/engine/src/cmd/text.rs: type.para params doc lists next's drop cap fields and #263's ruleAbove/ruleBelow; format_paras is #263's
Conflict: crates/ui-egui/src/dialogs.rs: kept both confirm arms (characterStyleOptions, paragraphRules) and both sets of tests
InDesign documents and templates (.indd, .indt) open through File › Open,
drop, the web inbox, file.open, file.openBytes, file.openIdml and the CLI.
The engine converts them to IDML in memory with indd-utils
(github.com/aiongg/indd-utils, rev 9cf456d, MIT OR Apache-2.0, no
dependencies, builds for wasm) and imports the result through the existing
IDML path. The converter's warnings come first in the open result's
`warnings`. A file the converter can't read is an open error ("can't
convert the InDesign file: ..."), shown in the Can't Open the File alert.
Routing: a path or name ending in .indd/.indt, or bytes starting with the
INDD signature (the web inbox passes the name without its extension).
opens_as_document and the desktop and web Open dialogs list indd/indt.
Tests use synthetic bytes only: signature-bearing junk, a zero-filled
.indd and a short .indt all fail as open errors with no document added;
a dropped unreadable .indd raises the open alert.
#218's test needs it.rs to cover every key of TABLE and ar::TABLE, and
#236's test needs the uk.rs keys to equal TABLE, ar and pt_br together.
Other PRs on next add 34 keys to those tables that neither catalog has:
- #80: Can't Open the File, Can't Place the File
- #83 (also carried by #81, #84, #96, #106): drop cap labels (Drop Caps,
Drop Lines, Drop Chars, Lines:, Characters:, Align Left Edge, Scale for
Descenders, dropcap)
- #84: Select an object or text to color its fill or stroke.
- #144: Character Style Options and its Basic/Advanced Character Formats
and OpenType sections (Case:, Tint:, Skew:, Kerning:, Ligatures, ...)
The Italian and Ukrainian entries are machine-translated and marked with
a comment in each catalog; a native speaker should review them. The
ROADMAP's Ukrainian line drops its fixed key count (1,430), which no
longer holds.