Commit Graph
563 Commits
Author SHA1 Message Date
aiongg 774ecf4fa5 Integration: book chapter-number test closes its chapters before Update Numbering (#341 x #615 open-chapter refusal) 2026-10-12 19:46:34 +00:00
aiongg 527e5cbc0c Merge main: atomic desktop and CLI exports, staged book updates, recovery checkpoint retention, exit recovery
upstream/main c3859c82 (#614 e198eb5d, #615 9509b2bc, #616 8e151a2f, #617 c3859c82).

Conflict: ROADMAP.md: header keeps next's change list plus orderly native exit recovery; progress log both
Conflict: apps/designcraft-cli/src/main.rs: next's case-insensitive .jpg/.jpeg check with main's write_atomic
Conflict: apps/designcraft/src/main.rs: on_exit keeps next's startup.presented() (not an Option) and adds preserve_documents_on_exit; next's discard_marked_text and main's preserve_documents_on_exit both; Services write uses write_atomic and keeps next's clipboard_text; tests both
Conflict: crates/engine/src/cmd/book.rs: main's ChapterBatch paginate with next's chapter-number resolution and {pages, chapters} result and doc
Conflict: crates/engine/src/cmd/file.rs: revert takes main's discard_document ordering without the revision + 1 (next's DocState::new hands out a fresh revision)
Conflict: crates/engine/src/recovery.rs: main's save_tracked, write_entry and open (st.bump_revision() for next's global revisions); next's reopen-twice test assertions kept
Conflict: docs/gaps.md, docs/target-app-parity.md: headers combined; next's Language, Books and Numbering lines plus main's book update safety line
2026-10-12 19:46:34 +00:00
aiongg 4be988f335 Integration: format 2026-10-12 18:57:40 +00:00
aiongg 203870ed64 Merge #591: Double-click a frame handle to fit the frame to its content; Fit Frame to Content fits text frames
Conflict: crates/engine/src/cmd/object.rs: object.fit's doc keeps next's text and adds the `axis` clause; test modules from both sides
Conflict: crates/ui-egui/src/canvas.rs: kept next's input code (it sends the second press as Down with clicks: 2) and dropped the PR's release-time DoubleClick; the PR's UI test stays
Conflict: crates/tools/src/select.rs: the handle double-click joins next's second-press preamble, after the port checks and before editing text and the frame/content toggle (Down or DoubleClick with click_count 2 on a handle runs object.fit along fitting_axis); the DoubleClick arm stays empty; module doc from both
Conflict: crates/tools/src/tests.rs, ROADMAP.md: both sides
2026-10-12 18:56:35 +00:00
aiongg 3b295ceed0 Integration: drop #402's JSON-parser overflow test (it tests serde_json, not Place) 2026-10-12 18:50:15 +00:00
aiongg f6a03984d4 Merge #402: Place: an explicit x, y, spread or width puts the image in a new frame
Conflict: crates/engine/src/cmd/file.rs: the spec keeps next's pdfCrop boxes and loadCursor with the PR's width bound and placement precedence; the PR validates `width` earlier, so next's later want_w line goes; next's loadCursor branch stays
2026-10-12 18:50:08 +00:00
aiongg 796e9d713d Integration: the Eyedropper matches the clicked frame where no image pixel shows; sampling skips clipped-out pixels and hidden states (#572, #561)
color.sample takes `matchFrom`: with no opaque image pixel under the point (an empty part of an image frame, a transparent pixel), it applies that object's attributes as object.matchAttributes does, in the same command; the tool passes the object under the pointer. sample_item and the tool walk shown_children(), so only a multi-state object's active state is sampled, and sample_item skips points outside the graphic's clipping path. object.matchAttributes's body is a function both commands share.
2026-10-12 18:47:51 +00:00
aiongg 20a14d95f0 Merge #572: Eyedropper: sample a placed image's colour into the selected text or objects
Conflict: crates/engine/src/cmd/style.rs: object.color keeps next's apply_color, spec and enabled check (#84); takes the PR's color.sample (with next's enabled check), image_color_at and sample_item; drops the PR's color_swatch, color_items and has_text_or_selection; explicit `id`/`ids` win over a text selection in apply_color; the PR's tests follow next's caret behaviour (a caret takes the sampled colour for the next typing)
Conflict: crates/tools/src/tests.rs: both sides; the eyedropper test's Asset and Graphic literals gain next's pdf_crop, pdf_box, clip and wrap fields
Conflict: crates/ui-egui/src/i18n.rs, i18n/{ar,it,ja,pt_br,uk}.rs, ROADMAP.md: both sides
2026-10-12 18:43:58 +00:00
aiongg f11097c3f8 Merge #608: UI: spring-loaded zoom (Cmd+Space / Cmd+Alt+Space)
Conflict: crates/engine/src/tooling.rs: every with_ctx caller (IME preedit, commit, end, caret) takes the PR's `|s, cx| s.tool.…` form; pointer keeps next's end_composition before dispatch and tool_key its composing() early return
Conflict: crates/ui-egui/src/canvas.rs: the cursor block takes `space` from navigation_space, then the zoom branch, then `(space && !cmd) || alt_text`; the spring-zoom pointer events carry next's `clicks`; the PR's tests name their button helper `press` (next's tests have a `primary`) and compare cursors with what cursors::show sets for the engine cursor (next paints or rasterizes cursors per platform)
Conflict: ROADMAP.md, docs/target-app-parity.md, docs/ui-parity.md: status lines list both sides; progress and change-log rows keep both
2026-10-12 18:36:04 +00:00
aiongg a680f2c937 Merge #606: Styles: selection capture accepts deleted-swatch fills 2026-10-12 18:29:52 +00:00
aiongg 3f6f8453ca Merge #577: fix(render): A group's gradient feather fades the group, on screen and in PDF
Conflict: crates/doc/src/item.rs: both tests (next's rotated group bounds, the PR's feather bounds)
Conflict: ROADMAP.md: both progress lines
2026-10-12 18:29:39 +00:00
aiongg c490660ced Merge #342 (update): feat(ui): Lay out Numbering & Section Options like InDesign's
Conflict: crates/engine/src/cmd/layout.rs: Document Setup keeps next's refusal of an out-of-range start page; layout.section's spec keeps next's styles (kanji) with the PR's 1–99999 bound; the section body takes the PR's SectionEdit, whose start number goes through next's start_number check; tests keep next's section_start_numbers_are_bounded with the PR's one-undo-step test (the PR's start_numbers_are_bounded expects Document Setup to clamp, which next refuses, so it is left out)
Conflict: crates/doc/src/lib.rs: kept next's iterative saturating page_number; dropped the PR's second MAX_PAGE_NUMBER (next has it in page.rs)
Conflict: crates/ui-egui/src/dialogs.rs: next already leaves Enter and Escape to an open popup; kept next's side and added the PR's Style-menu key test
Conflict: crates/engine/src/cmd/mod.rs, crates/ui-egui/src/{i18n.rs,i18n/it.rs}: rebased duplicates; kept next's side
2026-10-12 18:21:59 +00:00
aiongg 9d1a60785c Merge #537 (update): Engine: report the selected text; remember recently used fonts
Conflict: crates/engine/src/cmd/text.rs: kept next's selection_attrs (typing format, `mixed`) and took the PR's selected_text_preview for the selected text
2026-10-12 18:18:37 +00:00
aiongg e439d5d4d2 Merge main: preserve live state when persistence fails (#613)
Conflict: crates/engine/src/cmd/file.rs: spec strings keep next's (extension, return value, .indd); Save a Copy adds the extension then rebases data-source paths on a copy; file_save takes main's prepare-then-commit order with next's bump_revision
Conflict: ROADMAP.md: status line lists both changes; progress log keeps both sides
2026-10-12 18:17:47 +00:00
skylar taylor-barrick 8e151a2fd4 fix(recovery): retain recovered checkpoints until save or close
Keep recovered snapshots available through a second crash before autosave. Track checkpoint ownership across folders and restarted IDs; Save, Close and Revert clean only checkpoints owned by that document.

Follow-up to #506 and the retention concern in #380.

PR #616.
2026-10-12 12:15:46 -06:00
skylar taylor-barrick 9509b2bcea fix(book): stage chapter updates before saving
Prepare and stage every chapter before a book update writes files. Preserve imported IDML sources, reject open native chapters and report completed paths after a later write failure.

Follow-up to #485.

PR #615.
2026-10-12 12:12:01 -06:00
skylar taylor-barrick b9048a5b08 fix(save): preserve live state when persistence fails
Preserve document paths, revisions and collection contents when persistence fails. Rebase Save a Copy paths without changing the open document.

Follow-up to #485.

PR #613.
2026-10-12 11:53:46 -06:00
aiongg 3ac3bc90de Merge main (0.7.1): atomic saves, recovery per instance, quit keeps documents when cancelled
Conflict: crates/engine/src/atomic.rs: main's side (the reviewed #485 code supersedes the PR head on next)
Conflict: crates/engine/src/recovery.rs: main's #506 code, with next's write_entry helper kept
Conflict: apps/designcraft/src/profile.rs: main's own_run returning Option (and_then), with next's portable root_with argument
Conflict: crates/ui-egui/src/lib.rs: main's QuitState quit flow (d020b4e8) over the #545 head; next's Find Font alert guard; one import_warning_tests module (next's, with the Find Font test)
Conflict: apps/designcraft/src/native_menu.rs: next's MAC_APP_MENU layout, which already has the dc-quit item running app.quit
Conflict: ROADMAP.md: next's header with the quit change added; next's log entries then main's three
Conflict: docs/target-app-parity.md: main's atomic save, recovery and quit lines
2026-10-12 17:14:07 +00:00
moppeeerandClaude Opus 5.5 42a4846ba8 fix(ui): Numbering & Section Options applies in one step and keeps keys for its menus
Review follow-up.

- OK ran layout.section and then layout.chapterNumbering: two undo steps,
  and a chapter start the second command refused (over 99 999) left the
  section applied. `layout.numberingOptions {page, …section, chapter}`
  checks both parts before the document changes and applies them in one
  edit; the window's OK runs it. layout.section and
  layout.chapterNumbering share its parsing.
- Enter or Escape with a Style menu open confirmed or closed the whole
  dialog. Dialogs now leave both keys to an open popup (read before the
  dialog draws, since egui closes a popup on Escape that frame).
- A start page of 4294967295 overflowed page_number (a panic in debug
  builds, page 0 in release). Page numbers saturate; layout.section
  refuses start numbers outside 1-99 999 (MAX_PAGE_NUMBER, as chapter
  numbers) and Document Setup clamps its start page instead of wrapping
  a 64-bit number into 32 bits.

Also rebased on main: the restructured ROADMAP keeps main's text, and the
inventory in docs/target-app-parity.md lists chapter numbering and the
window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:05:51 +02:00
moppeeerandClaude Opus 5.5 73c37fdcca feat(ui): Lay out Numbering & Section Options like InDesign's
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>
2026-10-12 19:05:43 +02:00
moppeeerandClaude Opus 5.5 c828e1f97c fix(engine): Keep section prefixes to InDesign's rules
A section prefix is at most eight characters and contains no plus or
comma (page references and ranges use them); `layout.section` refuses
others and leaves the section unchanged. Symbols, a footnote style,
no longer number pages. The parameter documentation lists the 01, 001
and 0001 styles, and a test pins the fields the generated dialogs read
from both numbering commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:29:16 +02:00
moppeeerandClaude Opus 5.5 35ec14390f feat(engine): Document chapter numbering
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>
2026-10-12 18:29:16 +02:00
moppeeerandClaude Opus 5.5 d6635f180a fix(engine): The selected-text preview reads only the 60 characters it reports
type.selectionAttrs copied the whole selection to a string before taking
the first 60 characters, so selecting a long story copied all of it on
every query. It now skips leading blanks and stops after 60 characters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:22:03 +02:00
moppeeerandClaude Opus 5.5 ef87428481 feat(engine): Report the selected text; remember recently used fonts
type.selectionAttrs reports the start of the selected text on one line
(`selectedText`, up to 60 characters), for previews such as the font
menu's Selected Text sample. The preferences keep `recentFonts`, the
fonts last picked in the font menus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:20:17 +02:00
KnottyDyes 04319fce0f Styles: selection capture accepts deleted-swatch fills
Validate caller-supplied character fills before merging selection attributes.
Deleted swatch names already retained in text no longer block New Style from
Selection; explicit unknown fills still fail without changing state.

Cover swatch creation, text formatting, deletion and style capture, including
non-fill overrides and explicit-fill rejection with fromSelection.
2026-10-12 10:03:07 -06:00
moppeeerandClaude Opus 5.5 1411c29fbf fix(render): A group's gradient feather masks everything the group draws
The DestIn mask now covers the whole render target (and the PDF's
exported area), with the gradient kept in item space through the paint
transform, since past the gradient's ends the end opacity carries on: a
child's long drop shadow or thick stroke is faded, not cut off at a box.
feather_bounds counts only shown children and active states, walking
nested groups without recursion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:01:25 +02:00
moppeeerandClaude Opus 5.5 1c4b6885c7 fix(render): A group's gradient feather fades the group, on screen and in PDF
A gradient feather on a group (Gradient Feather tool over grouped text, as
in LYH Studio's poster tutorial) did nothing on screen: groups never went
through the effects path. In PDF the group's mask was the group's own path
bounds, and a group has no path, so the mask covered a box of zero size and
hid the group.

- Item::feather_bounds: the box the feather spans, the objects' bounds for
  a group.
- Render: a feathered group draws its objects in one layer, then fades it
  with the same mask as other objects (fx::gradient_feather_mask).
- PDF: the group's mask spans its objects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 18:01:25 +02:00
KnottyDyes e3acb8e388 Place: an explicit x, y, spread or width puts the image in a new frame
Explicit image placement leaves selected frames untouched; an explicit frame still wins. Null placement parameters behave like omitted values.

Reject nonnumeric, nonfinite and nonpositive image widths before editing. Cover rejection without document changes, valid sizing and null selection behavior with regression tests.
2026-10-12 10:00:30 -06:00
moppeeerandClaude Opus 5.5 9ab226d741 fix(eyedropper): Sample rasters only; colour text through object.color
A placed PDF, EPS or SVG under the Eyedropper matches attributes again,
as before, instead of failing with "no placed image under the point"
(Asset::is_raster, shared by the tool and color.sample). color.sample
hands its colour to object.color, which now colours selected text, the
text of selected frames ({text: true}), or the typing colour of an empty
story; a caret in existing text is refused before a swatch or undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:56:17 +02:00
moppeeerandClaude Opus 5.5 d7d6f27069 feat(eyedropper): Sample a placed image's colour into the selection
The Eyedropper on a placed image now does what InDesign does: with text
selected, clicking the photo colours the text with the image's colour under
the pointer; with objects selected, it fills them. The colour is an unnamed
colour (reused when the same colour is sampled again). Images on locked
layers can be sampled, and unfilled frames over the image let it show through.

- color.sample {at, spread?, target?: fill|stroke, ids?} samples the frontmost
  visible raster image at a spread point; one undo step; a caret or a point
  with no image is refused without an edit.
- object.color shares its swatch lookup with it.
- The Eyedropper tool sends color.sample over an image, matchAttributes
  elsewhere as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:56:17 +02:00
moppeeerandClaude Opus 5.5 56d140a34a fix(tools): Fit on a mouse double-click, along the frame's own axes; skip locked frames
The canvas reports a double-click on release (after the second Up), so the
handle double-click now fires from the mouse. Side handles map to the frame's
local axis through spread and frame rotation. Graphic frames honour the axis.
Locked frames and frames on locked layers are left alone. Text frames fit by
searching the frame height with its own columns and vertical justification,
so two columns stay two columns and Bottom/Center/Justify don't inflate it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:54:41 +02:00
moppeeerandClaude Opus 5.5 4e250565ac feat(tools): Double-click a frame handle to fit the frame to its content
In InDesign double-clicking a selection handle fits the frame to its
content: a corner fits both sides, a top or bottom handle the height, a
side handle the width. LYH Studio's tutorial uses it at 9:30 to fit the
INDESIGN text frame before moving it to the corner. In DesignCraft the
double-click switched to the Type tool.

- Selection tool: a double-click on a handle runs object.fit
  {mode: fitFrameToContent, axis: both|height|width}.
- object.fit fitFrameToContent fits text frames to their composed text:
  the bottom to the last line's descent, the right side to the longest
  line (one column), plus the insets, keeping the top-left. Overset text
  grows the frame first. Before, it fitted graphic frames only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:40:35 +02:00
Noah Scholzandskylar taylor-barrick 328b4d5a52 fix(recovery): isolate recovery data between app instances
Keep each app's recovery data in an owned run folder. Validate current folder and lock ownership and disable recovery when isolation fails instead of using the shared root.

Fixes #496.

Co-authored-by: noah1400 <48360809+noah1400@users.noreply.github.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
2026-10-12 09:26:34 -06:00
5cdcac4ace fix(save): replace files atomically
Replace native engine saves and engine/MCP exports atomically, preserving private permissions during staging and cleaning up failed writes. Add regressions for long filenames and caught writer unwinding.

Fixes #436.

Co-authored-by: aiongg <aiongtaigi@gmail.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
2026-10-12 09:19:36 -06:00
rasnoland 99ced6cc0a UI: spring-loaded zoom (Cmd+Space / Cmd+Alt+Space) 2026-10-12 16:09:24 +01:00
aiongg a5fbf5d8d4 Merge table-border-drag: Tables: drag row and column borders with the Type tool
Conflict: crates/compose/src/lib.rs: one re-export line with next's hit_cell_with and the branch's BorderHit/hit_border
Conflict: crates/tools/src/text.rs: next's IME/preedit, guides and unit_selected kept alongside the border drag; border press checked after the Down resets; drag keeps next's `cell_drag || unit_selected` guard after the border branch; Esc cancels a border drag before next's preedit guard; BorderHit via next's `compose` alias
Conflict: crates/tools/src/tests.rs: both sides' appended tests kept
Conflict: docs/target-app-parity.md: next's IDML line, branch's Tables line
Conflict: ROADMAP.md: branch entry on top of next's entries
2026-10-12 14:56:19 +00:00
aiongg 44fde50463 Tables: drag row and column borders with the Type tool
Hovering a table's inner column or row border, or its end or bottom
edge, shows a double-arrow cursor; dragging resizes instead of selecting
text. A column drag changes the column before the border and moves later
columns; Shift keeps the table width (the next column compensates), and
Shift on the end edge scales every column. Rows work the same way, and a
dragged row becomes At Least. Sizes clamp at 3 pt. One undo step per
drag, Esc cancels, locked frames refuse, and the pointer is mapped
through the frame's transform so rotated frames and turned spreads work.

New command table.resizeBorder {story?, table?, frame?, axis, index,
delta | size, keepTableSize?}; the Type tool emits it through
Begin/Preview/Commit. compose::hit_border finds the border under a point
in frame inner space.

Closes #595
2026-10-12 14:52:31 +00:00
aiongg b22fb933f8 Integration: format 2026-10-12 14:52:17 +00:00
aiongg 1ebefe4db4 Merge fill-stroke-keys: Engine: swap and default fill and stroke in one undo step
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
2026-10-12 14:48:16 +00:00
aiongg c0c4973f34 Merge place-loads-cursor: Place: with no frame selected, the graphic loads into the place cursor
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
2026-10-12 14:46:01 +00:00
aiongg bb45f12b05 Place: with no frame selected, the graphic loads into the place cursor
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.
2026-10-12 14:39:14 +00:00
aiongg 4ac6e9a540 Engine: swap and default fill and stroke in one undo step
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.
2026-10-12 14:28:58 +00:00
aiongg 3ff531ea73 Merge mac-font-activation (update): faces without drawable outlines aren't listed; packaged fonts keep a font extension (#443) 2026-10-12 12:41:20 +00:00
aiongg 22eac72797 Fonts: faces without drawable outlines aren't listed; packaged fonts keep a font extension 2026-10-12 12:33:12 +00:00
aiongg 91a2155cdd Integration: a selected graphic's Transform x/y are measured from the rulers' zero point
#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.
2026-10-12 12:32:01 +00:00
aiongg 4dbd73a6fd Merge #550: Transform values act on a selected placed graphic, not its frame
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
2026-10-12 12:29:25 +00:00
aiongg 8cd0e74a33 Merge #571: Styles: Load Styles from another document or IDML file
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
2026-10-12 12:24:34 +00:00
aiongg 4fb32bdb1b Merge #567: Swatches: Load Swatches refuses .ase files over 100,000 colors and merges in linear time
Conflict: ROADMAP.md: kept both progress-log lines (the PR's 2026-10-12 line above next's 2026-10-11 lines)
2026-10-12 12:24:00 +00:00
noah1400 d298555e43 Styles: Load Styles from another document or IDML file (#405)
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.
2026-10-12 10:41:37 +02:00
moppeeerandClaude Opus 5.5 be4f60ff85 fix: A selected graphic's Transform values are the graphic's
With a placed graphic selected, transform.set acted on the graphic but
the Control bar and Properties still read the frame's values: after
setting the image of a -45° frame to 0°, a spinner step sent -44, and a
200 pt frame holding a 400 pt image showed W 200, so 201 halved the
image. transform.info now reports the graphic's values at the top level
in that case, and sel_info gives the graphic's bounds.

Also: `id` names the target explicitly, like `ids`, so it isn't taken
as a content selection; and a content selection of locked frames
records no empty undo step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:42:06 +02:00