3553 Commits
Author SHA1 Message Date
Claude bfe3ab3d58 #2267: the Before label sits below the info overlay too
Review follow-up (CodeRabbit): zoomed in, the badge moves to the canvas'
top-left corner, where the info overlay draws its lines; with the overlay
on, the label was painted under its first line. The badge's top inset
now takes the overlay's extent as well as the filter pill's. The overlay
is split into its lines and an extent helper, laid out with the same
fonts, so the two can't disagree.

Test: zoomed_in_the_before_label_keeps_clear_of_the_info_overlay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-21 19:50:05 +00:00
Dylan M. Taylor 511908ab06 ci: add SonarCloud scan via shared reusable workflow
Calls storytold/craft-common-actions/.github/workflows/sonarcloud.yml@main
with secrets: inherit. Adds SonarCloud badge to README where missing and
removes the redundant sonar-project.properties (config now passed by the
reusable workflow).
2026-10-21 15:47:01 -04:00
Haocheng FangandClaude Opus 5.5 33585c93ef LRC-LIB-REFVIEW: release both Reference panes when the pin is not live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:40:24 -05:00
Haocheng FangandClaude Opus 5.5 977bbebcdc KEY-SLIDER-NUDGE: a drag that leaves the row disarms wheel edits
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>
2026-10-21 13:40:04 -05:00
Haocheng FangandClaude Opus 5.5 bb5d68978b LRC-LIB-REFVIEW: refuse malformed and deleted references clearly; release a dead pane
Review follow-ups for the Reference lifecycle fix:
- photo.setReference refuses an id that is not a photo id instead of
  pinning the active photo; only an absent or null id means the active one.
- A Recently Deleted photo is refused with a message that says to restore
  it (setReference and view.reference); the grid menu item is disabled for
  it and any refusal is shown as a toast, not dropped.
- Reference view with no live pin releases its panes (windows, region and
  pane textures, full capacity) like other views.
- A successful library switch leaves Reference for the grid; the Compare
  pair is now cleared only on success, like the reference pin.
- One compare::live helper replaces four copies of the "exists and not
  deleted" check.
- whats-new entry moved to 2026-10-21; checklist and ui-parity dates bumped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:31:05 -05:00
Haocheng FangandClaude Opus 5.5 868de3a9fe KEY-SLIDER-NUDGE: disarm the wheel on any move out of the row (#1355)
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>
2026-10-21 13:30:32 -05:00
Nathaniel Ledford 9116cc1615 docs: one 2026-10-19 heading in What's New 2026-10-21 14:29:53 -04:00
Haocheng FangandClaude Opus 5.5 6318364ce7 #323: keep the default_is_automatic regression test
The PR branch dropped it along with the PREVIEW_LIMITS import; nothing
here changes the default preview limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:16:29 -05:00
Nathaniel LedfordandClaude Opus 5.5 84dbd1b15a PERF-SMART: File Path rules compare in place instead of building strings per photo
An ASCII path and rule text are compared byte by byte, folding case and
backslashes, with no allocation; other text takes the old code unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:07:51 -04:00
Brandon Thomas ec0cda9a6f Merge pull request #2486 from storytold/release-0.11.0
Release 0.11.0
v0.11.0
2026-10-21 14:05:52 -04:00
Brandon ThomasandClaude Opus 5.5 79d916c149 Release 0.11.0
The web release now builds with craft-fonts too (web-craft-fonts), as VectorCraft's
does, so the published web app ships the Chinese and Japanese faces docs/releasing.md
promises.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 14:05:43 -04:00
Matthew James SivakandClaude Opus 5.5 85ceee31a7 Merge main into import-crs-false-warnings (conflicts resolved)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:57:58 +02:00
Matthew James SivakandClaude Opus 5.5 158923de1c Merge main into jxl-preview-thumbs (conflicts resolved)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:57:55 +02:00
Michael Anderson e93f1174c3 Merge remote-tracking branch 'upstream/main' into fix/local-browse-stamps
# Conflicts:
#	docs/parity-checklist.md
2026-10-21 12:40:16 -05:00
skybluu ad0b27c036 LRC-LIB-REFVIEW: fix Escape and catalog-local reference pins 2026-10-21 12:35:33 -05:00
Haocheng Fang f8978a0b93 Fix #1355: disarm slider wheel edits after pointer leaves 2026-10-21 12:34:49 -05:00
Claude 1df76a12da Merge upstream main into fix/issue-2267-before-label-in-view
#2274 landed with #2470; What's New keeps both entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-21 17:25:17 +00:00
Matthew James Sivak b4f387d311 Merge remote-tracking branch 'origin/main' into merge-lanczos-warps
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-21 19:19:38 +02:00
Nathaniel LedfordandClaude Opus 5.5 53ee38431d LR-VIEW-PHOTOGRID: follow test over five seeds; comment the mode switch and the names
The random-edit test now runs five seeds instead of one. A grid-mode change
re-reading every photo, and the group names growing unpruned, are now said in
the comments (the "a day or two at most" claim was wrong for capture-time edits).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:39 -04:00
Nathaniel LedfordandClaude d184b3ef50 LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched
Every catalog change gave the grid a new list of photos, and it read every
photo of it again: each one's date group (a lookup, a date parse and a
string) and its cell's shape. At 180,000 photos that was a 100 ms frame for
every batch an import added.

- catalog: Catalog::date_runs is split into date_group (one photo's own
  group) and date_runs_of (the stack rule and the runs), which the grid
  uses too.
- ui: GridCache keeps what it read of each photo of the list, position by
  position. A new list that differs by the photos the catalog says an edit
  touched is read again only for those; anything else (another view,
  order or grouping, a stack) is read whole. The square grid reads no
  shapes. A 16-photo batch at 181,749 photos: 101 ms -> 7 ms.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 13:17:39 -04:00
Nathaniel LedfordandClaude Opus 5.5 df1e6b4426 LRC-LIB-LIBFOLDERS: a scan cancelled while it goes through the files stops checking the cached probes against the disk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:05 -04:00
Nathaniel LedfordandClaude Opus 5.5 fd7fbe59e4 LRC-LIB-LIBFOLDERS: a scan cancelled during its listing asks the disk nothing more
The cancelled result is never used, but scan_files still checked each listed file's cached probe against the file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:05 -04:00
Nathaniel LedfordandClaude Opus 5.5 d1d3dbbb0e LRC-LIB-LIBFOLDERS: the sync module docs say the walk stops when the scan is cancelled
439ab04c2 fixed the checklist row but missed the module docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:05 -04:00
Nathaniel LedfordandClaude Opus 5.5 8ca082ba6a LRC-LIB-LIBFOLDERS: The docs say the walk for new files stops when the scan is cancelled
The module docs and the parity checklist still said it is not cancelled midway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:05 -04:00
Nathaniel LedfordandClaude Opus 5.5 80fcab83b0 LRC-LIB-LIBFOLDERS: The listing row counts folders and files as labels, so one reads right
The row read "1 folders, 1 files"; it now reads "folders: 1, files: 1" (all 13 catalogs).
`listed` is stored with Release and loaded with Acquire, so a reader that sees the listing over also sees what was stored before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 13:17:05 -04:00
Nathaniel LedfordandClaude 3bb084762d LRC-LIB-LIBFOLDERS: Synchronize Folder says it is listing the folder instead of sitting at "0 of N"
The scan lists the whole folder tree before it checks a photo. On a large
folder on a network share that takes minutes, and the scan's row showed
"0 of 64085" with an empty bar all that while: it looked frozen. ✕ did
not stop the listing either.

- engine: SyncProgress counts the folders and files the walk listed and
  says when the listing is over; a folder note (walk::NoteFolder) now
  answers whether to go on, and a cancelled scan answers no.
- ui: while the folder is listed, the row has an indeterminate bar and
  reads "Listing folders: N folders, M files · folder" (all 13
  catalogs); the dialog says the same; then the photos checked are
  counted as before.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 13:17:04 -04:00
Nathaniel LedfordandClaude 35cc05ef64 LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date, with one Close
When the scan finds nothing to import, relink, remove or read, the dialog
showed four greyed choices (two still ticked) and a Synchronize button
that started an empty job with an activity row. It now shows the folder,
"The library is up to date with this folder." and any Skipped lines, with
one Close and no Cancel (`only_shows`). `sync::confirm` answers
`{"upToDate": true}` and starts nothing, so `ui.dialog.confirm` and agents
get the same result.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 13:17:02 -04:00
mahmatias 77b0204331 fix(guided): the press position survives press+release in one frame
egui clears `press_origin` on the release, so a slow frame that swallows
press, move and release into one batch reports `primary_pressed` with no
origin: the gesture fell back to the release position and a real drag
wrote nothing (its length check saw a zero-length stub). The gate now
reads the primary press back from the frame's own events before that
fallback — the press decides what it means, wherever the batch ended.
2026-10-21 14:13:18 -03:00
mahmatias c19265dee0 fix(guided): the press point, not the current pointer, owns the gesture
`contains_pointer` reads where the pointer is NOW; a slow frame can
deliver the press on a menu and the move off it in the same pass, and
the gate would then pass with the saved press origin under the menu.
`layer_id_at(press_origin) == resp.layer_id` asks which layer owns the
press itself: the menu's area (or any modal) wins there and the guide
under it stays untouched. The navigator check stays for its own widget.
2026-10-21 14:13:18 -03:00
mahmatias f2e97d39fe fix(guided): the loupe's press is layer-aware, not just inside its rect
`primary_pressed` plus `resp.rect.contains` reads the raw pointer, so
anything floating above the photo — the context menu, a dropdown, a
dialog — also started a guide gesture under it. The gate now asks
`resp.contains_pointer()`, which the hit test keeps honest about
covering widgets; the navigator check stays. Two tests press on a menu
over a line and over an endpoint: nothing is selected, moved or drawn.
2026-10-21 14:13:18 -03:00
mahmatias b1c607d7ac fix(guided): the primary button and the canvas only; the press point is the gesture's own
- a secondary/middle press or one on the navigator panned the photo but
  also selected or drew a guide: the gestures take the primary button and
  skip the navigator's rect
- egui forgets the press origin by the release, so the endpoint drag
  compared against the guide's old position: a press that landed within
  the grab radius and never moved wrote a no-op guide; the gesture now
  carries the press point itself
- a selection left behind by a Delete past the last guide clears with the
  photo/tool check in crop_overlay
2026-10-21 14:13:17 -03:00
mahmatias ca26c4046a fix(guided): a stale selected index does not fire an empty guides edit; docs: un-mojibake the dashes 2026-10-21 14:13:17 -03:00
mahmatias 331e0d2103 style: fmt (blank line before point_segment_dist) 2026-10-21 14:13:17 -03:00
mahmatias aa0f9b92a7 docs(parity): LR-GUIDED-SELECT/DELETE rows land as done (press semantics) 2026-10-21 14:13:17 -03:00
mahmatias a22c496d03 feat(guided): guides start on the press and their endpoints can be dragged
A press starts what it means right away from the pointer's press point: on an endpoint (within 7 px) it drags that endpoint, committing one geometry.guides edit on release (the guide must stay at least 0.02 long; a press without a real move only selects, so a click never leaves a no-op undo entry); on a line (within 6 px) it selects the guide (a press on the selected one deselects); anywhere else it starts a new guide from the press point itself instead of where egui's drag threshold was crossed, leaving nothing selected. The endpoint being dragged is drawn bright while the pointer moves. tests_guided_guides 8/8.
2026-10-21 14:11:08 -03:00
mahmatias 7635b38c36 feat(guided): select and delete one Guided Upright guide
A click near a guide selects it (white, thicker, larger endpoints); drawing a new guide or clicking away clears the selection, and so does leaving the photo or the tool. Delete / Backspace with the tool open removes only the selected guide (geometry.guides minus its index, one undo step); with none selected it removes nothing — the photo itself is never deleted while Guided Upright is open. selected_guide is UI-only (serde skip). Coverage: tests_guided_guides 5/5.
2026-10-21 14:11:08 -03:00
helgehelge123 c631d4baed Merge branch 'main' of https://github.com/storytold/lightcraft into sidebar-adaptive-indent
# Conflicts:
#	docs/parity-checklist.md
2026-10-21 19:05:56 +02:00
Matthew James SivakandClaude Opus 5.5 a3c1d6c0f5 LR-IMP-PREVIEW-READ: UI thumbnail tests stub the reduced loader too
with_fs() now sets media.reduced_loader, which thumbnail jobs prefer over file_loader, so the render
fixture's stub file_loader was bypassed: the job read the nonexistent audit.jpg and
resizing_the_disk_cache_keeps_textures_and_skips_rebuilds got no texture (on every OS, not a flake).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 19:00:52 +02:00
Michael Anderson 536edba1e8 Merge remote-tracking branch 'upstream/main' into fix/1947-merge-duplicate-ids
# Conflicts:
#	docs/whats-new.md
2026-10-21 12:00:45 -05:00
aiongg e142e2ffa4 Merge PR #2470: integration of 43 reviewed PRs (round 1) 2026-10-21 12:59:32 -04:00
Matthew James SivakandClaude Opus 5.5 d87a8714ad LR-MERGE-HDR: merge warps sample Lanczos-3 instead of bilinear
Split out of #1887 (part 1 of 3). Every warp in the merge crate (HDR alignment,
panorama projection, Boundary Warp) sampled bilinearly: at a half-pixel offset
that is a [½ ½] filter, which keeps cos²(πf) of a pattern's fine detail (a third
at 0.3 cycles per pixel).

- lightcraft_raster::sample: Rgb32f::sample_lanczos3, a 6 × 6 Lanczos-3 point
  sampler with tabulated taps, each sample held to the range of the 4 × 4 pixels
  around it so hard edges (clipped highlights, stars) don't ring.
- align::warp, the panorama projection and Boundary Warp use it.
- align.rs: the merge luminance (`luma`) and the simplest-model choice among
  RANSAC fits (`choose_model`) are shared functions, for the full-size
  refinement that builds on them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 18:52:24 +02:00
aiongg 22ae8bc9a8 Integration: #2280 drop a clone of the Copy crop in its test 2026-10-21 15:04:38 +00:00
aiongg 21903294bf Merge track r1-rawcat into next
crates/ui-egui/locales/{cs,it,pl}-formats.json: kept the translations and added the track's new keys.
docs/parity-checklist.md: newer header line; revision rows from both sides.
docs/whats-new.md: both tracks' 2026-10-15 entries.
2026-10-21 14:58:55 +00:00
aiongg 69fcc25535 Revert "Merge PR #995: LR-VIEW-CLIPPING: ⌥-drag previews for Blacks, Whites, Exposure, Sharpening and NR (#937)"
Held for the owner: #995 and #999 overlap, and #995's author offered on 10-12 to
close #995 once his commit was in #999. docs/parity-checklist.md: header keeps the
#1485 note and drops the #995 part.
2026-10-21 14:56:17 +00:00
aiongg a1455fa7cd Merge PR #1988: #1507: web start-up treats only NotFoundError as a missing file
apps/lightcraft-web/src/files.rs: keeps #1987's and #1988's tests
docs/whats-new.md: keeps both 2026-10-15 entries
2026-10-21 14:56:12 +00:00
aiongg e9e44643a5 Revert "Integration: #995 time drag drafts only while the GPU draws the view"
This reverts commit 5aa5c6681f.
2026-10-21 14:55:59 +00:00
aiongg 697d201e97 Merge PR #1987: #1508: web backup refuses to start while changes are unsaved 2026-10-21 14:55:55 +00:00
aiongg 047e9bb962 Integration: #1924 a fresh re-import keeps its own stem sidecar 2026-10-21 14:55:45 +00:00
aiongg 5443225c3c Merge track r1-i18nci into next 2026-10-21 14:54:41 +00:00
aiongg 4e581739bd Merge PR #1924: Do not read a sibling's shared stem sidecar on import (#1905)
docs/parity-checklist.md: header keeps the newer 2026-10-18 change
2026-10-21 14:54:19 +00:00