5189 Commits
Author SHA1 Message Date
David Mann 09eef59e90 Integration: #5878 second fix-up (two instances keep each other's Shift tool switch choice) 2026-10-22 23:40:18 +02:00
David Mann c436f61d53 Merge PR #7202: fix(atn): import a recorded Save As with its destination (#7102) 2026-10-22 23:40:18 +02:00
David Mann ee85da2ffd Merge PR #8527: fix(atn): export Black & White adjustment layers with Photoshop's BanW class (#8481) 2026-10-22 23:40:17 +02:00
David Mann 9ee6c407b6 Merge PR #8254: Image Assets: optionally keep a transparent artboard's full size 2026-10-22 23:40:16 +02:00
David Mann a23c29b53a Merge PR #5878: Preferences: old settings files take Shift-to-switch-tools on (#5647) 2026-10-22 23:40:16 +02:00
David Mann 79ab013961 Merge PR #8496: fix(ui-egui): expand layer visibility eye hitbox and render sunken well (#8467) 2026-10-22 23:40:16 +02:00
David Mann b1e4c9b1f9 Merge PR #6041: Raw: charge the retained tile intermediates together (#4959) 2026-10-22 23:40:15 +02:00
David Mann 24051914fd Merge PR #6352: fix(engine): honor lock all on layer mask commands 2026-10-22 23:40:15 +02:00
David Mann 3fdcabded4 Merge PR #5248: Keep adjustment clipping visible in compact Properties panels 2026-10-22 23:40:15 +02:00
David Mann 49a98690ad Merge PR #8354: Keep the CPU canvas sharp at 100% zoom 2026-10-22 23:40:14 +02:00
David Mann 5301a128b8 Merge PR #8509: fix(atn): preserve unsupported event kinds 2026-10-22 23:40:13 +02:00
David Mann 7f68d4e06a Merge PR #5370: fix(gpu): catch validation errors in watched compositor work 2026-10-22 23:40:13 +02:00
David Mann 7be48940b3 Merge PR #8518: fix(engine): select files correctly in Windows Explorer 2026-10-22 23:40:13 +02:00
David Mann 0fcdd660cb Merge PR #7849: Menu bar: a held Alt's auto-repeat doesn't re-arm the Alt tap 2026-10-22 23:40:12 +02:00
David Mann 837242536b Merge PR #7840: gpu, docs: fix timing test skip guard and document Windows ARM64 build on RTX Spark 2026-10-22 23:40:12 +02:00
David Mann 6e4d89d13d Merge PR #8473: test(panic_hunt): give the panic-counting self-test its own deadline 2026-10-22 23:40:12 +02:00
David MannandClaude Opus 5.5 106776f598 Integration: fix the batch's merge seams (#5815, #6658)
- io tests/it/psd_structure.rs: main's Duotone test compares the raw
  block as a slice now that #5815 shares it as Arc<[u8]>.
- ru and fr catalogs: main and #6658 both added "Continue" with the same
  translation; the second copy goes (bundled_catalogs_are_consistent).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:40:12 +02:00
David MannandClaude Opus 5.5 494cdb236a Integration: batch tests join the io test binary, regenerate the scorecard
Main's #8644 builds each crate's integration tests as one binary; #3356's
cmyk_export.rs and #5769's cylinder_warp.rs move into crates/io/tests/it.
docs/scorecard.md regenerated for the batch (#5485 DIST-220-1, #6055
UI-217-17, preferences).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:40:12 +02:00
8a2d35fcd2 Integration: an unchanged dialog keeps a baked overlay's exact ends (#7335)
After merging main, the Layer Style dialog always sends From/To as 8-bit
hex (#7072). On a baked Gradient Overlay without a source record (PSD or
.asl import) the custom and no-record paths wrote those hex ends back,
so OK without a change rounded the curve's ends (a Smooth bake's white
end 0.99999994 became 1.0, Lab ends became RGB). Like edit_endpoint for
the recorded source, a hex end that only repeats the current end is now
left out. baked_overlay_is_unchanged_until_method_selection_then_edits_
the_whole_curve fails without this.

Co-authored-by: oRE-o <42003350+oRE-o@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:40:12 +02:00
f895f844e7 Integration: a hidden Work Path is no area type target (#6230)
After merging main, the Type tool's path target fell back to the Work
Path over its whole inside, while main's #6551 only draws an unselected
Work Path for path tools. Ctrl-click Load as Selection (or deselecting
the Work Path) and a Type tool click inside it started area type in a
path nobody could see. Now the Work Path's inside counts only while it
is selected in Paths (drawn), its outline still takes type on a path
with main's 6 px band, and a missed shape path falls back to the Work
Path as on main. an_unselected_work_path_is_not_an_area_target fails
without this.

Co-authored-by: SillySilk <31193727+SillySilk@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:40:12 +02:00
David Mann a7b833caf6 Integration: stack #8529 (its merge onto main, conflicts resolved) 2026-10-22 23:40:11 +02:00
David Mann fff01d8918 Integration: stack #7335 (its merge onto main, conflicts resolved) 2026-10-22 23:40:11 +02:00
David Mann 6cb8673e8f Integration: stack #6658 (its merge onto main, conflicts resolved) 2026-10-22 23:40:11 +02:00
David Mann 9e7b35b716 Integration: stack #6055 (its merge onto main, conflicts resolved) 2026-10-22 23:40:11 +02:00
David Mann c6e628afad Integration: stack #5815 (its merge onto main, conflicts resolved) 2026-10-22 23:40:10 +02:00
David Mann 8748dcbf16 Integration: stack #5598 (its merge onto main, conflicts resolved) 2026-10-22 23:40:09 +02:00
David Mann ddf1bba02f Integration: stack #5485 (its merge onto main, conflicts resolved) 2026-10-22 23:40:09 +02:00
David MannandClaude Opus 5.5 e0fed98f23 Merge PR #8529: perf(bench): run bench_filters2 from cargo xtask perf, four heavy filters now tracked (P64-P67)
docs/scorecard.md: conflict in generated file, kept ours (b7-base); regenerated later.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:39:17 +02:00
David MannandClaude Opus 5.5 6c7e920d5a Merge PR #7335: Gradient Overlay: add Method selector and retain editable source stops
- crates/ui-egui/src/layer_style.rs: values_of keeps the PR's method/smoothness keys and source-stop ends, and main's (#7072) unconditional From/To and geometry fields.
- crates/compose/src/cmyk_tests.rs (no textual conflict): add the PR's new `interpolation: None` field to main's CMYK test GradientOverlay literal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:39:14 +02:00
David MannandClaude Opus 5.5 6aa27edb06 Merge PR #6658: fix(ui): confirm opening damaged PSD/PSB documents
crates/io/src/lib.rs: kept main's ImportOptions; import_for_open/_with and import_stages now take &ImportOptions (plus the PR's damaged flag); import_with_options_and_interrupt delegates to import_for_open_with.
crates/engine/src/jobs.rs: open job decodes via import_for_open_with(&opts) so the damage flag reaches the held-open path; main's raw_defaults and docId kept.
crates/ui-egui/src/lib.rs: open_bytes_from uses main's import_options + raw_defaults and the PR's PSD damage check via import_for_open(&opts).
Also: moved crates/io/tests/psd_recovery_generated.rs to tests/it/ (mod added, support path fixed) and adapted PR tests to ImportOptions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:39:09 +02:00
David MannandClaude Opus 5.5 945a10dc7c Merge PR #6055: Color panel: Photoshop's panel-menu modes, the same in every theme (#6000)
Conflicts:
- crates/ui-egui/src/i18n/{cs,de,el,es,fr,hu,id,it,ja,ko,nl,pl,pt-br,ru,sr,tr,uk,vi,zh-hans,zh-hant}.tsv: kept every key of both sides (main's block, then the PR's Color panel block); no duplicate keys.
- crates/ui-egui/src/panels.rs: took the PR's removal of color_picker/hsb_sliders/rgb_sliders (moved to color_panel_ui.rs); kept main's color_field_height doc comment; main's #5842 slider recolour tests ported to color_panel_tests.rs for the new HSB/RGB slider modes; main's black-HSB test dropped as the PR's hsb_sliders_take_values_on_black covers it.
- crates/ui-egui/src/color_panel_ui.rs (no textual conflict, adapted): set_color now goes through apply_color::foreground_changed with the gesture (was type_tool::foreground_changed), so every mode (sliders, ramp, alerts, wheel) recolours selected type/shapes tool-gated in one undo step per gesture; panel() calls apply_color::track_focus.
- crates/ui-egui/src/color_panel_tests.rs (adapted): new every_slider_mode_recolours_the_selected_shape test.
- docs/gaps.md, docs/ui-parity.md: union of both sides' status lines, rows and revision history; the PR's done row replaces the old "missing" Color panel row.
- docs/scorecard.md: generated, took b7-base's version.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:39:04 +02:00
David MannandClaude Opus 5.5 cab3ef6191 Merge PR #5815: perf(doc): share the XMP packet, Duotone PSD data and unsupported adjustment bytes between snapshots
- crates/engine/src/tests.rs: kept both tests (main's restore_layer_selection test and the PR's history_states_share_large_document_payloads).
- crates/io/src/psd_import.rs: kept main's parsed Duotone inks (duotone_map) with the PR's Arc<[u8]> psd_raw; also main's unknown-adjustment-key import (#6575) now builds Arc<[u8]> raw.
- crates/io/tests/adjust_warnings.rs: moved to tests/it/adjust_warnings.rs on main; PR's .into() edits applied there, plus #6322's Color Lookup test (raw.as_slice().into()).
- docs/architecture.md: union; status line names both changes, both revision-history rows kept.
- Adapted main-new sites to the PR's types: psd_export.rs (Duotone write-back via as_deref/to_vec, Unsupported block compare by slice), inspect.rs and ui-egui unsupported_marker_tests.rs (raw .into()), io tests/it/psd_unknown_adjustment.rs (slice compare).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:56 +02:00
Gabriel Luís da SilvaandClaude Opus 5.5 0ec95fa266 View › Extras (Cmd+H) hides the Move tool's transform controls (#6699) (#6705)
As in Photoshop, the Move tool's Show Transform Controls box and handles are an Extra: hiding
Extras hides them, and their handles stop responding (no hover cursor, a press doesn't start Free
Transform). Cmd+H again brings them back. Show Transform Controls and the layer are unchanged.

Fixes #6699

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 17:38:53 -04:00
David MannandClaude Opus 5.5 ced9aa6947 Merge PR #5598: Plug-ins: wire Enable Generator (Image Assets needs it)
docs/scorecard.md: conflict in generated file, kept ours (b7-base); regenerated later.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:50 +02:00
David MannandClaude Opus 5.5 f56147655d Merge PR #5485: Add opt-out startup release checks and manual update status
Conflicts resolved:
- crates/ui-egui/src/i18n/hu.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/i18n/ru.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/i18n/sr.tsv: kept base's added sections, then the PR's update-check keys
- crates/ui-egui/src/i18n/tr.tsv: kept base's Bevel & Emboss keys, then the PR's update-check keys
- crates/ui-egui/src/menus.rs: kept base's saved-workspace entries, then the PR's Help › Check for Updates reordering
- docs/gaps.md: base status line with the PR's G17 clause prepended; PR revision row above base's rows
- docs/target-app-parity.md: base status line (updated 2026-10-22) with the PR's clause prepended; PR revision row above base's rows
- docs/scorecard.md: generated, took b7-base's version

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:46 +02:00
David MannandClaude Opus 5.5 08f951b909 Merge PR #4221: Options bar: the same tool options in every theme (#4178)
Conflicts:
- crates/ui-egui/src/panels.rs: took b7-base's file (keeps align_bar in the Move bar and all other main changes) and re-applied the PR's change: dropped the six `if t.pro` guards (Marquee, Lasso, Paint Bucket, Perspective Crop, Crop, Move) and deleted the eight non-Pro hint/fallback arms (incl. the Studio Move arm, now covered by the Pro arm which already has Auto-Select, Show Transform Controls and align_bar); rustfmt reindent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 23:38:40 +02:00
David Mann e7c53231a5 Merge PR #8547: perf(gpu): layer pages that just miss the budget borrow the effect-map share, P60/P61 10× faster on integrated GPUs 2026-10-22 23:38:40 +02:00
David Mann 4d6e2b08c5 Merge PR #8465: perf(camera-raw): exposure with all scopes under its 10 ms budget (P36), same output 2026-10-22 23:38:39 +02:00
skylar taylor-barrick d89828968d fix(actions): clean up paused playbacks and protect their tokens
Restore suspended recording when the Displace map picker is canceled or fails. Reject control requests that replace a dialog continuation token. Cover failure and successful continuation paths with regression tests.

PR #8680
2026-10-22 14:32:29 -06:00
5c772cf540 Integration: refuse empty artboard assets (#8254)
Exporting artboard assets at the full board wrote a blank, fully
transparent board-size PNG for an empty artboard, or one whose contents
all sit outside the board. main refused those with "the layer is empty",
and Photoshop's Generator refuses a zero-bounds pixmap before it pads to
the board. The board is now used only when its composite has a visible
pixel; otherwise the asset fails with "the layer is empty".

Test: image_assets_refuse_empty_artboards (an empty transparent board and
a board whose only layer is outside it) expects no files and two "the
layer is empty" errors; without the check both are written as blank PNGs.

Co-authored-by: IbrahimOezhan <89545837+IbrahimOezhan@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:05:01 +02:00
8ee9917e5d Integration: move eyedropper_ring tests into tests/it (#7021)
Main now builds each crate's integration tests as one binary (crates/ui-egui/tests/it). The PR's
tests/eyedropper_ring.rs moves to tests/it/eyedropper_ring.rs behind `mod eyedropper_ring;`,
and both wgpu tests take photocraft_testkit::gpu_lock() like their neighbours.
ring_reads_over_a_flat_area_of_its_own_colour still fails with main's canvas.rs and passes with the PR's.

Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:03:30 +02:00
David MannandClaude Opus 5.5 ad68fa36e0 Integration: merge main (#7021)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 22:03:07 +02:00
dc180cd891 Integration: write a shift tool switch change made before the first save (#5878)
When the file on disk is already version 2 (another instance saved the
migrated "on"), the save base took this instance's current value, so
turning the switch off here before the first save matched the base and
was never written; the file kept "on". The base now holds the migrated
value (on), so only a change made here since loading is written.

Test: turning_the_shift_tool_switch_off_is_saved_over_another_instances_migration
(fails with the previous base: true kept instead of false).

Co-authored-by: Higgs32584 <55243596+Higgs32584@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:57:43 +02:00
4efebbe2bf Integration: lock a Shift selection drag to multiples of 45° (#6254)
Photoshop constrains a Shift-mid-drag selection move to multiples of 45°
("Move a selection border"), and the Move tool's drag of selected pixels
already uses TRANSFORM_DIRECTIONS (8). selection_drag_to used
MOVE_DIRECTIONS (4), so a near-diagonal Shift drag (delta 13,11) snapped
to the horizontal axis (13,0) instead of 45° (12,12).

Test: shift_constrains_a_selection_drag_to_an_axis gains a diagonal case
(fails with 4 directions); the floating-drag test moves to (34,22) so it
stays an axis case with 8 directions.

Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:56:36 +02:00
d921fedcca Integration: export dialog-recorded Apply Image channels, refuse numeric selectors (#8180)
The Apply Image dialog sends Channels-panel names in sourceChannel ("RGB" by
default, "Red", "Alpha 1"), but the export matched only lowercase keys, so a
dialog-recorded Apply Image failed strict .atn export. Channel names now map
case-insensitively (RGB/CMYK/Lab to the composite), an alpha channel is written
as a Chnl name reference and read back on import, and a numeric layer or channel
selector is refused instead of becoming the merged composite.

Tests: apply_image_dialog_channel_names_survive_a_strict_export (the dialog's
exact params) and apply_image_numeric_source_selectors_are_refused; both fail
without the fix.

Co-authored-by: VishnuByrraju <112673081+VishnuByrraju@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:51:51 +02:00
06530cd1a1 Integration: skip CPU canvas pixel tests only without an adapter (#6966)
The two pixel/checker tests wrapped all of harness() in catch_unwind, so a
failing fixture command or a panic in the first 12 frames was reported as
"no offscreen graphics adapter" and the test passed without checking
anything (CodeRabbit thread on line 107). harness() now runs the fixture
commands first, catches only the wgpu renderer creation (the one step that
panics without an adapter) and builds and steps the harness outside it.

fixture_failures_are_not_skipped_as_a_missing_adapter feeds a 0x0 document:
with the old catch-all it was swallowed and the test fails; now it panics.

Co-authored-by: hogawish <60434858+hogawish@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:45:09 +02:00
3175a3c4cb Integration: keep failed compositor pipelines in the map (#8118)
The parallel build skipped a non-map pipeline whose creation raised an
error, so with new_with_format (errors logged, compositor still returned)
its key was missing from kit.pipelines and the first draw panicked on the
`self.kit.pipelines[&(kernel, acc)]` index. As before the PR, a failed
non-map pipeline now keeps its invalid handle (draws report GPU errors);
only a failed effect-map pipeline is skipped (all maps go to the CPU).

Test: a_compositor_with_failed_pipelines_draws_without_panicking builds
new_with_format(Rgb9e5Ufloat) on a device with an uncaptured-error
handler and renders: it panicked at the index without the fix. The PR's
test moves into tests/it (one test binary) and takes GPU_LOCK.

Co-authored-by: 00xJS <56056764+00xJS@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:42:40 +02:00
2e29033b50 Integration: no Outside stroke share under opaque pixels on the GPU too (#5937)
The PR gives an Outside stroke no share beneath fully covered pixels on the
CPU, but no test failed without it: under a Normal layer the opaque pixel hides
the stroke anyway. It shows with Blend Interior Effects as Group on a Multiply
layer: main multiplied the red interior with the blue stroke beneath it (black).
New test outside_stroke_under_multiply_layer_leaves_interior_to_backdrop
(raster and filled shape) fails on main's effects.rs, passes with the PR.

The GPU compositor mirrored the old math (outline_share 1 at full coverage, and
1 under an opaque pixel layer); compose.wgsl now matches the CPU. Blend Interior
Effects as Group itself renders on the CPU, so on the GPU this is consistency;
a parity case pins non-Normal layers with an Outside stroke.

Co-authored-by: seotarek <30214297+seotarek@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:41:01 +02:00
David Mann aa87afc886 Integration: merge main (#8180) 2026-10-22 21:39:51 +02:00
1bfae77c16 Integration: test stringID blend modes through .atn import (#8502)
The PR's test only called blend_label/blend_ps. This adds one through the
import entry point: a Set Lyr step with Md enm("BlnM","softLight") and a
Make layer step with Usng Md "luminosity", written with atn::write and
imported, must give layer.setProps blend "Soft Light" and layer.new.layer
mode "Luminosity" with no unsupported steps. Without the PR's table rows
the Set step is unsupported (and the Make falls back to Normal).

Co-authored-by: justinjohn0306 <34035011+justinjohn0306@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 21:39:28 +02:00