11464 Commits
Author SHA1 Message Date
David Mann b4383dbeed Merge pull request #13003 from rmsff/fix/sharpen-refusal-alerts-12952
Sharpen: alert on a hidden, locked or group layer
2026-11-11 01:08:19 +01:00
FredApps 847d87bb9b Windows: a pen moves and resizes the window through the custom title bar (#7967) (#12992)
* Windows: a pen or a finger moves and resizes the window through the custom title bar (#7967)

winit takes pen and touch input as WM_POINTER messages and Windows makes no mouse
input from them, so the OS move/size loop that StartDrag/BeginResize start saw no
button down and never ran. winit only clears its dragging flag when that loop ends,
so after one pen try the mouse could no longer move the window either. A pen or
touch press on the title bar's gap or an edge now moves or resizes the window
itself (OuterPosition/InnerSize), restores a maximized window under the pen, and
stops at the minimum size; the mouse still hands the move to the OS.

* Pen title-bar move and resize follow the pen's own screen position (#7967)

On Windows winit moves the window asynchronously (SWP_ASYNCWINDOWPOS), so the
window position egui reads can be ahead of the window-relative pen position and
the drag counted the move twice (an injected pen ran +687/+909 for +200/+120).
The tablet hook now keeps the pen's screen pixels from GetPointerPenInfo
(ptPixelLocation) while the pen is down, and a PenDrag follows that.

A drag that follows the OS position no longer needs egui's pointer position: the
parked mouse cursor can leave the window as it moves away, and egui-winit's
PointerGone ended the drag after a few steps. It ends on release or when no
touch is down.
2026-11-11 01:08:12 +01:00
David Mann c908c79235 Merge pull request #12355 from rmsff/fix/type-mask-off-canvas-12074
fix(engine): a Type Mask keeps the part of its selection past the canvas edge (#12074)
2026-11-11 00:55:07 +01:00
David Mann f1b9b09f29 Merge pull request #13006 from rmsff/fix/make-selection-dialog-12917
Make Selection: Rendering and Operation groups; the dialog's step is Selection Change
2026-11-11 00:54:51 +01:00
David Mann 18ec9b1dc8 Merge pull request #12334 from rmsff/fix/vertical-type-history-name-12058
fix(engine): new vertical text is the history state "New Vertical Type Layer" (#12058)
2026-11-11 00:53:57 +01:00
David Mann d58afecac9 Merge pull request #12244 from ElNeMeR70/fix/gradient-live-drops-selection-12196
fix(engine): drop selection after masking a live Gradient Fill layer
2026-11-11 00:53:39 +01:00
David Mann 00430df4fe Merge pull request #12161 from hectorviov/fix/wand-inside-selection
Magic Wand: a New-mode click inside the selection deselects, a drag moves the outline (#11782)
2026-11-11 00:53:22 +01:00
David Mann 723cd6483e Merge pull request #12165 from hnoerenberg/fix/rotate-dialog-two-decimals-12035
fix(ui): the Arbitrary rotation dialog keeps the ruler's two decimals (#12035)
2026-11-11 00:53:03 +01:00
David Mann 8e104a84ae Merge pull request #12270 from DuBearte/fix/11980-ruler-click-keeps
Ruler: a plain click keeps the current ruler instead of deleting it
2026-11-11 00:52:10 +01:00
David Mann 536d4e7b67 Merge pull request #12214 from hectorviov/fix/count-cursors
Count tool: arrow cursors with 1+, 1 over a marker and 1- with Alt (#11773)
2026-11-11 00:51:50 +01:00
David Mann 5ba0bb0a3a Merge pull request #12201 from hectorviov/fix/eyedropper-zoom-box
Eyedropper: at 100 % zoom and below an N by N Average covers (N+1) x (N+1) screen pixels (#11751)
2026-11-11 00:51:27 +01:00
David Mann e9ab58e1f5 Merge pull request #12209 from DuBearte/fix/11966-auto-erase-exact
Pencil Auto Erase: the start pixel must be exactly the foreground colour
2026-11-11 00:51:02 +01:00
David Mann c4b4afc0a9 Merge pull request #12169 from DuBearte/fix/11886-airbrush-rate
Airbrush: about ten dabs a second while held, and a click lays two dabs
2026-11-11 00:50:39 +01:00
rmsff 551f9d2369 Test the Sharpen tool's layer alerts
Makes the Brush alert tests' helpers pub(super) and reuses them.
2026-11-11 02:08:55 +03:00
rmsff 8122d83e7c Test the Make Selection dialog's groups, greyed operations and History step (#12917) 2026-11-11 02:08:55 +03:00
rmsff 72dbfd9725 Sharpen: alert on a hidden, locked or group layer (#12952)
A Sharpen press on a hidden target layer, a layer with Lock All or
Lock Image Pixels, or with a group active opens the reference
application's modal alert instead of a status-bar message. A tool with
a colour-mode alert now gets it first and falls through to the layer
checks otherwise; the Dodge tool still has no layer alerts.
2026-11-11 02:08:55 +03:00
rmsff 8824661f47 Make Selection: Rendering and Operation groups; the dialog's step is Selection Change (#12917)
The Pen's Make Selection dialog (canvas menu, options bar) now has
Photoshop's layout: Rendering with Feather Radius in pixels and
Anti-aliased, then Operation with New / Add to / Subtract from /
Intersect with Selection as radio buttons. The last three are greyed out
without a selection. The fields and params are the same as before.

OK with New Selection names the step it added "Selection Change".
Cmd/Ctrl+Enter, the Paths panel and the combining operations keep
"Make Selection" (not measured).
2026-11-11 02:08:55 +03:00
David Mann de9add28b2 Merge pull request #13023 from ljkx/fix/pen-enter-tests-make-labels
Pen Enter tests: look the Make buttons up by their new labels (main red since #12993)
2026-11-11 00:00:07 +01:00
Dylan M. Taylor f45711c749 codecs: check TIFF structural tags, predicted rows and JPEG chunk frames (#10983)
* codecs: check TIFF structural tags, predicted rows and JPEG chunk frames

- Duplicate structural tags: the directory checks read a tag's first
  entry and the tiff crate its last, so a small SamplesPerPixel first
  and a large one last was admitted with one value and sized with the
  other. A repeated structural tag is now refused.
- Floating-point predictor: the tiff crate reads each tile row at its
  full stored width into a buffer of its own, outside the scratch cap.
  That row (TileWidth x samples x sample size) must now fit the cap.
- JPEG-compressed chunks: the tiff crate decodes each chunk into a
  whole JPEG image sized by the embedded frame header, with no limits.
  Each chunk's frame (read from the chunk or JPEGTables, at most 256
  marker segments in) must now fit the nominal strip or tile, as
  libtiff requires, and its decoded size must fit the scratch cap.

* address review: JPEG chunk dedup by count, offset-2 frame, shared fill budget

* address review: bound JPEG chunk list by scratch cap

* address review: reserve JPEG chunk list at the budgeted length
2026-11-10 17:57:55 -05:00
Dylan M. Taylor 4b1055c732 fix(text): validate font table directories in one pass and cap collection faces (#11194) 2026-11-10 17:57:38 -05:00
Dylan M. Taylor 0ff76d6f0c fix(paint): cap the total steps one stroke emits (#11195) 2026-11-10 17:57:21 -05:00
Dylan M. Taylor 73eb06adce Icon themes: parse index.theme once and refuse gzip icons (#11227) 2026-11-10 17:57:02 -05:00
Dylan M. Taylor bbf3ad7fd0 xtask: only follow https redirects when fetching PngSuite (#11231) 2026-11-10 17:56:37 -05:00
ljkxandClaude Fable 5.2 0ef215dc8b Pen Enter tests: look the Make buttons up by their new labels
The Make row's buttons are Selection… and Shape since #12993; the tests of
#12892 still asked for Make Selection and Make Shape and failed on main.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 23:18:54 +01:00
David Mann ec40f3912a Merge pull request #12882 from Bobderto/codex/12829-freeform-history
fix: record Freeform Pen strokes with their tool name
2026-11-10 22:14:53 +01:00
David Mann 0ac93368d6 Merge pull request #12815 from TrevorBrown-dev/fix/anchor-tools-targeted-path-12762
Add/Delete Anchor Point: edit only the targeted path (#12762, #12705)
2026-11-10 22:14:39 +01:00
David Mann 8e71892115 Merge pull request #12372 from rmsff/fix/gradient-mode-greyed-12008
fix(ui): a Gradient fill layer greys the Gradient tool's mode choice and is edited live (#12008)
2026-11-10 22:14:26 +01:00
David Mann 3cc12bcb2b Merge pull request #12969 from Bobderto/codex/12936-bracket-size-steps
fix(engine): follow Photoshop bracket-key brush size steps
2026-11-10 22:14:13 +01:00
David Mann 72e17777bc Merge pull request #11170 from DingusMcRinkyDinky/warp-fold-layers
Warp: a fold shows what's under its transparent parts
2026-11-10 22:14:00 +01:00
David Mann e1d3ba223e Merge pull request #13000 from rmsff/fix/pen-menu-free-transform-label-12913
Pen menu: name the transform row after what it acts on
2026-11-10 21:47:01 +01:00
David Mann c76cc5b5ad Merge pull request #12998 from rmsff/fix/sharpen-refuses-indexed-12953
Sharpen: refuse Indexed Color and Bitmap documents
2026-11-10 21:46:48 +01:00
David Mann 6a9495c506 Merge pull request #12993 from ljkx/feat/pen-make-mask-button
Pen options bar: Make: Selection…, Mask, Shape — Mask adds a vector mask from the path (#12904)
2026-11-10 21:42:05 +01:00
David Mann 3dd36011ed Merge pull request #12984 from rmsff/fix/pen-enter-deselects-12892
Pen: Enter deselects the Work Path it finished
2026-11-10 21:41:51 +01:00
David Mann ecfa246f80 Merge pull request #12987 from Bobderto/codex/12881-pattern-stamp-origin
fix(paint): match unaligned Pattern Stamp origins
2026-11-10 21:21:56 +01:00
David Mann d6ead54a81 Merge pull request #12954 from rmsff/fix/object-selection-mode-refusal-12867
Object Selection: refuse Indexed Color and Bitmap documents
2026-11-10 21:21:45 +01:00
Michael Higginsandkayrockscreenprinting 6a676ee1be Save over a flat JPEG: JPEG Options, then in place; transparent ones offered as PNG (#2223)
Fixes #2223. Carries the in-place flat Save of #5865 (closed as superseded by this PR) and revives what #2515 (@kayrockscreenprinting, closed when its author stepped away) added beyond it.

File › Save now writes back over a flat file when that file still holds the document: one plain opaque layer the format can store, and only when the file held a single image. A JPEG (and a TIFF, Targa or DDS) asks its format options first, as Photoshop does; Cancel writes nothing. A JPEG whose lone layer has transparency it can't keep is offered as a PNG. Multi-image files (animations, multi-page TIFFs, multi-size icons, multi-part EXRs) still go through Save As; the source image count is kept through crash recovery.

Co-authored-by: kayrockscreenprinting <257643019+kayrockscreenprinting@users.noreply.github.com>
2026-11-10 20:26:48 +01:00
RickiNano 4258fc838f A click in a text field's padding focuses its editor (#12302) (#12400)
* A click in a text field's padding focuses its editor (#12302)

The shared text field's box sensed hover only, so a click in the outer
point of its 6 pt sides (past egui's 5 pt reach to the editor) did
nothing. The box now senses clicks (not focus, so Tab still stops on the
editor alone); since the editor sits on top, only padding clicks reach
it, and they focus the editor with the caret at the nearest point inside.

* Text field: the editor covers the box, so a padding click is its own (#12302)

The box sensing clicks and placing the caret itself broke on a scrolled
value: pressing the padding takes the focus from the editor, which then
scrolls back to the start before the click lands, so the caret went to
the wrong character. The editor now fills the box but the trailing space,
with the padding as its frame's inner margin, so egui handles a padding
click like any other: focus, caret, scroll, drag and double-click.

Tests from review: corner clicks (fail on main), an empty field, a
scrolled value, a disabled field, the trailing popup arrow keeping its
click, and the editor-click test no longer depends on glyph widths.
2026-11-10 20:08:39 +01:00
RickiNano 65bd584259 fix(ui): Reset Tool gives the Dodge tool a 65 px soft tip at 25 % spacing (#12684) (#12793)
fresh_brush gave the Dodge tool the plain 20 px hard default at 10 %
spacing. It now gets the reference's 65 px soft round at 25 % spacing
after Reset Tool and Reset All Tools, and on its first pick. The Burn
tool has the same measured tip, so both share TONING_TOOL_TIP.
2026-11-10 20:08:31 +01:00
RickiNano 4af62e8abb fix(ui): Delete on an anchor selected with Add Anchor Point removes it, not the layer (#12703) (#12796)
* fix(ui): Delete on an anchor selected with Add Anchor Point removes it, not the layer (#12703)

With the Add Anchor Point tool and one anchor selected (Ctrl+click), Delete
and Backspace fell through to Edit > Clear and deleted the active layer.
They now remove the anchor and its two segments, as in the reference
application: a closed subpath opens there. One history step, Delete Anchor
Point.

- vector: edit::delete_anchor_and_segments (a closed subpath opens at the
  anchor; an open one loses an end or splits at an inner anchor)
- engine: path.deleteAnchor takes "segments": bool (default false keeps
  joining the neighbours, as the tool's click does)
- ui: delete_key_deletes_anchor next to delete_key_deletes_work_path, and a
  Delete/Backspace branch before the work path's

* test(vector): Delete on one anchor of a closed two-anchor subpath leaves the other, open (#12703)

The kept anchor retains its handles and smooth flag, and the subpath keeps its path operation.
2026-11-10 20:08:21 +01:00
RickiNano 3e55928e63 Smudge Strength: alert when a typed value is out of range (#12982)
* fix(ui): Sharpen Strength alerts when a typed value is out of range (#12949)

With the Sharpen tool, Strength now takes whole numbers 1 to 100 and a
value typed past either end becomes the closest one with the "Closest
value inserted" alert, as the Blur tool's does since #12650. Smudge keeps
its silent clamp. The field edits a copy, so showing the Sharpen bar does
not round a fraction already in the shared Strength.

* fix(ui): Smudge Strength alerts when a typed value is out of range (#12962)

With the Smudge tool, Strength now takes whole numbers 1 to 100 and a
value typed past either end becomes the closest one with the "Closest
value inserted" alert, as the Blur (#12650) and Sharpen (#12949) tools'
do. All three tools now share one path through the field, which edits a
copy, so showing the Smudge bar does not round a fraction already in the
shared Strength.
2026-11-10 20:07:25 +01:00
David Mann 0d08cb7dd6 Merge pull request #6215 from davidmann4/feat/ui-217-4-columns-unit
Image Size: a Columns width unit from the Column Size preference (#6214)
2026-11-10 19:36:23 +01:00
rmsff a37665f4f3 Test the Pen menu's Free Transform row labels
Covers no path, a path being drawn, a closed path, a path that exists but
isn't active, and the unchanged Path Selection and Direct Selection menus,
on screen and in ui.inspect. Reuses the canvas tool menu test helpers (app,
choose_open, harness, right_click) instead of copying them.
2026-11-10 21:13:40 +03:00
rmsff 01a2a3455b Pen menu: name the transform row after what it acts on
The Pen's canvas menu now reads Free Transform (greyed) when the document
has no path, Free Transform Points while a path is being drawn, and Free
Transform Path on a finished path, as in the reference application. A path
that exists but isn't active keeps Free Transform Path, as do the Path
Selection and Direct Selection menus. ui.inspect lists the same label.
2026-11-10 21:13:40 +03:00
rmsff cbff770f0e Test the Sharpen tool's Indexed Color and Bitmap refusal
Makes the Dodge refusal tests' session, steps and pixels helpers
pub(super) and reuses them.
2026-11-10 21:03:11 +03:00
rmsff 3b5a62e75f Sharpen: refuse Indexed Color and Bitmap documents (#12953)
paint.sharpen and its live stroke fail with the reference application's
alert text, and a press with the Sharpen tool opens that alert, as the
Dodge tool does since #12686.
2026-11-10 21:03:11 +03:00
ljkxandClaude Fable 5.2 e530d6c9f4 Pen options bar: Make: Selection…, Mask, Shape; Mask adds a vector mask from the path (#12904)
Path mode now shows the caption "Make:" followed by Selection…, Mask and
Shape, all greyed without an active path. Mask runs
layer.vectorMask.fromPath on the path being drawn (finished first) or the
active path: one History step, Add Vector Mask, with the Background
turned into Layer 0 inside it.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-10 19:00:42 +01:00
FredApps 96581039a8 Merge main into feat/ui-217-4-columns-unit 2026-11-10 18:41:49 +01:00
David Mann 609e2aa727 Merge pull request #12883 from rmsff/fix/warp-split-default-thirds-12495
Warp: a one-way split on the Default grid keeps only the thirds across it
2026-11-10 18:38:59 +01:00
DingusMcRinkyDinkyandClaude 54ea149f2f Warp: working out a fold's order can't stall the thread pool
Tiles are drawn on the thread pool, and the first tile that meets a fold works
out the fold's order while the others that need it wait. The order's sort was
shared with the pool, so while the working thread waited for its halves the
pool could hand it another folded tile, which then waited for the order on the
same thread: the warp never finished. It needed some tiles folding and others
not, and showed about once in ten 24 MP warps on 16 threads.

The sort now runs on the working thread alone. It costs nothing measurable:
a 24 MP fold in stacking order takes 0.28 s, as before.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EZbgszHyuEuWAzxaamteuU
2026-11-10 18:36:10 +01:00
Dan ea771f39e0 fix(paint): match unaligned Pattern Stamp origins 2026-11-10 17:29:12 +00:00