- FTcs reference points used a 3x3 grid (Qcs0..Qcs8). The reference application has
Qcsa centre, Qcs0..Qcs3 corners clockwise from top-left and Qcs4..Qcs7 the sides
top/right/bottom/left (measured: 50 % scale, Qcs6 keeps the bottom centre, Qcs1 the
top-right corner). Qcs8 and Qcsi stay kept steps; nothing writes Qcs8.
- file.close {"save": false} (used by ui-egui tests) became an error; it discards again
and saves as Svng N.
- Batch never performs the action's Save As, so the scratch document stayed dirty and the
recorded Close (no Svng -> "save":"ask") failed every file of "...; Save As; Close".
A Save / Save As save point now marks the document saved.
- Adjustment-layer opacity is quantised to 8 bits on load; a recorded 70 % saved back as
70.196 %. The whole percent that quantises to the same level is saved again.
- Cmd-clicking a group's thumbnail errored; it loads the whole canvas again as before.
A recorded Cmd-click on another layer's thumbnail kept the numeric id and failed strict
Save Actions; it records the layer by name (or as the Background).
Co-authored-by: yoriswind <164435053+yoriswind@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Artboards share one canvas, so a layer dragged from one board onto another in
the Layers panel (layer.moveTo, including the Alt-drag copy) changed parent but
kept its old canvas position, outside the board it now belonged to, and the
board clipped it away.
apply_move now shifts a layer that lands on a different board by the offset
between the two boards' origins, through move_layers (the Move tool's path).
Reordering within a board, leaving or joining a board from the top level,
position-locked layers and moving a board itself are unchanged. The Layers
panel's drop preview uses apply_move, so it shows the same result.
Locks are read before the drop as well as after, so a layer whose position
was locked only through the board it left stays put (review follow-up).
Co-authored-by: Claude <noreply@anthropic.com>
Main's noop_step now takes the step's params (an Arrange that cannot move the layer is a no-op too); it is public for the CLI's run and batch, which pass them.
Main now carries #9031 (Halftone) and #8923; this branch keeps only what it adds on top: the guard for a setting beside a Gallery stack's effect list, its test, and the PSD open warning for patterns that paint nothing.
step_damage narrows a layer whose only change is in its surfaces (pixels, mask, type,
smart-object and fill caches) to the bounding box of the tiles that differ: a merge walk of
the two tile maps, pointer compares only. A mask's tiles grow by its feather, all of them by
the layer's effects and the effects of the groups around it, never past the layer's whole
extents. A frame-spanning effect whose frame moved keeps the whole extents (#4053). Undo,
redo and History jumps get it for free: undoing a 60 px dab on a full-canvas layer redraws
its tiles, not the canvas, and so does a fill or filter on a small selection.
The painting commands' own damage rects go through one door, Session::hint_damage, which
intersects them with the edit's damage. Debug and test builds count a hint that misses a
changed tile in Session::damage_misses and log it; nothing panics. refresh_type_layers reports
step_damage instead of None.
Deleted: note_damage and layers_damage (identical to step_damage after layer.setProps and
layer.translate), note_inert_insert (step_damage already steps over inert layers, #1771),
and the engine's siblings_of they used.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Conflicts with main's batch #9880:
- psd file.rs / layer.rs: #5287 (PSB by encoded size, RLE tables widened on
promotion) against #6583's lazy reader. Main's new widening and length code
read `.data`, which #6583 leaves empty while the bytes stay in the source;
it now goes through `encoded()` / `encoded_len()` (also the auto-merged
lines in `rle_widening`, `encoded_len` and `LayerRecord::write`), and the
lazy reader sets `write_as_psb: false`. New test
`a_lazy_psd_promotes_to_the_same_psb_as_an_eager_one`: a lazily read PSD
writes the same PSB bytes as an eager one; it fails with a `.data` read.
- direct_select.rs / vector_ui.rs: #9321's Type Path and #6353's hidden
Work Path both kept.
- io tests main.rs: both modules. scorecard.md regenerated (12 of 181);
ui-parity.md and gaps.md follow it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main moved the engine commands into crates/engine/src/cmd/ and the
dialogs and panels into submodules. The PR's placement calls follow
them, and main's new insert sites (new_adjustment in adjust_params.rs,
Place in file_cmds/open.rs, shapes in vector_cmds/shape.rs) use
layer_place::insert_new like the PR's originals. The New Group dialog
moves to dialogs/new_group_ui.rs; the Layers panel flyout's New Group…
opens it.
Main's Session::precheck now also checks layer.new.group's and
layer.new.groupFromLayers' new params (name, color, mode, opacity,
position), so precheck_agrees_with_execute holds. Main had since added
"New Group…" to every catalog: the PR's duplicate rows are dropped.
Main's newer tests that made a layer with an open group active now
open the group last, as the PR did for the older ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main reorganised the source tree (command modules under engine/src/cmd, tools and dialogs under ui-egui/src, large files split into modules, inline test modules moved to their own files). This branch's changes to the moved and split files are ported to their new locations.