Commit Graph
625 Commits
Author SHA1 Message Date
aiongg dfeb18178c Merge #284: Text: a justified line with a tab justifies the text after its last tab
Conflict: crates/compose/src/lib.rs: tab loop keeps #282's tab_advance and records #284's last tab (no stop = default left tab); squeeze_last keeps next's mojikumi condition with #284's seg_justifies; single-word gaps keep next's moji filter after #284's skip(seg)
Conflict: crates/compose/src/tests.rs: kept both
2026-10-10 03:13:36 +00:00
aiongg 58388e6ec5 Text: a justified line with a tab justifies the text after its last tab 2026-10-10 03:02:01 +00:00
aiongg 79e6ab6569 Merge #281: Keep menus and dialogs usable at larger UI scales
Conflict: crates/ui-egui/src/menus.rs: #281's menu_bar (MenuButton with CloseOnClickOutside, scroll_menu) with #249's top_down_justified rows
Conflict: crates/ui-egui/src/dialogs.rs: next's per-dialog widths (alert 440, closeDocument 380, RTL newDocument 380, else 640) clamped to the window as #281 does; tests: kept both
2026-10-10 02:44:32 +00:00
aiongg c32b5ee54a Revert "Merge #279: Menus: menus taller than the window scroll"
This reverts commit f3c32bcb90, reversing
changes made to 0f2dbd2fcd.
2026-10-10 02:41:45 +00:00
aiongg 9e66ced113 Revert "Integration: the Paragraph section's menu (#263) uses #279's menu_button"
This reverts commit 34e1c439a7.
2026-10-10 02:41:45 +00:00
aiongg 8c6bab93c7 Merge #283: Text: the line before a column, frame or page break is a last line
Conflict: crates/compose/src/lib.rs: next's trailing-space and drop cap code after layout_line kept; the call takes #283's ends_para and forced_mid
2026-10-10 02:36:00 +00:00
aiongg 8a8ecb383a Integration: the line breaker measures a tab beside a drop cap from the drop cap
#282 measures tabs in the line breaker from where layout starts the line; next's drop caps (#83) start lines beside the drop cap after it (on the right in RTL). The breaker's tab closure uses the same indent as next's width closure and line placement; measured from the frame edge, a tab looked wider and the line broke a word early.
2026-10-10 02:35:37 +00:00
aiongg 57688aa82e Merge #282: Text: a line with a tab wraps at the column edge
Conflict: crates/compose/src/breaker.rs: next's greedy (end_elastic, kinsoku priority 2, unconditional shrink) with #282's tab advance in its three uses of the glyph advance
2026-10-10 02:34:09 +00:00
skylar taylor-barrick 07b33edbef UI: keep menus and dialogs reachable at larger scales 2026-10-09 20:29:01 -06:00
skylar taylor-barrick 392f414322 ci: simplify testkit dependency match for Clippy 2026-10-09 20:28:56 -06:00
aiongg 54a4f16759 Text: the line before a page break is a paragraph's last line
A line ended by a column, frame or page break takes the paragraph's
last-line alignment, so a Left Justify paragraph sets it flush left.
A line ended by a forced line break stays justified.

The break that moves the following text to the next column or frame
is the line's last glyph, so a space after the break no longer keeps
the text in the same column.
2026-10-10 02:25:44 +00:00
aiongg 53a83139d9 Footnotes: the first line wraps at the column edge after the number
Line breaking gave tabs no width: a tab only reached its stop when the
line was laid out, so a line holding a tab ran past the measure by the
tab's advance. A footnote whose separator is a tab overflowed its first
line by the gap between the number and the tab stop, and body lines
with tabs did the same.

The greedy breaker now asks for each tab's advance at its position on
the line, computed by the same tab_advance helper line layout uses.
2026-10-10 02:13:18 +00:00
aiongg 34e1c439a7 Integration: the Paragraph section's menu (#263) uses #279's menu_button
#263 adds a ☰ menu to the Properties panel's Paragraph section; #279 routes every menu_button through menus::menu_button so a menu taller than the window scrolls. This one gets the same behaviour.
2026-10-10 01:57:03 +00:00
aiongg f3c32bcb90 Merge #279: Menus: menus taller than the window scroll
Conflict: crates/ui-egui/src/chrome.rs: next's horizontally scrolling app bar kept; its workspace menu and Delete Workspace submenu call #279's menus::menu_button
Conflict: crates/ui-egui/src/menus.rs: kept next's activate_native/native_menu_enabled/forward_to_text_field and #279's menu_button/menu_max_height
2026-10-10 01:56:53 +00:00
aiongg 717ddb6070 Menus: menus taller than the window scroll
At a large UI scale the menu bar menus ran off the bottom of the window,
so items such as Edit > Preferences could not be reached (#267).

Every menu_button popup (menu bar menus and submenus, workspace and zoom
menus, panel menus) now goes through menus::menu_button. It caps the
menu's height at the larger of the spaces below and above its button,
and the rest scrolls with the mouse wheel. Short menus are unchanged.
2026-10-10 01:35:54 +00:00
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