Commit Graph
610 Commits
Author SHA1 Message Date
aiongg 0f2dbd2fcd Merge #275: fix(engine): object.opacity accepts its documented lowercase blend modes
Conflict: crates/engine/src/cmd/object.rs: tests only; kept next's column_rule_tests and #275's blend_mode_tests
2026-10-10 01:23:28 +00:00
aiongg 3a77ea593b Merge upstream main 4e0e394 (version 0.5.0) into next 2026-10-10 01:15:38 +00:00
aiongg 91fca00abf Integration: Italian and Ukrainian entries for #274's strings
#274 adds Column Rules, Insert Column Rule, Tint %, Top Inset, Bottom Inset
and Horizontal Offset to TABLE, ar and pt_br. #218's test needs it.rs to
cover TABLE and ar; #236's needs uk.rs to cover TABLE, ar and pt_br. The
entries are machine-translated and go in each file's machine-translated
block.
2026-10-10 01:09:28 +00:00
aiongg 35ebbe6f71 Integration: test column rules around a spanning paragraph between bands
#274 draws column rules from the frame's columns and breaks them where a
paragraph's lines cross the gutter. The span-columns fix puts text after a
spanning paragraph below it (a band of columns under the heading). The test
sets a heading mid-frame in three columns and checks that each gutter's rule
stops above the heading and resumes at its bottom, with text after the
heading flowing below it.
2026-10-10 01:08:17 +00:00
aiongg 70edc2399f Merge fix/span-columns-flow: Text: text after a paragraph that spans columns flows below it
Conflict: crates/compose/src/lib.rs: next computes spacing_for earlier; kept the fix's spanning/span_paras/next_column lines and dropped its duplicate spacing line
Conflict: crates/compose/src/tests.rs: tests only; kept both
2026-10-10 01:07:45 +00:00
aiongg 66d6479c09 Merge #274: Text frames: column rules on screen, in PDF and in IDML; Column Rules in Text Frame Options
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
2026-10-10 01:05:14 +00:00
aiongg 00cf932892 Integration: Control bar tests read #255's object Control groups
#112's and #142's Control bar tests found controls by accessibility label
(Fill, Columns, Y:). #255 replaces control_object with object_control::show,
whose captions are painted and whose last group with nothing text-specific
selected is Align. The tests now use #255's group responses
(("object_control", id)): #142's second-row test checks the X/Y/W/H group,
#112's scroll test uses Align bottom edges as the last control and opens the
Fill picker from the appearance group with a frame selected (#255 disables
the controls without a selection), and the one-line caption test checks that
the text frame's Columns group keeps its full width after scrolling.
2026-10-10 01:02:57 +00:00
aiongg 1134f9e760 Merge #255: fix(ui): Compact the Advanced object Control panel into aligned rows
Conflict: crates/ui-egui/src/chrome.rs: control_bar keeps next's #112 ScrollArea and #142 horizontal_top and calls #255's object_control::show where next called control_object; #255's nested ScrollArea dropped
Conflict: crates/ui-egui/src/widgets.rs: tests only; kept next's clearable-field test and #255's two-row grid test
Conflict: contributors/people.toml: kept next's entries (#255 adds none)
2026-10-10 01:02:20 +00:00
Brandon ThomasandClaude Opus 5.5 4e0e3949f1 Bump version to 0.5.0 (from 0.4.0) for release; refresh contributors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.5.0
2026-10-09 21:02:05 -04:00
aiongg ebe646e917 Merge #272: i18n: translate the whole interface into Japanese
Conflict: crates/ui-egui/src/i18n.rs: kept both module declarations (mod it; mod ja;)
2026-10-10 00:59:51 +00:00
aiongg 02da5681fa Merge #266: Autoflow: add only the pages breaks ask for 2026-10-10 00:59:47 +00:00
aiongg b8f4a6fdf0 Merge #254: fix(cli): --help prints usage to stdout and exits 0
Conflict: apps/designcraft-cli/src/main.rs: #254's USAGE const and usage_footer(); #127's '(--page, --scale and --pdf-options apply to the exports that follow them)' line moved into USAGE
2026-10-10 00:59:46 +00:00
aiongg 8a25bbe4de Merge #269: docs: register the MCP server from an installed release 2026-10-10 00:59:37 +00:00
aiongg b4fa77ce65 Merge #257: Word import: keep tracked moved text (w:moveTo)
Conflict: contributors/people.toml: kept both entries
2026-10-10 00:59:37 +00:00
aiongg 1443c3a8a8 Span columns: text after a spanning paragraph flows below it
A spanning paragraph closes the band of columns above it. Those columns
are balanced first and the paragraph sits below the deepest of them; the
columns after it start below the paragraph, so text that moves to the
next column no longer restarts at the frame top over the heading. A
spanning paragraph that doesn't fit moves to the next frame. Span counts
below the column count set the paragraph across the first columns only.
2026-10-10 00:58:10 +00:00
kubuntugamer a2dbe793f3 fix(engine): object.opacity accepts its documented lowercase blend modes
`object.opacity` documents `blend?: normal|multiply|…`, but parsed the
value with `serde_json::from_value`, which only accepts the enum's
PascalCase variant names. Every documented lowercase form was silently
dropped: the command returned `{"changed": 1}` while the stored blend
stayed as it was, so a client following the parameter description could
save and export the previous appearance without any error (#260).

Parse with the codebase's own `BlendMode::parse`, which is already
case-, space-, underscore- and hyphen-insensitive and covered by tests,
so `multiply`, `MULTIPLY`, `Color Burn`, `soft_light` and the serialized
`Multiply` all resolve to the same mode. An unrecognized value is now an
error rather than a silent no-op, matching how sibling commands treat a
bad parameter — restoring `normal` after `Multiply` really does go back
to Normal.

Three tests in `blend_mode_tests`: the documented forms apply, the
PascalCase names the Properties panel submits still apply, and an
unknown value is rejected without changing the item.

Fixes #260

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-10-09 19:55:57 -05:00
aiongg 7d0bdbc916 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.
2026-10-10 00:33:27 +00:00
aiongg 36d1338fa7 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.
2026-10-10 00:26:13 +00:00
aiongg 1efbf0f894 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.
2026-10-10 00:26:13 +00:00
Ikki NishiharaandClaude Sonnet 5.5 70d9fafa0b i18n: translate the whole interface into Japanese
Japanese covered menu titles, about 140 menu items and panel names. Of the
1,391 rows of the shared table, about 1,240 carried the English text in
their Japanese column, so every dialog, panel field, tooltip and status
line was still English.

Add i18n/ja.rs, a full catalog in the shape of ar.rs and pt_br.rs. It has a
row for every key of the shared table and of the Arabic and Brazilian
Portuguese tables (1,430 strings), keeps the existing Japanese menu words
unchanged, and adds 213 rows for labels the code passes to tr() but no table
had: command labels without their trailing ellipsis (the shortcut list), menu
paths (the menu list), special characters, colour-profile names and a few
field labels.

tr("ja", ..) looks in ja::TABLE first and falls back to the shared table's
Japanese column. The shared table is left as it is.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-10 09:12:16 +09:00
SawizzleandClaude Opus 5.5 778822702b docs: register the MCP server from an installed release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:05:40 -07:00
Jeffrey ThayneandClaude Opus 5.5 7b3afb0b21 Autoflow: add only the pages breaks ask for
A frame that a column, frame or page break ends early held only a few
characters, and autoflow took that as the rate frames fill at: placing
text that starts with a page break added a page per few characters
(33 pages for 98 characters, 271 for a one-page Word section). The
estimate now comes from full frames only; with none yet, one page is
added and the story measured again. Regression test covers a leading
break and a break between every paragraph. Fixes #262.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GLcnoDFjqsh5x3MzVbfZeb
2026-10-09 18:02:15 -06:00
aiongg 30264ca004 Integration: Italian and Ukrainian entries for #263's strings
#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.
#263 (Paragraph Rules) adds three keys neither catalog has: Paragraph
Rules…, Paragraph Rules and Rule Below. Its other new keys (Tint:,
Column) were already covered.

The Italian and Ukrainian entries are machine-translated and sit in each
catalog's machine-translated block; a native speaker should review them.
2026-10-10 00:01:03 +00:00
aiongg 35d011fccd Integration: one "Tint:" entry for #144 and #263
#144 (Character Style Options) and #263 (Paragraph Rules) each add a
"Tint:" row to the shared table and to the Arabic and Portuguese
tables, which the i18n tests reject as duplicates. One row stays in
each table, at #144's position, with #263's German, French, Spanish
and Japanese translations (#144's row kept those as English).
2026-10-10 00:00:40 +00:00
aiongg 24ab4a1f6b Merge #264: UI: the shortcut recorder waits for the key; Interactive for PDF and Digital Publishing open their panels
Conflict: crates/ui-egui/src/dialogs.rs: tests only; kept next's character style tests and #264's shortcut recorder test
2026-10-09 23:59:54 +00:00
aiongg e1cc16325a Merge #263: Paragraph Rules: a dialog for the selected paragraphs and a section in Paragraph Style Options
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
2026-10-09 23:59:08 +00:00
aiongg 0d491dbdd9 Workspaces: Interactive for PDF and Digital Publishing open their own panels 2026-10-09 23:53:55 +00:00
aiongg baa0fa3494 Keyboard Shortcuts: the recorder waits for the key pressed with the modifiers 2026-10-09 23:52:38 +00:00
aiongg cbe960ce55 Paragraph Rules: dialog for the selected paragraphs and a Paragraph Style Options section 2026-10-09 23:42:11 +00:00
aiongg fa13bf24f4 Paragraph rules: a partial ruleAbove/ruleBelow edit keeps the other rule fields; Rule Above honours Text width 2026-10-09 23:42:11 +00:00
aiongg bb8a6a23fa INDD: open .indd files through indd-utils
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.
2026-10-09 23:06:40 +00:00
Jeffrey ThayneandClaude Opus 5.5 c812c83d95 Word import: keep tracked moved text (w:moveTo)
Text inside a tracked move destination was dropped on .docx import, so
moved passages vanished from both places. Treat moveTo like ins (both
kept as accepted); moveFrom stays skipped like del. Regression test
covers ins, del, moveFrom and moveTo together. Fixes #256.

Also adds my contributor credit entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:04:18 -06:00
aiongg 92b1a96829 Integration: Italian and Ukrainian entries for strings added by the merged PRs
#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.
2026-10-09 23:01:00 +00:00
aiongg 9b2304e996 Merge #236: Add Ukrainian interface translation
Conflict: ROADMAP.md: kept next's lines (Italian in the language list) and appended #236's Ukrainian sentence to the Interface language line
Conflict: crates/ui-egui/src/i18n.rs: kept both languages (it then uk in LANGUAGES, both tr() branches, both test loops; the unknown-label test checks every language)
Conflict: crates/ui-egui/src/menus.rs: kept both (app.language params doc lists it|uk, both menu entries, both language tests; the geometry test switches through uk and it)
2026-10-09 22:58:33 +00:00
aiongg 772489ace4 Merge #218: I18n italian
Conflict: ROADMAP.md: kept next's Right-to-left line (with IDML Kashidas) and next's Interface language line with #218's "Italian" added
Conflict: contributors/people.toml: kept both entries (moppeeer from #248, then emanuelebonaventura)
2026-10-09 22:57:53 +00:00
aiongg 76746924fd Integration: rustfmt the composite note label call in shape_para
The #126 merge resolution moved #126's composite-font note label shaping into #81's
piece pass and passed #81's StyleRuns; the resulting call is longer than one line.
2026-10-09 22:54:32 +00:00
aiongg 66bf8585f9 Integration: #177's glyph-cache test reads #230's underline list
#230 splits LineGlyphs::decos into underlines and strikes (underlines paint before the
glyphs, strikethroughs after). #177's in-flight owner test still read `decos`, so the
render tests did not compile once both were merged. The test's composition has an
underline, so it checks `underlines`.
2026-10-09 22:54:32 +00:00
aiongg 9f0b34e876 Merge #177: Memory: release retired layouts and reserve text growth exactly
Brings #175 (abf9a40, PSD fixed-size chunks).
Conflict: crates/engine/src/cmd/text.rs: tests only; kept #118's story_query_contract_tests and #177's reserve_tests (insert()'s code merged cleanly: #177's reservations around #84's typing format)
2026-10-09 22:53:16 +00:00
aiongg ee24cb949b Merge #129: Fix IDML Mojikumi spacing, kinsoku composition, and nested text preflight
#129's first commit (4f8d230) holds #124 and #126, which are already merged. Each conflicted file is a three-way merge of #129's own commits (4f8d230..pr/129) onto this branch, which takes #129's side against #126 and keeps the chain's (#81/#84) code.
Conflict: ROADMAP.md: kept both entries
Conflict: crates/compose/src/shape.rs: #129's Mojikumi metrics added; #81's pieces, the #126 composite-note piece and the #124 inline-object metrics unchanged
Conflict: crates/compose/src/tests.rs: tests only; #129's tests added, no duplicates of #124/#126's
Conflict: crates/engine/src/cmd/fonts.rs: #129's pub(super) for_each_story; #126's tests kept once
Conflict: crates/engine/src/cmd/preflight.rs: #129's nested-story paragraph rules; the used_fonts loop kept once
Conflict: crates/engine/src/tests.rs: tests only; #129's test added
Conflict: crates/fonts/src/fontdb.rs: #126 content (same in #129); no change
Conflict: crates/idml/src/import.rs: #129's Mojikumi import added
Conflict: crates/idml/src/tests.rs: tests only; #129's tests added
Conflict: crates/ui-egui/src/dialogs.rs: #126 content (same in #129); no change
Conflict: crates/ui-egui/src/lib.rs: #126 content (same in #129); no change
2026-10-09 22:52:22 +00:00
aiongg 988e45b0bb Merge #126: Fix composite font resolution, missing-glyph diagnostics, and document-wide font replacement
Conflict: crates/compose/src/shape.rs: #81 collects paint-only pieces and shapes them later, #126 shapes composite-font note labels inline. A footnote reference in a composite font becomes a Piece with `composite_note`, shaped alone in the piece pass with #126's per-entry label code (from the run's env, as in #126); other references stay ordinary pieces. #126's label fallback in shape_segment passes #81's StyleRuns.
Conflict: crates/fonts/src/fontdb.rs: #126's canonical_family lookup sits at the top of exact_style_traits, so #81's styles/traits_of/linked_style and #247's format-suffix fallback all use it; face() resolves canonical, then canonical without the format suffix, then #126's substitute_family, through #247's find_or_load; has_family is canonical_family as named or without the suffix
Conflict: crates/ui-egui/src/lib.rs: kept #84's system-clipboard copy match and added #126's Find Font on open and _fonts reset after it
Conflict: crates/ui-egui/src/dialogs.rs: OK label match has #146's Save and #126's Replace All; #80's alert-only OK kept, #126's Done label for findFont; find_font keeps #143's font_combo with #126's FALLBACK_FAMILY default
Conflict: crates/compose/src/tests.rs, crates/idml/src/tests.rs: tests only; kept both
Conflict: ROADMAP.md: kept both entries
2026-10-09 22:49:44 +00:00
aiongg 01799b4927 Merge #124: IDML: preserve anchored text frames and footnote artwork
Conflict: crates/compose/src/shape.rs: inline object on the baseline: #124's rule (its box alone sets the extents, not max with the font's) applied to every metric #83 tracks (ascent, typo_ascent, cap, xh); the above-line arm keeps #83's four fields
Conflict: crates/compose/src/tests.rs: tests only; kept both
Conflict: crates/engine/src/tests.rs: tests only; kept both
Conflict: crates/idml/src/tests.rs: tests only; kept both
2026-10-09 22:46:08 +00:00
aiongg 83e1b768e6 Merge #247: IDML: layers import and export in stacking order; font names with a format suffix
Conflict: crates/fonts/src/fontdb.rs: kept #81's typo_ascent/plausible and #247's without_format_suffix; the format-suffix fallback goes inside #81's style_traits() through exact_style_traits() (same as wip 57ebfb2)
Conflict: crates/idml/src/tests.rs: tests only; kept #83's drop-cap and object-style tests and #247's layer-order test
2026-10-09 22:44:34 +00:00
aiongg d268d998a9 Merge #230: Preserve text decoration color resets, geometry and paint order
Conflict: crates/idml/src/import.rs: kept #230's Underline/StrikeThru colour line (Text Color resets) and #83's tint() helper
Conflict: ROADMAP.md: kept the chain's Text engine line and added #230's FID2 line
2026-10-09 22:43:44 +00:00
moppeeer 88dab50978 Compact the Advanced object Control panel into aligned rows 2026-10-10 00:43:19 +02:00
aiongg 277c442814 Merge #96: Compose: an empty paragraph takes its mark's character format 2026-10-09 22:43:00 +00:00
aiongg fa8492232e Merge #106: Compose: fit horizontal text frames by the last baseline 2026-10-09 22:41:32 +00:00
aiongg caa01d063e Merge #81: Text: kerning survives a colour change (#29) 2026-10-09 22:41:29 +00:00
aiongg 71074a987b Merge #84: Text editing, snapping and text threading (#23)
Conflict: crates/ui-egui/src/control.rs: tests only; kept #118's automation_contract_tests module and #84's tests module
Conflict: crates/ui-egui/src/lib.rs: kept #119's ImportedFile Inbox type and #84's ClipboardFn
Conflict: crates/ui-egui/src/menus.rs: tests only; kept #239's two Quick Apply tests and #84's copy/paste test
2026-10-09 22:41:29 +00:00
aiongg 4b24103b24 Merge #83: Layout: first baselines, Jump Object wrap, drop caps, IDML defaults 2026-10-09 22:40:47 +00:00
aiongg e5e48d2ed1 Merge #119: Web Place/Open/swatches remember the document and purpose they started from; multipage PDF Place shows the page dialog in the browser
Conflict: crates/ui-egui/src/lib.rs: kept #119's drain_inbox, import_file and ImportRequest (and its Services.inbox doc); import_file's and confirm_pdf_import's file.place/file.openBytes go through #80's open_file, so a failure shows the alert; import_file uses #80's opens_as_document for layout files
Conflict: crates/ui-egui/src/dialogs.rs: kept #119's pdfImport arm (async confirm, target activation); its native file.place goes through #80's open_file
2026-10-09 22:38:07 +00:00