Preserve current main, adapt frame/input and IME handling, and keep library
check results stable across layout passes. Include the matching Nix font lock
and reviewed attribution changes.
The bottom bar, the Info panel and the filter bar each drew their own
row of stars, and the grid badge, filmstrip badges and compare caption
had private painter loops. They now share rating::Rating (a clickable
row: hover previews, clicking the current rating clears it, read-only
and disabled states, left/right arrows on a focused star) and
rating::paint_rating / paint_star for painter-only contexts.
Existing automation ids (star:bottom:n, star:info:n, filter:starN) are
unchanged. The preset, profile and theme favourite stars use
paint_star too, so Icon::Star lives only in rating.rs.
Co-Authored-By: Claude <noreply@anthropic.com>
crates/ui-egui/src/widgets/tests_numeric_entry.rs: keep both sides' tests.
docs/parity-checklist.md: newer header (2026-10-21); KEY-SLIDER-NUDGE from #1402, KEY-SLIDER-TYPE from #1687; both revision rows.
The disarm waited for the button to be released outside the row, so a
drag that went out and came back kept the wheel armed. Leaving disarms
now even mid-drag, and a drag that starts outside the row does not arm.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups:
- Check every PointerMoved / PointerGone of the frame, not only where the
pointer ended: a slow frame merged leaving the row and coming back, so
the slider stayed armed (new test for both events).
- One global armed slider (`wheel_slider_key`) instead of a bool per
slider: unarmed sliders no longer write context data every frame, and
arming another slider disarms the previous one. The wheel remainder is
cleared on arming and disarming, so the second focus check is gone.
- The sideways branch uses `pointer_in_row` too.
- Document that Tab focus arms the arrows only; move the whats-new entry
to 2026-10-21; update the KEY-SLIDER-NUDGE row, header and history; fix
a test comment that described the old remainder carry-over.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rule's − and + were laid out right to left in whatever room the row had
left. The dialogs share one window, which keeps the width the previous
dialog left it at, so after a narrower one the rule editor only grew to
the end of its longest value: a date "is between" then had no room left,
and the − and + were drawn over its end date and the end date's calendar
button. That calendar was there all along, but the + on top of it took
the click. The buttons now follow the value (pushed to the right edge
when there is room, as before), so the dialog widens to the row.
Every dropdown list drew its items with the theme's resting button
border. An unhovered item gives up that border's width of padding, so a
hovered one needed 2 points more, and the longest name of a submenu
sized to it (Date ▸ Capture Date, Keywords & People ▸ Keyword Count, and
the longest name of every other group) wrapped onto a second line. The
dropdowns' lists and their submenus now drop the resting border, as
egui's own menus do.
Fixes#2353Fixes#2352Fixes#2354
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A right-click on a photo (or any widget) while its own context menu was open
flashed the menu at the new spot and closed it again on the same frame. egui's
`Popup::show` judges "was open last frame" by the popup's id, so the click that
reopened the menu at the pointer also counted as a click while open and closed
it under `CloseOnClick`. A right-click on a different widget was fine.
`widgets::context_menu` wraps `Popup::context_menu` and ignores clicks on the
frame of the right-click that opens or moves the menu; every context menu
(30 sites) goes through it, and `TextField` applies the same rule to its
close-on-click-outside menu (`widgets::context_menu_close`).
Tests: `right_clicking_elsewhere_moves_the_context_menu` (headless grid; failed
at the second frame before the fix) and `right_clicking_again_moves_the_menu`
(text field). docs/ui-parity.md: Context menus row and revision history.
Fixes#1877
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Keep the HDR histogram and SDR/HDR legend, virtualized sidebar rows and current preset grouping while retaining shared chevrons and inset interactive clipping buttons. Apply shared submenu arrows to the new album import menus. Drop the earlier inpainting compatibility change now present upstream.
Validation: formatting, strict native Clippy and HEIF checks passed; 811 compiled UI tests passed; native SDR and HDR screenshots checked. Full workspace CI is blocked by all_masks_overlay_shows_every_visible_mask_at_once, reproduced unchanged on clean upstream b3d392b4. Publish this prepared rebase at the contributor’s explicit request with that baseline failure documented.
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
A press on a slider's value held past egui's click time ended with no click on
release, so the field it had opened closed again (the field "flashes and
vanishes"). Any release now keeps the field open; a sideways drag of more than
a few points on the value scrubs it instead (as along the track, a tenth with
Shift, one undo step), as in Lightroom Classic.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A raw imported while its format couldn't be decoded kept preview_only until a
manual Reload, so new decoders in a release never reached existing photos.
When a library opens in another app version, its preview-only photos whose
stamp differs are probed again in the background and get exactly what Reload
from Disk gives them (shared reload_ops): a file that decodes now loses the
flag, one that still doesn't gets the current reason and a fresh stamp. The
result is one journaled system batch, not an undo step; develop settings and
history are kept. Unreadable files are left for next time, photos changed
while probing are skipped, and a result for a library closed meanwhile is
dropped. A toast says how many raws now develop from their raw data.
- engine: cmd/recheck.rs (stale / probe / apply) and
library.recheckPreviewOnly {all?} -> {checked, updated, cleared}; refused
without file access, where every probe would clear every flag
- desktop: recheck::tick once per library generation, through tasks::spawn
("Checking raw files" in the activity stack)
- the preview-only notice (Edit, Info) gains a Reload from Disk button
- strings translated in all nine catalogs; docs/mcp.md and the parity row
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As over Lightroom's values, a press on the number next to a slider's name
that moves sideways now changes the value as dragging the thumb would: the
pointer's travel over the track's width, a tenth as far with Shift, on the
control's steps and range, as one undo step. A press that moves less than
3 points sideways is still a click that opens the value for typing
(KEY-SLIDER-TYPE), and the pointer over the value is the horizontal-resize
cursor. The tooltip says both ("Click to type a value, drag to change it"),
translated in every catalog.
Tests: scrub distance and direction, Shift, clamping, steps, one interaction
per scrub, no field or draft left behind, a jittery click still types, a
disabled slider doesn't scrub. The readout test that drags away from the
value now drags straight down, so it still checks that a cancelled press
keeps neither a value nor the keyboard.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A trackpad swipe, a tilting wheel or Shift+wheel over a Develop slider nudges it by the
wheel/arrow-key steps, without selecting it first (the right panel only scrolls vertically).
Only a mostly sideways movement counts, so scrolling the panel leaves the sliders alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A double-click on a slider's name or thumb already reset it, but nothing said so: only the value had a
tooltip. Resting the pointer on the name or on the thumb now shows "Exposure — double-click to reset
it", the wording (and translations) the curve channels already use. The rest of the track, which is
clicked and dragged, gets no tooltip, and the value keeps "Click to type a value".
The first click of a double-click on the thumb moved the value to where the pointer landed, a few
points off its centre: one history step, then the reset another. A click on the thumb now leaves the
value alone, so the reset is one undo step, as from the name. A disabled slider's name no longer
resets it.
No per-slider reset button: Lightroom has none, and the double-click it documents is now shown where
it works. Tests: tests_slider_reset.rs (name and thumb reset Exposure and Contrast in one undo step,
the hints, a click on the thumb keeps the value, typing a value still works) and
widgets/tests_slider_reset.rs (a disabled slider's name).
egui gives the opening release's click to the readout, so the field under it surrenders the focus. Only the field's first two frames took it back: a click held any longer ended the edit, and the value could only be typed while holding the button.
A Color Mixer Hue/Saturation/Luminance (or curve) targeted-adjustment tool
left on takes over every click and drag on the photo, so click-to-zoom and
panning stopped working and the canvas looked frozen (user report). Esc
already turned it off, but nothing said the tool was on: the mixer's
buttons look like tabs. Turning one on now shows a toast: drag up or down
on the photo, Esc to stop.
A mouse wheel notch scrolled egui's default 40 points; an open Edit panel
is 2000+ points tall. Lines now scroll 100 points (theme::WHEEL_LINE_POINTS,
set in apply_kind so every theme has it), about Lightroom's step; trackpads
report points and are unaffected. What assumed a 40-point notch keeps its
per-notch behaviour: wheel zoom (Ctrl+wheel and the loupe's plain wheel)
uses theme::WHEEL_ZOOM_PER_POINT so a notch still zooms ~1.22x, and a
focused slider's wheel nudge counts one notch (WHEEL_LINE_POINTS) per step.
Tests: the tool announces itself and Esc leaves it (view unchanged); three
wheel notches scroll at least 300 points (120 before); every theme sets the
notch and keeps the zoom per notch; wheel nudges in notch units; the
slider wheel-nudge test lets egui's smoothing deliver its 120 points.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
canvas_keys.rs gives every handle on the photo a focusable stand-in with
an AccessKit name and position: crop corners, edges and box (crop.drag),
spot targets and sources plus a New spot point (Return adds), radial and
linear gradient handles and mask pins. Arrows move by 0.5% (Shift 5%),
one undo step per press; the stand-in keeps arrows/Return/Space from the
shortcuts. The audit now counts any focusable or clickable node; ~50
hand-drawn icons, tiles and rows are announced as buttons. A test walks
Tab through the Edit/Crop/Remove/Masking panels top to bottom.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tests/accessibility.rs walks the AccessKit tree headless in every view,
Develop tool and 13 dialogs and fails on unnamed controls, sliders without
value/range and untitled dialogs. Fixes what it found: text fields are
named by caption or hint, develop sliders expose min/max/step/value text
and take Increment/Decrement, Tab-focused sliders take the arrow keys,
Auto Stack's slider is named. Also as_chunks in spots.rs for the newer
clippy lint. Docs: ui-parity audit section, checklist, gaps, ROADMAP.
Sources: own design.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
#884 focuses a develop slider on click so the wheel and arrows adjust it, but a focused widget
owned the whole keyboard, so after touching a slider no shortcut fired (O for the mask overlay,
caught by mask_adjustments_hide_overlay_without_disabling_the_mask). Now a selected slider owns
the arrow keys only. The wheel test opens the Edit panel explicitly (the demo may start on it, and
panel.edit then toggles it shut), and the Export dialog snapshot is 546 px wide since #833's
nine watermark positions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BKWB9TCnvzJHV6xMLAj2J4