Conflict: ROADMAP.md: both progress lines kept
Conflict: docs/target-app-parity.md: next's UI and tools lines kept, with the Fill/Stroke proxy keys added to the UI line
Conflict: crates/ui-egui/src/lib.rs: UiState keeps next's tabs_panel and the branch's stroke_front
Conflict: crates/ui-egui/src/menus.rs: UI_COMMANDS keep next's togglePresentation and formattingAffectsText entries and add the color.* entries
Conflict: crates/ui-egui/src/toolbar.rs: next's text-aware proxy buttons (color_target, colors_affect_text, apply_swatch) kept; the proxy reads stroke_front from UiState instead of egui temp data
Conflict: crates/engine/src/cmd/file.rs: spec keeps next's pdfCrop list and adds loadCursor; file_place loads next's asset (pdf_crop/pdf_box already set) with the box size (bw, bh), so LoadedGraphic carries no separate crop and place_drop keeps next's xf with clip: None; load_cursor takes the branch's body, place_load builds the Asset with ..Default::default()
Conflict: crates/engine/src/lib.rs: LoadedGraphic is { asset, size }; on next the crop box lives in the asset
Conflict: crates/ui-egui/src/lib.rs: next's open_documents_later/open_os_documents and the branch's place_file both kept
Conflict: crates/ui-egui/src/canvas.rs: focus-lock filter placed after request_focus, before next's menu_open/keyboard_pane early return; the new test kept after next's added tests
File › Place (native picker, browser import, Place with Import Options
and the PDF page dialog) passes loadCursor to file.place. With no empty
or graphic frame selected and no x/y given, an image is added to the
document and loaded into the place cursor instead of landing in a new
frame on the first spread; a click places it at its natural size, a drag
draws its frame. The loaded graphic keeps the chosen PDF page and crop
box. Escape or choosing another tool unloads the cursor. Dropped files
and file.place without loadCursor behave as before.
While the canvas has keyboard focus, arrow keys, Tab and Escape no longer
move egui's focus to a neighbouring widget. Before, Down or Tab while
typing focused e.g. the status bar's Next Spread button, and the next
Space or Return pressed it, so the view jumped to another spread.
A portable copy unzipped into a read-only folder such as Program Files
kept pointing settings and recovery at a DesignCraftData it could not
write, so both were lost without a word. The data folder is now probed
(created, then a file written and removed) and, when that fails, the
platform folders are used as if there were no portable.txt; the log and
the status bar say which folder could not be written.
DESIGNCRAFT_CONFIG_DIR still wins. Adds
a_portable_install_that_cannot_write_its_data_uses_the_platform_paths.
object.swapFillStroke and object.defaultFillStroke change every unlocked
target in one edit, so one undo restores them all. Swap works per object
and keeps each object's tints; a stroke that gets a colour at zero weight
gets the default 1 pt. Objects that are locked, or on a locked layer,
stay as they are. color.swapFillStroke and color.defaultFillStroke run
these commands.
The proxy's tooltips named keys that did nothing. color.defaultFillStroke
(D), color.swapFillStroke (Shift+X), color.toggleFillStroke (X) and
color.applyNone (/) are UI commands; the proxy's buttons run the same
commands. Swap keeps the fill and stroke tints.
Which of fill and stroke is in front lives in UiState, shared by the
Tools panel proxy, the Color panel and the commands. The single-key
shortcuts stay out of text being typed, like the tool shortcuts.
Conflict: crates/compose/src/lib.rs: next's wrap_obstacles and free_slots kept; frame_specs keeps only exclusions that reach the frame's text area (as wrap.rs does for anchored obstacles), and free_slots applies the 1.5 em minimum segment only when an exclusion reaches the column
Conflict: crates/compose/src/tests.rs: both sides kept; the PR's tombstone tests plus tests for a sliver beside a wrap object in a narrow frame and a narrow first column beside a wrap object in column 2
Inside a macOS bundle the executable sits in DesignCraft.app/Contents/MacOS,
a signed folder nobody edits, so the marker and DesignCraftData are looked
for next to the .app, as craft-settings does. Adds
inside_a_macos_bundle_the_marker_sits_next_to_the_app.
InDesign's Hyphenation Zone ("the white space allowed at the end of a
line of unjustified text before hyphenation begins") applies only with the
Single-line Composer. The Paragraph Composer, the default, weighs every
break of the paragraph instead. DesignCraft applied the default 3p0 zone
to both, so ragged paragraphs under the Paragraph Composer refused
hyphens InDesign makes. In LYH Studio's poster tutorial the placeholder
text breaks "aper-natem" and "mosticsia-tur"; ours ran a line longer.
The breaker now gets the zone only for unjustified Single-line Composer
paragraphs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#466 and #537 (already on next) add the same test at different places in
tests_sysfonts.rs, so the merge kept both and the fonts tests no longer compiled.
Conflict: crates/idml/src/import.rs: the branch's `over.change` line moved into next's `range_format()`, which takes the enclosing format for it (its CrossReferenceSource caller passes it too); next's `TextVariableInstance` arm kept beside the branch's `Change` arm, with next's ignore list
Conflict: crates/idml/src/export.rs: kept next's metadata, text-variable and CJK settings helpers and the branch's `change_type`
Conflict: crates/idml/src/tests.rs: kept next's `$ID/` font test and the branch's tracked-change test
Conflict: crates/compose/src/lib.rs: kept next's baseline-grid code (grid_end/carry_grid, gyoudori placement) and wrap_slot loop; ported the branch's `need`/`holds`, the `position(holds)` carry selection (which also takes carry_grid) and the `skip_while(!holds)` segment filter, now inside wrap_slot through a `holds` argument (the slot predictor passes one that accepts every segment); #563's wraps_line(line_start) filtering stays
Conflict: crates/compose/src/tests.rs: kept next's Same As Clipping test and the branch's sliver-wrap tests
Conflict: crates/ui-egui/src/chrome.rs: kept next's app bar constants, macOS title-bar layout and search field, and the PR's `tools_slot_width` beside them (the slot-width call itself merged cleanly)
#550 places a selected graphic at x/y from its page's left edge; next measures
transform.set x/y from the rulers' zero point (view.zeroPoint, ruler origin), and the
Transform fields show a graphic's bounds from that point. transform_content now targets
x/y from the same origin as the frame path, so a typed value lands where the fields
say it is.
Conflict: crates/engine/src/cmd/object.rs: transform.set doc string joins next's "measured from the rulers' zero point" with the PR's `content?`; test modules: kept next's copy_ids_tests/tint_alone_tests and the PR's content_transform_tests
Conflict: crates/ui-egui/src/panels/mod.rs: kept next's swatch_list_tests and the PR's content_selection_tests
Conflict: ROADMAP.md: kept both progress-log lines
#573 adds a "Columns:" row to the shared table and the ar, it, pt_br and uk catalogs,
which next already has for text frame columns, so the catalogs held the key twice (the
Italian and Ukrainian tests reject duplicates). The earlier rows stay; Step and Repeat
asks for "Columns:" in a "grid" context, which Japanese, Ukrainian and Russian
translate as grid columns (列, Стовпці, Столбцы) rather than text columns.
#466 makes font_menu_body return a FontPick (family, and the style when a style row
was picked); next's CJK style dialog (ruby/kenten fonts) still expected a family
string. It sets the family and, when picked, the style, as the PR's own callers do.
#466 moves font_menu_body into font_menu.rs with its own preview cache, which calls
egui's load_texture directly; next's #393 routes every texture through
widgets::load_texture so one past the GPU's maximum side is scaled down instead of
crashing.
The PR's first three commits are patch-identical to #536/#537, already on next.
Conflict: crates/engine/src/cmd/text.rs: next's side (its `type.selectionAttrs` already carries the PR's selected text, plus next's later `mixed` and typing-format work)
Conflict: crates/fonts/src/fontdb.rs, crates/fonts/src/lib.rs: next's side (the PR's font-kind code is already there through #536; next adds aliases, PostScript names, mac_fonts)
Conflict: crates/ui-egui/src/lib.rs: kept both field sets (`recent_new_documents`, `font_sample`/`font_preview_size`)
Conflict: crates/ui-egui/src/panels/mod.rs: took the PR's move of `font_menu_body` into font_menu.rs; next's #447 test edit and `swatch_list_tests` stay
Conflict: crates/ui-egui/src/i18n.rs, crates/ui-egui/src/i18n/it.rs, ROADMAP.md: kept both sides' rows
Conflict: crates/ui-egui/src/dialogs.rs: kept next's Cell Options functions and the PR's Step and Repeat code; both sides added `cancel()`, joined into one that ends a dialog preview (PR) and puts back the Preferences language (next); tests keep next's `document_setup_app` and the PR's Step and Repeat test (the PR's copy of `dialog_context` already exists further down)
Conflict: ROADMAP.md: kept both progress-log lines
Conflict: crates/ui-egui/src/lib.rs: import_file takes the PR's `styles` early return first, then next's content-sniffing `layout` line
Conflict: ROADMAP.md: kept both progress-log lines
Conflict: crates/render/src/lib.rs: push_layer after next's back document-grid drawing and pop_layer before the front grid, so items never blend with the grid
Conflict: ROADMAP.md: kept both progress-log lines
A file named portable.txt beside the executable keeps settings, logs,
the GPU start-up record and crash recovery in a DesignCraftData folder
next to it instead of the per-user folders, as PhotoCraft and FilmCraft
do. A folder of that name is not a marker. DESIGNCRAFT_CONFIG_DIR still
wins, empty or not. The Windows portable zip now ships portable.txt;
the MSI and the macOS app bundle don't, so nothing changes there.
The Effects panel had the blend mode, opacity and Drop Shadow only. Like InDesign's it now names the level the settings apply to with its blend mode and opacity (Group: Color Dodge 100%, Object: Normal 100%), and has Isolate Blending and Knockout Group, enabled for a selected group, through object.transparencyGroup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Edit > Step and Repeat opened the generic command form (Count 1..1000, Dx, Dy, Rows, Columns, Ids). It now has InDesign's dialog: Repeat (Count, or Rows and Columns when Create as a grid is on), Offset (Vertical, Horizontal, in the document's ruler units or any unit typed) and Preview, which shows the copies on the page while the dialog is open. Cancel, Esc and ui.dialog.cancel take the preview away; OK makes the copies once, as one undo step. A value that isn't a number keeps the dialog open and says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Styles could not be taken from one document into another; a client's
styles had to be rebuilt in every new file. The Paragraph Styles and
Character Styles panels now have Load Paragraph Styles, Load Character
Styles and Load All Text Styles: pick a .designcraft or .idml file,
tick the styles to load and choose what happens to one the document
defines differently (redefine, keep, or load under a new name). The
styles, swatches and lists a loaded style names come along.
`style.load` does it in one undo step.
The renderer painted the paper, then blended page items with it: black
text in Color Dodge over blank paper dodged the white to white and
vanished, and other modes showed the same way. In InDesign (and in PDF,
where the page group starts transparent) the paper is not a backdrop:
over blank paper an object in any blend mode shows as it is, and only
the objects below it are blended with. On spreads that use a blend mode
the items are now drawn in their own group, laid over the paper once;
other spreads render as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Previews were kept in the context's data for each sample text, size
and colour, and never let go: every new text selection loaded textures
for every visible row. They now live in a cache of at most 256 that
drops the least recently used.
- A family the background read didn't list (installed since) was read
from disk on the UI thread every frame and never kept; it is now read
once and stored with the others.
- Return and Escape in a dialog's font menu are covered by #447's test
on main; this branch's duplicate is dropped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>