* 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.
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.
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).
* 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
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>
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>
* 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.
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.
* 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.
* 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.
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.
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.
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.
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>
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