1818 Commits

Author SHA1 Message Date
aiongg fab871dadb Merge pull request #10535 from davidmann4/integration-batch-11
Integration batch 11: 9 ATN PRs on main
2026-11-01 19:11:02 -05:00
Gabriel Heuser 24be8ea6e2 Add editable arrowheads to Line tool (#6408) (#9259)
* Add configurable arrowheads to line tool

* Add editable arrowheads to Line tool

* Fix arrow scaling validation and PSD import defaults

* Preserve arrow geometry under affine transforms

* Preserve scaled arrowhead dimensions and prevent non-finite geometry

* Localize arrowhead Start and End labels

* Fix arrow transform editability and short line handling

* Fix PSD arrow concavity serialization

* Fix arrow dimension fallback validation

* Refine arrowhead options UI to match Photoshop

* Add opt-in arrowhead defaults to Shape properties

* Fix tool reset syntax after upstream merge

* Validate arrowhead flags and clamp copied defaults

* Preserve editable headless lines under transforms

* Fix arrowhead UI imports and formatting after v0.17 merge

* Format arrowhead properties after v0.18 merge

* Fix Clippy lint errors in arrow geometry and tests

* Fix headless arrow geometry after nonuniform scaling

* Fix proportional arrow scaling in Properties panel

* Fix Rust formatting in Properties arrow scaling tests

* test: validate invalid arrowhead dimensions without mutation

* fix: preserve arrow compatibility with older pcraft versions
2026-11-01 18:46:05 -05:00
Khawar Zamman Wani 209bce8d46 Budget PSD pattern expansion and bound multichannel conversion (#10541)
* Stream PSD user and real masks into tile rows

* Correct streamed-mask fixture metadata and test lint issues

* Budget PSD pattern expansion and bound multichannel conversion

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-01 16:00:21 +01:00
aiongg 84732d09bc Merge pull request #9618 from RickiNano/prefs/gpu-adapter-typed-read
Prefs: startup reads Graphics Adapter through the typed Performance section
2026-11-01 08:56:16 -05:00
aiongg dbe24c7e92 Merge pull request #10658 from RickiNano/fix/10640-preset-group-reimport
Ask before re-importing a brush or gradient file over its group (#10640)
2026-11-01 08:55:56 -05:00
David Mann 4b053e15ae Integration: keep the ATN contract tests, drop the extra workflow (#7561)
The contract tests no longer compiled on main (AtnItem::dictionary is now
Vec<u8>, so it is compared with b"Future event"), sat outside main's
tests/it layout, and the new atn.yml added six legs (two macOS) to every
PR against ci.yml's policy. Move the tests into tests/it so the existing
CI runs them, drop atn.yml and docs/atn-testing.md, keep main's ci.yml and
fuzz target, and note the committed fixtures in ATTRIBUTION.md.

Co-authored-by: denstu473 <63150090+denstu473@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:25:51 +01:00
David Mann 893d12bee2 Merge main into #7561 2026-11-01 14:19:49 +01:00
aiongg 713197635d Merge origin/main into prefs/gpu-adapter-typed-read 2026-11-01 13:16:28 +00:00
Khawar Zamman Wani 5d815c5a4b Stream PSD user and real masks into tile rows (#10532)
* Bound PSD import pixel storage before decoding

* Include ZIP inflater workspace in PSD preflight

* PSD import: budget unknown-mode layers, stop after a fatal layer error, keep best-effort for non-allocation limits (#8593 review)

* Stream PSD user and real masks into tile rows

* Correct streamed-mask fixture metadata and test lint issues

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-01 14:03:08 +01:00
Khawar Zamman Wani 97a83f074f Bound PSD layer and mask import memory before decoding (#10503)
* Bound PSD import pixel storage before decoding

* Include ZIP inflater workspace in PSD preflight

* PSD import: budget unknown-mode layers, stop after a fatal layer error, keep best-effort for non-allocation limits (#8593 review)
2026-11-01 12:33:09 +01:00
RickiNano 122e55a4a0 Ask before re-importing a brush or gradient file over its group (#10640)
Importing an .abr or .grd whose name matched an existing group silently
deleted that group's user presets (edited or moved-in ones included); the
preset libraries are outside document history, so it could not be undone.

- brush.presets.importAbr / gradient.presets.importGrd: `replace` now
  defaults to false; a taken group name imports beside it as "Kit (2)",
  "Kit (3)"…, and the result's `group` names the one it landed in.
- UI: when the group already holds the user's presets, a prompt asks
  Import as New Group (default) / Replace (can't be undone) / Cancel.
  Agents drive it with ui.dialog.set {"choice":"replace"} / confirm / cancel.
- The status bar names the group the file landed in.

Fixes #10640

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:49:33 +01:00
David Mann 9ec0f51dc1 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	crates/ui-egui/src/i18n/nb.tsv
2026-10-31 13:55:06 +01:00
aiongg 27f9b5be9a docs: tidy wording 2026-10-31 04:25:34 +00:00
aiongg 6d737c219e docs: tidy agent, contributor and release docs 2026-10-31 04:17:45 +00:00
David Mann e5b4ea6781 Merge main at e7b7cf11e into integration batch 10
i18n catalogs: main's new rows (#10328) appended after the batch's, as a union.
2026-10-31 02:05:31 +01:00
David Mann 28185d6dc3 Shift+right-click menu: Edit Brush… and every painting tool's own Mode list
#4985 added a canvas Shift+right-click popup that worked only for the
Brush and listed only its painting modes. In the reference application
Shift+right-click opens a menu for every painting tool: Edit Brush…
(the Brush Preset picker a plain right-click opens), a separator, then
the tool's own Mode list from its options bar:

- Brush, Pencil: the painting modes with Behind and Clear
- Clone Stamp, Pattern Stamp, History Brush: the blend modes
- Mixer Brush, Color Replacement, Background Eraser: Edit Brush… only
- Eraser: Brush / Pencil / Block (no Edit Brush…)
- Blur, Sharpen, Smudge: Edit Brush… (the reference lists modes too)
- Dodge, Burn: Shadows / Midtones / Highlights; Sponge: Desaturate /
  Saturate
- Healing Brush: its blend modes; Gradient: the blend modes; Paint
  Bucket: the blend modes with Clear (no Edit Brush…)
- Spot Healing, Magic Eraser and non-painting tools: no menu, the
  gesture keeps its old route

brush_mode_menu.rs is now a per-tool item list (Item enum + items(tool))
instead of a Brush-only list. Each row sets exactly what the tool's
options-bar control sets: a brush-based tool's mode through
tools.setBrush (Brush/Pencil also Behind and their own Clear flag), the
Eraser mode, tone range, sponge mode, gradient and bucket modes as tool
options. Blend modes are grouped with separators; the current choice is
checked; Behind and Clear are greyed on the Background layer. The menu
remembers the tool that opened it and closes on a tool change.

Only settings the options bar already has are offered. Not offered yet
(no setting here): Behind for the stamps, History Brush, Gradient and
Paint Bucket; the Blur/Sharpen/Smudge modes; the Spot Healing modes;
the Healing Brush's Sampled/Pattern source and Replace; the History
Brush source.

Control: ui.inspect's brushModeMenu reports tool, mode, choices (the
active tool's labels) and items (label/enabled/checked, separators);
ui.context.choose {id: <label>} picks a row, an unknown or greyed row
is an error that changes nothing.

Tests (kittest): each representative tool's rows in order, choosing a
row sets the options-bar state and journal, Edit Brush… opens the
picker at the click, Behind/Clear greyed on the Background, Magic
Eraser and Spot Healing open nothing; control graceful failure for bad
choices. "Edit Brush…" added to every catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:34:03 +01:00
David Mann 8e01f18a37 Merge PR #8725: feat(ui): Photoshop Fill/Stroke popover and full Color Picker for every colour swatch 2026-10-30 16:07:08 +01:00
David Mann 298178a5ed Integration: live preview for swatch Color Pickers, no-document options-bar pick, recent colours after success (#8725)
The swatches that now open the full Color Picker changed only on OK, so Photo Filter, B&W Tint,
Gradient Map stops (Properties and Image > Adjustments), the Content-Aware Fill and Select and Mask
overlays, Neon Glow and Save for Web lost the live preview main's popup had. The open picker now
previews its colour on the swatch every frame, Cancel (or OK unchanged) restores the exact opening
value (bit-exact for linear floats), and the Properties panel commits one history step when the
picker closes. A picker closed without OK or a preview changes nothing (a Gradient Map stop at a
PSD's 1229/4096 kept its location on Cancel).

With no document open, the options-bar popover's Color Picker refused OK ("no document open")
before reaching the tool-only path; it now sets the next shape's colour as on main.

A popover swatch the shape refused (a job holding the document) still joined Recently Used Colors;
it now joins only after the edit succeeds. Adds a CAF keys test for an open widget picker, and
fixes the ui-parity date and count the main merge set back.

Co-authored-by: SimoneRecchia <201361065+SimoneRecchia@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:44:50 +01:00
David Mann ac3dbfd2bc HUD Color Picker: Esc closes the HUD and keeps the picked colour
#6236 made Escape put back the colour the gesture started from. In the
reference application Escape while the right button is held closes the
HUD and keeps the colour picked so far; moving the pointer afterwards
changes nothing (measured: picked 0,40,96 from 40,90,160; after Esc and
a further move it stayed 0,40,96, also after the release).

Escape now ends the gesture like the button release does. The pick is
still one coalesced history step, so Undo takes it back.

Test: Escape closes the HUD with the picked colour kept, a later move
picks nothing, and releasing the button afterwards opens nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:08:33 +01:00
David Mann 833e69794d HUD Color Picker: square on the left, current colour under the pointer
#6236 drew the hue strip left of the saturation/value square and opened
the HUD just below the press point. In the reference application the
square is on the left with the hue strip to its right, and the HUD opens
so the colour you start from sits under the pointer: pressing without
moving changes nothing, and a small move nudges the colour from there.

The HUD now uses that layout and placement (still pulled in to stay on
screen near an edge). The rects come from one `layout` function, shared
by drawing, hit-testing and the tests.

Tests: the square is left of the strip and the starting colour's spot is
under the pointer; a mid colour opens with the pointer inside the square
and picks nothing until it moves; near the bottom-right corner the HUD
stays on screen and the press alone picks nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 15:07:22 +01:00
David Mann a19139fbda Merge PR #9757: feat(ui): live canvas preview in the text and gradient stop Color Pickers
# Conflicts:
#	docs/ui-parity.md
2026-10-30 15:02:07 +01:00
David Mann bf80e2d2fa Select and Mask: Shift Edge is a curve on coverage, so hard edges stay put
#5176 made ±100% move the edge by max(radius, feather, 2σ smooth), at
least 1 px. Measured in the reference application (a 100 px square,
Radius/Feather/Smooth each varied, Shift Edge -100/-50/+100):

- A hard selection does not move at all, at any Shift Edge.
- On a feathered edge the result is a fixed per-pixel curve, the same at
  2, 5 and 10 px feather: the pixel's odds a/(1-a) are multiplied by
  49^(shift/100). At -100% a 50% pixel becomes 2%, at -50% 1/8, at
  +100% 98%. The fit holds within ±0.05 in log-odds on every sample.

So Shift Edge is now that curve, applied last as before. It needs no
neighbours, so the morphology callback and the halo/spread it added are
gone, with the ignored benchmark that timed it (matting::morph itself
stays for Select › Modify and the mask view).

Tests: a hard edge is unchanged at ±50/±100%; seven measured
before→after coverage pairs; a feathered edge is pulled in; the engine
refine tests now check the hard edge stays and a feathered one moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:58:18 +01:00
David Mann c5ad3ed53b Merge PR #9274: Support editing selected color channel sets
# Conflicts:
#	docs/gaps.md
#	docs/ui-parity.md
2026-10-30 14:28:46 +01:00
David Mann b2db24400e Merge main at b1cfff9d3 into integration batch 10
Conflicts resolved as unions of both sides: codecs re-exports (PngRows + TiffBands), smart_cmds source imports
(main's source_surface_from_buffer and cache API with #8571's svg_source_image_in/convert_svg_source; main's
duplicate rendering import dropped), io flat.rs test modules (#8536's banded TIFF tests and main's PNG ones),
menus/invoke.rs (#8571's smart SVG intercept and main's layer.selectUnderCursor), state.rs (#8311's
type_box_overflow and main's type_insertion_style), the canvas_geom test keeps the is_finite guard, docs
status lines keep both change lists, i18n catalogs keep both sides' rows (hi.tsv: main's wording where both
added the same string).
2026-10-30 14:28:02 +01:00
Claude a825498e05 Merge storytold/photocraft main into the Fill/Stroke popover branch
748 upstream commits: append-only conflicts (i18n, ui-parity, people.toml,
the tools module lists) keep both sides. Scorecard: 12 of 183 settings do
nothing; docs/ui-parity.md follows it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsCL5E2GM6hUabP9dmYAv
2026-10-30 13:11:19 +00:00
David Mann f5ae6d5276 Merge main into pr-9274-fixup
# Conflicts:
#	crates/ui-egui/src/canvas.rs
#	crates/ui-egui/src/dialogs/adjust_editors/curves.rs
#	docs/gaps.md
#	docs/target-app-parity.md
#	docs/ui-parity.md
2026-10-30 13:16:39 +01:00
FredApps 722a9bd5cf Merge current main and remove app-local integration workflow additions 2026-10-30 12:22:42 +01:00
FredApps 0f120bbda1 Merge current main, reconcile streamed PNG profiles and workflow inputs 2026-10-30 06:52:05 +01:00
FredApps a4ab4873e8 Merge current main, retain full-sweep and new benchmark inputs 2026-10-30 03:05:00 +01:00
Claude 7a2794c730 Merge storytold/photocraft main into the Fill/Stroke popover branch
217 upstream commits. Upstream added a colour swatch (Select and Mask's
overlay colour): it now opens the Color Picker titled "Color Picker
(Overlay Color)". Content-Aware Fill and Select and Mask leave their keys
to an open Color Picker, as they did for the swatch popup it replaced
(test keys_wait_while_the_overlay_colour_picker_is_open).
docs/ui-parity.md keeps the scorecard's 12 of 182.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYsCL5E2GM6hUabP9dmYAv
2026-10-30 01:11:55 +00:00
aiongg 7d66766afb Merge pull request #10157 from FredApps/integration/reviewed-performance-2026-10-29
Integrate 16 reviewed performance and UI fixes
2026-10-29 21:07:40 -04:00
David Mann fea300dd4c Merge origin/main into integration batch 10 2026-10-30 01:47:01 +01:00
FredApps 0cb4ec56d3 Merge current main and complete retained Pen messages in Nordic catalogs 2026-10-30 00:48:24 +01:00
Dylan M. Taylor 6fdd6bb1b7 packaging: Flatpak finds and prints to CUPS printers (#10196)
* packaging: Flatpak finds and prints to CUPS printers

The Print dialog listed no printers in the Flatpak: the runtime has libcups but not
lpstat/lp, the sandbox couldn't reach the CUPS socket, and driverless network printers
(lpstat -e) need Avahi. Bundle lpstat/lp/lpoptions from CUPS 2.4.20 (Apache-2.0,
statically linked, licence installed) and grant --socket=cups and
--system-talk-name=org.freedesktop.Avahi in both manifests.

* print: lp takes the job only when CUPS lists a printer; the only printer by default; ~/.cups read-only

Review (CodeRabbit) on bundling lp in the Flatpak:
- With lp present but CUPS down or empty, the job failed on lp instead of reaching the
  IPP route and the print portal. lp_route now gives up the route when lpstat lists no
  printer, before anything is submitted.
- With no printer named, no default and one queue, IPP picked it but lp failed. lp_route
  names the only printer.
- The sandbox ignored the user's default printer, saved options and client.conf server:
  grant ~/.cups read-only in both manifests.

* print: no printers for lp means the portal, not IPP; bounded listing; CUPS socket wrapper

Review:
- When lp is there but CUPS lists no printer, the job went to the IPP route, whose
  server detection ignores ~/.cups/client.conf and could print to a local default
  printer instead of the configured server. It now goes to the print portal, or fails
  with no portal.
- The lpstat listing before a job is bounded (10 s, then lp takes the job as before)
  and runs outside SPOOLER, which guards only Windows driver calls.
- Flatpak mounts the host's CUPS socket at /var/run/cups/cups.sock whatever path
  client.conf or CUPS_SERVER names; the CUPS tools now run through a wrapper that
  points a socket path missing in the sandbox there, leaving server names alone.

* packaging: redirect a custom CUPS socket only when it is the one Flatpak mounted

Review (CodeRabbit): Flatpak picks the socket it mounts at /var/run/cups/cups.sock
with stricter rules than CUPS (flatpak-run-cups.c: a socket CUPS_SERVER, else the
first line spelled exactly "ServerName /path" in ~/.cups/client.conf, else the
default), while CUPS reads the keyword in any case and takes the last ServerName. The
wrapper now redirects only when CUPS' socket is the one Flatpak chose, so a job can't
reach a different server; otherwise CUPS fails on the missing path.

* print: a printer listing past its deadline kills and reaps lpstat

Review: the 10 s limit stopped waiting but left a hung lpstat and its thread
running, so repeated print attempts could pile them up. photocraft now runs the two
lpstat listings itself (craft-print's lpstat_command and an equivalent lpstat -e,
parsed by printers_parsed) and kills and reaps each one at the shared deadline. The
output is read on a thread that ends with the process, so nothing outlives the job.

* packaging: never redirect a CUPS_SERVER the sandbox was given

Review (CodeRabbit): Flatpak picks the socket it mounts from the host's CUPS_SERVER,
so one set by flatpak run --env or an override may not be what it mounted. The
wrapper now leaves any CUPS_SERVER alone and redirects only a client.conf socket that
matches Flatpak's choice; otherwise CUPS fails on the missing path instead of
reaching a different server.

* packaging: point CUPS at the mounted socket only when it is the one Flatpak chose, else fail

Review (CodeRabbit): with a custom socket listed first and the default last in
~/.cups/client.conf, Flatpak mounts the custom one at /var/run/cups/cups.sock while
CUPS picks the last line, finds that path, and talks to the custom server. The
wrapper now compares CUPS' socket with Flatpak's choice even when the path exists:
equal, CUPS is pointed at the mount; different, the tool fails with an error instead
of reaching another server.

Also (CodeRabbit):
- A printer named in the job goes to lp even when CUPS lists none: listing can be
  forbidden while printing is not, and the portal can't honour a name.
- A failed lpstat -e (CUPS unreachable, listing forbidden) means the list can't be
  told, so lp takes the job, instead of an empty list sending it to the portal.
- A listing longer than 1 MiB counts as no answer, instead of growing without bound.
- The kill test checks the process with kill -0, which works on every Unix.
- docs/printing.md: the only-printer fallback is on the lp and IPP routes, and the
  portal is Linux only.
2026-10-29 18:51:10 -04:00
FredApps c93c0bb36d Merge main into trimmed integration; reconcile blur, pattern and Liquify behavior 2026-10-29 23:47:53 +01:00
aiongg e74bcc4eda Merge pull request #10021 from davidmann4/i18n/swedish-combined
Swedish, Finnish, Danish and Norwegian interface languages, combined from the community catalogs (#10020)
2026-10-29 18:45:28 -04:00
FredApps 29bf828ec2 Merge upstream main into reviewed performance integration
Preserve both UI parity status entries; retain all reviewed performance changes.
2026-10-29 23:35:19 +01:00
FredApps 4f6ebb1b6e test: partition long parity matrices without dropping cases 2026-10-29 23:23:32 +01:00
Dylan M. Taylor 0d9a0f6613 Enable update checks in Flatpak (#10206) 2026-10-29 17:24:04 -04:00
FredApps 63637c4d80 Merge current main into trimmed integration, preserving exclusions and interpolation behavior 2026-10-29 21:31:18 +01:00
David Mann a3f8ef4816 Merge PR #8536: TIFF: images over 2^30 px open, decoded a group of rows at a time into the layer (#8169)
# Conflicts:
#	docs/file-format-parity.md
2026-10-29 21:06:41 +01:00
David Mann 03a0299bdb Merge PR #7795: Print: Scale to Fit Media fills the driver's printable area (#7782)
Conflicts with main's module moves resolved: driver_printable takes main's
spooler-held settings_for_layout (which already wraps the page query in
with_spooler) and drops the now unused settings/pg lines; take_turned_page and
its test move to dialogs/file_ui/print.rs and dialogs/file_ui/tests.rs;
crates/engine/src/cmd/print_cmds/tests.rs keeps main's version (the PR did
not change it in its own commit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 20:15:41 +01:00
David Mann 355831f845 Merge PR #7621: Play .atn steps that switch to another open document
# Conflicts:
#	docs/gaps.md
2026-10-29 20:04:40 +01:00
David Mann 29f37b2c40 Localization parity: the Swedish catalog has 4,552 rows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:52:23 +01:00
David Mann c0fb32db24 Finnish, Danish and Norwegian Bokmål interface languages, combined from the community catalogs
Finnish (fi) combines #5666 and #6961, Danish (da) is based on #7267 and
completed for the current UI, Norwegian Bokmål (nb) combines #8072 and
#9025. Each catalog covers the same 4,552 keys as the Swedish one, with one
term per concept. `no` and `nn` locales resolve to Bokmål; `fi-FI` to
Finnish while `sv-FI` stays Swedish.

Co-authored-by: Janiz-zzz <267742026+Janiz-zzz@users.noreply.github.com>
Co-authored-by: metuuu <25014162+metuuu@users.noreply.github.com>
Co-authored-by: pechnikov2026-star <266495960+pechnikov2026-star@users.noreply.github.com>
Co-authored-by: nikolainyegaard <6809008+nikolainyegaard@users.noreply.github.com>
Co-authored-by: Bolla76 <200539769+Bolla76@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:34:10 +01:00
FredApps 5349314b7f Refresh generated scorecard and restore original documentation workflow 2026-10-29 19:30:11 +01:00
David Mann fefd90d576 Merge remote-tracking branch 'fork/integration-batch-10' into HEAD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 19:16:12 +01:00
FredApps 255ecc81d0 Remove 21 requested PR contributions from the 108-PR integration
Retain 87 PRs. Reconcile overlapping integration fixes and update testing scope.
Removed: #7153 #7742 #5493 #9282 #3455 #9172 #3139 #3967 #4783 #5453 #8347 #1991 #3345 #4042 #4305 #4883 #4890 #5090 #6621 #5870 #5939.

Combined CI pending for this source; historical portable artifact is not applicable.
2026-10-29 18:49:17 +01:00
David Mann 528ecf842e Merge remote-tracking branch 'origin/main' into HEAD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:44:24 +01:00
David Mann f2f2ba84da Merge remote-tracking branch 'origin/main' into i18n/swedish-combined-wt 2026-10-29 18:18:06 +01:00