Commit Graph
9532 Commits
Author SHA1 Message Date
David Mann eb83e5cc22 Merge PR #11092: Add Group filter to Layers panel (#10883) 2026-11-06 15:57:07 +01:00
32ca273fe6 PR #11092: the Artboard filter control test expects the error to list group
Co-Authored-By: Nurana100 <Nurana100@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:49:53 +01:00
David Mann eaddba69bd Merge PR #11249: Actions: load and save Blend If and Gradient Fill layers (#10771) 2026-11-06 15:36:23 +01:00
0217be25b4 Batch fix-up: #10438's zoomed-out nudge test expects "Nudge"
Main's #11383 renamed an arrow-key run's History step to "Nudge", as the reference
application names it; #10438's new zoomed-out test still expected "Move".

Co-Authored-By: hectorviov <hectorviov@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:10:15 +01:00
92de311b2b Actions: keep more Blend If and Gradient Fill forms exact (#11249)
Review fix-ups on #11249 after merging main:
- A midpoint outside 5..95 %, transparency stops out of range or out of
  order, and a Gradient Fill Set without transparency stops stay
  reference-application steps instead of playing clamped or keeping the
  layer's own transparency.
- An inverted Blend If range stays a reference-application step; the
  command rejects it at play.
- The Layer Style dialog's OK records `Lefx` = {Scl} beside Blend If on a
  layer without effects (measured). That Set is still the dialog's one
  step and saves back with the `Lefx` it was recorded with.

Co-Authored-By: NaufalDzz <90562913+NaufalDzz@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:07:32 +01:00
David Mann 72645904c7 Merge remote-tracking branch 'origin/main' into pr-11249
# Conflicts:
#	crates/engine/src/cmd/atn_cmds/steps_make.rs
#	crates/engine/src/cmd/atn_cmds/tests.rs
#	docs/atn.md
2026-11-06 14:55:00 +01:00
David Mann 0b765b2fbe Merge PR #11005: Pen: Make Shape turns the path into a shape layer (#10934) 2026-11-06 14:53:39 +01:00
David Mann 22e03d0bcb Merge PR #9876: New Guide: add a position unit selector for pixels, millimeters and inches 2026-11-06 14:53:38 +01:00
David Mann fdaa33c386 Merge PR #9456: feat(ui): Path mode for the Shape tools (part of #9453) 2026-11-06 14:53:37 +01:00
David Mann 6deb79ad1f Merge PR #10559: Select and Mask: resize the brush with Alt+right-drag 2026-11-06 14:53:29 +01:00
David Mann 7d10325213 Merge PR #10438: Move tool: an arrow nudge is one screen pixel, as in Photoshop (#9511) 2026-11-06 14:53:28 +01:00
2a9426cfe2 Merge origin/main into #11092 (Group filter) and fit it to main's filter row
Main added Effect, Attribute, Color, Smart Object and Artboard to the Layers
panel filter. Group is now the last type in the list, and works like Artboard:
`Filter::with_selection` fills the listed rows once per frame from
`group::listed`, so the panel, the deselect-on-apply step (#10879) and the
control channel all see the same rows; `shows_in`/`group_ids` and the
layers.rs change are gone. This also removes the duplicate `mod group;` and
`mod tests;` lines (E0428) and the rustfmt issues from the review.

- `group::listed` walks the tree with a stack instead of recursion and
  returns `LayerId`s.
- `Filter::show_all` is documented: Group keeps each group open or closed.
- Tests go through `Filter::of_app` and `panel_rows`, as the panel does,
  plus a deselect-on-apply case and a document without groups.
- control-protocol.md: `group` added to main's `layerFilter` entry.

Co-Authored-By: Nurana100 <Nurana100@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:42:50 +01:00
David Mann 8b0dd7129b Merge PR #9862: fix(transform): a click on another layer's pixels commits the box; the next click picks it (#11100, #8208) 2026-11-06 13:28:18 +01:00
David Mann 7904eee761 Merge pull request #11563 from davidmann4/integration-batch-18
Integration batch 18: 23 epic PRs (toolbar, move, selection, artboard, menus)
2026-11-06 12:42:38 +01:00
8f7d916ba5 Single Row / Column Marquee: a drag from inside the selection moves it (#11392) (#11534)
* Single Row / Column Marquee: a drag from inside the selection moves it (#11392)

`selection_drag_kind` lists the Single Row and Single Column Marquee with the
other marquees, so a plain drag that starts inside the selection moves the
outline (one step, as the Rectangular Marquee's move) instead of replacing it
with one new line. A click inside without moving still selects a line
(`finish_gesture`), never deselects, and snaps it as a click outside the
selection does (`snap_ui::snap_click`: guides, grid, layers and document bounds,
not the selection's own edges, which would pick the line beside a 1 px one). A
click on a floating piece drops it where it is first, then selects the line.
⇧ / ⌥ and drags from outside are unchanged.

A selection drag is a click only when the pointer, before snapping, never left
the press by half a pixel or more (`Drag::left_press`, `selection_release`); a
click ends where it was pressed, unsnapped, as with snapping off. With View ›
Snap on, a click inside a selection whose edge sat within reach of a guide or
the canvas edge moved it onto that edge instead of selecting the line (or, with
the Rectangular and Elliptical Marquee, deselecting). `tool_input` passes the
classification on (`finish_release`), so a drag that snapping pulls back to
where it started, or that comes back there, leaves the selection as it was
instead of taking the click's path.

Fixes #11392

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Selection drags: judge a press inside the selection before snapping (#11392)

The press handler asked `selection_drag_kind` about the snapped press point. With
View › Snap on, a press just outside a selected row snapped onto the row's edge
and counted as inside, so a Single Row / Column Marquee drag from there moved the
selection instead of selecting a new line. It now asks about the press as it
was, as `snap_ui::begin` does when it picks the drag's snapping.

The Move tool's click shortcut also needs the pointer never to have left the
press (`Drag::left_press`): a drag that snapping held at the press point and that
came back there dropped a floating piece. A drag that ends unmoved without being
a click now clears the floating piece's move preview, which nothing else
releases on that path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-06 11:01:37 +01:00
David MannandClaude Opus 5.5 64ac44bcfc Batch 18: edit.transform's stepName is a History step name, not a file path
The new `"stepName":"Transform Path"` parameter made the registry probe in
registry_filesystem_path_params_are_classified count edit.transform as a
command that takes a host filesystem path. Add it to the vector-path list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 10:24:16 +01:00
David Mann ec5eb1e2d0 Merge commit 'refs/fixprs/main' into HEAD 2026-11-06 10:21:59 +01:00
David Mann 7271c8cca7 Merge pull request #3634 from davidmann4/feat/history-snapshot-options
History Options: Automatically Create First Snapshot, New Snapshot When Saving, Show New Snapshot Dialog by Default (#2966)
2026-11-06 10:07:19 +01:00
David MannandClaude Opus 5.5 99b93f82da Batch 18 (CodeRabbit nitpicks): crop test checks the active layer's covered pixels; Esc test goes through the shortcut handler
- #11458: the straight-crop rows also check that the active layer's pixels
  inside the old canvas are the plain crop's, so a fill that recolours them
  fails.
- #11295: the Esc case sends the key through shortcuts::handle instead of
  calling cancel directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 04:04:26 +01:00
David MannandClaude Opus 5.5 2fcb4d699e Batch 18 (CodeRabbit): a zero nudge must leave History exactly as it was
The test accepted an added Nudge step; layer.translate records nothing for
a zero offset, so require unchanged entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 03:31:27 +01:00
David Mann a259993118 Merge pull request #9204 from davidmann4/fix/crop-doc-switch-view-turn
Crop: switching documents leaves the old document's view turned (#9202)
2026-11-06 03:22:25 +01:00
David Mann a46e6e0e4a Merge pull request #9286 from davidmann4/fix/crop-history-jump
Crop: History jumps wait for a pending crop (#9285)
2026-11-06 03:20:56 +01:00
David Mann bab0e5c2e2 Merge pull request #9278 from davidmann4/fix/crop-straighten-snap
Crop: a Straighten line inside the frame no longer snaps like a frame move (#9277)
2026-11-06 03:20:43 +01:00
David Mann dee552a817 Merge pull request #9284 from davidmann4/fix/crop-click-snap
Crop: a click on the frame or a handle never snaps it (#9283)
2026-11-06 03:20:20 +01:00
David Mann 5d10956221 Merge pull request #9261 from davidmann4/fix/image-size-resolution-range
Image Size: refuse a resolution outside 1..30000 ppi instead of clamping it (#9260)
2026-11-06 03:16:20 +01:00
David Mann 7122a21fec Merge pull request #9670 from davidmann4/fix/svg-markup-check
SVG: a DTD entity can't hide nesting from the depth check (#9669)
2026-11-06 03:15:57 +01:00
David Mann 03f9f53b13 Merge pull request #9213 from davidmann4/fix/crop-hidden-resample-budget
Crop W x H budgets the hidden pixels it resamples (#9212)
2026-11-06 03:15:14 +01:00
David Mann b81932c64a Merge pull request #9224 from davidmann4/fix/crop-drag-tool-switch
Crop: a tool switch during a frame drag ends the drag (#9223)
2026-11-06 03:14:21 +01:00
David Mann b7b61addcd Merge pull request #9276 from davidmann4/fix/9275-crop-esc-mid-drag
Crop: Esc in full screen cancels a drag on the default frame (#9275)
2026-11-06 03:13:52 +01:00
David MannandClaude Opus 5.5 55a2dffcaa Batch 18 (CodeRabbit): Layers empty-list menu under a filter; the pen's eraser end ends Add New Artboard
- #11500: a filter that matches no layer draws no row, so the empty-area
  right-click was never created; the whole empty list now takes it.
- #11532: flipping the pen to its eraser end is a tool switch, so Add New
  Artboard's placing mode ends as with any other switch.

Tests for both (the Layers one fails without the fix).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 03:13:29 +01:00
David Mann 908afc7bb3 Merge pull request #5533 from davidmann4/fix/5532-blend-separators
Layers: separators between the Blend Mode groups (#5532)
2026-11-06 03:12:28 +01:00
David Mann 5b9900e52e Merge pull request #9310 from davidmann4/fix/crop-drag-autoscroll
Crop / Perspective Crop: a drag held past the canvas edge scrolls the view (#9307)
2026-11-06 03:10:57 +01:00
David Mann 0b9a113414 Merge pull request #9672 from davidmann4/fix/svg-fallback-cmap-cache
SVG: the fallback font search reads each font's character map once (#9671)
2026-11-06 03:10:12 +01:00
David MannandClaude Opus 5.5 ea15b297f5 Batch 18 (CodeRabbit): parity floor back to 660; Nudge relabel only after a move; shape box drag ends on a tool switch
- menus/parity.rs: #11503 lowered FLOOR to 658 (two Warp rows went);
  with #11497's two entries the batch has 660 live again.
- #11443: a nudge that changed nothing (zero offset) no longer renames
  the state on top to "Nudge".
- #11295: a handle drag remembers its tool and ends on any tool switch,
  also to another tool that shows the box; the release of a drag that was
  just dropped is consumed instead of reaching the new tool; the box is
  drawn only over the active document's view.

Tests for each (both new UI tests fail without their fix).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 03:07:11 +01:00
David MannandClaude Opus 5.5 8f7815adc5 Batch 18 (#11295): the shape box names its own step when the transform lands as a job
In the app (background jobs on) edit.transform runs as a job and lands
after app.run returns, so renaming the top History step to "Transform
Path" right away renamed the step before it (the second shape's "New
Shape Layer") and left the scale as "Free Transform". Found in the batch
smoke run; the PR's tests run with background jobs off.

edit.transform now takes stepName "Transform Path" (any other name is
refused, as select.transformSelection's stepName from #11444), and the box
passes it instead of renaming afterwards. New tests: the box with
background jobs on (fails without the fix), and the parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 03:01:30 +01:00
David Mann 4c6d5e259a Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	docs/ui-parity.md
2026-11-06 02:32:59 +01:00
Zinadin ZidanandClaude Opus 5.5 3d60ad01f9 Channels: the panel menu has the channel commands, New Spot Channel among them (#11451) (#11557)
* Channels: the panel menu has the channel commands, New Spot Channel among them (#11451)

The Channels panel's menu had no channel items, so New Spot Channel... and
the rest could only be reached from a row's right-click menu. It now lists
New Channel..., Duplicate Channel, Delete Channel, New Spot Channel...,
Merge Spot Channel, Channel Options..., Split Channels and Merge
Channels..., each acting on the targeted channel and greyed where it can't:
Duplicate takes a single colour, alpha or spot channel, the composite of a
one-channel image, the Quick Mask or a targeted layer mask. Channel
Options... in Quick Mask mode now opens the targeted alpha or spot
channel's options, not Quick Mask Options. The panel menus run their
commands through the menu bar's enabled rules, so the Layers panel menu
greys its dialog items the same way too. The labels are in every catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Channels: New Channel... and Merge Channels... ask first, from the panel and row menus (#11451)

The panel menu's Merge Channels... ran channel.merge with no parameters, and
the engine merged the first grayscale documents into RGB and closed them with
no choice; New Channel... added a channel straight away. Both now open a
dialog when called without parameters, as New Spot Channel... and Channel
Options... already did: New Channel... reuses the Channel Options dialog
(name, colour indicates, colour and opacity), and a new Merge Channels
dialog picks the mode and the open grayscale document for each channel. The
channel rows' menu had the same two items and goes through the same path.
With parameters (scripts, the New button) both still run at once.

The Merge Spot Channel test now checks pixels, so a delete couldn't pass it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Channels: Merge Channels waits for three grayscale documents and the dialog offers only modes they fill (#11451)

With two grayscale documents open, Merge Channels... was enabled and its
dialog repeated a document for the third channel; OK then failed in the
engine and the dialog closed. The engine's rule now needs three documents
of one size (no mode merges fewer), so the menus grey the item below that.
The dialog offers only the modes the open documents can fill (RGB and Lab
from three, CMYK from four), greys OK with the reason while the picks
repeat, keeps itself open when OK is refused, and comes back with the
engine's message if the merge itself fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Channels: the Merge Channels dialog keeps its picks by document id (#11451)

The dialog kept the picked source documents by tab index, and background
work can still run while it is open, so a document moved or closed in the
meantime could leave another one at a picked index; OK would then merge,
and close, the wrong document. The picks are now document ids, resolved to
the current tabs when OK is pressed: a closed pick, or one that is no
longer a grayscale document of the same size, is refused with the reason
and the dialog stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 02:20:08 +01:00
David Mann cc361c306d Merge commit '9bef3b2dc8b84c1b6cefc8ce0dc2b01d089cd9e8' into HEAD
# Conflicts:
#	crates/engine/Cargo.toml
#	crates/engine/src/prefs.rs
#	docs/ui-parity.md
2026-11-06 02:16:44 +01:00
David Mann 3af79c0cb7 Merge main 9b02eac2c4 into integration batch 18 2026-11-06 02:14:46 +01:00
Zinadin ZidanandClaude Opus 5.5 9b02eac2c4 Export to files: a Custom JPEG quality in Artboards, Layers and Layer Comps to Files (#11481) (#11558)
* Export to files: a Custom JPEG quality in Artboards, Layers and Layer Comps to Files (#11481)

The engine commands already took `quality` (0..12), but their dialogs
offered no way to set it. Each dialog now has a Quality row with a Custom
checkbox, shared with Batch: quality is sent only for JPEG with Custom on,
so an export left alone writes exactly what it wrote before (the source
JPEG's own quality, else the encoder default), and PNG, WebP (still
lossless), PSD, TIFF and BMP never get one. Alt+Reset restores the Custom
state too. The fields follow the reference dialog's order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Tests: the export quality tests go through the dialog's own controls (#11481)

Custom and Quality are now ticked and typed through their widgets, a new
test switches one dialog from JPEG to PNG and WebP and back and checks the
Custom quality survives, and Alt+Reset is clicked through the same path the
app uses instead of calling reset_form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 02:10:18 +01:00
David MannandClaude Opus 5.5 88704d2350 Merge fix-up: the turned crop's hidden pixels after Layer 0 replaces the Background
Since #10867 the non-deleting crop turns a 2000 px layer to 2001 px bounds, so
the budget refusal names 200100 x 200100 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 02:06:41 +01:00
David Mann 4b61c8ef34 Merge commit '9bef3b2dc8b84c1b6cefc8ce0dc2b01d089cd9e8' into HEAD
# Conflicts:
#	crates/algo/src/resample/tests.rs
2026-11-06 01:58:38 +01:00
Higgs32584andClaude Opus 5.5 178bf45062 fix(transform): keep main's Distort comment; only the frontmost hit commits the box
Restore main's comment that Distort moves corners and edges (#10085), which the
merge with main had reverted. on_other_layer now checks the frontmost hit under
the click (skipping the moved and fully locked layers, as Auto-Select does), so a
grouped layer covering a top-level layer keeps the box open instead of
committing through the covered layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:52:44 -05:00
David MannandClaude Opus 5.5 5b1b6cf13d Merge fix-up: check entity markup in main's bounded embedded-SVG parse too
nesting_depth now returns a Result; main's parse_image_bounded_with gets the
same entity-markup rejection as the other callers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 01:49:40 +01:00
David Mann d563b3100b Merge commit '9bef3b2dc8b84c1b6cefc8ce0dc2b01d089cd9e8' into HEAD
# Conflicts:
#	crates/engine/tests/it/svg_smart_object.rs
2026-11-06 01:46:48 +01:00
David Mann 1d36dc5f0d Merge main into fix/5532-blend-separators 2026-11-06 01:40:39 +01:00
David MannandClaude Opus 5.5 82f5a11067 Address review: separators on main's ComboBox, without #5501
Merge main (0f15223e18) and rebuild #5532 on main's craft_ui::ComboBox:
#5501's hand-written combo_list and its call-site migrations (gradient
map, crop ratio, kerning, press_menu, the wheel and height tests) are
dropped in favour of main's versions; the list height stays #7622's.

The group lines are drawn inside ComboBox::show_ui: a 1 pt line that
takes no width during egui's sizing pass, above Darken, Lighten,
Overlay, Difference and Hue, never above the first row. Used by the
Layers panel's Blend Mode box (also the greyed one with no layer), the
Brush/Pencil Mode list (Clear starts no group), the retouch and Paint
Bucket Mode lists when they hold every blend mode (the Healing Brush's
short list draws none) and the Gradient's Mode list. The Brush Mode
right-click menu shares the same rule (starts_blend_group).

Tests: the Layers kittest at 1440x900 finds exactly the five group
boundaries; a widget test checks the first row gets no line and the list
keeps its width; a 1440x900 click released in place on the Blend Mode box
opens the list beside the box and changes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 01:40:15 +01:00
David Mann 9bef3b2dc8 Merge pull request #6088 from davidmann4/fix/snapshot-followups
History snapshots: follow-ups to #3567 (#6087)
2026-11-06 01:32:54 +01:00
David Mann 0f15223e18 Merge pull request #7739 from davidmann4/fix/crop-swap-button-turns-frame
Crop: the options-bar swap button turns the frame instead of shrinking it (#7738)
2026-11-06 01:07:36 +01:00
David Mann bac5c2802b Merge pull request #9405 from davidmann4/fix/svg-guard
SVG: a drawing the renderer panics on is an error, not a crash (#9404)
2026-11-06 01:06:04 +01:00