diff --git a/docs/gestures.md b/docs/gestures.md
index 7f8a1ce..25ee983 100644
--- a/docs/gestures.md
+++ b/docs/gestures.md
@@ -5,7 +5,7 @@
Every entry here is extracted from the comment beside the code that implements it, so this file cannot describe a gesture the application does not have. Add one by writing a `GESTURE:` block next to the implementation; there is nowhere else to write it.
-31 gestures, in 3 places.
+30 gestures, in 3 places.
## Develop
@@ -16,7 +16,7 @@ Every entry here is extracted from the comment beside the code that implements i
Sampling a neutral is the first move of the tonal pass — every colour judgement afterwards is measured against where the grey was put — and guessing at two sliders until a wall stops looking green is the wrong way round. One click is one sample and one step to undo; the sliders stay, because a sampled neutral is where the decision starts rather than where it ends.
-`ui/dr-ui/ui/adjust.slint:157`
+`ui/dr-ui/ui/adjust.slint:158`
### Magnify the photograph by any amount
@@ -25,16 +25,7 @@ Sampling a neutral is the first move of the tonal pass — every colour judgemen
Anchored on the fingers' midpoint, and on the pointer, so the gesture reads as magnifying the picture rather than sliding it about. Double-tap is the way to an exact 1:1; this is the way to everything in between.
-`ui/dr-ui/ui/app.slint:2018`
-
-### Paint a mask by hand
-
-- **Touch** — Choose Paint or Erase, then drag on the photograph
-- **Pointer** — Choose Paint or Erase, then drag
-
-A model's mask stops inside a shoulder and leaks into the hair, and no single edge control fixes two errors that go opposite ways. The whole stroke is one step in the history, so taking a mark back costs one press however long it took to make.
-
-`ui/dr-ui/ui/app.slint:2091`
+`ui/dr-ui/ui/app.slint:1849`
### Move a magnified photograph about
@@ -43,7 +34,7 @@ A model's mask stops inside a shoulder and leaks into the hair, and no single ed
Only once there is something outside the viewport to reach, which is why the cursor becomes a hand exactly then. The view is clamped to the frame: panning past the edge would show undefined area beside the photograph, and that reads as a rendering fault rather than as the end of the picture.
-`ui/dr-ui/ui/app.slint:2224`
+`ui/dr-ui/ui/app.slint:2002`
### Take back the last change
@@ -53,7 +44,7 @@ Only once there is something outside the viewport to reach, which is why the cur
A whole drag is one step, so undo takes back a decision rather than a frame of a gesture. The list is there because arriving six steps back costs what arriving from one does.
-`ui/dr-ui/ui/app.slint:2391`
+`ui/dr-ui/ui/app.slint:2169`
### Do it again after taking it back
@@ -61,7 +52,7 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
- **Pointer** — Click it, or press Redo in the History header
- **Keyboard** — Ctrl+Shift+Z
-`ui/dr-ui/ui/app.slint:2404`
+`ui/dr-ui/ui/app.slint:2182`
### Copy the settings from this photograph
@@ -71,7 +62,7 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
The panel is the copy that has to work: a tablet has no modifier key to hold and no menu bar to hang the action from. The shortcut is an accelerator for a control that is on screen either way.
-`ui/dr-ui/ui/app.slint:2437`
+`ui/dr-ui/ui/app.slint:2215`
### Paste the settings onto this photograph
@@ -81,7 +72,7 @@ The panel is the copy that has to work: a tablet has no modifier key to hold and
The button names what would be pasted — "3 adjustments", and whether the crop is coming with it — which the shortcut cannot say. Both paste the same scope.
-`ui/dr-ui/ui/app.slint:2449`
+`ui/dr-ui/ui/app.slint:2227`
### Change which group of adjustments is on screen
@@ -91,7 +82,7 @@ The button names what would be pasted — "3 adjustments", and whether the crop
The groups are whatever the operation set declares itself to be about, so there are as many as the pipeline has and no key can be assigned to one of them by name. Stepping is the binding that survives a node being added.
-`ui/dr-ui/ui/app.slint:2477`
+`ui/dr-ui/ui/app.slint:2255`
### Look at the photograph at 1:1
@@ -101,7 +92,7 @@ The groups are whatever the operation set declares itself to be about, so there
Noise reduction and capture sharpening are judgements about single pixels, and a fitted view averages several of the file's into each one on screen — so the frame looks softer than it is and the correction goes too far. The point and the magnification survive opening the next photograph, which is what makes checking the same eye across forty portraits forty keystrokes rather than forty pans.
-`ui/dr-ui/ui/app.slint:2512`
+`ui/dr-ui/ui/app.slint:2290`
### Move to the next or previous photograph
@@ -111,7 +102,7 @@ Noise reduction and capture sharpening are judgements about single pixels, and a
The edit on screen is saved on the way out, so stepping through a folder is as much a departure as going back to the grid and loses nothing.
-`ui/dr-ui/ui/app.slint:2542`
+`ui/dr-ui/ui/app.slint:2320`
### See the photograph before you edited it
@@ -121,7 +112,7 @@ The edit on screen is saved on the way out, so stepping through a folder is as m
Held rather than toggled, and no split screen: a split halves the working image on the tablet the column was sized for, and the comparison photographers describe making is a flick back and forth. It takes no history step, so checking whether a frame is overcooked costs nothing to undo afterwards.
-`ui/dr-ui/ui/app.slint:2666`
+`ui/dr-ui/ui/app.slint:2444`
### Put one control back to its default
@@ -139,7 +130,7 @@ The column is 280px wide and the colour mixer alone puts thirty-six of these in
Disabling a layer is the before-and-after a local edit constantly wants, so it is one press away rather than inside the row. It is an edit and does take a history step, unlike holding "Before" — the layer really is off until it is switched back on.
-`ui/dr-ui/ui/masks.slint:195`
+`ui/dr-ui/ui/masks.slint:164`
## People
diff --git a/docs/traceability.md b/docs/traceability.md
index e73a523..9c8f537 100644
--- a/docs/traceability.md
+++ b/docs/traceability.md
@@ -9,8 +9,8 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
| Metric | Value |
|---|---|
-| Source files scanned | 345 |
-| TRACES tags found | 1249 |
+| Source files scanned | 346 |
+| TRACES tags found | 1253 |
| Requirements defined | 183 |
| Requirements covered | 131 |
| **Coverage** | **71.6%** (131/183) |
@@ -34,114 +34,114 @@ _None._
| ID | Tagged in |
|---|---|
| FR-CAT-1 | [`core/dr-catalog/src/scan.rs:1`](../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/walk.rs:109`](../core/dr-catalog/src/walk.rs#L109), [`core/dr-catalog/src/walk.rs:162`](../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-sync/src/scan.rs:118`](../core/dr-sync/src/scan.rs#L118), [`core/dr-types/src/lib.rs:203`](../core/dr-types/src/lib.rs#L203), [`core/dr-types/src/lib.rs:272`](../core/dr-types/src/lib.rs#L272), [`core/dr-types/src/lib.rs:305`](../core/dr-types/src/lib.rs#L305), [`platform/dr-plat/src/storage.rs:1`](../platform/dr-plat/src/storage.rs#L1), [`platform/dr-plat/src/storage.rs:216`](../platform/dr-plat/src/storage.rs#L216), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1) |
-| FR-CAT-10 | [`core/dr-ingest/src/layout.rs:1`](../core/dr-ingest/src/layout.rs#L1), [`core/dr-ingest/src/lib.rs:1`](../core/dr-ingest/src/lib.rs#L1), [`core/dr-ingest/src/lib.rs:733`](../core/dr-ingest/src/lib.rs#L733), [`core/dr-types/src/settings.rs:206`](../core/dr-types/src/settings.rs#L206), [`platform/dr-plat/src/storage.rs:287`](../platform/dr-plat/src/storage.rs#L287), [`platform/dr-plat/src/storage.rs:586`](../platform/dr-plat/src/storage.rs#L586), [`platform/dr-plat/src/volumes.rs:1`](../platform/dr-plat/src/volumes.rs#L1), [`platform/dr-plat/src/volumes.rs:62`](../platform/dr-plat/src/volumes.rs#L62), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import.rs:336`](../ui/dr-ui/src/import.rs#L336), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1379`](../ui/dr-ui/src/lib.rs#L1379), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5), [`ui/dr-ui/ui/library.slint:1033`](../ui/dr-ui/ui/library.slint#L1033), [`ui/dr-ui/ui/library.slint:1254`](../ui/dr-ui/ui/library.slint#L1254), [`ui/dr-ui/ui/library.slint:979`](../ui/dr-ui/ui/library.slint#L979) |
-| FR-CAT-11 | [`core/dr-catalog/src/dedup.rs:1`](../core/dr-catalog/src/dedup.rs#L1), [`core/dr-ingest/src/lib.rs:1`](../core/dr-ingest/src/lib.rs#L1), [`core/dr-ingest/src/lib.rs:392`](../core/dr-ingest/src/lib.rs#L392), [`core/dr-sync/src/upload.rs:40`](../core/dr-sync/src/upload.rs#L40), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1379`](../ui/dr-ui/src/lib.rs#L1379), [`ui/dr-ui/src/library.rs:183`](../ui/dr-ui/src/library.rs#L183), [`ui/dr-ui/src/library.rs:2819`](../ui/dr-ui/src/library.rs#L2819), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5) |
+| FR-CAT-10 | [`core/dr-ingest/src/layout.rs:1`](../core/dr-ingest/src/layout.rs#L1), [`core/dr-ingest/src/lib.rs:1`](../core/dr-ingest/src/lib.rs#L1), [`core/dr-ingest/src/lib.rs:733`](../core/dr-ingest/src/lib.rs#L733), [`core/dr-types/src/settings.rs:206`](../core/dr-types/src/settings.rs#L206), [`platform/dr-plat/src/storage.rs:287`](../platform/dr-plat/src/storage.rs#L287), [`platform/dr-plat/src/storage.rs:586`](../platform/dr-plat/src/storage.rs#L586), [`platform/dr-plat/src/volumes.rs:1`](../platform/dr-plat/src/volumes.rs#L1), [`platform/dr-plat/src/volumes.rs:62`](../platform/dr-plat/src/volumes.rs#L62), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import.rs:336`](../ui/dr-ui/src/import.rs#L336), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1421`](../ui/dr-ui/src/lib.rs#L1421), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5), [`ui/dr-ui/ui/library.slint:1033`](../ui/dr-ui/ui/library.slint#L1033), [`ui/dr-ui/ui/library.slint:1254`](../ui/dr-ui/ui/library.slint#L1254), [`ui/dr-ui/ui/library.slint:979`](../ui/dr-ui/ui/library.slint#L979) |
+| FR-CAT-11 | [`core/dr-catalog/src/dedup.rs:1`](../core/dr-catalog/src/dedup.rs#L1), [`core/dr-ingest/src/lib.rs:1`](../core/dr-ingest/src/lib.rs#L1), [`core/dr-ingest/src/lib.rs:392`](../core/dr-ingest/src/lib.rs#L392), [`core/dr-sync/src/upload.rs:40`](../core/dr-sync/src/upload.rs#L40), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1421`](../ui/dr-ui/src/lib.rs#L1421), [`ui/dr-ui/src/library.rs:183`](../ui/dr-ui/src/library.rs#L183), [`ui/dr-ui/src/library.rs:2819`](../ui/dr-ui/src/library.rs#L2819), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5) |
| FR-CAT-12 | [`core/dr-pipeline/src/sidecar.rs:120`](../core/dr-pipeline/src/sidecar.rs#L120) |
| FR-CAT-13 | [`core/dr-xmp/src/lib.rs:1`](../core/dr-xmp/src/lib.rs#L1), [`core/dr-xmp/src/lib.rs:331`](../core/dr-xmp/src/lib.rs#L331), [`core/dr-xmp/src/lib.rs:442`](../core/dr-xmp/src/lib.rs#L442), [`core/dr-xmp/src/lib.rs:535`](../core/dr-xmp/src/lib.rs#L535), [`core/dr-xmp/src/lib.rs:733`](../core/dr-xmp/src/lib.rs#L733), [`core/dr-xmp/src/lib.rs:746`](../core/dr-xmp/src/lib.rs#L746), [`core/dr-xmp/src/read.rs:1`](../core/dr-xmp/src/read.rs#L1), [`core/dr-xmp/src/write.rs:1`](../core/dr-xmp/src/write.rs#L1), [`core/dr-xmp/tests/round_trip.rs:1`](../core/dr-xmp/tests/round_trip.rs#L1) |
| FR-CAT-15 | [`core/dr-catalog/src/schema.rs:813`](../core/dr-catalog/src/schema.rs#L813), [`core/dr-catalog/src/trash.rs:1`](../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:457`](../core/dr-sync-nextcloud/src/lib.rs#L457), [`core/dr-sync/src/lib.rs:135`](../core/dr-sync/src/lib.rs#L135), [`core/dr-sync/src/scan.rs:604`](../core/dr-sync/src/scan.rs#L604), [`core/dr-sync/src/scan.rs:82`](../core/dr-sync/src/scan.rs#L82), [`core/dr-thumbs/src/lib.rs:376`](../core/dr-thumbs/src/lib.rs#L376), [`core/dr-types/src/place.rs:91`](../core/dr-types/src/place.rs#L91), [`ui/dr-ui/src/collections_ui.rs:1283`](../ui/dr-ui/src/collections_ui.rs#L1283), [`ui/dr-ui/src/collections_ui.rs:2189`](../ui/dr-ui/src/collections_ui.rs#L2189), [`ui/dr-ui/src/library.rs:183`](../ui/dr-ui/src/library.rs#L183), [`ui/dr-ui/src/library.rs:200`](../ui/dr-ui/src/library.rs#L200), [`ui/dr-ui/src/library.rs:249`](../ui/dr-ui/src/library.rs#L249), [`ui/dr-ui/src/library.rs:4440`](../ui/dr-ui/src/library.rs#L4440), [`ui/dr-ui/src/library.rs:4474`](../ui/dr-ui/src/library.rs#L4474), [`ui/dr-ui/src/library_ui.rs:238`](../ui/dr-ui/src/library_ui.rs#L238), [`ui/dr-ui/src/library_ui.rs:838`](../ui/dr-ui/src/library_ui.rs#L838), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:621`](../ui/dr-ui/ui/collections.slint#L621) |
| FR-CAT-1a | [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:56`](../core/dr-types/src/lib.rs#L56), [`platform/dr-plat/src/storage.rs:1`](../platform/dr-plat/src/storage.rs#L1), [`platform/dr-plat/src/storage.rs:216`](../platform/dr-plat/src/storage.rs#L216), [`platform/dr-plat/src/storage.rs:46`](../platform/dr-plat/src/storage.rs#L46) |
| FR-CAT-2 | [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/schema.rs:1`](../core/dr-catalog/src/schema.rs#L1) |
-| FR-CAT-3 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/walk.rs:66`](../core/dr-catalog/src/walk.rs#L66), [`core/dr-sync/src/scan.rs:94`](../core/dr-sync/src/scan.rs#L94), [`core/dr-thumbs/src/codec.rs:1`](../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/import.rs:463`](../ui/dr-ui/src/import.rs#L463), [`ui/dr-ui/src/import.rs:488`](../ui/dr-ui/src/import.rs#L488), [`ui/dr-ui/src/library.rs:3292`](../ui/dr-ui/src/library.rs#L3292), [`ui/dr-ui/src/library.rs:3883`](../ui/dr-ui/src/library.rs#L3883), [`ui/dr-ui/src/library_ui.rs:177`](../ui/dr-ui/src/library_ui.rs#L177), [`ui/dr-ui/src/library_ui.rs:4236`](../ui/dr-ui/src/library_ui.rs#L4236), [`ui/dr-ui/src/library_ui.rs:5735`](../ui/dr-ui/src/library_ui.rs#L5735), [`ui/dr-ui/ui/app.slint:490`](../ui/dr-ui/ui/app.slint#L490), [`ui/dr-ui/ui/settings.slint:395`](../ui/dr-ui/ui/settings.slint#L395), [`ui/dr-ui/ui/settings.slint:73`](../ui/dr-ui/ui/settings.slint#L73) |
+| FR-CAT-3 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/walk.rs:66`](../core/dr-catalog/src/walk.rs#L66), [`core/dr-sync/src/scan.rs:94`](../core/dr-sync/src/scan.rs#L94), [`core/dr-thumbs/src/codec.rs:1`](../core/dr-thumbs/src/codec.rs#L1), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/import.rs:463`](../ui/dr-ui/src/import.rs#L463), [`ui/dr-ui/src/import.rs:488`](../ui/dr-ui/src/import.rs#L488), [`ui/dr-ui/src/library.rs:3292`](../ui/dr-ui/src/library.rs#L3292), [`ui/dr-ui/src/library.rs:3883`](../ui/dr-ui/src/library.rs#L3883), [`ui/dr-ui/src/library_ui.rs:177`](../ui/dr-ui/src/library_ui.rs#L177), [`ui/dr-ui/src/library_ui.rs:4236`](../ui/dr-ui/src/library_ui.rs#L4236), [`ui/dr-ui/src/library_ui.rs:5735`](../ui/dr-ui/src/library_ui.rs#L5735), [`ui/dr-ui/ui/app.slint:374`](../ui/dr-ui/ui/app.slint#L374), [`ui/dr-ui/ui/settings.slint:395`](../ui/dr-ui/ui/settings.slint#L395), [`ui/dr-ui/ui/settings.slint:73`](../ui/dr-ui/ui/settings.slint#L73) |
| FR-CAT-4 | [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/schema.rs:356`](../core/dr-catalog/src/schema.rs#L356), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library.rs:230`](../ui/dr-ui/src/library.rs#L230), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1) |
-| FR-CAT-5 | [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:1231`](../core/dr-catalog/src/schema.rs#L1231), [`core/dr-catalog/src/schema.rs:728`](../core/dr-catalog/src/schema.rs#L728), [`core/dr-decode/src/lib.rs:285`](../core/dr-decode/src/lib.rs#L285), [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-pipeline/src/sidecar.rs:137`](../core/dr-pipeline/src/sidecar.rs#L137), [`ui/dr-ui/src/collections_ui.rs:1579`](../ui/dr-ui/src/collections_ui.rs#L1579), [`ui/dr-ui/src/collections_ui.rs:1685`](../ui/dr-ui/src/collections_ui.rs#L1685), [`ui/dr-ui/src/collections_ui.rs:1734`](../ui/dr-ui/src/collections_ui.rs#L1734), [`ui/dr-ui/src/collections_ui.rs:238`](../ui/dr-ui/src/collections_ui.rs#L238), [`ui/dr-ui/src/collections_ui.rs:335`](../ui/dr-ui/src/collections_ui.rs#L335), [`ui/dr-ui/src/collections_ui.rs:87`](../ui/dr-ui/src/collections_ui.rs#L87), [`ui/dr-ui/src/library.rs:4488`](../ui/dr-ui/src/library.rs#L4488), [`ui/dr-ui/src/library_ui.rs:713`](../ui/dr-ui/src/library_ui.rs#L713), [`ui/dr-ui/src/library_ui.rs:7727`](../ui/dr-ui/src/library_ui.rs#L7727), [`ui/dr-ui/src/library_ui.rs:7738`](../ui/dr-ui/src/library_ui.rs#L7738), [`ui/dr-ui/src/library_ui.rs:7751`](../ui/dr-ui/src/library_ui.rs#L7751), [`ui/dr-ui/src/library_ui.rs:7766`](../ui/dr-ui/src/library_ui.rs#L7766), [`ui/dr-ui/src/library_ui.rs:7775`](../ui/dr-ui/src/library_ui.rs#L7775), [`ui/dr-ui/ui/app.slint:411`](../ui/dr-ui/ui/app.slint#L411), [`ui/dr-ui/ui/app.slint:633`](../ui/dr-ui/ui/app.slint#L633), [`ui/dr-ui/ui/library.slint:1360`](../ui/dr-ui/ui/library.slint#L1360), [`ui/dr-ui/ui/library.slint:1384`](../ui/dr-ui/ui/library.slint#L1384), [`ui/dr-ui/ui/library.slint:1437`](../ui/dr-ui/ui/library.slint#L1437), [`ui/dr-ui/ui/library.slint:19`](../ui/dr-ui/ui/library.slint#L19), [`ui/dr-ui/ui/library.slint:4195`](../ui/dr-ui/ui/library.slint#L4195) |
-| FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:728`](../core/dr-catalog/src/schema.rs#L728), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:64`](../core/dr-types/src/settings.rs#L64), [`core/dr-types/src/time.rs:67`](../core/dr-types/src/time.rs#L67), [`core/dr-types/src/time.rs:90`](../core/dr-types/src/time.rs#L90), [`ui/dr-ui/src/library.rs:254`](../ui/dr-ui/src/library.rs#L254), [`ui/dr-ui/src/library.rs:4964`](../ui/dr-ui/src/library.rs#L4964), [`ui/dr-ui/src/library_ui.rs:389`](../ui/dr-ui/src/library_ui.rs#L389), [`ui/dr-ui/src/library_ui.rs:470`](../ui/dr-ui/src/library_ui.rs#L470), [`ui/dr-ui/src/library_ui.rs:6457`](../ui/dr-ui/src/library_ui.rs#L6457), [`ui/dr-ui/src/library_ui.rs:6510`](../ui/dr-ui/src/library_ui.rs#L6510), [`ui/dr-ui/src/library_ui.rs:7867`](../ui/dr-ui/src/library_ui.rs#L7867), [`ui/dr-ui/ui/app.slint:423`](../ui/dr-ui/ui/app.slint#L423), [`ui/dr-ui/ui/app.slint:633`](../ui/dr-ui/ui/app.slint#L633), [`ui/dr-ui/ui/app.slint:951`](../ui/dr-ui/ui/app.slint#L951), [`ui/dr-ui/ui/library.slint:111`](../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1547`](../ui/dr-ui/ui/library.slint#L1547), [`ui/dr-ui/ui/library.slint:4195`](../ui/dr-ui/ui/library.slint#L4195), [`ui/dr-ui/ui/settings.slint:158`](../ui/dr-ui/ui/settings.slint#L158) |
-| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1073`](../ui/dr-ui/src/collections_ui.rs#L1073), [`ui/dr-ui/src/collections_ui.rs:117`](../ui/dr-ui/src/collections_ui.rs#L117), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1598`](../ui/dr-ui/src/collections_ui.rs#L1598), [`ui/dr-ui/src/collections_ui.rs:1848`](../ui/dr-ui/src/collections_ui.rs#L1848), [`ui/dr-ui/src/collections_ui.rs:1913`](../ui/dr-ui/src/collections_ui.rs#L1913), [`ui/dr-ui/src/collections_ui.rs:1973`](../ui/dr-ui/src/collections_ui.rs#L1973), [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2963`](../ui/dr-ui/src/collections_ui.rs#L2963), [`ui/dr-ui/src/collections_ui.rs:365`](../ui/dr-ui/src/collections_ui.rs#L365), [`ui/dr-ui/src/collections_ui.rs:569`](../ui/dr-ui/src/collections_ui.rs#L569), [`ui/dr-ui/src/collections_ui.rs:965`](../ui/dr-ui/src/collections_ui.rs#L965), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library.rs:4769`](../ui/dr-ui/src/library.rs#L4769), [`ui/dr-ui/src/library.rs:4795`](../ui/dr-ui/src/library.rs#L4795), [`ui/dr-ui/src/library.rs:4850`](../ui/dr-ui/src/library.rs#L4850), [`ui/dr-ui/src/library_ui.rs:2700`](../ui/dr-ui/src/library_ui.rs#L2700), [`ui/dr-ui/src/library_ui.rs:4098`](../ui/dr-ui/src/library_ui.rs#L4098), [`ui/dr-ui/src/library_ui.rs:4849`](../ui/dr-ui/src/library_ui.rs#L4849), [`ui/dr-ui/ui/app.slint:414`](../ui/dr-ui/ui/app.slint#L414), [`ui/dr-ui/ui/app.slint:628`](../ui/dr-ui/ui/app.slint#L628), [`ui/dr-ui/ui/app.slint:657`](../ui/dr-ui/ui/app.slint#L657), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/library.slint:1327`](../ui/dr-ui/ui/library.slint#L1327), [`ui/dr-ui/ui/library.slint:2896`](../ui/dr-ui/ui/library.slint#L2896), [`ui/dr-ui/ui/library.slint:4173`](../ui/dr-ui/ui/library.slint#L4173), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998) |
-| FR-CAT-8 | [`core/dr-catalog/src/schema.rs:532`](../core/dr-catalog/src/schema.rs#L532), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:492`](../core/dr-pipeline/src/graph.rs#L492), [`core/dr-pipeline/src/graph.rs:540`](../core/dr-pipeline/src/graph.rs#L540), [`core/dr-pipeline/src/ops/curve.rs:137`](../core/dr-pipeline/src/ops/curve.rs#L137), [`core/dr-pipeline/src/ops/curve.rs:656`](../core/dr-pipeline/src/ops/curve.rs#L656), [`core/dr-pipeline/src/sidecar.rs:1205`](../core/dr-pipeline/src/sidecar.rs#L1205), [`core/dr-pipeline/src/sidecar.rs:1918`](../core/dr-pipeline/src/sidecar.rs#L1918), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`core/dr-pipeline/tests/tone_curve.rs:34`](../core/dr-pipeline/tests/tone_curve.rs#L34), [`core/dr-sync/src/scan.rs:31`](../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:45`](../core/dr-sync/src/scan.rs#L45), [`core/dr-sync/src/scan.rs:912`](../core/dr-sync/src/scan.rs#L912), [`ui/dr-ui/src/develop.rs:2000`](../ui/dr-ui/src/develop.rs#L2000), [`ui/dr-ui/src/develop.rs:4758`](../ui/dr-ui/src/develop.rs#L4758), [`ui/dr-ui/src/develop.rs:4787`](../ui/dr-ui/src/develop.rs#L4787), [`ui/dr-ui/src/develop.rs:5867`](../ui/dr-ui/src/develop.rs#L5867), [`ui/dr-ui/src/develop.rs:5921`](../ui/dr-ui/src/develop.rs#L5921), [`ui/dr-ui/src/develop.rs:6023`](../ui/dr-ui/src/develop.rs#L6023), [`ui/dr-ui/src/export.rs:799`](../ui/dr-ui/src/export.rs#L799), [`ui/dr-ui/src/lib.rs:1157`](../ui/dr-ui/src/lib.rs#L1157), [`ui/dr-ui/src/lib.rs:1673`](../ui/dr-ui/src/lib.rs#L1673), [`ui/dr-ui/src/lib.rs:2216`](../ui/dr-ui/src/lib.rs#L2216), [`ui/dr-ui/src/lib.rs:2353`](../ui/dr-ui/src/lib.rs#L2353), [`ui/dr-ui/src/lib.rs:709`](../ui/dr-ui/src/lib.rs#L709), [`ui/dr-ui/src/library.rs:1376`](../ui/dr-ui/src/library.rs#L1376), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:2219`](../ui/dr-ui/src/library.rs#L2219), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:547`](../ui/dr-ui/src/library.rs#L547), [`ui/dr-ui/src/library.rs:584`](../ui/dr-ui/src/library.rs#L584), [`ui/dr-ui/src/library.rs:7144`](../ui/dr-ui/src/library.rs#L7144), [`ui/dr-ui/src/library.rs:73`](../ui/dr-ui/src/library.rs#L73), [`ui/dr-ui/src/library.rs:845`](../ui/dr-ui/src/library.rs#L845), [`ui/dr-ui/src/library_ui.rs:1265`](../ui/dr-ui/src/library_ui.rs#L1265), [`ui/dr-ui/src/library_ui.rs:6058`](../ui/dr-ui/src/library_ui.rs#L6058), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
+| FR-CAT-5 | [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:1231`](../core/dr-catalog/src/schema.rs#L1231), [`core/dr-catalog/src/schema.rs:728`](../core/dr-catalog/src/schema.rs#L728), [`core/dr-decode/src/lib.rs:285`](../core/dr-decode/src/lib.rs#L285), [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-pipeline/src/sidecar.rs:137`](../core/dr-pipeline/src/sidecar.rs#L137), [`ui/dr-ui/src/collections_ui.rs:1579`](../ui/dr-ui/src/collections_ui.rs#L1579), [`ui/dr-ui/src/collections_ui.rs:1685`](../ui/dr-ui/src/collections_ui.rs#L1685), [`ui/dr-ui/src/collections_ui.rs:1734`](../ui/dr-ui/src/collections_ui.rs#L1734), [`ui/dr-ui/src/collections_ui.rs:238`](../ui/dr-ui/src/collections_ui.rs#L238), [`ui/dr-ui/src/collections_ui.rs:335`](../ui/dr-ui/src/collections_ui.rs#L335), [`ui/dr-ui/src/collections_ui.rs:87`](../ui/dr-ui/src/collections_ui.rs#L87), [`ui/dr-ui/src/library.rs:4488`](../ui/dr-ui/src/library.rs#L4488), [`ui/dr-ui/src/library_ui.rs:713`](../ui/dr-ui/src/library_ui.rs#L713), [`ui/dr-ui/src/library_ui.rs:7727`](../ui/dr-ui/src/library_ui.rs#L7727), [`ui/dr-ui/src/library_ui.rs:7738`](../ui/dr-ui/src/library_ui.rs#L7738), [`ui/dr-ui/src/library_ui.rs:7751`](../ui/dr-ui/src/library_ui.rs#L7751), [`ui/dr-ui/src/library_ui.rs:7766`](../ui/dr-ui/src/library_ui.rs#L7766), [`ui/dr-ui/src/library_ui.rs:7775`](../ui/dr-ui/src/library_ui.rs#L7775), [`ui/dr-ui/ui/app.slint:295`](../ui/dr-ui/ui/app.slint#L295), [`ui/dr-ui/ui/app.slint:517`](../ui/dr-ui/ui/app.slint#L517), [`ui/dr-ui/ui/library.slint:1360`](../ui/dr-ui/ui/library.slint#L1360), [`ui/dr-ui/ui/library.slint:1384`](../ui/dr-ui/ui/library.slint#L1384), [`ui/dr-ui/ui/library.slint:1437`](../ui/dr-ui/ui/library.slint#L1437), [`ui/dr-ui/ui/library.slint:19`](../ui/dr-ui/ui/library.slint#L19), [`ui/dr-ui/ui/library.slint:4195`](../ui/dr-ui/ui/library.slint#L4195) |
+| FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:728`](../core/dr-catalog/src/schema.rs#L728), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:64`](../core/dr-types/src/settings.rs#L64), [`core/dr-types/src/time.rs:67`](../core/dr-types/src/time.rs#L67), [`core/dr-types/src/time.rs:90`](../core/dr-types/src/time.rs#L90), [`ui/dr-ui/src/library.rs:254`](../ui/dr-ui/src/library.rs#L254), [`ui/dr-ui/src/library.rs:4964`](../ui/dr-ui/src/library.rs#L4964), [`ui/dr-ui/src/library_ui.rs:389`](../ui/dr-ui/src/library_ui.rs#L389), [`ui/dr-ui/src/library_ui.rs:470`](../ui/dr-ui/src/library_ui.rs#L470), [`ui/dr-ui/src/library_ui.rs:6457`](../ui/dr-ui/src/library_ui.rs#L6457), [`ui/dr-ui/src/library_ui.rs:6510`](../ui/dr-ui/src/library_ui.rs#L6510), [`ui/dr-ui/src/library_ui.rs:7867`](../ui/dr-ui/src/library_ui.rs#L7867), [`ui/dr-ui/ui/app.slint:307`](../ui/dr-ui/ui/app.slint#L307), [`ui/dr-ui/ui/app.slint:517`](../ui/dr-ui/ui/app.slint#L517), [`ui/dr-ui/ui/app.slint:781`](../ui/dr-ui/ui/app.slint#L781), [`ui/dr-ui/ui/library.slint:111`](../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1547`](../ui/dr-ui/ui/library.slint#L1547), [`ui/dr-ui/ui/library.slint:4195`](../ui/dr-ui/ui/library.slint#L4195), [`ui/dr-ui/ui/settings.slint:158`](../ui/dr-ui/ui/settings.slint#L158) |
+| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1073`](../ui/dr-ui/src/collections_ui.rs#L1073), [`ui/dr-ui/src/collections_ui.rs:117`](../ui/dr-ui/src/collections_ui.rs#L117), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1598`](../ui/dr-ui/src/collections_ui.rs#L1598), [`ui/dr-ui/src/collections_ui.rs:1848`](../ui/dr-ui/src/collections_ui.rs#L1848), [`ui/dr-ui/src/collections_ui.rs:1913`](../ui/dr-ui/src/collections_ui.rs#L1913), [`ui/dr-ui/src/collections_ui.rs:1973`](../ui/dr-ui/src/collections_ui.rs#L1973), [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2963`](../ui/dr-ui/src/collections_ui.rs#L2963), [`ui/dr-ui/src/collections_ui.rs:365`](../ui/dr-ui/src/collections_ui.rs#L365), [`ui/dr-ui/src/collections_ui.rs:569`](../ui/dr-ui/src/collections_ui.rs#L569), [`ui/dr-ui/src/collections_ui.rs:965`](../ui/dr-ui/src/collections_ui.rs#L965), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library.rs:4769`](../ui/dr-ui/src/library.rs#L4769), [`ui/dr-ui/src/library.rs:4795`](../ui/dr-ui/src/library.rs#L4795), [`ui/dr-ui/src/library.rs:4850`](../ui/dr-ui/src/library.rs#L4850), [`ui/dr-ui/src/library_ui.rs:2700`](../ui/dr-ui/src/library_ui.rs#L2700), [`ui/dr-ui/src/library_ui.rs:4098`](../ui/dr-ui/src/library_ui.rs#L4098), [`ui/dr-ui/src/library_ui.rs:4849`](../ui/dr-ui/src/library_ui.rs#L4849), [`ui/dr-ui/ui/app.slint:298`](../ui/dr-ui/ui/app.slint#L298), [`ui/dr-ui/ui/app.slint:512`](../ui/dr-ui/ui/app.slint#L512), [`ui/dr-ui/ui/app.slint:541`](../ui/dr-ui/ui/app.slint#L541), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/library.slint:1327`](../ui/dr-ui/ui/library.slint#L1327), [`ui/dr-ui/ui/library.slint:2896`](../ui/dr-ui/ui/library.slint#L2896), [`ui/dr-ui/ui/library.slint:4173`](../ui/dr-ui/ui/library.slint#L4173), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998) |
+| FR-CAT-8 | [`core/dr-catalog/src/schema.rs:532`](../core/dr-catalog/src/schema.rs#L532), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:492`](../core/dr-pipeline/src/graph.rs#L492), [`core/dr-pipeline/src/graph.rs:540`](../core/dr-pipeline/src/graph.rs#L540), [`core/dr-pipeline/src/ops/curve.rs:137`](../core/dr-pipeline/src/ops/curve.rs#L137), [`core/dr-pipeline/src/ops/curve.rs:656`](../core/dr-pipeline/src/ops/curve.rs#L656), [`core/dr-pipeline/src/sidecar.rs:1205`](../core/dr-pipeline/src/sidecar.rs#L1205), [`core/dr-pipeline/src/sidecar.rs:1918`](../core/dr-pipeline/src/sidecar.rs#L1918), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`core/dr-pipeline/tests/tone_curve.rs:34`](../core/dr-pipeline/tests/tone_curve.rs#L34), [`core/dr-sync/src/scan.rs:31`](../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:45`](../core/dr-sync/src/scan.rs#L45), [`core/dr-sync/src/scan.rs:912`](../core/dr-sync/src/scan.rs#L912), [`ui/dr-ui/src/develop.rs:2000`](../ui/dr-ui/src/develop.rs#L2000), [`ui/dr-ui/src/develop.rs:4758`](../ui/dr-ui/src/develop.rs#L4758), [`ui/dr-ui/src/develop.rs:4787`](../ui/dr-ui/src/develop.rs#L4787), [`ui/dr-ui/src/develop.rs:5867`](../ui/dr-ui/src/develop.rs#L5867), [`ui/dr-ui/src/develop.rs:5921`](../ui/dr-ui/src/develop.rs#L5921), [`ui/dr-ui/src/develop.rs:6023`](../ui/dr-ui/src/develop.rs#L6023), [`ui/dr-ui/src/export.rs:799`](../ui/dr-ui/src/export.rs#L799), [`ui/dr-ui/src/lib.rs:1199`](../ui/dr-ui/src/lib.rs#L1199), [`ui/dr-ui/src/lib.rs:1715`](../ui/dr-ui/src/lib.rs#L1715), [`ui/dr-ui/src/lib.rs:2263`](../ui/dr-ui/src/lib.rs#L2263), [`ui/dr-ui/src/lib.rs:2401`](../ui/dr-ui/src/lib.rs#L2401), [`ui/dr-ui/src/lib.rs:744`](../ui/dr-ui/src/lib.rs#L744), [`ui/dr-ui/src/library.rs:1376`](../ui/dr-ui/src/library.rs#L1376), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:2219`](../ui/dr-ui/src/library.rs#L2219), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:547`](../ui/dr-ui/src/library.rs#L547), [`ui/dr-ui/src/library.rs:584`](../ui/dr-ui/src/library.rs#L584), [`ui/dr-ui/src/library.rs:7144`](../ui/dr-ui/src/library.rs#L7144), [`ui/dr-ui/src/library.rs:73`](../ui/dr-ui/src/library.rs#L73), [`ui/dr-ui/src/library.rs:845`](../ui/dr-ui/src/library.rs#L845), [`ui/dr-ui/src/library_ui.rs:1265`](../ui/dr-ui/src/library_ui.rs#L1265), [`ui/dr-ui/src/library_ui.rs:6058`](../ui/dr-ui/src/library_ui.rs#L6058), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
| FR-CAT-9 | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/scan.rs:1`](../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/schema.rs:785`](../core/dr-catalog/src/schema.rs#L785), [`core/dr-catalog/src/walk.rs:1022`](../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:162`](../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-catalog/src/walk.rs:435`](../core/dr-catalog/src/walk.rs#L435), [`core/dr-catalog/src/walk.rs:728`](../core/dr-catalog/src/walk.rs#L728), [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-sync/src/error.rs:113`](../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1), [`core/dr-sync/src/scan.rs:200`](../core/dr-sync/src/scan.rs#L200), [`core/dr-sync/src/scan.rs:505`](../core/dr-sync/src/scan.rs#L505), [`core/dr-types/src/lib.rs:122`](../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop.rs:4047`](../ui/dr-ui/src/develop.rs#L4047), [`ui/dr-ui/src/develop.rs:4090`](../ui/dr-ui/src/develop.rs#L4090), [`ui/dr-ui/src/library.rs:1276`](../ui/dr-ui/src/library.rs#L1276), [`ui/dr-ui/src/library.rs:1329`](../ui/dr-ui/src/library.rs#L1329), [`ui/dr-ui/src/library.rs:1360`](../ui/dr-ui/src/library.rs#L1360), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:169`](../ui/dr-ui/src/library.rs#L169), [`ui/dr-ui/src/library.rs:1727`](../ui/dr-ui/src/library.rs#L1727), [`ui/dr-ui/src/library.rs:2179`](../ui/dr-ui/src/library.rs#L2179), [`ui/dr-ui/src/library.rs:2255`](../ui/dr-ui/src/library.rs#L2255), [`ui/dr-ui/src/library.rs:274`](../ui/dr-ui/src/library.rs#L274), [`ui/dr-ui/src/library.rs:5072`](../ui/dr-ui/src/library.rs#L5072), [`ui/dr-ui/src/library.rs:584`](../ui/dr-ui/src/library.rs#L584), [`ui/dr-ui/src/library.rs:829`](../ui/dr-ui/src/library.rs#L829), [`ui/dr-ui/src/library.rs:845`](../ui/dr-ui/src/library.rs#L845), [`ui/dr-ui/src/library.rs:899`](../ui/dr-ui/src/library.rs#L899), [`ui/dr-ui/src/library_ui.rs:1332`](../ui/dr-ui/src/library_ui.rs#L1332), [`ui/dr-ui/src/library_ui.rs:1923`](../ui/dr-ui/src/library_ui.rs#L1923), [`ui/dr-ui/src/library_ui.rs:1967`](../ui/dr-ui/src/library_ui.rs#L1967), [`ui/dr-ui/src/library_ui.rs:1983`](../ui/dr-ui/src/library_ui.rs#L1983), [`ui/dr-ui/src/library_ui.rs:2077`](../ui/dr-ui/src/library_ui.rs#L2077), [`ui/dr-ui/src/library_ui.rs:284`](../ui/dr-ui/src/library_ui.rs#L284), [`ui/dr-ui/src/library_ui.rs:2940`](../ui/dr-ui/src/library_ui.rs#L2940), [`ui/dr-ui/src/library_ui.rs:317`](../ui/dr-ui/src/library_ui.rs#L317), [`ui/dr-ui/src/library_ui.rs:325`](../ui/dr-ui/src/library_ui.rs#L325), [`ui/dr-ui/src/library_ui.rs:3378`](../ui/dr-ui/src/library_ui.rs#L3378), [`ui/dr-ui/src/library_ui.rs:3600`](../ui/dr-ui/src/library_ui.rs#L3600), [`ui/dr-ui/src/library_ui.rs:3878`](../ui/dr-ui/src/library_ui.rs#L3878), [`ui/dr-ui/src/library_ui.rs:3966`](../ui/dr-ui/src/library_ui.rs#L3966), [`ui/dr-ui/src/library_ui.rs:4149`](../ui/dr-ui/src/library_ui.rs#L4149), [`ui/dr-ui/src/library_ui.rs:4263`](../ui/dr-ui/src/library_ui.rs#L4263), [`ui/dr-ui/src/library_ui.rs:523`](../ui/dr-ui/src/library_ui.rs#L523), [`ui/dr-ui/src/library_ui.rs:586`](../ui/dr-ui/src/library_ui.rs#L586), [`ui/dr-ui/src/library_ui.rs:6555`](../ui/dr-ui/src/library_ui.rs#L6555), [`ui/dr-ui/src/library_ui.rs:6670`](../ui/dr-ui/src/library_ui.rs#L6670), [`ui/dr-ui/src/presets.rs:468`](../ui/dr-ui/src/presets.rs#L468), [`ui/dr-ui/src/presets.rs:480`](../ui/dr-ui/src/presets.rs#L480), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) |
| FR-CULL-1 | [`core/dr-decode/src/preview.rs:121`](../core/dr-decode/src/preview.rs#L121) |
-| FR-CULL-10 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:395`](../core/dr-catalog/src/schema.rs#L395), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`core/dr-face/src/assign.rs:1`](../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:117`](../core/dr-types/src/settings.rs#L117), [`ui/dr-ui/src/develop.rs:121`](../ui/dr-ui/src/develop.rs#L121), [`ui/dr-ui/src/develop.rs:130`](../ui/dr-ui/src/develop.rs#L130), [`ui/dr-ui/src/develop.rs:196`](../ui/dr-ui/src/develop.rs#L196), [`ui/dr-ui/src/develop.rs:2245`](../ui/dr-ui/src/develop.rs#L2245), [`ui/dr-ui/src/develop.rs:689`](../ui/dr-ui/src/develop.rs#L689), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity.rs:1`](../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2325`](../ui/dr-ui/src/lib.rs#L2325), [`ui/dr-ui/ui/identity.slint:1`](../ui/dr-ui/ui/identity.slint#L1) |
+| FR-CULL-10 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:395`](../core/dr-catalog/src/schema.rs#L395), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`core/dr-face/src/assign.rs:1`](../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:117`](../core/dr-types/src/settings.rs#L117), [`ui/dr-ui/src/develop.rs:121`](../ui/dr-ui/src/develop.rs#L121), [`ui/dr-ui/src/develop.rs:130`](../ui/dr-ui/src/develop.rs#L130), [`ui/dr-ui/src/develop.rs:196`](../ui/dr-ui/src/develop.rs#L196), [`ui/dr-ui/src/develop.rs:2245`](../ui/dr-ui/src/develop.rs#L2245), [`ui/dr-ui/src/develop.rs:689`](../ui/dr-ui/src/develop.rs#L689), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity.rs:1`](../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2373`](../ui/dr-ui/src/lib.rs#L2373), [`ui/dr-ui/ui/identity.slint:1`](../ui/dr-ui/ui/identity.slint#L1) |
| FR-CULL-11 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`ui/dr-ui/src/identity.rs:1`](../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/library.rs:295`](../ui/dr-ui/src/library.rs#L295), [`ui/dr-ui/src/library.rs:325`](../ui/dr-ui/src/library.rs#L325), [`ui/dr-ui/ui/identity.slint:1`](../ui/dr-ui/ui/identity.slint#L1) |
| FR-CULL-12 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:395`](../core/dr-catalog/src/schema.rs#L395), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`ui/dr-ui/src/identity.rs:1`](../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/ui/identity.slint:1`](../ui/dr-ui/ui/identity.slint#L1) |
| FR-CULL-2 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../core/dr-decode/src/preview.rs#L148), [`ui/dr-ui/src/import.rs:463`](../ui/dr-ui/src/import.rs#L463) |
-| FR-CULL-3 | [`core/dr-gpu/src/focus.rs:154`](../core/dr-gpu/src/focus.rs#L154), [`core/dr-gpu/src/focus.rs:186`](../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/raw_histogram.rs:129`](../core/dr-gpu/src/raw_histogram.rs#L129), [`core/dr-gpu/src/raw_histogram.rs:1`](../core/dr-gpu/src/raw_histogram.rs#L1), [`core/dr-gpu/src/raw_histogram.rs:272`](../core/dr-gpu/src/raw_histogram.rs#L272), [`core/dr-gpu/src/raw_histogram.rs:407`](../core/dr-gpu/src/raw_histogram.rs#L407), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`core/dr-gpu/src/shaders/raw_histogram.wgsl:1`](../core/dr-gpu/src/shaders/raw_histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:3478`](../ui/dr-ui/src/develop.rs#L3478), [`ui/dr-ui/src/develop.rs:3491`](../ui/dr-ui/src/develop.rs#L3491), [`ui/dr-ui/src/develop.rs:3536`](../ui/dr-ui/src/develop.rs#L3536), [`ui/dr-ui/src/develop.rs:3547`](../ui/dr-ui/src/develop.rs#L3547), [`ui/dr-ui/src/develop.rs:3553`](../ui/dr-ui/src/develop.rs#L3553), [`ui/dr-ui/src/develop.rs:3570`](../ui/dr-ui/src/develop.rs#L3570), [`ui/dr-ui/src/develop.rs:763`](../ui/dr-ui/src/develop.rs#L763), [`ui/dr-ui/src/develop.rs:7666`](../ui/dr-ui/src/develop.rs#L7666), [`ui/dr-ui/src/develop.rs:7730`](../ui/dr-ui/src/develop.rs#L7730), [`ui/dr-ui/src/develop.rs:7753`](../ui/dr-ui/src/develop.rs#L7753), [`ui/dr-ui/src/develop.rs:783`](../ui/dr-ui/src/develop.rs#L783), [`ui/dr-ui/src/develop.rs:789`](../ui/dr-ui/src/develop.rs#L789), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/histogram.rs:208`](../ui/dr-ui/src/histogram.rs#L208), [`ui/dr-ui/src/histogram.rs:228`](../ui/dr-ui/src/histogram.rs#L228), [`ui/dr-ui/src/histogram.rs:272`](../ui/dr-ui/src/histogram.rs#L272), [`ui/dr-ui/src/histogram.rs:544`](../ui/dr-ui/src/histogram.rs#L544), [`ui/dr-ui/src/histogram.rs:565`](../ui/dr-ui/src/histogram.rs#L565), [`ui/dr-ui/src/histogram.rs:593`](../ui/dr-ui/src/histogram.rs#L593), [`ui/dr-ui/src/histogram.rs:621`](../ui/dr-ui/src/histogram.rs#L621), [`ui/dr-ui/src/histogram.rs:658`](../ui/dr-ui/src/histogram.rs#L658), [`ui/dr-ui/src/lib.rs:1712`](../ui/dr-ui/src/lib.rs#L1712), [`ui/dr-ui/src/lib.rs:1809`](../ui/dr-ui/src/lib.rs#L1809), [`ui/dr-ui/src/lib.rs:1916`](../ui/dr-ui/src/lib.rs#L1916), [`ui/dr-ui/src/lib.rs:1957`](../ui/dr-ui/src/lib.rs#L1957), [`ui/dr-ui/src/lib.rs:3345`](../ui/dr-ui/src/lib.rs#L3345), [`ui/dr-ui/src/lib.rs:396`](../ui/dr-ui/src/lib.rs#L396), [`ui/dr-ui/src/peaking.rs:1`](../ui/dr-ui/src/peaking.rs#L1), [`ui/dr-ui/ui/app.slint:1948`](../ui/dr-ui/ui/app.slint#L1948), [`ui/dr-ui/ui/app.slint:2853`](../ui/dr-ui/ui/app.slint#L2853), [`ui/dr-ui/ui/app.slint:95`](../ui/dr-ui/ui/app.slint#L95), [`ui/dr-ui/ui/peaking.slint:1`](../ui/dr-ui/ui/peaking.slint#L1), [`ui/dr-ui/ui/peaking.slint:25`](../ui/dr-ui/ui/peaking.slint#L25), [`ui/dr-ui/ui/peaking.slint:56`](../ui/dr-ui/ui/peaking.slint#L56) |
+| FR-CULL-3 | [`core/dr-gpu/src/focus.rs:154`](../core/dr-gpu/src/focus.rs#L154), [`core/dr-gpu/src/focus.rs:186`](../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/raw_histogram.rs:129`](../core/dr-gpu/src/raw_histogram.rs#L129), [`core/dr-gpu/src/raw_histogram.rs:1`](../core/dr-gpu/src/raw_histogram.rs#L1), [`core/dr-gpu/src/raw_histogram.rs:272`](../core/dr-gpu/src/raw_histogram.rs#L272), [`core/dr-gpu/src/raw_histogram.rs:407`](../core/dr-gpu/src/raw_histogram.rs#L407), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`core/dr-gpu/src/shaders/raw_histogram.wgsl:1`](../core/dr-gpu/src/shaders/raw_histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:3478`](../ui/dr-ui/src/develop.rs#L3478), [`ui/dr-ui/src/develop.rs:3491`](../ui/dr-ui/src/develop.rs#L3491), [`ui/dr-ui/src/develop.rs:3536`](../ui/dr-ui/src/develop.rs#L3536), [`ui/dr-ui/src/develop.rs:3547`](../ui/dr-ui/src/develop.rs#L3547), [`ui/dr-ui/src/develop.rs:3553`](../ui/dr-ui/src/develop.rs#L3553), [`ui/dr-ui/src/develop.rs:3570`](../ui/dr-ui/src/develop.rs#L3570), [`ui/dr-ui/src/develop.rs:763`](../ui/dr-ui/src/develop.rs#L763), [`ui/dr-ui/src/develop.rs:7666`](../ui/dr-ui/src/develop.rs#L7666), [`ui/dr-ui/src/develop.rs:7730`](../ui/dr-ui/src/develop.rs#L7730), [`ui/dr-ui/src/develop.rs:7753`](../ui/dr-ui/src/develop.rs#L7753), [`ui/dr-ui/src/develop.rs:783`](../ui/dr-ui/src/develop.rs#L783), [`ui/dr-ui/src/develop.rs:789`](../ui/dr-ui/src/develop.rs#L789), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/histogram.rs:208`](../ui/dr-ui/src/histogram.rs#L208), [`ui/dr-ui/src/histogram.rs:228`](../ui/dr-ui/src/histogram.rs#L228), [`ui/dr-ui/src/histogram.rs:272`](../ui/dr-ui/src/histogram.rs#L272), [`ui/dr-ui/src/histogram.rs:544`](../ui/dr-ui/src/histogram.rs#L544), [`ui/dr-ui/src/histogram.rs:565`](../ui/dr-ui/src/histogram.rs#L565), [`ui/dr-ui/src/histogram.rs:593`](../ui/dr-ui/src/histogram.rs#L593), [`ui/dr-ui/src/histogram.rs:621`](../ui/dr-ui/src/histogram.rs#L621), [`ui/dr-ui/src/histogram.rs:658`](../ui/dr-ui/src/histogram.rs#L658), [`ui/dr-ui/src/lib.rs:1754`](../ui/dr-ui/src/lib.rs#L1754), [`ui/dr-ui/src/lib.rs:1851`](../ui/dr-ui/src/lib.rs#L1851), [`ui/dr-ui/src/lib.rs:1960`](../ui/dr-ui/src/lib.rs#L1960), [`ui/dr-ui/src/lib.rs:2001`](../ui/dr-ui/src/lib.rs#L2001), [`ui/dr-ui/src/lib.rs:3405`](../ui/dr-ui/src/lib.rs#L3405), [`ui/dr-ui/src/lib.rs:429`](../ui/dr-ui/src/lib.rs#L429), [`ui/dr-ui/src/peaking.rs:1`](../ui/dr-ui/src/peaking.rs#L1), [`ui/dr-ui/ui/app.slint:1807`](../ui/dr-ui/ui/app.slint#L1807), [`ui/dr-ui/ui/app.slint:2713`](../ui/dr-ui/ui/app.slint#L2713), [`ui/dr-ui/ui/app.slint:78`](../ui/dr-ui/ui/app.slint#L78), [`ui/dr-ui/ui/peaking.slint:1`](../ui/dr-ui/ui/peaking.slint#L1), [`ui/dr-ui/ui/peaking.slint:25`](../ui/dr-ui/ui/peaking.slint#L25), [`ui/dr-ui/ui/peaking.slint:56`](../ui/dr-ui/ui/peaking.slint#L56), [`ui/dr-ui/ui/peaking.slint:91`](../ui/dr-ui/ui/peaking.slint#L91) |
| FR-CULL-4 | [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-pipeline/src/sidecar.rs:137`](../core/dr-pipeline/src/sidecar.rs#L137), [`core/dr-xmp/src/lib.rs:442`](../core/dr-xmp/src/lib.rs#L442), [`ui/dr-ui/src/library.rs:254`](../ui/dr-ui/src/library.rs#L254), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500) |
| FR-CULL-5 | [`core/dr-catalog/src/bursts.rs:1`](../core/dr-catalog/src/bursts.rs#L1), [`core/dr-catalog/src/schema.rs:438`](../core/dr-catalog/src/schema.rs#L438), [`ui/dr-ui/src/bursts.rs:1`](../ui/dr-ui/src/bursts.rs#L1), [`ui/dr-ui/src/library.rs:210`](../ui/dr-ui/src/library.rs#L210), [`ui/dr-ui/src/library.rs:5853`](../ui/dr-ui/src/library.rs#L5853) |
-| FR-CULL-8 | [`core/dr-catalog/src/face_shard.rs:1`](../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:506`](../core/dr-catalog/src/schema.rs#L506), [`core/dr-catalog/src/schema.rs:573`](../core/dr-catalog/src/schema.rs#L573), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`core/dr-face/src/align.rs:291`](../core/dr-face/src/align.rs#L291), [`ui/dr-ui/examples/face_native.rs:1`](../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:330`](../ui/dr-ui/src/faces.rs#L330), [`ui/dr-ui/src/faces.rs:346`](../ui/dr-ui/src/faces.rs#L346), [`ui/dr-ui/src/identity_ui.rs:540`](../ui/dr-ui/src/identity_ui.rs#L540), [`ui/dr-ui/src/lib.rs:1331`](../ui/dr-ui/src/lib.rs#L1331), [`ui/dr-ui/src/library.rs:3293`](../ui/dr-ui/src/library.rs#L3293), [`ui/dr-ui/src/library.rs:3385`](../ui/dr-ui/src/library.rs#L3385), [`ui/dr-ui/src/library.rs:3606`](../ui/dr-ui/src/library.rs#L3606), [`ui/dr-ui/src/library.rs:3742`](../ui/dr-ui/src/library.rs#L3742), [`ui/dr-ui/src/library.rs:3778`](../ui/dr-ui/src/library.rs#L3778), [`ui/dr-ui/ui/settings.slint:427`](../ui/dr-ui/ui/settings.slint#L427), [`ui/dr-ui/ui/settings.slint:82`](../ui/dr-ui/ui/settings.slint#L82) |
+| FR-CULL-8 | [`core/dr-catalog/src/face_shard.rs:1`](../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:506`](../core/dr-catalog/src/schema.rs#L506), [`core/dr-catalog/src/schema.rs:573`](../core/dr-catalog/src/schema.rs#L573), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`core/dr-face/src/align.rs:291`](../core/dr-face/src/align.rs#L291), [`ui/dr-ui/examples/face_native.rs:1`](../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:330`](../ui/dr-ui/src/faces.rs#L330), [`ui/dr-ui/src/faces.rs:346`](../ui/dr-ui/src/faces.rs#L346), [`ui/dr-ui/src/identity_ui.rs:540`](../ui/dr-ui/src/identity_ui.rs#L540), [`ui/dr-ui/src/lib.rs:1373`](../ui/dr-ui/src/lib.rs#L1373), [`ui/dr-ui/src/library.rs:3293`](../ui/dr-ui/src/library.rs#L3293), [`ui/dr-ui/src/library.rs:3385`](../ui/dr-ui/src/library.rs#L3385), [`ui/dr-ui/src/library.rs:3606`](../ui/dr-ui/src/library.rs#L3606), [`ui/dr-ui/src/library.rs:3742`](../ui/dr-ui/src/library.rs#L3742), [`ui/dr-ui/src/library.rs:3778`](../ui/dr-ui/src/library.rs#L3778), [`ui/dr-ui/ui/settings.slint:427`](../ui/dr-ui/ui/settings.slint#L427), [`ui/dr-ui/ui/settings.slint:82`](../ui/dr-ui/ui/settings.slint#L82) |
| FR-CULL-9 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:614`](../core/dr-catalog/src/schema.rs#L614), [`core/dr-face/src/assign.rs:1`](../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:117`](../core/dr-types/src/settings.rs#L117), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/ui/identity.slint:283`](../ui/dr-ui/ui/identity.slint#L283) |
| FR-DEV-1 | [`core/dr-pipeline/src/graph.rs:1`](../core/dr-pipeline/src/graph.rs#L1), [`core/dr-pipeline/src/sidecar.rs:1`](../core/dr-pipeline/src/sidecar.rs#L1) |
-| FR-DEV-10 | [`core/dr-gpu/src/mask.rs:1062`](../core/dr-gpu/src/mask.rs#L1062), [`core/dr-gpu/src/mask.rs:1150`](../core/dr-gpu/src/mask.rs#L1150), [`core/dr-gpu/src/mask.rs:402`](../core/dr-gpu/src/mask.rs#L402), [`core/dr-gpu/src/mask.rs:444`](../core/dr-gpu/src/mask.rs#L444), [`core/dr-gpu/src/mask.rs:58`](../core/dr-gpu/src/mask.rs#L58), [`core/dr-gpu/src/mask.rs:60`](../core/dr-gpu/src/mask.rs#L60), [`core/dr-gpu/src/mask.rs:658`](../core/dr-gpu/src/mask.rs#L658), [`core/dr-gpu/src/mask.rs:717`](../core/dr-gpu/src/mask.rs#L717), [`core/dr-gpu/src/mask.rs:829`](../core/dr-gpu/src/mask.rs#L829), [`core/dr-gpu/src/mask.rs:85`](../core/dr-gpu/src/mask.rs#L85), [`core/dr-gpu/src/shaders/mask.wgsl:101`](../core/dr-gpu/src/shaders/mask.wgsl#L101), [`core/dr-gpu/src/shaders/mask.wgsl:59`](../core/dr-gpu/src/shaders/mask.wgsl#L59), [`core/dr-gpu/tests/range_masks.rs:119`](../core/dr-gpu/tests/range_masks.rs#L119), [`core/dr-gpu/tests/range_masks.rs:147`](../core/dr-gpu/tests/range_masks.rs#L147), [`core/dr-gpu/tests/range_masks.rs:175`](../core/dr-gpu/tests/range_masks.rs#L175), [`core/dr-gpu/tests/range_masks.rs:1`](../core/dr-gpu/tests/range_masks.rs#L1), [`core/dr-gpu/tests/range_masks.rs:94`](../core/dr-gpu/tests/range_masks.rs#L94), [`core/dr-pipeline/src/mask.rs:125`](../core/dr-pipeline/src/mask.rs#L125), [`core/dr-pipeline/src/mask.rs:2162`](../core/dr-pipeline/src/mask.rs#L2162), [`core/dr-pipeline/src/mask.rs:2175`](../core/dr-pipeline/src/mask.rs#L2175), [`core/dr-pipeline/src/mask.rs:2194`](../core/dr-pipeline/src/mask.rs#L2194), [`core/dr-pipeline/src/mask.rs:2208`](../core/dr-pipeline/src/mask.rs#L2208), [`core/dr-pipeline/src/mask.rs:2218`](../core/dr-pipeline/src/mask.rs#L2218), [`core/dr-pipeline/src/mask.rs:709`](../core/dr-pipeline/src/mask.rs#L709), [`core/dr-pipeline/src/mask.rs:748`](../core/dr-pipeline/src/mask.rs#L748), [`core/dr-pipeline/src/mask.rs:808`](../core/dr-pipeline/src/mask.rs#L808), [`core/dr-pipeline/src/mask.rs:827`](../core/dr-pipeline/src/mask.rs#L827), [`core/dr-pipeline/src/mask.rs:851`](../core/dr-pipeline/src/mask.rs#L851), [`core/dr-pipeline/src/mask.rs:863`](../core/dr-pipeline/src/mask.rs#L863), [`core/dr-pipeline/src/mask.rs:875`](../core/dr-pipeline/src/mask.rs#L875), [`core/dr-pipeline/src/sidecar.rs:1132`](../core/dr-pipeline/src/sidecar.rs#L1132), [`core/dr-pipeline/src/sidecar.rs:1320`](../core/dr-pipeline/src/sidecar.rs#L1320), [`core/dr-pipeline/src/sidecar.rs:1414`](../core/dr-pipeline/src/sidecar.rs#L1414), [`core/dr-pipeline/src/sidecar.rs:1518`](../core/dr-pipeline/src/sidecar.rs#L1518), [`core/dr-pipeline/src/sidecar.rs:1602`](../core/dr-pipeline/src/sidecar.rs#L1602), [`core/dr-pipeline/tests/mask_sidecar.rs:1132`](../core/dr-pipeline/tests/mask_sidecar.rs#L1132), [`core/dr-pipeline/tests/mask_sidecar.rs:1161`](../core/dr-pipeline/tests/mask_sidecar.rs#L1161), [`core/dr-pipeline/tests/mask_sidecar.rs:1179`](../core/dr-pipeline/tests/mask_sidecar.rs#L1179), [`core/dr-pipeline/tests/mask_sidecar.rs:1209`](../core/dr-pipeline/tests/mask_sidecar.rs#L1209), [`ui/dr-ui/src/develop.rs:2148`](../ui/dr-ui/src/develop.rs#L2148), [`ui/dr-ui/src/develop.rs:3003`](../ui/dr-ui/src/develop.rs#L3003), [`ui/dr-ui/src/develop.rs:3029`](../ui/dr-ui/src/develop.rs#L3029), [`ui/dr-ui/src/develop.rs:3061`](../ui/dr-ui/src/develop.rs#L3061), [`ui/dr-ui/src/develop.rs:3085`](../ui/dr-ui/src/develop.rs#L3085), [`ui/dr-ui/src/develop.rs:3094`](../ui/dr-ui/src/develop.rs#L3094), [`ui/dr-ui/src/develop.rs:3103`](../ui/dr-ui/src/develop.rs#L3103), [`ui/dr-ui/src/develop.rs:3123`](../ui/dr-ui/src/develop.rs#L3123), [`ui/dr-ui/src/labels.rs:60`](../ui/dr-ui/src/labels.rs#L60), [`ui/dr-ui/src/masks_ui.rs:628`](../ui/dr-ui/src/masks_ui.rs#L628), [`ui/dr-ui/src/masks_ui.rs:741`](../ui/dr-ui/src/masks_ui.rs#L741) |
+| FR-DEV-10 | [`core/dr-gpu/src/mask.rs:1062`](../core/dr-gpu/src/mask.rs#L1062), [`core/dr-gpu/src/mask.rs:1150`](../core/dr-gpu/src/mask.rs#L1150), [`core/dr-gpu/src/mask.rs:402`](../core/dr-gpu/src/mask.rs#L402), [`core/dr-gpu/src/mask.rs:444`](../core/dr-gpu/src/mask.rs#L444), [`core/dr-gpu/src/mask.rs:58`](../core/dr-gpu/src/mask.rs#L58), [`core/dr-gpu/src/mask.rs:60`](../core/dr-gpu/src/mask.rs#L60), [`core/dr-gpu/src/mask.rs:658`](../core/dr-gpu/src/mask.rs#L658), [`core/dr-gpu/src/mask.rs:717`](../core/dr-gpu/src/mask.rs#L717), [`core/dr-gpu/src/mask.rs:829`](../core/dr-gpu/src/mask.rs#L829), [`core/dr-gpu/src/mask.rs:85`](../core/dr-gpu/src/mask.rs#L85), [`core/dr-gpu/src/shaders/mask.wgsl:101`](../core/dr-gpu/src/shaders/mask.wgsl#L101), [`core/dr-gpu/src/shaders/mask.wgsl:59`](../core/dr-gpu/src/shaders/mask.wgsl#L59), [`core/dr-gpu/tests/range_masks.rs:119`](../core/dr-gpu/tests/range_masks.rs#L119), [`core/dr-gpu/tests/range_masks.rs:147`](../core/dr-gpu/tests/range_masks.rs#L147), [`core/dr-gpu/tests/range_masks.rs:175`](../core/dr-gpu/tests/range_masks.rs#L175), [`core/dr-gpu/tests/range_masks.rs:1`](../core/dr-gpu/tests/range_masks.rs#L1), [`core/dr-gpu/tests/range_masks.rs:94`](../core/dr-gpu/tests/range_masks.rs#L94), [`core/dr-pipeline/src/mask.rs:125`](../core/dr-pipeline/src/mask.rs#L125), [`core/dr-pipeline/src/mask.rs:2162`](../core/dr-pipeline/src/mask.rs#L2162), [`core/dr-pipeline/src/mask.rs:2175`](../core/dr-pipeline/src/mask.rs#L2175), [`core/dr-pipeline/src/mask.rs:2194`](../core/dr-pipeline/src/mask.rs#L2194), [`core/dr-pipeline/src/mask.rs:2208`](../core/dr-pipeline/src/mask.rs#L2208), [`core/dr-pipeline/src/mask.rs:2218`](../core/dr-pipeline/src/mask.rs#L2218), [`core/dr-pipeline/src/mask.rs:709`](../core/dr-pipeline/src/mask.rs#L709), [`core/dr-pipeline/src/mask.rs:748`](../core/dr-pipeline/src/mask.rs#L748), [`core/dr-pipeline/src/mask.rs:808`](../core/dr-pipeline/src/mask.rs#L808), [`core/dr-pipeline/src/mask.rs:827`](../core/dr-pipeline/src/mask.rs#L827), [`core/dr-pipeline/src/mask.rs:851`](../core/dr-pipeline/src/mask.rs#L851), [`core/dr-pipeline/src/mask.rs:863`](../core/dr-pipeline/src/mask.rs#L863), [`core/dr-pipeline/src/mask.rs:875`](../core/dr-pipeline/src/mask.rs#L875), [`core/dr-pipeline/src/sidecar.rs:1132`](../core/dr-pipeline/src/sidecar.rs#L1132), [`core/dr-pipeline/src/sidecar.rs:1320`](../core/dr-pipeline/src/sidecar.rs#L1320), [`core/dr-pipeline/src/sidecar.rs:1414`](../core/dr-pipeline/src/sidecar.rs#L1414), [`core/dr-pipeline/src/sidecar.rs:1518`](../core/dr-pipeline/src/sidecar.rs#L1518), [`core/dr-pipeline/src/sidecar.rs:1602`](../core/dr-pipeline/src/sidecar.rs#L1602), [`core/dr-pipeline/tests/mask_sidecar.rs:1132`](../core/dr-pipeline/tests/mask_sidecar.rs#L1132), [`core/dr-pipeline/tests/mask_sidecar.rs:1161`](../core/dr-pipeline/tests/mask_sidecar.rs#L1161), [`core/dr-pipeline/tests/mask_sidecar.rs:1179`](../core/dr-pipeline/tests/mask_sidecar.rs#L1179), [`core/dr-pipeline/tests/mask_sidecar.rs:1209`](../core/dr-pipeline/tests/mask_sidecar.rs#L1209), [`ui/dr-ui/src/develop.rs:2148`](../ui/dr-ui/src/develop.rs#L2148), [`ui/dr-ui/src/develop.rs:3003`](../ui/dr-ui/src/develop.rs#L3003), [`ui/dr-ui/src/develop.rs:3029`](../ui/dr-ui/src/develop.rs#L3029), [`ui/dr-ui/src/develop.rs:3061`](../ui/dr-ui/src/develop.rs#L3061), [`ui/dr-ui/src/develop.rs:3085`](../ui/dr-ui/src/develop.rs#L3085), [`ui/dr-ui/src/develop.rs:3094`](../ui/dr-ui/src/develop.rs#L3094), [`ui/dr-ui/src/develop.rs:3103`](../ui/dr-ui/src/develop.rs#L3103), [`ui/dr-ui/src/develop.rs:3123`](../ui/dr-ui/src/develop.rs#L3123), [`ui/dr-ui/src/labels.rs:60`](../ui/dr-ui/src/labels.rs#L60), [`ui/dr-ui/src/masks_ui.rs:646`](../ui/dr-ui/src/masks_ui.rs#L646), [`ui/dr-ui/src/masks_ui.rs:771`](../ui/dr-ui/src/masks_ui.rs#L771) |
| FR-DEV-12 | [`core/dr-pipeline/ops/colour_grading.yaml:1`](../core/dr-pipeline/ops/colour_grading.yaml#L1) |
| FR-DEV-18 | [`core/dr-pipeline/src/ops/dehaze.rs:1`](../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:221`](../core/dr-pipeline/src/ops/dehaze.rs#L221) |
| FR-DEV-2 | [`core/dr-pipeline/src/operation.rs:403`](../core/dr-pipeline/src/operation.rs#L403) |
-| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:651`](../core/dr-gpu/src/adjust.rs#L651), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/tests/tone_curve.rs:1`](../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/framing.rs:177`](../core/dr-pipeline/src/framing.rs#L177), [`core/dr-pipeline/src/framing.rs:234`](../core/dr-pipeline/src/framing.rs#L234), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-pipeline/src/framing.rs:753`](../core/dr-pipeline/src/framing.rs#L753), [`core/dr-pipeline/src/graph.rs:209`](../core/dr-pipeline/src/graph.rs#L209), [`core/dr-pipeline/src/graph.rs:290`](../core/dr-pipeline/src/graph.rs#L290), [`core/dr-pipeline/src/graph.rs:762`](../core/dr-pipeline/src/graph.rs#L762), [`core/dr-pipeline/src/mask.rs:205`](../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/neutral.rs:1`](../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:300`](../core/dr-pipeline/src/neutral.rs#L300), [`core/dr-pipeline/src/neutral.rs:316`](../core/dr-pipeline/src/neutral.rs#L316), [`core/dr-pipeline/src/neutral.rs:332`](../core/dr-pipeline/src/neutral.rs#L332), [`core/dr-pipeline/src/neutral.rs:354`](../core/dr-pipeline/src/neutral.rs#L354), [`core/dr-pipeline/src/neutral.rs:79`](../core/dr-pipeline/src/neutral.rs#L79), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:535`](../core/dr-pipeline/src/operation.rs#L535), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:635`](../core/dr-pipeline/src/ops/curve.rs#L635), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/sidecar.rs:1205`](../core/dr-pipeline/src/sidecar.rs#L1205), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:1918`](../core/dr-pipeline/src/sidecar.rs#L1918), [`core/dr-pipeline/src/sidecar.rs:1978`](../core/dr-pipeline/src/sidecar.rs#L1978), [`core/dr-pipeline/tests/tone_curve.rs:1`](../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:850`](../core/dr-segment/src/refine.rs#L850), [`ui/dr-ui/src/develop.rs:103`](../ui/dr-ui/src/develop.rs#L103), [`ui/dr-ui/src/develop.rs:1188`](../ui/dr-ui/src/develop.rs#L1188), [`ui/dr-ui/src/develop.rs:1277`](../ui/dr-ui/src/develop.rs#L1277), [`ui/dr-ui/src/develop.rs:1313`](../ui/dr-ui/src/develop.rs#L1313), [`ui/dr-ui/src/develop.rs:1584`](../ui/dr-ui/src/develop.rs#L1584), [`ui/dr-ui/src/develop.rs:165`](../ui/dr-ui/src/develop.rs#L165), [`ui/dr-ui/src/develop.rs:2000`](../ui/dr-ui/src/develop.rs#L2000), [`ui/dr-ui/src/develop.rs:2227`](../ui/dr-ui/src/develop.rs#L2227), [`ui/dr-ui/src/develop.rs:2245`](../ui/dr-ui/src/develop.rs#L2245), [`ui/dr-ui/src/develop.rs:2259`](../ui/dr-ui/src/develop.rs#L2259), [`ui/dr-ui/src/develop.rs:2281`](../ui/dr-ui/src/develop.rs#L2281), [`ui/dr-ui/src/develop.rs:2427`](../ui/dr-ui/src/develop.rs#L2427), [`ui/dr-ui/src/develop.rs:2525`](../ui/dr-ui/src/develop.rs#L2525), [`ui/dr-ui/src/develop.rs:328`](../ui/dr-ui/src/develop.rs#L328), [`ui/dr-ui/src/develop.rs:365`](../ui/dr-ui/src/develop.rs#L365), [`ui/dr-ui/src/develop.rs:3741`](../ui/dr-ui/src/develop.rs#L3741), [`ui/dr-ui/src/develop.rs:3897`](../ui/dr-ui/src/develop.rs#L3897), [`ui/dr-ui/src/develop.rs:3957`](../ui/dr-ui/src/develop.rs#L3957), [`ui/dr-ui/src/develop.rs:4358`](../ui/dr-ui/src/develop.rs#L4358), [`ui/dr-ui/src/develop.rs:4388`](../ui/dr-ui/src/develop.rs#L4388), [`ui/dr-ui/src/develop.rs:4454`](../ui/dr-ui/src/develop.rs#L4454), [`ui/dr-ui/src/develop.rs:4468`](../ui/dr-ui/src/develop.rs#L4468), [`ui/dr-ui/src/develop.rs:4670`](../ui/dr-ui/src/develop.rs#L4670), [`ui/dr-ui/src/develop.rs:4758`](../ui/dr-ui/src/develop.rs#L4758), [`ui/dr-ui/src/develop.rs:5586`](../ui/dr-ui/src/develop.rs#L5586), [`ui/dr-ui/src/develop.rs:5779`](../ui/dr-ui/src/develop.rs#L5779), [`ui/dr-ui/src/develop.rs:5867`](../ui/dr-ui/src/develop.rs#L5867), [`ui/dr-ui/src/develop.rs:588`](../ui/dr-ui/src/develop.rs#L588), [`ui/dr-ui/src/develop.rs:6023`](../ui/dr-ui/src/develop.rs#L6023), [`ui/dr-ui/src/develop.rs:6159`](../ui/dr-ui/src/develop.rs#L6159), [`ui/dr-ui/src/develop.rs:6203`](../ui/dr-ui/src/develop.rs#L6203), [`ui/dr-ui/src/develop.rs:6253`](../ui/dr-ui/src/develop.rs#L6253), [`ui/dr-ui/src/develop.rs:649`](../ui/dr-ui/src/develop.rs#L649), [`ui/dr-ui/src/develop.rs:6678`](../ui/dr-ui/src/develop.rs#L6678), [`ui/dr-ui/src/develop.rs:7355`](../ui/dr-ui/src/develop.rs#L7355), [`ui/dr-ui/src/develop.rs:803`](../ui/dr-ui/src/develop.rs#L803), [`ui/dr-ui/src/develop.rs:850`](../ui/dr-ui/src/develop.rs#L850), [`ui/dr-ui/src/develop.rs:879`](../ui/dr-ui/src/develop.rs#L879), [`ui/dr-ui/src/labels.rs:32`](../ui/dr-ui/src/labels.rs#L32), [`ui/dr-ui/src/lib.rs:1790`](../ui/dr-ui/src/lib.rs#L1790), [`ui/dr-ui/src/lib.rs:2644`](../ui/dr-ui/src/lib.rs#L2644), [`ui/dr-ui/src/lib.rs:2842`](../ui/dr-ui/src/lib.rs#L2842), [`ui/dr-ui/src/lib.rs:2901`](../ui/dr-ui/src/lib.rs#L2901), [`ui/dr-ui/src/lib.rs:3106`](../ui/dr-ui/src/lib.rs#L3106), [`ui/dr-ui/src/lib.rs:3170`](../ui/dr-ui/src/lib.rs#L3170), [`ui/dr-ui/src/lib.rs:3224`](../ui/dr-ui/src/lib.rs#L3224), [`ui/dr-ui/src/lib.rs:381`](../ui/dr-ui/src/lib.rs#L381), [`ui/dr-ui/src/lib.rs:402`](../ui/dr-ui/src/lib.rs#L402), [`ui/dr-ui/src/lib.rs:507`](../ui/dr-ui/src/lib.rs#L507), [`ui/dr-ui/src/lib.rs:530`](../ui/dr-ui/src/lib.rs#L530), [`ui/dr-ui/src/library.rs:547`](../ui/dr-ui/src/library.rs#L547), [`ui/dr-ui/src/masks_ui.rs:1065`](../ui/dr-ui/src/masks_ui.rs#L1065), [`ui/dr-ui/src/masks_ui.rs:263`](../ui/dr-ui/src/masks_ui.rs#L263), [`ui/dr-ui/src/masks_ui.rs:41`](../ui/dr-ui/src/masks_ui.rs#L41), [`ui/dr-ui/src/masks_ui.rs:951`](../ui/dr-ui/src/masks_ui.rs#L951), [`ui/dr-ui/src/presets.rs:409`](../ui/dr-ui/src/presets.rs#L409), [`ui/dr-ui/src/segmentation.rs:116`](../ui/dr-ui/src/segmentation.rs#L116), [`ui/dr-ui/src/segmentation.rs:330`](../ui/dr-ui/src/segmentation.rs#L330), [`ui/dr-ui/src/segmentation.rs:346`](../ui/dr-ui/src/segmentation.rs#L346), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476), [`ui/dr-ui/src/segmentation.rs:504`](../ui/dr-ui/src/segmentation.rs#L504), [`ui/dr-ui/ui/adjust.slint:1073`](../ui/dr-ui/ui/adjust.slint#L1073), [`ui/dr-ui/ui/adjust.slint:125`](../ui/dr-ui/ui/adjust.slint#L125), [`ui/dr-ui/ui/adjust.slint:1369`](../ui/dr-ui/ui/adjust.slint#L1369), [`ui/dr-ui/ui/adjust.slint:170`](../ui/dr-ui/ui/adjust.slint#L170), [`ui/dr-ui/ui/adjust.slint:45`](../ui/dr-ui/ui/adjust.slint#L45), [`ui/dr-ui/ui/adjust.slint:624`](../ui/dr-ui/ui/adjust.slint#L624), [`ui/dr-ui/ui/adjust.slint:743`](../ui/dr-ui/ui/adjust.slint#L743), [`ui/dr-ui/ui/app.slint:1067`](../ui/dr-ui/ui/app.slint#L1067), [`ui/dr-ui/ui/app.slint:156`](../ui/dr-ui/ui/app.slint#L156), [`ui/dr-ui/ui/app.slint:202`](../ui/dr-ui/ui/app.slint#L202), [`ui/dr-ui/ui/app.slint:2087`](../ui/dr-ui/ui/app.slint#L2087), [`ui/dr-ui/ui/app.slint:2226`](../ui/dr-ui/ui/app.slint#L2226), [`ui/dr-ui/ui/app.slint:242`](../ui/dr-ui/ui/app.slint#L242), [`ui/dr-ui/ui/app.slint:3057`](../ui/dr-ui/ui/app.slint#L3057), [`ui/dr-ui/ui/app.slint:68`](../ui/dr-ui/ui/app.slint#L68), [`ui/dr-ui/ui/develop.slint:220`](../ui/dr-ui/ui/develop.slint#L220), [`ui/dr-ui/ui/masks.slint:767`](../ui/dr-ui/ui/masks.slint#L767) |
-| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:212`](../core/dr-pipeline/src/descriptor.rs#L212), [`core/dr-pipeline/src/descriptor.rs:252`](../core/dr-pipeline/src/descriptor.rs#L252), [`core/dr-pipeline/src/descriptor.rs:276`](../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/descriptor.rs:331`](../core/dr-pipeline/src/descriptor.rs#L331), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:25`](../core/dr-pipeline/src/graph.rs#L25), [`core/dr-pipeline/src/graph.rs:337`](../core/dr-pipeline/src/graph.rs#L337), [`core/dr-pipeline/src/graph.rs:439`](../core/dr-pipeline/src/graph.rs#L439), [`core/dr-pipeline/src/graph.rs:47`](../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:60`](../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1331`](../core/dr-pipeline/src/mask.rs#L1331), [`core/dr-pipeline/src/neutral.rs:1`](../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:372`](../core/dr-pipeline/src/neutral.rs#L372), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1200`](../ui/dr-ui/src/develop.rs#L1200), [`ui/dr-ui/src/develop.rs:1479`](../ui/dr-ui/src/develop.rs#L1479), [`ui/dr-ui/src/develop.rs:6678`](../ui/dr-ui/src/develop.rs#L6678), [`ui/dr-ui/src/lib.rs:824`](../ui/dr-ui/src/lib.rs#L824), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1), [`ui/dr-ui/ui/app.slint:2410`](../ui/dr-ui/ui/app.slint#L2410) |
-| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:276`](../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:60`](../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`ui/dr-ui/ui/app.slint:2599`](../ui/dr-ui/ui/app.slint#L2599) |
+| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:651`](../core/dr-gpu/src/adjust.rs#L651), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/tests/tone_curve.rs:1`](../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/framing.rs:177`](../core/dr-pipeline/src/framing.rs#L177), [`core/dr-pipeline/src/framing.rs:234`](../core/dr-pipeline/src/framing.rs#L234), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-pipeline/src/framing.rs:753`](../core/dr-pipeline/src/framing.rs#L753), [`core/dr-pipeline/src/graph.rs:209`](../core/dr-pipeline/src/graph.rs#L209), [`core/dr-pipeline/src/graph.rs:290`](../core/dr-pipeline/src/graph.rs#L290), [`core/dr-pipeline/src/graph.rs:762`](../core/dr-pipeline/src/graph.rs#L762), [`core/dr-pipeline/src/mask.rs:205`](../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/neutral.rs:1`](../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:300`](../core/dr-pipeline/src/neutral.rs#L300), [`core/dr-pipeline/src/neutral.rs:316`](../core/dr-pipeline/src/neutral.rs#L316), [`core/dr-pipeline/src/neutral.rs:332`](../core/dr-pipeline/src/neutral.rs#L332), [`core/dr-pipeline/src/neutral.rs:354`](../core/dr-pipeline/src/neutral.rs#L354), [`core/dr-pipeline/src/neutral.rs:79`](../core/dr-pipeline/src/neutral.rs#L79), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:535`](../core/dr-pipeline/src/operation.rs#L535), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:635`](../core/dr-pipeline/src/ops/curve.rs#L635), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/sidecar.rs:1205`](../core/dr-pipeline/src/sidecar.rs#L1205), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:1918`](../core/dr-pipeline/src/sidecar.rs#L1918), [`core/dr-pipeline/src/sidecar.rs:1978`](../core/dr-pipeline/src/sidecar.rs#L1978), [`core/dr-pipeline/tests/tone_curve.rs:1`](../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:850`](../core/dr-segment/src/refine.rs#L850), [`ui/dr-ui/src/develop.rs:103`](../ui/dr-ui/src/develop.rs#L103), [`ui/dr-ui/src/develop.rs:1188`](../ui/dr-ui/src/develop.rs#L1188), [`ui/dr-ui/src/develop.rs:1277`](../ui/dr-ui/src/develop.rs#L1277), [`ui/dr-ui/src/develop.rs:1313`](../ui/dr-ui/src/develop.rs#L1313), [`ui/dr-ui/src/develop.rs:1584`](../ui/dr-ui/src/develop.rs#L1584), [`ui/dr-ui/src/develop.rs:165`](../ui/dr-ui/src/develop.rs#L165), [`ui/dr-ui/src/develop.rs:2000`](../ui/dr-ui/src/develop.rs#L2000), [`ui/dr-ui/src/develop.rs:2227`](../ui/dr-ui/src/develop.rs#L2227), [`ui/dr-ui/src/develop.rs:2245`](../ui/dr-ui/src/develop.rs#L2245), [`ui/dr-ui/src/develop.rs:2259`](../ui/dr-ui/src/develop.rs#L2259), [`ui/dr-ui/src/develop.rs:2281`](../ui/dr-ui/src/develop.rs#L2281), [`ui/dr-ui/src/develop.rs:2427`](../ui/dr-ui/src/develop.rs#L2427), [`ui/dr-ui/src/develop.rs:2525`](../ui/dr-ui/src/develop.rs#L2525), [`ui/dr-ui/src/develop.rs:328`](../ui/dr-ui/src/develop.rs#L328), [`ui/dr-ui/src/develop.rs:365`](../ui/dr-ui/src/develop.rs#L365), [`ui/dr-ui/src/develop.rs:3741`](../ui/dr-ui/src/develop.rs#L3741), [`ui/dr-ui/src/develop.rs:3897`](../ui/dr-ui/src/develop.rs#L3897), [`ui/dr-ui/src/develop.rs:3957`](../ui/dr-ui/src/develop.rs#L3957), [`ui/dr-ui/src/develop.rs:4358`](../ui/dr-ui/src/develop.rs#L4358), [`ui/dr-ui/src/develop.rs:4388`](../ui/dr-ui/src/develop.rs#L4388), [`ui/dr-ui/src/develop.rs:4454`](../ui/dr-ui/src/develop.rs#L4454), [`ui/dr-ui/src/develop.rs:4468`](../ui/dr-ui/src/develop.rs#L4468), [`ui/dr-ui/src/develop.rs:4670`](../ui/dr-ui/src/develop.rs#L4670), [`ui/dr-ui/src/develop.rs:4758`](../ui/dr-ui/src/develop.rs#L4758), [`ui/dr-ui/src/develop.rs:5586`](../ui/dr-ui/src/develop.rs#L5586), [`ui/dr-ui/src/develop.rs:5779`](../ui/dr-ui/src/develop.rs#L5779), [`ui/dr-ui/src/develop.rs:5867`](../ui/dr-ui/src/develop.rs#L5867), [`ui/dr-ui/src/develop.rs:588`](../ui/dr-ui/src/develop.rs#L588), [`ui/dr-ui/src/develop.rs:6023`](../ui/dr-ui/src/develop.rs#L6023), [`ui/dr-ui/src/develop.rs:6159`](../ui/dr-ui/src/develop.rs#L6159), [`ui/dr-ui/src/develop.rs:6203`](../ui/dr-ui/src/develop.rs#L6203), [`ui/dr-ui/src/develop.rs:6253`](../ui/dr-ui/src/develop.rs#L6253), [`ui/dr-ui/src/develop.rs:649`](../ui/dr-ui/src/develop.rs#L649), [`ui/dr-ui/src/develop.rs:6678`](../ui/dr-ui/src/develop.rs#L6678), [`ui/dr-ui/src/develop.rs:7355`](../ui/dr-ui/src/develop.rs#L7355), [`ui/dr-ui/src/develop.rs:803`](../ui/dr-ui/src/develop.rs#L803), [`ui/dr-ui/src/develop.rs:850`](../ui/dr-ui/src/develop.rs#L850), [`ui/dr-ui/src/develop.rs:879`](../ui/dr-ui/src/develop.rs#L879), [`ui/dr-ui/src/labels.rs:32`](../ui/dr-ui/src/labels.rs#L32), [`ui/dr-ui/src/lib.rs:1832`](../ui/dr-ui/src/lib.rs#L1832), [`ui/dr-ui/src/lib.rs:2698`](../ui/dr-ui/src/lib.rs#L2698), [`ui/dr-ui/src/lib.rs:2900`](../ui/dr-ui/src/lib.rs#L2900), [`ui/dr-ui/src/lib.rs:2959`](../ui/dr-ui/src/lib.rs#L2959), [`ui/dr-ui/src/lib.rs:3164`](../ui/dr-ui/src/lib.rs#L3164), [`ui/dr-ui/src/lib.rs:3228`](../ui/dr-ui/src/lib.rs#L3228), [`ui/dr-ui/src/lib.rs:3282`](../ui/dr-ui/src/lib.rs#L3282), [`ui/dr-ui/src/lib.rs:412`](../ui/dr-ui/src/lib.rs#L412), [`ui/dr-ui/src/lib.rs:435`](../ui/dr-ui/src/lib.rs#L435), [`ui/dr-ui/src/lib.rs:541`](../ui/dr-ui/src/lib.rs#L541), [`ui/dr-ui/src/lib.rs:565`](../ui/dr-ui/src/lib.rs#L565), [`ui/dr-ui/src/library.rs:547`](../ui/dr-ui/src/library.rs#L547), [`ui/dr-ui/src/masks_ui.rs:1098`](../ui/dr-ui/src/masks_ui.rs#L1098), [`ui/dr-ui/src/masks_ui.rs:271`](../ui/dr-ui/src/masks_ui.rs#L271), [`ui/dr-ui/src/masks_ui.rs:44`](../ui/dr-ui/src/masks_ui.rs#L44), [`ui/dr-ui/src/masks_ui.rs:984`](../ui/dr-ui/src/masks_ui.rs#L984), [`ui/dr-ui/src/presets.rs:409`](../ui/dr-ui/src/presets.rs#L409), [`ui/dr-ui/src/segmentation.rs:116`](../ui/dr-ui/src/segmentation.rs#L116), [`ui/dr-ui/src/segmentation.rs:330`](../ui/dr-ui/src/segmentation.rs#L330), [`ui/dr-ui/src/segmentation.rs:346`](../ui/dr-ui/src/segmentation.rs#L346), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476), [`ui/dr-ui/src/segmentation.rs:504`](../ui/dr-ui/src/segmentation.rs#L504), [`ui/dr-ui/ui/adjust.slint:126`](../ui/dr-ui/ui/adjust.slint#L126), [`ui/dr-ui/ui/adjust.slint:1431`](../ui/dr-ui/ui/adjust.slint#L1431), [`ui/dr-ui/ui/adjust.slint:171`](../ui/dr-ui/ui/adjust.slint#L171), [`ui/dr-ui/ui/adjust.slint:46`](../ui/dr-ui/ui/adjust.slint#L46), [`ui/dr-ui/ui/adjust.slint:603`](../ui/dr-ui/ui/adjust.slint#L603), [`ui/dr-ui/ui/adjust.slint:629`](../ui/dr-ui/ui/adjust.slint#L629), [`ui/dr-ui/ui/adjust.slint:648`](../ui/dr-ui/ui/adjust.slint#L648), [`ui/dr-ui/ui/adjust.slint:769`](../ui/dr-ui/ui/adjust.slint#L769), [`ui/dr-ui/ui/adjust.slint:926`](../ui/dr-ui/ui/adjust.slint#L926), [`ui/dr-ui/ui/adjust.slint:986`](../ui/dr-ui/ui/adjust.slint#L986), [`ui/dr-ui/ui/app.slint:137`](../ui/dr-ui/ui/app.slint#L137), [`ui/dr-ui/ui/app.slint:1946`](../ui/dr-ui/ui/app.slint#L1946), [`ui/dr-ui/ui/app.slint:2085`](../ui/dr-ui/ui/app.slint#L2085), [`ui/dr-ui/ui/develop.slint:223`](../ui/dr-ui/ui/develop.slint#L223), [`ui/dr-ui/ui/masks.slint:433`](../ui/dr-ui/ui/masks.slint#L433), [`ui/dr-ui/ui/masks.slint:460`](../ui/dr-ui/ui/masks.slint#L460), [`ui/dr-ui/ui/masks.slint:789`](../ui/dr-ui/ui/masks.slint#L789) |
+| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:212`](../core/dr-pipeline/src/descriptor.rs#L212), [`core/dr-pipeline/src/descriptor.rs:252`](../core/dr-pipeline/src/descriptor.rs#L252), [`core/dr-pipeline/src/descriptor.rs:276`](../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/descriptor.rs:331`](../core/dr-pipeline/src/descriptor.rs#L331), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:25`](../core/dr-pipeline/src/graph.rs#L25), [`core/dr-pipeline/src/graph.rs:337`](../core/dr-pipeline/src/graph.rs#L337), [`core/dr-pipeline/src/graph.rs:439`](../core/dr-pipeline/src/graph.rs#L439), [`core/dr-pipeline/src/graph.rs:47`](../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:60`](../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1331`](../core/dr-pipeline/src/mask.rs#L1331), [`core/dr-pipeline/src/neutral.rs:1`](../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:372`](../core/dr-pipeline/src/neutral.rs#L372), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1200`](../ui/dr-ui/src/develop.rs#L1200), [`ui/dr-ui/src/develop.rs:1479`](../ui/dr-ui/src/develop.rs#L1479), [`ui/dr-ui/src/develop.rs:6678`](../ui/dr-ui/src/develop.rs#L6678), [`ui/dr-ui/src/lib.rs:860`](../ui/dr-ui/src/lib.rs#L860), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1), [`ui/dr-ui/ui/app.slint:2269`](../ui/dr-ui/ui/app.slint#L2269) |
+| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:276`](../core/dr-pipeline/src/descriptor.rs#L276), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:60`](../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`ui/dr-ui/ui/app.slint:2458`](../ui/dr-ui/ui/app.slint#L2458) |
| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:337`](../core/dr-pipeline/src/graph.rs#L337), [`core/dr-pipeline/src/graph.rs:47`](../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/mask.rs:1331`](../core/dr-pipeline/src/mask.rs#L1331), [`ui/dr-ui/src/develop.rs:6876`](../ui/dr-ui/src/develop.rs#L6876) |
| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:104`](../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1079`](../core/dr-gpu/src/adjust.rs#L1079), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/src/adjust.rs:986`](../core/dr-gpu/src/adjust.rs#L986), [`core/dr-gpu/tests/capture_sharpen.rs:434`](../core/dr-gpu/tests/capture_sharpen.rs#L434), [`core/dr-gpu/tests/detail_stage.rs:242`](../core/dr-gpu/tests/detail_stage.rs#L242), [`core/dr-gpu/tests/local_contrast.rs:558`](../core/dr-gpu/tests/local_contrast.rs#L558), [`core/dr-gpu/tests/noise_reduction.rs:556`](../core/dr-gpu/tests/noise_reduction.rs#L556), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/graph.rs:801`](../core/dr-pipeline/src/graph.rs#L801), [`core/dr-pipeline/src/operation.rs:32`](../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:403`](../core/dr-pipeline/src/operation.rs#L403), [`core/dr-pipeline/src/operation.rs:53`](../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../core/dr-pipeline/src/operation.rs#L71) |
| FR-DEV-3e | [`core/dr-decode/src/base_curve.rs:145`](../core/dr-decode/src/base_curve.rs#L145), [`core/dr-decode/src/base_curve.rs:158`](../core/dr-decode/src/base_curve.rs#L158), [`core/dr-decode/src/base_curve.rs:1`](../core/dr-decode/src/base_curve.rs#L1), [`core/dr-decode/src/base_curve.rs:267`](../core/dr-decode/src/base_curve.rs#L267), [`core/dr-decode/src/base_curve.rs:347`](../core/dr-decode/src/base_curve.rs#L347), [`core/dr-decode/src/base_curve.rs:55`](../core/dr-decode/src/base_curve.rs#L55), [`core/dr-decode/src/lib.rs:121`](../core/dr-decode/src/lib.rs#L121), [`core/dr-decode/src/lib.rs:708`](../core/dr-decode/src/lib.rs#L708), [`core/dr-decode/src/lib.rs:748`](../core/dr-decode/src/lib.rs#L748), [`core/dr-decode/src/profile.rs:102`](../core/dr-decode/src/profile.rs#L102), [`core/dr-decode/src/profile.rs:151`](../core/dr-decode/src/profile.rs#L151), [`core/dr-decode/src/profile.rs:1`](../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:235`](../core/dr-decode/src/profile.rs#L235), [`core/dr-decode/src/profile.rs:286`](../core/dr-decode/src/profile.rs#L286), [`core/dr-decode/src/profile.rs:343`](../core/dr-decode/src/profile.rs#L343), [`core/dr-decode/src/profile.rs:458`](../core/dr-decode/src/profile.rs#L458), [`core/dr-decode/src/profile.rs:492`](../core/dr-decode/src/profile.rs#L492), [`core/dr-decode/src/profile.rs:630`](../core/dr-decode/src/profile.rs#L630), [`core/dr-gpu/src/adjust.rs:37`](../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:967`](../core/dr-gpu/src/adjust.rs#L967), [`core/dr-gpu/src/demosaic.rs:121`](../core/dr-gpu/src/demosaic.rs#L121), [`core/dr-gpu/src/demosaic.rs:86`](../core/dr-gpu/src/demosaic.rs#L86), [`core/dr-gpu/tests/base_curve.rs:1`](../core/dr-gpu/tests/base_curve.rs#L1), [`core/dr-pipeline/src/operation.rs:1762`](../core/dr-pipeline/src/operation.rs#L1762), [`core/dr-pipeline/src/operation.rs:1843`](../core/dr-pipeline/src/operation.rs#L1843), [`core/dr-pipeline/src/operation.rs:1868`](../core/dr-pipeline/src/operation.rs#L1868), [`core/dr-pipeline/src/operation.rs:1883`](../core/dr-pipeline/src/operation.rs#L1883), [`core/dr-pipeline/src/operation.rs:1907`](../core/dr-pipeline/src/operation.rs#L1907), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:454`](../core/dr-pipeline/src/operation.rs#L454), [`core/dr-pipeline/src/operation.rs:464`](../core/dr-pipeline/src/operation.rs#L464), [`core/dr-pipeline/src/operation.rs:625`](../core/dr-pipeline/src/operation.rs#L625) |
-| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:103`](../core/dr-pipeline/src/graph.rs#L103), [`core/dr-pipeline/src/graph.rs:153`](../core/dr-pipeline/src/graph.rs#L153), [`core/dr-pipeline/src/graph.rs:471`](../core/dr-pipeline/src/graph.rs#L471), [`core/dr-pipeline/src/operation.rs:1137`](../core/dr-pipeline/src/operation.rs#L1137), [`core/dr-pipeline/src/operation.rs:1165`](../core/dr-pipeline/src/operation.rs#L1165), [`core/dr-pipeline/src/operation.rs:1211`](../core/dr-pipeline/src/operation.rs#L1211), [`core/dr-pipeline/src/operation.rs:1762`](../core/dr-pipeline/src/operation.rs#L1762), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:102`](../core/dr-pipeline/src/ops/film_sim.rs#L102), [`core/dr-pipeline/src/ops/film_sim.rs:139`](../core/dr-pipeline/src/ops/film_sim.rs#L139), [`core/dr-pipeline/src/ops/film_sim.rs:163`](../core/dr-pipeline/src/ops/film_sim.rs#L163), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:341`](../core/dr-pipeline/src/ops/film_sim.rs#L341), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:97`](../core/dr-pipeline/src/ops/film_sim.rs#L97), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2264`](../core/dr-pipeline/src/sidecar.rs#L2264), [`core/dr-pipeline/src/sidecar.rs:2340`](../core/dr-pipeline/src/sidecar.rs#L2340), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:779`](../core/dr-pipeline/src/sidecar.rs#L779), [`core/dr-pipeline/src/sidecar.rs:911`](../core/dr-pipeline/src/sidecar.rs#L911), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:4105`](../ui/dr-ui/src/develop.rs#L4105), [`ui/dr-ui/src/develop.rs:4122`](../ui/dr-ui/src/develop.rs#L4122), [`ui/dr-ui/src/develop.rs:4134`](../ui/dr-ui/src/develop.rs#L4134), [`ui/dr-ui/src/develop.rs:4172`](../ui/dr-ui/src/develop.rs#L4172), [`ui/dr-ui/src/develop.rs:4181`](../ui/dr-ui/src/develop.rs#L4181), [`ui/dr-ui/src/develop.rs:4284`](../ui/dr-ui/src/develop.rs#L4284), [`ui/dr-ui/src/develop.rs:4795`](../ui/dr-ui/src/develop.rs#L4795), [`ui/dr-ui/src/develop.rs:4810`](../ui/dr-ui/src/develop.rs#L4810), [`ui/dr-ui/src/lib.rs:2618`](../ui/dr-ui/src/lib.rs#L2618), [`ui/dr-ui/src/lib.rs:757`](../ui/dr-ui/src/lib.rs#L757), [`ui/dr-ui/src/lib.rs:815`](../ui/dr-ui/src/lib.rs#L815), [`ui/dr-ui/src/library.rs:538`](../ui/dr-ui/src/library.rs#L538), [`ui/dr-ui/src/library.rs:800`](../ui/dr-ui/src/library.rs#L800), [`ui/dr-ui/src/presets.rs:417`](../ui/dr-ui/src/presets.rs#L417), [`ui/dr-ui/ui/adjust.slint:1086`](../ui/dr-ui/ui/adjust.slint#L1086), [`ui/dr-ui/ui/adjust.slint:1162`](../ui/dr-ui/ui/adjust.slint#L1162), [`ui/dr-ui/ui/app.slint:3068`](../ui/dr-ui/ui/app.slint#L3068), [`ui/dr-ui/ui/app.slint:777`](../ui/dr-ui/ui/app.slint#L777) |
+| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:103`](../core/dr-pipeline/src/graph.rs#L103), [`core/dr-pipeline/src/graph.rs:153`](../core/dr-pipeline/src/graph.rs#L153), [`core/dr-pipeline/src/graph.rs:471`](../core/dr-pipeline/src/graph.rs#L471), [`core/dr-pipeline/src/operation.rs:1137`](../core/dr-pipeline/src/operation.rs#L1137), [`core/dr-pipeline/src/operation.rs:1165`](../core/dr-pipeline/src/operation.rs#L1165), [`core/dr-pipeline/src/operation.rs:1211`](../core/dr-pipeline/src/operation.rs#L1211), [`core/dr-pipeline/src/operation.rs:1762`](../core/dr-pipeline/src/operation.rs#L1762), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:102`](../core/dr-pipeline/src/ops/film_sim.rs#L102), [`core/dr-pipeline/src/ops/film_sim.rs:139`](../core/dr-pipeline/src/ops/film_sim.rs#L139), [`core/dr-pipeline/src/ops/film_sim.rs:163`](../core/dr-pipeline/src/ops/film_sim.rs#L163), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:341`](../core/dr-pipeline/src/ops/film_sim.rs#L341), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:97`](../core/dr-pipeline/src/ops/film_sim.rs#L97), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2264`](../core/dr-pipeline/src/sidecar.rs#L2264), [`core/dr-pipeline/src/sidecar.rs:2340`](../core/dr-pipeline/src/sidecar.rs#L2340), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:779`](../core/dr-pipeline/src/sidecar.rs#L779), [`core/dr-pipeline/src/sidecar.rs:911`](../core/dr-pipeline/src/sidecar.rs#L911), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:4105`](../ui/dr-ui/src/develop.rs#L4105), [`ui/dr-ui/src/develop.rs:4122`](../ui/dr-ui/src/develop.rs#L4122), [`ui/dr-ui/src/develop.rs:4134`](../ui/dr-ui/src/develop.rs#L4134), [`ui/dr-ui/src/develop.rs:4172`](../ui/dr-ui/src/develop.rs#L4172), [`ui/dr-ui/src/develop.rs:4181`](../ui/dr-ui/src/develop.rs#L4181), [`ui/dr-ui/src/develop.rs:4284`](../ui/dr-ui/src/develop.rs#L4284), [`ui/dr-ui/src/develop.rs:4795`](../ui/dr-ui/src/develop.rs#L4795), [`ui/dr-ui/src/develop.rs:4810`](../ui/dr-ui/src/develop.rs#L4810), [`ui/dr-ui/src/lib.rs:2670`](../ui/dr-ui/src/lib.rs#L2670), [`ui/dr-ui/src/lib.rs:792`](../ui/dr-ui/src/lib.rs#L792), [`ui/dr-ui/src/lib.rs:851`](../ui/dr-ui/src/lib.rs#L851), [`ui/dr-ui/src/library.rs:538`](../ui/dr-ui/src/library.rs#L538), [`ui/dr-ui/src/library.rs:800`](../ui/dr-ui/src/library.rs#L800), [`ui/dr-ui/src/presets.rs:417`](../ui/dr-ui/src/presets.rs#L417), [`ui/dr-ui/ui/adjust.slint:1007`](../ui/dr-ui/ui/adjust.slint#L1007), [`ui/dr-ui/ui/adjust.slint:1224`](../ui/dr-ui/ui/adjust.slint#L1224) |
| FR-DEV-3h | [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1067`](../core/dr-pipeline/src/framing.rs#L1067), [`core/dr-pipeline/src/framing.rs:328`](../core/dr-pipeline/src/framing.rs#L328), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-types/src/lib.rs:339`](../core/dr-types/src/lib.rs#L339), [`core/dr-types/src/lib.rs:447`](../core/dr-types/src/lib.rs#L447), [`core/dr-types/src/lib.rs:459`](../core/dr-types/src/lib.rs#L459), [`core/dr-types/src/lib.rs:475`](../core/dr-types/src/lib.rs#L475), [`ui/dr-ui/src/develop.rs:140`](../ui/dr-ui/src/develop.rs#L140), [`ui/dr-ui/src/develop.rs:2444`](../ui/dr-ui/src/develop.rs#L2444), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476) |
| FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:351`](../core/dr-gpu/src/lib.rs#L351), [`ui/dr-ui/ui/crop.slint:1`](../ui/dr-ui/ui/crop.slint#L1) |
-| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:492`](../core/dr-pipeline/src/graph.rs#L492), [`core/dr-pipeline/src/graph.rs:540`](../core/dr-pipeline/src/graph.rs#L540), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3741`](../ui/dr-ui/src/develop.rs#L3741), [`ui/dr-ui/src/develop.rs:4134`](../ui/dr-ui/src/develop.rs#L4134), [`ui/dr-ui/src/develop.rs:4810`](../ui/dr-ui/src/develop.rs#L4810), [`ui/dr-ui/src/develop.rs:4840`](../ui/dr-ui/src/develop.rs#L4840), [`ui/dr-ui/src/develop.rs:4853`](../ui/dr-ui/src/develop.rs#L4853), [`ui/dr-ui/src/develop.rs:4865`](../ui/dr-ui/src/develop.rs#L4865), [`ui/dr-ui/src/develop.rs:4881`](../ui/dr-ui/src/develop.rs#L4881), [`ui/dr-ui/src/develop.rs:4913`](../ui/dr-ui/src/develop.rs#L4913), [`ui/dr-ui/src/develop.rs:4917`](../ui/dr-ui/src/develop.rs#L4917), [`ui/dr-ui/src/develop.rs:4936`](../ui/dr-ui/src/develop.rs#L4936), [`ui/dr-ui/src/develop.rs:4952`](../ui/dr-ui/src/develop.rs#L4952), [`ui/dr-ui/src/develop.rs:5759`](../ui/dr-ui/src/develop.rs#L5759), [`ui/dr-ui/src/develop.rs:5779`](../ui/dr-ui/src/develop.rs#L5779), [`ui/dr-ui/src/develop.rs:5810`](../ui/dr-ui/src/develop.rs#L5810), [`ui/dr-ui/src/develop.rs:746`](../ui/dr-ui/src/develop.rs#L746), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:246`](../ui/dr-ui/src/labels.rs#L246), [`ui/dr-ui/src/lib.rs:1706`](../ui/dr-ui/src/lib.rs#L1706), [`ui/dr-ui/src/lib.rs:1768`](../ui/dr-ui/src/lib.rs#L1768), [`ui/dr-ui/src/lib.rs:1776`](../ui/dr-ui/src/lib.rs#L1776), [`ui/dr-ui/src/lib.rs:2875`](../ui/dr-ui/src/lib.rs#L2875), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) |
-| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:381`](../core/dr-pipeline/src/preset.rs#L381), [`core/dr-pipeline/src/preset.rs:414`](../core/dr-pipeline/src/preset.rs#L414), [`core/dr-pipeline/src/starter.rs:1`](../core/dr-pipeline/src/starter.rs#L1), [`core/dr-preset-xmp/src/lib.rs:1`](../core/dr-preset-xmp/src/lib.rs#L1), [`core/dr-types/src/settings.rs:272`](../core/dr-types/src/settings.rs#L272), [`ui/dr-ui/src/develop.rs:4752`](../ui/dr-ui/src/develop.rs#L4752), [`ui/dr-ui/src/develop.rs:4773`](../ui/dr-ui/src/develop.rs#L4773), [`ui/dr-ui/src/lib.rs:1673`](../ui/dr-ui/src/lib.rs#L1673), [`ui/dr-ui/src/lib.rs:2423`](../ui/dr-ui/src/lib.rs#L2423), [`ui/dr-ui/src/lib.rs:2452`](../ui/dr-ui/src/lib.rs#L2452), [`ui/dr-ui/src/library.rs:2219`](../ui/dr-ui/src/library.rs#L2219), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:528`](../ui/dr-ui/src/library.rs#L528), [`ui/dr-ui/src/library_ui.rs:3200`](../ui/dr-ui/src/library_ui.rs#L3200), [`ui/dr-ui/src/library_ui.rs:3600`](../ui/dr-ui/src/library_ui.rs#L3600), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/presets.rs:679`](../ui/dr-ui/src/presets.rs#L679), [`ui/dr-ui/src/presets.rs:713`](../ui/dr-ui/src/presets.rs#L713), [`ui/dr-ui/ui/adjust.slint:817`](../ui/dr-ui/ui/adjust.slint#L817), [`ui/dr-ui/ui/adjust.slint:844`](../ui/dr-ui/ui/adjust.slint#L844), [`ui/dr-ui/ui/adjust.slint:878`](../ui/dr-ui/ui/adjust.slint#L878), [`ui/dr-ui/ui/app.slint:1689`](../ui/dr-ui/ui/app.slint#L1689), [`ui/dr-ui/ui/app.slint:2379`](../ui/dr-ui/ui/app.slint#L2379), [`ui/dr-ui/ui/app.slint:3157`](../ui/dr-ui/ui/app.slint#L3157), [`ui/dr-ui/ui/app.slint:861`](../ui/dr-ui/ui/app.slint#L861), [`ui/dr-ui/ui/app.slint:872`](../ui/dr-ui/ui/app.slint#L872), [`ui/dr-ui/ui/library.slint:1574`](../ui/dr-ui/ui/library.slint#L1574), [`ui/dr-ui/ui/library.slint:1580`](../ui/dr-ui/ui/library.slint#L1580), [`ui/dr-ui/ui/library.slint:4211`](../ui/dr-ui/ui/library.slint#L4211), [`ui/dr-ui/ui/library.slint:4226`](../ui/dr-ui/ui/library.slint#L4226), [`ui/dr-ui/ui/presets.slint:105`](../ui/dr-ui/ui/presets.slint#L105), [`ui/dr-ui/ui/presets.slint:113`](../ui/dr-ui/ui/presets.slint#L113), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/presets.slint:276`](../ui/dr-ui/ui/presets.slint#L276), [`ui/dr-ui/ui/presets.slint:297`](../ui/dr-ui/ui/presets.slint#L297), [`ui/dr-ui/ui/presets.slint:5`](../ui/dr-ui/ui/presets.slint#L5), [`ui/dr-ui/ui/presets.slint:60`](../ui/dr-ui/ui/presets.slint#L60), [`ui/dr-ui/ui/settings.slint:101`](../ui/dr-ui/ui/settings.slint#L101), [`ui/dr-ui/ui/settings.slint:595`](../ui/dr-ui/ui/settings.slint#L595) |
-| FR-DEV-7 | [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`ui/dr-ui/src/develop.rs:3675`](../ui/dr-ui/src/develop.rs#L3675), [`ui/dr-ui/src/develop.rs:3716`](../ui/dr-ui/src/develop.rs#L3716), [`ui/dr-ui/src/develop.rs:4881`](../ui/dr-ui/src/develop.rs#L4881), [`ui/dr-ui/src/develop.rs:4913`](../ui/dr-ui/src/develop.rs#L4913), [`ui/dr-ui/src/develop.rs:5810`](../ui/dr-ui/src/develop.rs#L5810), [`ui/dr-ui/src/lib.rs:1776`](../ui/dr-ui/src/lib.rs#L1776), [`ui/dr-ui/src/lib.rs:1837`](../ui/dr-ui/src/lib.rs#L1837), [`ui/dr-ui/src/lib.rs:2814`](../ui/dr-ui/src/lib.rs#L2814), [`ui/dr-ui/src/lib.rs:2875`](../ui/dr-ui/src/lib.rs#L2875), [`ui/dr-ui/src/lib.rs:373`](../ui/dr-ui/src/lib.rs#L373), [`ui/dr-ui/ui/app.slint:224`](../ui/dr-ui/ui/app.slint#L224), [`ui/dr-ui/ui/app.slint:2286`](../ui/dr-ui/ui/app.slint#L2286), [`ui/dr-ui/ui/app.slint:2301`](../ui/dr-ui/ui/app.slint#L2301), [`ui/dr-ui/ui/app.slint:2599`](../ui/dr-ui/ui/app.slint#L2599), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/widgets.slint:71`](../ui/dr-ui/ui/widgets.slint#L71) |
-| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:405`](../core/dr-gpu/src/detail.rs#L405), [`core/dr-gpu/src/detail.rs:623`](../core/dr-gpu/src/detail.rs#L623), [`core/dr-gpu/tests/detail_instances.rs:1`](../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:410`](../core/dr-pipeline/src/detail.rs#L410), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:469`](../core/dr-pipeline/src/detail.rs#L469), [`core/dr-pipeline/src/detail.rs:555`](../core/dr-pipeline/src/detail.rs#L555), [`core/dr-pipeline/src/graph.rs:115`](../core/dr-pipeline/src/graph.rs#L115), [`core/dr-pipeline/src/graph.rs:231`](../core/dr-pipeline/src/graph.rs#L231), [`core/dr-pipeline/src/graph.rs:886`](../core/dr-pipeline/src/graph.rs#L886), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:579`](../core/dr-pipeline/src/operation.rs#L579), [`core/dr-pipeline/src/sidecar.rs:1011`](../core/dr-pipeline/src/sidecar.rs#L1011), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:791`](../core/dr-pipeline/src/sidecar.rs#L791), [`core/dr-pipeline/src/sidecar.rs:927`](../core/dr-pipeline/src/sidecar.rs#L927), [`core/dr-pipeline/src/sidecar.rs:981`](../core/dr-pipeline/src/sidecar.rs#L981), [`core/dr-pipeline/src/spot.rs:115`](../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop.rs:2596`](../ui/dr-ui/src/develop.rs#L2596), [`ui/dr-ui/src/develop.rs:2634`](../ui/dr-ui/src/develop.rs#L2634), [`ui/dr-ui/src/develop.rs:2699`](../ui/dr-ui/src/develop.rs#L2699), [`ui/dr-ui/src/develop.rs:2782`](../ui/dr-ui/src/develop.rs#L2782), [`ui/dr-ui/src/develop.rs:2796`](../ui/dr-ui/src/develop.rs#L2796), [`ui/dr-ui/src/develop.rs:833`](../ui/dr-ui/src/develop.rs#L833), [`ui/dr-ui/src/labels.rs:64`](../ui/dr-ui/src/labels.rs#L64), [`ui/dr-ui/src/lib.rs:1797`](../ui/dr-ui/src/lib.rs#L1797), [`ui/dr-ui/src/lib.rs:3026`](../ui/dr-ui/src/lib.rs#L3026), [`ui/dr-ui/src/lib.rs:407`](../ui/dr-ui/src/lib.rs#L407), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/adjust.slint:909`](../ui/dr-ui/ui/adjust.slint#L909), [`ui/dr-ui/ui/app.slint:146`](../ui/dr-ui/ui/app.slint#L146), [`ui/dr-ui/ui/app.slint:2063`](../ui/dr-ui/ui/app.slint#L2063), [`ui/dr-ui/ui/app.slint:2344`](../ui/dr-ui/ui/app.slint#L2344), [`ui/dr-ui/ui/app.slint:2951`](../ui/dr-ui/ui/app.slint#L2951), [`ui/dr-ui/ui/icons.slint:338`](../ui/dr-ui/ui/icons.slint#L338), [`ui/dr-ui/ui/spots.slint:172`](../ui/dr-ui/ui/spots.slint#L172), [`ui/dr-ui/ui/spots.slint:48`](../ui/dr-ui/ui/spots.slint#L48), [`ui/dr-ui/ui/spots.slint:5`](../ui/dr-ui/ui/spots.slint#L5) |
-| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2140`](../core/dr-gpu/src/adjust.rs#L2140), [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:2302`](../core/dr-gpu/src/adjust.rs#L2302), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:172`](../core/dr-gpu/src/lib.rs#L172), [`core/dr-gpu/src/lib.rs:192`](../core/dr-gpu/src/lib.rs#L192), [`core/dr-gpu/src/lib.rs:70`](../core/dr-gpu/src/lib.rs#L70), [`core/dr-gpu/src/lib.rs:93`](../core/dr-gpu/src/lib.rs#L93), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:264`](../core/dr-gpu/tests/local_contrast.rs#L264), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/graph.rs:732`](../core/dr-pipeline/src/graph.rs#L732), [`core/dr-pipeline/src/graph.rs:762`](../core/dr-pipeline/src/graph.rs#L762), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:659`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L659), [`core/dr-pipeline/src/ops/dehaze.rs:1`](../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:592`](../core/dr-pipeline/src/ops/dehaze.rs#L592), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:971`](../core/dr-pipeline/src/ops/local_contrast.rs#L971), [`core/dr-pipeline/src/ops/noise_reduction.rs:700`](../core/dr-pipeline/src/ops/noise_reduction.rs#L700), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:3367`](../ui/dr-ui/src/develop.rs#L3367), [`ui/dr-ui/src/develop.rs:4620`](../ui/dr-ui/src/develop.rs#L4620), [`ui/dr-ui/src/develop.rs:5207`](../ui/dr-ui/src/develop.rs#L5207), [`ui/dr-ui/src/develop.rs:6377`](../ui/dr-ui/src/develop.rs#L6377), [`ui/dr-ui/src/develop.rs:6411`](../ui/dr-ui/src/develop.rs#L6411), [`ui/dr-ui/src/lib.rs:1024`](../ui/dr-ui/src/lib.rs#L1024), [`ui/dr-ui/src/lib.rs:93`](../ui/dr-ui/src/lib.rs#L93), [`ui/dr-ui/src/lib.rs:965`](../ui/dr-ui/src/lib.rs#L965) |
+| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:492`](../core/dr-pipeline/src/graph.rs#L492), [`core/dr-pipeline/src/graph.rs:540`](../core/dr-pipeline/src/graph.rs#L540), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3741`](../ui/dr-ui/src/develop.rs#L3741), [`ui/dr-ui/src/develop.rs:4134`](../ui/dr-ui/src/develop.rs#L4134), [`ui/dr-ui/src/develop.rs:4810`](../ui/dr-ui/src/develop.rs#L4810), [`ui/dr-ui/src/develop.rs:4840`](../ui/dr-ui/src/develop.rs#L4840), [`ui/dr-ui/src/develop.rs:4853`](../ui/dr-ui/src/develop.rs#L4853), [`ui/dr-ui/src/develop.rs:4865`](../ui/dr-ui/src/develop.rs#L4865), [`ui/dr-ui/src/develop.rs:4881`](../ui/dr-ui/src/develop.rs#L4881), [`ui/dr-ui/src/develop.rs:4913`](../ui/dr-ui/src/develop.rs#L4913), [`ui/dr-ui/src/develop.rs:4917`](../ui/dr-ui/src/develop.rs#L4917), [`ui/dr-ui/src/develop.rs:4936`](../ui/dr-ui/src/develop.rs#L4936), [`ui/dr-ui/src/develop.rs:4952`](../ui/dr-ui/src/develop.rs#L4952), [`ui/dr-ui/src/develop.rs:5759`](../ui/dr-ui/src/develop.rs#L5759), [`ui/dr-ui/src/develop.rs:5779`](../ui/dr-ui/src/develop.rs#L5779), [`ui/dr-ui/src/develop.rs:5810`](../ui/dr-ui/src/develop.rs#L5810), [`ui/dr-ui/src/develop.rs:746`](../ui/dr-ui/src/develop.rs#L746), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:246`](../ui/dr-ui/src/labels.rs#L246), [`ui/dr-ui/src/lib.rs:1748`](../ui/dr-ui/src/lib.rs#L1748), [`ui/dr-ui/src/lib.rs:1810`](../ui/dr-ui/src/lib.rs#L1810), [`ui/dr-ui/src/lib.rs:1819`](../ui/dr-ui/src/lib.rs#L1819), [`ui/dr-ui/src/lib.rs:2933`](../ui/dr-ui/src/lib.rs#L2933), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:92`](../ui/dr-ui/ui/history.slint#L92) |
+| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:381`](../core/dr-pipeline/src/preset.rs#L381), [`core/dr-pipeline/src/preset.rs:414`](../core/dr-pipeline/src/preset.rs#L414), [`core/dr-pipeline/src/starter.rs:1`](../core/dr-pipeline/src/starter.rs#L1), [`core/dr-preset-xmp/src/lib.rs:1`](../core/dr-preset-xmp/src/lib.rs#L1), [`core/dr-types/src/settings.rs:272`](../core/dr-types/src/settings.rs#L272), [`ui/dr-ui/src/develop.rs:4752`](../ui/dr-ui/src/develop.rs#L4752), [`ui/dr-ui/src/develop.rs:4773`](../ui/dr-ui/src/develop.rs#L4773), [`ui/dr-ui/src/lib.rs:1715`](../ui/dr-ui/src/lib.rs#L1715), [`ui/dr-ui/src/lib.rs:2471`](../ui/dr-ui/src/lib.rs#L2471), [`ui/dr-ui/src/lib.rs:2500`](../ui/dr-ui/src/lib.rs#L2500), [`ui/dr-ui/src/library.rs:2219`](../ui/dr-ui/src/library.rs#L2219), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:528`](../ui/dr-ui/src/library.rs#L528), [`ui/dr-ui/src/library_ui.rs:3200`](../ui/dr-ui/src/library_ui.rs#L3200), [`ui/dr-ui/src/library_ui.rs:3600`](../ui/dr-ui/src/library_ui.rs#L3600), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/presets.rs:680`](../ui/dr-ui/src/presets.rs#L680), [`ui/dr-ui/src/presets.rs:714`](../ui/dr-ui/src/presets.rs#L714), [`ui/dr-ui/ui/adjust.slint:832`](../ui/dr-ui/ui/adjust.slint#L832), [`ui/dr-ui/ui/adjust.slint:857`](../ui/dr-ui/ui/adjust.slint#L857), [`ui/dr-ui/ui/adjust.slint:868`](../ui/dr-ui/ui/adjust.slint#L868), [`ui/dr-ui/ui/adjust.slint:911`](../ui/dr-ui/ui/adjust.slint#L911), [`ui/dr-ui/ui/app.slint:1490`](../ui/dr-ui/ui/app.slint#L1490), [`ui/dr-ui/ui/app.slint:2238`](../ui/dr-ui/ui/app.slint#L2238), [`ui/dr-ui/ui/app.slint:2851`](../ui/dr-ui/ui/app.slint#L2851), [`ui/dr-ui/ui/app.slint:691`](../ui/dr-ui/ui/app.slint#L691), [`ui/dr-ui/ui/app.slint:702`](../ui/dr-ui/ui/app.slint#L702), [`ui/dr-ui/ui/library.slint:1574`](../ui/dr-ui/ui/library.slint#L1574), [`ui/dr-ui/ui/library.slint:1580`](../ui/dr-ui/ui/library.slint#L1580), [`ui/dr-ui/ui/library.slint:4211`](../ui/dr-ui/ui/library.slint#L4211), [`ui/dr-ui/ui/library.slint:4226`](../ui/dr-ui/ui/library.slint#L4226), [`ui/dr-ui/ui/presets.slint:105`](../ui/dr-ui/ui/presets.slint#L105), [`ui/dr-ui/ui/presets.slint:113`](../ui/dr-ui/ui/presets.slint#L113), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/presets.slint:276`](../ui/dr-ui/ui/presets.slint#L276), [`ui/dr-ui/ui/presets.slint:297`](../ui/dr-ui/ui/presets.slint#L297), [`ui/dr-ui/ui/presets.slint:5`](../ui/dr-ui/ui/presets.slint#L5), [`ui/dr-ui/ui/presets.slint:60`](../ui/dr-ui/ui/presets.slint#L60), [`ui/dr-ui/ui/settings.slint:101`](../ui/dr-ui/ui/settings.slint#L101), [`ui/dr-ui/ui/settings.slint:595`](../ui/dr-ui/ui/settings.slint#L595) |
+| FR-DEV-7 | [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`ui/dr-ui/src/develop.rs:3675`](../ui/dr-ui/src/develop.rs#L3675), [`ui/dr-ui/src/develop.rs:3716`](../ui/dr-ui/src/develop.rs#L3716), [`ui/dr-ui/src/develop.rs:4881`](../ui/dr-ui/src/develop.rs#L4881), [`ui/dr-ui/src/develop.rs:4913`](../ui/dr-ui/src/develop.rs#L4913), [`ui/dr-ui/src/develop.rs:5810`](../ui/dr-ui/src/develop.rs#L5810), [`ui/dr-ui/src/lib.rs:1819`](../ui/dr-ui/src/lib.rs#L1819), [`ui/dr-ui/src/lib.rs:1881`](../ui/dr-ui/src/lib.rs#L1881), [`ui/dr-ui/src/lib.rs:2872`](../ui/dr-ui/src/lib.rs#L2872), [`ui/dr-ui/src/lib.rs:2933`](../ui/dr-ui/src/lib.rs#L2933), [`ui/dr-ui/src/lib.rs:404`](../ui/dr-ui/src/lib.rs#L404), [`ui/dr-ui/ui/app.slint:119`](../ui/dr-ui/ui/app.slint#L119), [`ui/dr-ui/ui/app.slint:2145`](../ui/dr-ui/ui/app.slint#L2145), [`ui/dr-ui/ui/app.slint:2160`](../ui/dr-ui/ui/app.slint#L2160), [`ui/dr-ui/ui/app.slint:2458`](../ui/dr-ui/ui/app.slint#L2458), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/widgets.slint:71`](../ui/dr-ui/ui/widgets.slint#L71) |
+| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:405`](../core/dr-gpu/src/detail.rs#L405), [`core/dr-gpu/src/detail.rs:623`](../core/dr-gpu/src/detail.rs#L623), [`core/dr-gpu/tests/detail_instances.rs:1`](../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:410`](../core/dr-pipeline/src/detail.rs#L410), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:469`](../core/dr-pipeline/src/detail.rs#L469), [`core/dr-pipeline/src/detail.rs:555`](../core/dr-pipeline/src/detail.rs#L555), [`core/dr-pipeline/src/graph.rs:115`](../core/dr-pipeline/src/graph.rs#L115), [`core/dr-pipeline/src/graph.rs:231`](../core/dr-pipeline/src/graph.rs#L231), [`core/dr-pipeline/src/graph.rs:886`](../core/dr-pipeline/src/graph.rs#L886), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:579`](../core/dr-pipeline/src/operation.rs#L579), [`core/dr-pipeline/src/sidecar.rs:1011`](../core/dr-pipeline/src/sidecar.rs#L1011), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:791`](../core/dr-pipeline/src/sidecar.rs#L791), [`core/dr-pipeline/src/sidecar.rs:927`](../core/dr-pipeline/src/sidecar.rs#L927), [`core/dr-pipeline/src/sidecar.rs:981`](../core/dr-pipeline/src/sidecar.rs#L981), [`core/dr-pipeline/src/spot.rs:115`](../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop.rs:2596`](../ui/dr-ui/src/develop.rs#L2596), [`ui/dr-ui/src/develop.rs:2634`](../ui/dr-ui/src/develop.rs#L2634), [`ui/dr-ui/src/develop.rs:2699`](../ui/dr-ui/src/develop.rs#L2699), [`ui/dr-ui/src/develop.rs:2782`](../ui/dr-ui/src/develop.rs#L2782), [`ui/dr-ui/src/develop.rs:2796`](../ui/dr-ui/src/develop.rs#L2796), [`ui/dr-ui/src/develop.rs:833`](../ui/dr-ui/src/develop.rs#L833), [`ui/dr-ui/src/labels.rs:64`](../ui/dr-ui/src/labels.rs#L64), [`ui/dr-ui/src/lib.rs:1839`](../ui/dr-ui/src/lib.rs#L1839), [`ui/dr-ui/src/lib.rs:3084`](../ui/dr-ui/src/lib.rs#L3084), [`ui/dr-ui/src/lib.rs:440`](../ui/dr-ui/src/lib.rs#L440), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/app.slint:1922`](../ui/dr-ui/ui/app.slint#L1922), [`ui/dr-ui/ui/app.slint:2203`](../ui/dr-ui/ui/app.slint#L2203), [`ui/dr-ui/ui/app.slint:2757`](../ui/dr-ui/ui/app.slint#L2757), [`ui/dr-ui/ui/icons.slint:338`](../ui/dr-ui/ui/icons.slint#L338), [`ui/dr-ui/ui/session.slint:102`](../ui/dr-ui/ui/session.slint#L102), [`ui/dr-ui/ui/session.slint:52`](../ui/dr-ui/ui/session.slint#L52), [`ui/dr-ui/ui/spots.slint:191`](../ui/dr-ui/ui/spots.slint#L191), [`ui/dr-ui/ui/spots.slint:49`](../ui/dr-ui/ui/spots.slint#L49), [`ui/dr-ui/ui/spots.slint:6`](../ui/dr-ui/ui/spots.slint#L6), [`ui/dr-ui/ui/spots.slint:91`](../ui/dr-ui/ui/spots.slint#L91) |
+| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2140`](../core/dr-gpu/src/adjust.rs#L2140), [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:2302`](../core/dr-gpu/src/adjust.rs#L2302), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:172`](../core/dr-gpu/src/lib.rs#L172), [`core/dr-gpu/src/lib.rs:192`](../core/dr-gpu/src/lib.rs#L192), [`core/dr-gpu/src/lib.rs:70`](../core/dr-gpu/src/lib.rs#L70), [`core/dr-gpu/src/lib.rs:93`](../core/dr-gpu/src/lib.rs#L93), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:264`](../core/dr-gpu/tests/local_contrast.rs#L264), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/graph.rs:732`](../core/dr-pipeline/src/graph.rs#L732), [`core/dr-pipeline/src/graph.rs:762`](../core/dr-pipeline/src/graph.rs#L762), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:659`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L659), [`core/dr-pipeline/src/ops/dehaze.rs:1`](../core/dr-pipeline/src/ops/dehaze.rs#L1), [`core/dr-pipeline/src/ops/dehaze.rs:592`](../core/dr-pipeline/src/ops/dehaze.rs#L592), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:971`](../core/dr-pipeline/src/ops/local_contrast.rs#L971), [`core/dr-pipeline/src/ops/noise_reduction.rs:700`](../core/dr-pipeline/src/ops/noise_reduction.rs#L700), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:3367`](../ui/dr-ui/src/develop.rs#L3367), [`ui/dr-ui/src/develop.rs:4620`](../ui/dr-ui/src/develop.rs#L4620), [`ui/dr-ui/src/develop.rs:5207`](../ui/dr-ui/src/develop.rs#L5207), [`ui/dr-ui/src/develop.rs:6377`](../ui/dr-ui/src/develop.rs#L6377), [`ui/dr-ui/src/develop.rs:6411`](../ui/dr-ui/src/develop.rs#L6411), [`ui/dr-ui/src/lib.rs:1007`](../ui/dr-ui/src/lib.rs#L1007), [`ui/dr-ui/src/lib.rs:1066`](../ui/dr-ui/src/lib.rs#L1066), [`ui/dr-ui/src/lib.rs:93`](../ui/dr-ui/src/lib.rs#L93) |
| FR-DSP-3 | [`core/dr-gpu/tests/frame_budget.rs:101`](../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/local_contrast.rs:329`](../core/dr-gpu/tests/local_contrast.rs#L329), [`core/dr-pipeline/src/ops/local_contrast.rs:447`](../core/dr-pipeline/src/ops/local_contrast.rs#L447) |
| FR-DSP-5 | [`core/dr-gpu/tests/frame_budget.rs:101`](../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/zoom_resolution.rs:135`](../core/dr-gpu/tests/zoom_resolution.rs#L135), [`core/dr-gpu/tests/zoom_resolution.rs:166`](../core/dr-gpu/tests/zoom_resolution.rs#L166), [`core/dr-gpu/tests/zoom_resolution.rs:1`](../core/dr-gpu/tests/zoom_resolution.rs#L1), [`core/dr-gpu/tests/zoom_resolution.rs:216`](../core/dr-gpu/tests/zoom_resolution.rs#L216) |
-| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:497`](../core/dr-pipeline/src/operation.rs#L497), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:3397`](../ui/dr-ui/src/develop.rs#L3397), [`ui/dr-ui/src/develop.rs:7899`](../ui/dr-ui/src/develop.rs#L7899), [`ui/dr-ui/src/lib.rs:1753`](../ui/dr-ui/src/lib.rs#L1753), [`ui/dr-ui/src/lib.rs:3409`](../ui/dr-ui/src/lib.rs#L3409) |
-| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:3446`](../ui/dr-ui/src/develop.rs#L3446), [`ui/dr-ui/src/develop.rs:7573`](../ui/dr-ui/src/develop.rs#L7573), [`ui/dr-ui/src/develop.rs:757`](../ui/dr-ui/src/develop.rs#L757), [`ui/dr-ui/src/develop.rs:7605`](../ui/dr-ui/src/develop.rs#L7605), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1871`](../ui/dr-ui/src/lib.rs#L1871), [`ui/dr-ui/src/lib.rs:386`](../ui/dr-ui/src/lib.rs#L386), [`ui/dr-ui/ui/app.slint:80`](../ui/dr-ui/ui/app.slint#L80), [`ui/dr-ui/ui/histogram.slint:168`](../ui/dr-ui/ui/histogram.slint#L168), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
-| FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop.rs:3343`](../ui/dr-ui/src/develop.rs#L3343), [`ui/dr-ui/src/develop.rs:3397`](../ui/dr-ui/src/develop.rs#L3397), [`ui/dr-ui/src/develop.rs:7899`](../ui/dr-ui/src/develop.rs#L7899), [`ui/dr-ui/src/develop.rs:7945`](../ui/dr-ui/src/develop.rs#L7945), [`ui/dr-ui/src/develop.rs:7964`](../ui/dr-ui/src/develop.rs#L7964), [`ui/dr-ui/src/develop.rs:864`](../ui/dr-ui/src/develop.rs#L864), [`ui/dr-ui/src/display_ui.rs:192`](../ui/dr-ui/src/display_ui.rs#L192), [`ui/dr-ui/src/display_ui.rs:1`](../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:325`](../ui/dr-ui/src/display_ui.rs#L325), [`ui/dr-ui/src/display_ui.rs:346`](../ui/dr-ui/src/display_ui.rs#L346), [`ui/dr-ui/src/display_ui.rs:379`](../ui/dr-ui/src/display_ui.rs#L379), [`ui/dr-ui/src/lib.rs:1695`](../ui/dr-ui/src/lib.rs#L1695), [`ui/dr-ui/src/lib.rs:1753`](../ui/dr-ui/src/lib.rs#L1753), [`ui/dr-ui/src/lib.rs:3322`](../ui/dr-ui/src/lib.rs#L3322), [`ui/dr-ui/src/lib.rs:3409`](../ui/dr-ui/src/lib.rs#L3409), [`ui/dr-ui/ui/app.slint:1901`](../ui/dr-ui/ui/app.slint#L1901), [`ui/dr-ui/ui/app.slint:53`](../ui/dr-ui/ui/app.slint#L53), [`ui/dr-ui/ui/settings.slint:132`](../ui/dr-ui/ui/settings.slint#L132), [`ui/dr-ui/ui/settings.slint:832`](../ui/dr-ui/ui/settings.slint#L832) |
+| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:497`](../core/dr-pipeline/src/operation.rs#L497), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:3397`](../ui/dr-ui/src/develop.rs#L3397), [`ui/dr-ui/src/develop.rs:7899`](../ui/dr-ui/src/develop.rs#L7899), [`ui/dr-ui/src/lib.rs:1795`](../ui/dr-ui/src/lib.rs#L1795), [`ui/dr-ui/src/lib.rs:3475`](../ui/dr-ui/src/lib.rs#L3475) |
+| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:3446`](../ui/dr-ui/src/develop.rs#L3446), [`ui/dr-ui/src/develop.rs:7573`](../ui/dr-ui/src/develop.rs#L7573), [`ui/dr-ui/src/develop.rs:757`](../ui/dr-ui/src/develop.rs#L757), [`ui/dr-ui/src/develop.rs:7605`](../ui/dr-ui/src/develop.rs#L7605), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1915`](../ui/dr-ui/src/lib.rs#L1915), [`ui/dr-ui/src/lib.rs:417`](../ui/dr-ui/src/lib.rs#L417), [`ui/dr-ui/ui/histogram.slint:184`](../ui/dr-ui/ui/histogram.slint#L184), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
+| FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop.rs:3343`](../ui/dr-ui/src/develop.rs#L3343), [`ui/dr-ui/src/develop.rs:3397`](../ui/dr-ui/src/develop.rs#L3397), [`ui/dr-ui/src/develop.rs:7899`](../ui/dr-ui/src/develop.rs#L7899), [`ui/dr-ui/src/develop.rs:7945`](../ui/dr-ui/src/develop.rs#L7945), [`ui/dr-ui/src/develop.rs:7964`](../ui/dr-ui/src/develop.rs#L7964), [`ui/dr-ui/src/develop.rs:864`](../ui/dr-ui/src/develop.rs#L864), [`ui/dr-ui/src/display_ui.rs:192`](../ui/dr-ui/src/display_ui.rs#L192), [`ui/dr-ui/src/display_ui.rs:1`](../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:325`](../ui/dr-ui/src/display_ui.rs#L325), [`ui/dr-ui/src/display_ui.rs:346`](../ui/dr-ui/src/display_ui.rs#L346), [`ui/dr-ui/src/display_ui.rs:379`](../ui/dr-ui/src/display_ui.rs#L379), [`ui/dr-ui/src/lib.rs:1737`](../ui/dr-ui/src/lib.rs#L1737), [`ui/dr-ui/src/lib.rs:1795`](../ui/dr-ui/src/lib.rs#L1795), [`ui/dr-ui/src/lib.rs:3382`](../ui/dr-ui/src/lib.rs#L3382), [`ui/dr-ui/src/lib.rs:3475`](../ui/dr-ui/src/lib.rs#L3475), [`ui/dr-ui/ui/app.slint:1760`](../ui/dr-ui/ui/app.slint#L1760), [`ui/dr-ui/ui/app.slint:60`](../ui/dr-ui/ui/app.slint#L60), [`ui/dr-ui/ui/settings.slint:132`](../ui/dr-ui/ui/settings.slint#L132), [`ui/dr-ui/ui/settings.slint:832`](../ui/dr-ui/ui/settings.slint#L832) |
| FR-EXP-1 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:153`](../core/dr-export/src/lib.rs#L153), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:53`](../core/dr-export/src/lib.rs#L53), [`core/dr-gpu/src/adjust.rs:2450`](../core/dr-gpu/src/adjust.rs#L2450), [`core/dr-pipeline/src/graph.rs:715`](../core/dr-pipeline/src/graph.rs#L715), [`core/dr-pipeline/src/graph.rs:776`](../core/dr-pipeline/src/graph.rs#L776), [`core/dr-pipeline/src/operation.rs:497`](../core/dr-pipeline/src/operation.rs#L497), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:761`](../core/dr-types/src/settings.rs#L761), [`ui/dr-ui/src/develop.rs:7964`](../ui/dr-ui/src/develop.rs#L7964), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
-| FR-EXP-3 | [`core/dr-export/src/lib.rs:182`](../core/dr-export/src/lib.rs#L182), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:136`](../core/dr-export/src/size.rs#L136), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../core/dr-export/src/size.rs#L25), [`core/dr-export/src/size.rs:84`](../core/dr-export/src/size.rs#L84), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:806`](../core/dr-types/src/settings.rs#L806), [`core/dr-types/src/settings.rs:814`](../core/dr-types/src/settings.rs#L814), [`core/dr-types/src/settings.rs:830`](../core/dr-types/src/settings.rs#L830), [`core/dr-types/src/settings.rs:899`](../core/dr-types/src/settings.rs#L899), [`core/dr-types/src/settings.rs:927`](../core/dr-types/src/settings.rs#L927), [`core/dr-types/src/settings.rs:938`](../core/dr-types/src/settings.rs#L938), [`core/dr-types/src/settings.rs:944`](../core/dr-types/src/settings.rs#L944), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:237`](../ui/dr-ui/src/settings_ui.rs#L237), [`ui/dr-ui/src/settings_ui.rs:250`](../ui/dr-ui/src/settings_ui.rs#L250), [`ui/dr-ui/src/settings_ui.rs:265`](../ui/dr-ui/src/settings_ui.rs#L265), [`ui/dr-ui/src/settings_ui.rs:615`](../ui/dr-ui/src/settings_ui.rs#L615), [`ui/dr-ui/ui/settings.slint:735`](../ui/dr-ui/ui/settings.slint#L735), [`ui/dr-ui/ui/settings.slint:745`](../ui/dr-ui/ui/settings.slint#L745) |
+| FR-EXP-3 | [`core/dr-export/src/lib.rs:182`](../core/dr-export/src/lib.rs#L182), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:136`](../core/dr-export/src/size.rs#L136), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../core/dr-export/src/size.rs#L25), [`core/dr-export/src/size.rs:84`](../core/dr-export/src/size.rs#L84), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:806`](../core/dr-types/src/settings.rs#L806), [`core/dr-types/src/settings.rs:814`](../core/dr-types/src/settings.rs#L814), [`core/dr-types/src/settings.rs:830`](../core/dr-types/src/settings.rs#L830), [`core/dr-types/src/settings.rs:899`](../core/dr-types/src/settings.rs#L899), [`core/dr-types/src/settings.rs:927`](../core/dr-types/src/settings.rs#L927), [`core/dr-types/src/settings.rs:938`](../core/dr-types/src/settings.rs#L938), [`core/dr-types/src/settings.rs:944`](../core/dr-types/src/settings.rs#L944), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:237`](../ui/dr-ui/src/settings_ui.rs#L237), [`ui/dr-ui/src/settings_ui.rs:250`](../ui/dr-ui/src/settings_ui.rs#L250), [`ui/dr-ui/src/settings_ui.rs:265`](../ui/dr-ui/src/settings_ui.rs#L265), [`ui/dr-ui/src/settings_ui.rs:616`](../ui/dr-ui/src/settings_ui.rs#L616), [`ui/dr-ui/ui/settings.slint:735`](../ui/dr-ui/ui/settings.slint#L735), [`ui/dr-ui/ui/settings.slint:745`](../ui/dr-ui/ui/settings.slint#L745) |
| FR-EXP-4 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/sharpen.rs:1`](../core/dr-export/src/sharpen.rs#L1), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
| FR-EXP-5 | [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) |
-| FR-EXP-6 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/name.rs:1`](../core/dr-export/src/name.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:559`](../ui/dr-ui/src/lib.rs#L559), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:49`](../ui/dr-ui/src/settings_ui.rs#L49), [`ui/dr-ui/src/settings_ui.rs:729`](../ui/dr-ui/src/settings_ui.rs#L729) |
-| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/export.rs:992`](../ui/dr-ui/src/export.rs#L992), [`ui/dr-ui/src/lib.rs:232`](../ui/dr-ui/src/lib.rs#L232), [`ui/dr-ui/src/lib.rs:2560`](../ui/dr-ui/src/lib.rs#L2560), [`ui/dr-ui/src/lib.rs:559`](../ui/dr-ui/src/lib.rs#L559), [`ui/dr-ui/src/lib.rs:605`](../ui/dr-ui/src/lib.rs#L605), [`ui/dr-ui/src/lib.rs:632`](../ui/dr-ui/src/lib.rs#L632), [`ui/dr-ui/src/library_ui.rs:3983`](../ui/dr-ui/src/library_ui.rs#L3983), [`ui/dr-ui/src/library_ui.rs:645`](../ui/dr-ui/src/library_ui.rs#L645), [`ui/dr-ui/src/library_ui.rs:745`](../ui/dr-ui/src/library_ui.rs#L745), [`ui/dr-ui/src/library_ui.rs:7709`](../ui/dr-ui/src/library_ui.rs#L7709), [`ui/dr-ui/src/library_ui.rs:7786`](../ui/dr-ui/src/library_ui.rs#L7786), [`ui/dr-ui/src/library_ui.rs:7798`](../ui/dr-ui/src/library_ui.rs#L7798), [`ui/dr-ui/src/library_ui.rs:802`](../ui/dr-ui/src/library_ui.rs#L802), [`ui/dr-ui/ui/app.slint:1209`](../ui/dr-ui/ui/app.slint#L1209), [`ui/dr-ui/ui/app.slint:1699`](../ui/dr-ui/ui/app.slint#L1699), [`ui/dr-ui/ui/library.slint:1583`](../ui/dr-ui/ui/library.slint#L1583), [`ui/dr-ui/ui/library.slint:4251`](../ui/dr-ui/ui/library.slint#L4251) |
-| FR-EXP-8 | [`core/dr-decode/src/lib.rs:326`](../core/dr-decode/src/lib.rs#L326), [`core/dr-decode/src/lib.rs:350`](../core/dr-decode/src/lib.rs#L350), [`core/dr-decode/src/lib.rs:364`](../core/dr-decode/src/lib.rs#L364), [`core/dr-decode/src/lib.rs:71`](../core/dr-decode/src/lib.rs#L71), [`core/dr-decode/src/lib.rs:79`](../core/dr-decode/src/lib.rs#L79), [`core/dr-decode/src/lib.rs:82`](../core/dr-decode/src/lib.rs#L82), [`core/dr-decode/src/locate.rs:1164`](../core/dr-decode/src/locate.rs#L1164), [`core/dr-decode/src/locate.rs:1223`](../core/dr-decode/src/locate.rs#L1223), [`core/dr-decode/src/locate.rs:316`](../core/dr-decode/src/locate.rs#L316), [`core/dr-decode/src/locate.rs:487`](../core/dr-decode/src/locate.rs#L487), [`core/dr-decode/src/locate.rs:571`](../core/dr-decode/src/locate.rs#L571), [`core/dr-decode/src/locate.rs:584`](../core/dr-decode/src/locate.rs#L584), [`core/dr-decode/src/locate.rs:667`](../core/dr-decode/src/locate.rs#L667), [`core/dr-export/examples/export.rs:99`](../core/dr-export/examples/export.rs#L99), [`core/dr-export/src/encode.rs:117`](../core/dr-export/src/encode.rs#L117), [`core/dr-export/src/encode.rs:161`](../core/dr-export/src/encode.rs#L161), [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/encode.rs:206`](../core/dr-export/src/encode.rs#L206), [`core/dr-export/src/encode.rs:235`](../core/dr-export/src/encode.rs#L235), [`core/dr-export/src/encode.rs:311`](../core/dr-export/src/encode.rs#L311), [`core/dr-export/src/encode.rs:325`](../core/dr-export/src/encode.rs#L325), [`core/dr-export/src/encode.rs:408`](../core/dr-export/src/encode.rs#L408), [`core/dr-export/src/encode.rs:456`](../core/dr-export/src/encode.rs#L456), [`core/dr-export/src/encode.rs:70`](../core/dr-export/src/encode.rs#L70), [`core/dr-export/src/encode.rs:795`](../core/dr-export/src/encode.rs#L795), [`core/dr-export/src/encode.rs:809`](../core/dr-export/src/encode.rs#L809), [`core/dr-export/src/encode.rs:850`](../core/dr-export/src/encode.rs#L850), [`core/dr-export/src/encode.rs:898`](../core/dr-export/src/encode.rs#L898), [`core/dr-export/src/exif.rs:1`](../core/dr-export/src/exif.rs#L1), [`core/dr-export/src/lib.rs:136`](../core/dr-export/src/lib.rs#L136), [`core/dr-export/src/metadata.rs:1`](../core/dr-export/src/metadata.rs#L1), [`core/dr-export/src/metadata.rs:41`](../core/dr-export/src/metadata.rs#L41), [`core/dr-export/src/metadata.rs:74`](../core/dr-export/src/metadata.rs#L74), [`core/dr-types/src/lib.rs:655`](../core/dr-types/src/lib.rs#L655), [`core/dr-types/src/settings.rs:474`](../core/dr-types/src/settings.rs#L474), [`ui/dr-ui/src/develop.rs:3880`](../ui/dr-ui/src/develop.rs#L3880), [`ui/dr-ui/src/develop.rs:3988`](../ui/dr-ui/src/develop.rs#L3988), [`ui/dr-ui/src/develop.rs:703`](../ui/dr-ui/src/develop.rs#L703), [`ui/dr-ui/src/export.rs:467`](../ui/dr-ui/src/export.rs#L467), [`ui/dr-ui/src/export.rs:634`](../ui/dr-ui/src/export.rs#L634), [`ui/dr-ui/src/export.rs:680`](../ui/dr-ui/src/export.rs#L680), [`ui/dr-ui/src/export.rs:702`](../ui/dr-ui/src/export.rs#L702), [`ui/dr-ui/src/export.rs:826`](../ui/dr-ui/src/export.rs#L826), [`ui/dr-ui/src/export.rs:844`](../ui/dr-ui/src/export.rs#L844), [`ui/dr-ui/src/lib.rs:232`](../ui/dr-ui/src/lib.rs#L232), [`ui/dr-ui/src/lib.rs:255`](../ui/dr-ui/src/lib.rs#L255), [`ui/dr-ui/src/lib.rs:591`](../ui/dr-ui/src/lib.rs#L591), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
-| FR-EXP-9 | [`core/dr-decode/src/lib.rs:506`](../core/dr-decode/src/lib.rs#L506), [`core/dr-export/src/lib.rs:128`](../core/dr-export/src/lib.rs#L128), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1106`](../core/dr-gpu/src/adjust.rs#L1106), [`ui/dr-ui/examples/face_native.rs:1`](../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/develop.rs:4009`](../ui/dr-ui/src/develop.rs#L4009), [`ui/dr-ui/src/develop.rs:4047`](../ui/dr-ui/src/develop.rs#L4047), [`ui/dr-ui/src/develop.rs:5921`](../ui/dr-ui/src/develop.rs#L5921), [`ui/dr-ui/src/lib.rs:559`](../ui/dr-ui/src/lib.rs#L559), [`ui/dr-ui/src/library.rs:3385`](../ui/dr-ui/src/library.rs#L3385), [`ui/dr-ui/src/library.rs:3742`](../ui/dr-ui/src/library.rs#L3742), [`ui/dr-ui/src/library.rs:3778`](../ui/dr-ui/src/library.rs#L3778), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) |
+| FR-EXP-6 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/name.rs:1`](../core/dr-export/src/name.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:594`](../ui/dr-ui/src/lib.rs#L594), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:49`](../ui/dr-ui/src/settings_ui.rs#L49), [`ui/dr-ui/src/settings_ui.rs:730`](../ui/dr-ui/src/settings_ui.rs#L730) |
+| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/export.rs:992`](../ui/dr-ui/src/export.rs#L992), [`ui/dr-ui/src/lib.rs:2610`](../ui/dr-ui/src/lib.rs#L2610), [`ui/dr-ui/src/lib.rs:261`](../ui/dr-ui/src/lib.rs#L261), [`ui/dr-ui/src/lib.rs:594`](../ui/dr-ui/src/lib.rs#L594), [`ui/dr-ui/src/lib.rs:640`](../ui/dr-ui/src/lib.rs#L640), [`ui/dr-ui/src/lib.rs:667`](../ui/dr-ui/src/lib.rs#L667), [`ui/dr-ui/src/library_ui.rs:3983`](../ui/dr-ui/src/library_ui.rs#L3983), [`ui/dr-ui/src/library_ui.rs:645`](../ui/dr-ui/src/library_ui.rs#L645), [`ui/dr-ui/src/library_ui.rs:745`](../ui/dr-ui/src/library_ui.rs#L745), [`ui/dr-ui/src/library_ui.rs:7709`](../ui/dr-ui/src/library_ui.rs#L7709), [`ui/dr-ui/src/library_ui.rs:7786`](../ui/dr-ui/src/library_ui.rs#L7786), [`ui/dr-ui/src/library_ui.rs:7798`](../ui/dr-ui/src/library_ui.rs#L7798), [`ui/dr-ui/src/library_ui.rs:802`](../ui/dr-ui/src/library_ui.rs#L802), [`ui/dr-ui/ui/app.slint:1500`](../ui/dr-ui/ui/app.slint#L1500), [`ui/dr-ui/ui/app.slint:995`](../ui/dr-ui/ui/app.slint#L995), [`ui/dr-ui/ui/library.slint:1583`](../ui/dr-ui/ui/library.slint#L1583), [`ui/dr-ui/ui/library.slint:4251`](../ui/dr-ui/ui/library.slint#L4251) |
+| FR-EXP-8 | [`core/dr-decode/src/lib.rs:326`](../core/dr-decode/src/lib.rs#L326), [`core/dr-decode/src/lib.rs:350`](../core/dr-decode/src/lib.rs#L350), [`core/dr-decode/src/lib.rs:364`](../core/dr-decode/src/lib.rs#L364), [`core/dr-decode/src/lib.rs:71`](../core/dr-decode/src/lib.rs#L71), [`core/dr-decode/src/lib.rs:79`](../core/dr-decode/src/lib.rs#L79), [`core/dr-decode/src/lib.rs:82`](../core/dr-decode/src/lib.rs#L82), [`core/dr-decode/src/locate.rs:1164`](../core/dr-decode/src/locate.rs#L1164), [`core/dr-decode/src/locate.rs:1223`](../core/dr-decode/src/locate.rs#L1223), [`core/dr-decode/src/locate.rs:316`](../core/dr-decode/src/locate.rs#L316), [`core/dr-decode/src/locate.rs:487`](../core/dr-decode/src/locate.rs#L487), [`core/dr-decode/src/locate.rs:571`](../core/dr-decode/src/locate.rs#L571), [`core/dr-decode/src/locate.rs:584`](../core/dr-decode/src/locate.rs#L584), [`core/dr-decode/src/locate.rs:667`](../core/dr-decode/src/locate.rs#L667), [`core/dr-export/examples/export.rs:99`](../core/dr-export/examples/export.rs#L99), [`core/dr-export/src/encode.rs:117`](../core/dr-export/src/encode.rs#L117), [`core/dr-export/src/encode.rs:161`](../core/dr-export/src/encode.rs#L161), [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/encode.rs:206`](../core/dr-export/src/encode.rs#L206), [`core/dr-export/src/encode.rs:235`](../core/dr-export/src/encode.rs#L235), [`core/dr-export/src/encode.rs:311`](../core/dr-export/src/encode.rs#L311), [`core/dr-export/src/encode.rs:325`](../core/dr-export/src/encode.rs#L325), [`core/dr-export/src/encode.rs:408`](../core/dr-export/src/encode.rs#L408), [`core/dr-export/src/encode.rs:456`](../core/dr-export/src/encode.rs#L456), [`core/dr-export/src/encode.rs:70`](../core/dr-export/src/encode.rs#L70), [`core/dr-export/src/encode.rs:795`](../core/dr-export/src/encode.rs#L795), [`core/dr-export/src/encode.rs:809`](../core/dr-export/src/encode.rs#L809), [`core/dr-export/src/encode.rs:850`](../core/dr-export/src/encode.rs#L850), [`core/dr-export/src/encode.rs:898`](../core/dr-export/src/encode.rs#L898), [`core/dr-export/src/exif.rs:1`](../core/dr-export/src/exif.rs#L1), [`core/dr-export/src/lib.rs:136`](../core/dr-export/src/lib.rs#L136), [`core/dr-export/src/metadata.rs:1`](../core/dr-export/src/metadata.rs#L1), [`core/dr-export/src/metadata.rs:41`](../core/dr-export/src/metadata.rs#L41), [`core/dr-export/src/metadata.rs:74`](../core/dr-export/src/metadata.rs#L74), [`core/dr-types/src/lib.rs:655`](../core/dr-types/src/lib.rs#L655), [`core/dr-types/src/settings.rs:474`](../core/dr-types/src/settings.rs#L474), [`ui/dr-ui/src/develop.rs:3880`](../ui/dr-ui/src/develop.rs#L3880), [`ui/dr-ui/src/develop.rs:3988`](../ui/dr-ui/src/develop.rs#L3988), [`ui/dr-ui/src/develop.rs:703`](../ui/dr-ui/src/develop.rs#L703), [`ui/dr-ui/src/export.rs:467`](../ui/dr-ui/src/export.rs#L467), [`ui/dr-ui/src/export.rs:634`](../ui/dr-ui/src/export.rs#L634), [`ui/dr-ui/src/export.rs:680`](../ui/dr-ui/src/export.rs#L680), [`ui/dr-ui/src/export.rs:702`](../ui/dr-ui/src/export.rs#L702), [`ui/dr-ui/src/export.rs:826`](../ui/dr-ui/src/export.rs#L826), [`ui/dr-ui/src/export.rs:844`](../ui/dr-ui/src/export.rs#L844), [`ui/dr-ui/src/lib.rs:261`](../ui/dr-ui/src/lib.rs#L261), [`ui/dr-ui/src/lib.rs:284`](../ui/dr-ui/src/lib.rs#L284), [`ui/dr-ui/src/lib.rs:626`](../ui/dr-ui/src/lib.rs#L626), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
+| FR-EXP-9 | [`core/dr-decode/src/lib.rs:506`](../core/dr-decode/src/lib.rs#L506), [`core/dr-export/src/lib.rs:128`](../core/dr-export/src/lib.rs#L128), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1106`](../core/dr-gpu/src/adjust.rs#L1106), [`ui/dr-ui/examples/face_native.rs:1`](../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/develop.rs:4009`](../ui/dr-ui/src/develop.rs#L4009), [`ui/dr-ui/src/develop.rs:4047`](../ui/dr-ui/src/develop.rs#L4047), [`ui/dr-ui/src/develop.rs:5921`](../ui/dr-ui/src/develop.rs#L5921), [`ui/dr-ui/src/lib.rs:594`](../ui/dr-ui/src/lib.rs#L594), [`ui/dr-ui/src/library.rs:3385`](../ui/dr-ui/src/library.rs#L3385), [`ui/dr-ui/src/library.rs:3742`](../ui/dr-ui/src/library.rs#L3742), [`ui/dr-ui/src/library.rs:3778`](../ui/dr-ui/src/library.rs#L3778), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) |
| FR-NC-1 | [`core/dr-sync-nextcloud/src/auth.rs:132`](../core/dr-sync-nextcloud/src/auth.rs#L132), [`core/dr-sync-nextcloud/src/auth.rs:44`](../core/dr-sync-nextcloud/src/auth.rs#L44), [`core/dr-sync-nextcloud/src/provider.rs:1`](../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:355`](../core/dr-sync/src/account.rs#L355), [`ui/dr-ui/src/launch.rs:277`](../ui/dr-ui/src/launch.rs#L277), [`ui/dr-ui/src/launch.rs:61`](../ui/dr-ui/src/launch.rs#L61), [`ui/dr-ui/src/launch_ui.rs:417`](../ui/dr-ui/src/launch_ui.rs#L417) |
-| FR-NC-10 | [`core/dr-sync/src/account.rs:220`](../core/dr-sync/src/account.rs#L220), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:632`](../ui/dr-ui/src/lib.rs#L632), [`ui/dr-ui/src/library.rs:1155`](../ui/dr-ui/src/library.rs#L1155), [`ui/dr-ui/src/library.rs:2255`](../ui/dr-ui/src/library.rs#L2255), [`ui/dr-ui/src/library.rs:584`](../ui/dr-ui/src/library.rs#L584), [`ui/dr-ui/src/library.rs:899`](../ui/dr-ui/src/library.rs#L899), [`ui/dr-ui/src/library_ui.rs:1983`](../ui/dr-ui/src/library_ui.rs#L1983), [`ui/dr-ui/src/library_ui.rs:3983`](../ui/dr-ui/src/library_ui.rs#L3983), [`ui/dr-ui/src/library_ui.rs:586`](../ui/dr-ui/src/library_ui.rs#L586), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
+| FR-NC-10 | [`core/dr-sync/src/account.rs:220`](../core/dr-sync/src/account.rs#L220), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:667`](../ui/dr-ui/src/lib.rs#L667), [`ui/dr-ui/src/library.rs:1155`](../ui/dr-ui/src/library.rs#L1155), [`ui/dr-ui/src/library.rs:2255`](../ui/dr-ui/src/library.rs#L2255), [`ui/dr-ui/src/library.rs:584`](../ui/dr-ui/src/library.rs#L584), [`ui/dr-ui/src/library.rs:899`](../ui/dr-ui/src/library.rs#L899), [`ui/dr-ui/src/library_ui.rs:1983`](../ui/dr-ui/src/library_ui.rs#L1983), [`ui/dr-ui/src/library_ui.rs:3983`](../ui/dr-ui/src/library_ui.rs#L3983), [`ui/dr-ui/src/library_ui.rs:586`](../ui/dr-ui/src/library_ui.rs#L586), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
| FR-NC-12 | [`core/dr-sync-folder/src/lib.rs:1`](../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:40`](../core/dr-sync-nextcloud/src/lib.rs#L40), [`core/dr-sync-nextcloud/src/lib.rs:914`](../core/dr-sync-nextcloud/src/lib.rs#L914), [`core/dr-sync-nextcloud/src/provider.rs:1`](../core/dr-sync-nextcloud/src/provider.rs#L1), [`core/dr-sync/src/account.rs:1`](../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:81`](../core/dr-sync/src/account.rs#L81), [`core/dr-sync/src/lib.rs:218`](../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/lib.rs:51`](../core/dr-sync/src/lib.rs#L51), [`core/dr-sync/src/provider.rs:106`](../core/dr-sync/src/provider.rs#L106), [`core/dr-sync/src/provider.rs:1`](../core/dr-sync/src/provider.rs#L1), [`core/dr-sync/src/provider.rs:53`](../core/dr-sync/src/provider.rs#L53), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1), [`ui/dr-ui/src/remote.rs:1`](../ui/dr-ui/src/remote.rs#L1) |
| FR-NC-13 | [`core/dr-sync-folder/src/lib.rs:197`](../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:1`](../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/lib.rs:73`](../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync/src/provider.rs:106`](../core/dr-sync/src/provider.rs#L106), [`ui/dr-ui/src/launch_ui.rs:316`](../ui/dr-ui/src/launch_ui.rs#L316), [`ui/dr-ui/src/remote.rs:1`](../ui/dr-ui/src/remote.rs#L1) |
| FR-NC-2 | [`core/dr-sync/src/account.rs:1`](../core/dr-sync/src/account.rs#L1), [`core/dr-sync/src/account.rs:298`](../core/dr-sync/src/account.rs#L298), [`core/dr-sync/src/account.rs:355`](../core/dr-sync/src/account.rs#L355), [`core/dr-sync/src/account.rs:59`](../core/dr-sync/src/account.rs#L59), [`platform/dr-plat/src/secrets.rs:82`](../platform/dr-plat/src/secrets.rs#L82) |
-| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../core/dr-decode/src/preview.rs#L148), [`core/dr-sync/src/capability.rs:85`](../core/dr-sync/src/capability.rs#L85), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library.rs:3292`](../ui/dr-ui/src/library.rs#L3292), [`ui/dr-ui/src/library.rs:3883`](../ui/dr-ui/src/library.rs#L3883), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1), [`ui/dr-ui/src/library_ui.rs:4236`](../ui/dr-ui/src/library_ui.rs#L4236), [`ui/dr-ui/src/library_ui.rs:5735`](../ui/dr-ui/src/library_ui.rs#L5735), [`ui/dr-ui/ui/app.slint:490`](../ui/dr-ui/ui/app.slint#L490), [`ui/dr-ui/ui/settings.slint:395`](../ui/dr-ui/ui/settings.slint#L395), [`ui/dr-ui/ui/settings.slint:73`](../ui/dr-ui/ui/settings.slint#L73) |
+| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:148`](../core/dr-decode/src/preview.rs#L148), [`core/dr-sync/src/capability.rs:85`](../core/dr-sync/src/capability.rs#L85), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library.rs:3292`](../ui/dr-ui/src/library.rs#L3292), [`ui/dr-ui/src/library.rs:3883`](../ui/dr-ui/src/library.rs#L3883), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1), [`ui/dr-ui/src/library_ui.rs:4236`](../ui/dr-ui/src/library_ui.rs#L4236), [`ui/dr-ui/src/library_ui.rs:5735`](../ui/dr-ui/src/library_ui.rs#L5735), [`ui/dr-ui/ui/app.slint:374`](../ui/dr-ui/ui/app.slint#L374), [`ui/dr-ui/ui/settings.slint:395`](../ui/dr-ui/ui/settings.slint#L395), [`ui/dr-ui/ui/settings.slint:73`](../ui/dr-ui/ui/settings.slint#L73) |
| FR-NC-4 | [`core/dr-sync-folder/src/lib.rs:197`](../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-nextcloud/src/propfind.rs:103`](../core/dr-sync-nextcloud/src/propfind.rs#L103), [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51), [`core/dr-sync/src/capability.rs:6`](../core/dr-sync/src/capability.rs#L6), [`core/dr-sync/src/lib.rs:218`](../core/dr-sync/src/lib.rs#L218), [`core/dr-sync/src/scan.rs:118`](../core/dr-sync/src/scan.rs#L118), [`ui/dr-ui/src/launch.rs:61`](../ui/dr-ui/src/launch.rs#L61) |
| FR-NC-5 | [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51), [`ui/dr-ui/src/import.rs:488`](../ui/dr-ui/src/import.rs#L488) |
| FR-NC-6 | [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1) |
-| FR-NC-6a | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/cache.rs:225`](../core/dr-catalog/src/cache.rs#L225), [`core/dr-catalog/src/schema.rs:1186`](../core/dr-catalog/src/schema.rs#L1186), [`core/dr-catalog/src/schema.rs:785`](../core/dr-catalog/src/schema.rs#L785), [`core/dr-sync-folder/src/borrow.rs:1`](../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/collections_ui.rs:3413`](../ui/dr-ui/src/collections_ui.rs#L3413), [`ui/dr-ui/src/collections_ui.rs:636`](../ui/dr-ui/src/collections_ui.rs#L636), [`ui/dr-ui/src/collections_ui.rs:704`](../ui/dr-ui/src/collections_ui.rs#L704), [`ui/dr-ui/src/lib.rs:2246`](../ui/dr-ui/src/lib.rs#L2246), [`ui/dr-ui/src/lib.rs:3493`](../ui/dr-ui/src/lib.rs#L3493), [`ui/dr-ui/src/library.rs:1881`](../ui/dr-ui/src/library.rs#L1881), [`ui/dr-ui/src/library.rs:1904`](../ui/dr-ui/src/library.rs#L1904), [`ui/dr-ui/src/library.rs:2179`](../ui/dr-ui/src/library.rs#L2179), [`ui/dr-ui/src/library_ui.rs:1408`](../ui/dr-ui/src/library_ui.rs#L1408), [`ui/dr-ui/src/library_ui.rs:1481`](../ui/dr-ui/src/library_ui.rs#L1481), [`ui/dr-ui/src/library_ui.rs:1582`](../ui/dr-ui/src/library_ui.rs#L1582), [`ui/dr-ui/src/library_ui.rs:1637`](../ui/dr-ui/src/library_ui.rs#L1637), [`ui/dr-ui/src/library_ui.rs:1772`](../ui/dr-ui/src/library_ui.rs#L1772), [`ui/dr-ui/src/library_ui.rs:1890`](../ui/dr-ui/src/library_ui.rs#L1890), [`ui/dr-ui/src/library_ui.rs:2657`](../ui/dr-ui/src/library_ui.rs#L2657), [`ui/dr-ui/src/library_ui.rs:341`](../ui/dr-ui/src/library_ui.rs#L341), [`ui/dr-ui/src/library_ui.rs:352`](../ui/dr-ui/src/library_ui.rs#L352), [`ui/dr-ui/src/library_ui.rs:360`](../ui/dr-ui/src/library_ui.rs#L360), [`ui/dr-ui/src/library_ui.rs:372`](../ui/dr-ui/src/library_ui.rs#L372), [`ui/dr-ui/src/library_ui.rs:381`](../ui/dr-ui/src/library_ui.rs#L381), [`ui/dr-ui/src/library_ui.rs:482`](../ui/dr-ui/src/library_ui.rs#L482), [`ui/dr-ui/src/library_ui.rs:492`](../ui/dr-ui/src/library_ui.rs#L492), [`ui/dr-ui/src/library_ui.rs:539`](../ui/dr-ui/src/library_ui.rs#L539), [`ui/dr-ui/src/library_ui.rs:602`](../ui/dr-ui/src/library_ui.rs#L602), [`ui/dr-ui/src/library_ui.rs:633`](../ui/dr-ui/src/library_ui.rs#L633), [`ui/dr-ui/src/library_ui.rs:645`](../ui/dr-ui/src/library_ui.rs#L645), [`ui/dr-ui/src/library_ui.rs:6572`](../ui/dr-ui/src/library_ui.rs#L6572), [`ui/dr-ui/src/library_ui.rs:6590`](../ui/dr-ui/src/library_ui.rs#L6590), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1597`](../ui/dr-ui/ui/app.slint#L1597), [`ui/dr-ui/ui/app.slint:3147`](../ui/dr-ui/ui/app.slint#L3147), [`ui/dr-ui/ui/app.slint:622`](../ui/dr-ui/ui/app.slint#L622), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:360`](../ui/dr-ui/ui/collections.slint#L360), [`ui/dr-ui/ui/collections.slint:369`](../ui/dr-ui/ui/collections.slint#L369), [`ui/dr-ui/ui/collections.slint:372`](../ui/dr-ui/ui/collections.slint#L372), [`ui/dr-ui/ui/collections.slint:395`](../ui/dr-ui/ui/collections.slint#L395), [`ui/dr-ui/ui/collections.slint:52`](../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:596`](../ui/dr-ui/ui/collections.slint#L596), [`ui/dr-ui/ui/collections.slint:747`](../ui/dr-ui/ui/collections.slint#L747), [`ui/dr-ui/ui/collections.slint:84`](../ui/dr-ui/ui/collections.slint#L84), [`ui/dr-ui/ui/icons.slint:261`](../ui/dr-ui/ui/icons.slint#L261) |
+| FR-NC-6a | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/cache.rs:225`](../core/dr-catalog/src/cache.rs#L225), [`core/dr-catalog/src/schema.rs:1186`](../core/dr-catalog/src/schema.rs#L1186), [`core/dr-catalog/src/schema.rs:785`](../core/dr-catalog/src/schema.rs#L785), [`core/dr-sync-folder/src/borrow.rs:1`](../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/collections_ui.rs:3413`](../ui/dr-ui/src/collections_ui.rs#L3413), [`ui/dr-ui/src/collections_ui.rs:636`](../ui/dr-ui/src/collections_ui.rs#L636), [`ui/dr-ui/src/collections_ui.rs:704`](../ui/dr-ui/src/collections_ui.rs#L704), [`ui/dr-ui/src/lib.rs:2293`](../ui/dr-ui/src/lib.rs#L2293), [`ui/dr-ui/src/lib.rs:3572`](../ui/dr-ui/src/lib.rs#L3572), [`ui/dr-ui/src/library.rs:1881`](../ui/dr-ui/src/library.rs#L1881), [`ui/dr-ui/src/library.rs:1904`](../ui/dr-ui/src/library.rs#L1904), [`ui/dr-ui/src/library.rs:2179`](../ui/dr-ui/src/library.rs#L2179), [`ui/dr-ui/src/library_ui.rs:1408`](../ui/dr-ui/src/library_ui.rs#L1408), [`ui/dr-ui/src/library_ui.rs:1481`](../ui/dr-ui/src/library_ui.rs#L1481), [`ui/dr-ui/src/library_ui.rs:1582`](../ui/dr-ui/src/library_ui.rs#L1582), [`ui/dr-ui/src/library_ui.rs:1637`](../ui/dr-ui/src/library_ui.rs#L1637), [`ui/dr-ui/src/library_ui.rs:1772`](../ui/dr-ui/src/library_ui.rs#L1772), [`ui/dr-ui/src/library_ui.rs:1890`](../ui/dr-ui/src/library_ui.rs#L1890), [`ui/dr-ui/src/library_ui.rs:2657`](../ui/dr-ui/src/library_ui.rs#L2657), [`ui/dr-ui/src/library_ui.rs:341`](../ui/dr-ui/src/library_ui.rs#L341), [`ui/dr-ui/src/library_ui.rs:352`](../ui/dr-ui/src/library_ui.rs#L352), [`ui/dr-ui/src/library_ui.rs:360`](../ui/dr-ui/src/library_ui.rs#L360), [`ui/dr-ui/src/library_ui.rs:372`](../ui/dr-ui/src/library_ui.rs#L372), [`ui/dr-ui/src/library_ui.rs:381`](../ui/dr-ui/src/library_ui.rs#L381), [`ui/dr-ui/src/library_ui.rs:482`](../ui/dr-ui/src/library_ui.rs#L482), [`ui/dr-ui/src/library_ui.rs:492`](../ui/dr-ui/src/library_ui.rs#L492), [`ui/dr-ui/src/library_ui.rs:539`](../ui/dr-ui/src/library_ui.rs#L539), [`ui/dr-ui/src/library_ui.rs:602`](../ui/dr-ui/src/library_ui.rs#L602), [`ui/dr-ui/src/library_ui.rs:633`](../ui/dr-ui/src/library_ui.rs#L633), [`ui/dr-ui/src/library_ui.rs:645`](../ui/dr-ui/src/library_ui.rs#L645), [`ui/dr-ui/src/library_ui.rs:6572`](../ui/dr-ui/src/library_ui.rs#L6572), [`ui/dr-ui/src/library_ui.rs:6590`](../ui/dr-ui/src/library_ui.rs#L6590), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1398`](../ui/dr-ui/ui/app.slint#L1398), [`ui/dr-ui/ui/app.slint:2841`](../ui/dr-ui/ui/app.slint#L2841), [`ui/dr-ui/ui/app.slint:506`](../ui/dr-ui/ui/app.slint#L506), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:360`](../ui/dr-ui/ui/collections.slint#L360), [`ui/dr-ui/ui/collections.slint:369`](../ui/dr-ui/ui/collections.slint#L369), [`ui/dr-ui/ui/collections.slint:372`](../ui/dr-ui/ui/collections.slint#L372), [`ui/dr-ui/ui/collections.slint:395`](../ui/dr-ui/ui/collections.slint#L395), [`ui/dr-ui/ui/collections.slint:52`](../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:596`](../ui/dr-ui/ui/collections.slint#L596), [`ui/dr-ui/ui/collections.slint:747`](../ui/dr-ui/ui/collections.slint#L747), [`ui/dr-ui/ui/collections.slint:84`](../ui/dr-ui/ui/collections.slint#L84), [`ui/dr-ui/ui/icons.slint:261`](../ui/dr-ui/ui/icons.slint#L261) |
| FR-NC-6b | [`ui/dr-ui/src/library_ui.rs:1637`](../ui/dr-ui/src/library_ui.rs#L1637), [`ui/dr-ui/src/memory.rs:1`](../ui/dr-ui/src/memory.rs#L1) |
| FR-NC-6c | [`core/dr-catalog/src/cache.rs:225`](../core/dr-catalog/src/cache.rs#L225), [`core/dr-sync-folder/src/borrow.rs:1`](../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-sync-folder/src/lib.rs:197`](../core/dr-sync-folder/src/lib.rs#L197), [`core/dr-sync-folder/src/lib.rs:73`](../core/dr-sync-folder/src/lib.rs#L73), [`core/dr-sync-folder/src/lib.rs:818`](../core/dr-sync-folder/src/lib.rs#L818), [`core/dr-sync-folder/src/lib.rs:857`](../core/dr-sync-folder/src/lib.rs#L857), [`core/dr-sync-folder/src/vfs.rs:1`](../core/dr-sync-folder/src/vfs.rs#L1), [`core/dr-sync-nextcloud/src/desktop_client.rs:167`](../core/dr-sync-nextcloud/src/desktop_client.rs#L167), [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-sync/src/capability.rs:41`](../core/dr-sync/src/capability.rs#L41), [`core/dr-sync/src/error.rs:39`](../core/dr-sync/src/error.rs#L39), [`core/dr-sync/src/lib.rs:158`](../core/dr-sync/src/lib.rs#L158), [`core/dr-sync/src/types.rs:101`](../core/dr-sync/src/types.rs#L101), [`core/dr-types/src/lib.rs:122`](../core/dr-types/src/lib.rs#L122), [`core/dr-types/src/lib.rs:204`](../core/dr-types/src/lib.rs#L204), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/collections_ui.rs:3413`](../ui/dr-ui/src/collections_ui.rs#L3413), [`ui/dr-ui/src/collections_ui.rs:636`](../ui/dr-ui/src/collections_ui.rs#L636), [`ui/dr-ui/src/collections_ui.rs:704`](../ui/dr-ui/src/collections_ui.rs#L704), [`ui/dr-ui/src/derived_sync.rs:585`](../ui/dr-ui/src/derived_sync.rs#L585), [`ui/dr-ui/src/derived_sync.rs:805`](../ui/dr-ui/src/derived_sync.rs#L805), [`ui/dr-ui/src/library.rs:1003`](../ui/dr-ui/src/library.rs#L1003), [`ui/dr-ui/src/library.rs:2001`](../ui/dr-ui/src/library.rs#L2001), [`ui/dr-ui/src/library.rs:2091`](../ui/dr-ui/src/library.rs#L2091), [`ui/dr-ui/src/library.rs:3569`](../ui/dr-ui/src/library.rs#L3569), [`ui/dr-ui/src/library.rs:4003`](../ui/dr-ui/src/library.rs#L4003), [`ui/dr-ui/src/library_ui.rs:1408`](../ui/dr-ui/src/library_ui.rs#L1408), [`ui/dr-ui/src/library_ui.rs:1481`](../ui/dr-ui/src/library_ui.rs#L1481), [`ui/dr-ui/src/library_ui.rs:1680`](../ui/dr-ui/src/library_ui.rs#L1680), [`ui/dr-ui/src/remote.rs:40`](../ui/dr-ui/src/remote.rs#L40), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:747`](../ui/dr-ui/ui/collections.slint#L747), [`ui/dr-ui/ui/icons.slint:261`](../ui/dr-ui/ui/icons.slint#L261) |
| FR-NC-6d | [`core/dr-sync-folder/src/borrow.rs:1`](../core/dr-sync-folder/src/borrow.rs#L1), [`core/dr-sync-folder/src/lib.rs:1`](../core/dr-sync-folder/src/lib.rs#L1), [`core/dr-sync-folder/src/vfs.rs:1`](../core/dr-sync-folder/src/vfs.rs#L1) |
| FR-NC-7 | [`core/dr-catalog/src/face_shard.rs:1`](../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:105`](../core/dr-sync-nextcloud/src/lib.rs#L105), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library.rs:3883`](../ui/dr-ui/src/library.rs#L3883), [`ui/dr-ui/src/library_ui.rs:4236`](../ui/dr-ui/src/library_ui.rs#L4236), [`ui/dr-ui/ui/settings.slint:395`](../ui/dr-ui/ui/settings.slint#L395) |
-| FR-NC-7a | [`core/dr-ingest/src/layout.rs:1`](../core/dr-ingest/src/layout.rs#L1), [`core/dr-sync/src/upload.rs:1`](../core/dr-sync/src/upload.rs#L1), [`core/dr-sync/src/upload.rs:40`](../core/dr-sync/src/upload.rs#L40), [`core/dr-types/src/settings.rs:206`](../core/dr-types/src/settings.rs#L206), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import.rs:97`](../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1379`](../ui/dr-ui/src/lib.rs#L1379), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5) |
-| FR-NC-7b | [`core/dr-ingest/src/lib.rs:733`](../core/dr-ingest/src/lib.rs#L733), [`core/dr-sync/src/upload.rs:1`](../core/dr-sync/src/upload.rs#L1), [`ui/dr-ui/src/import.rs:122`](../ui/dr-ui/src/import.rs#L122), [`ui/dr-ui/src/import.rs:336`](../ui/dr-ui/src/import.rs#L336), [`ui/dr-ui/src/import.rs:584`](../ui/dr-ui/src/import.rs#L584), [`ui/dr-ui/src/import.rs:97`](../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1379`](../ui/dr-ui/src/lib.rs#L1379) |
-| FR-NC-8 | [`core/dr-catalog/src/rating.rs:204`](../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:900`](../core/dr-catalog/src/rating.rs#L900), [`core/dr-catalog/src/schema.rs:155`](../core/dr-catalog/src/schema.rs#L155), [`core/dr-pipeline/src/sidecar.rs:120`](../core/dr-pipeline/src/sidecar.rs#L120), [`core/dr-pipeline/src/sidecar.rs:2574`](../core/dr-pipeline/src/sidecar.rs#L2574), [`core/dr-pipeline/src/sidecar.rs:619`](../core/dr-pipeline/src/sidecar.rs#L619), [`core/dr-pipeline/src/sidecar.rs:649`](../core/dr-pipeline/src/sidecar.rs#L649), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`ui/dr-ui/src/lib.rs:2216`](../ui/dr-ui/src/lib.rs#L2216), [`ui/dr-ui/src/library.rs:1045`](../ui/dr-ui/src/library.rs#L1045), [`ui/dr-ui/src/library.rs:2310`](../ui/dr-ui/src/library.rs#L2310), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:7312`](../ui/dr-ui/src/library.rs#L7312), [`ui/dr-ui/src/library.rs:755`](../ui/dr-ui/src/library.rs#L755), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/presets.rs:288`](../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:335`](../ui/dr-ui/src/presets.rs#L335) |
+| FR-NC-7a | [`core/dr-ingest/src/layout.rs:1`](../core/dr-ingest/src/layout.rs#L1), [`core/dr-sync/src/upload.rs:1`](../core/dr-sync/src/upload.rs#L1), [`core/dr-sync/src/upload.rs:40`](../core/dr-sync/src/upload.rs#L40), [`core/dr-types/src/settings.rs:206`](../core/dr-types/src/settings.rs#L206), [`ui/dr-ui/src/import.rs:1`](../ui/dr-ui/src/import.rs#L1), [`ui/dr-ui/src/import.rs:97`](../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1421`](../ui/dr-ui/src/lib.rs#L1421), [`ui/dr-ui/ui/import.slint:5`](../ui/dr-ui/ui/import.slint#L5) |
+| FR-NC-7b | [`core/dr-ingest/src/lib.rs:733`](../core/dr-ingest/src/lib.rs#L733), [`core/dr-sync/src/upload.rs:1`](../core/dr-sync/src/upload.rs#L1), [`ui/dr-ui/src/import.rs:122`](../ui/dr-ui/src/import.rs#L122), [`ui/dr-ui/src/import.rs:336`](../ui/dr-ui/src/import.rs#L336), [`ui/dr-ui/src/import.rs:584`](../ui/dr-ui/src/import.rs#L584), [`ui/dr-ui/src/import.rs:97`](../ui/dr-ui/src/import.rs#L97), [`ui/dr-ui/src/import_ui.rs:1`](../ui/dr-ui/src/import_ui.rs#L1), [`ui/dr-ui/src/lib.rs:1421`](../ui/dr-ui/src/lib.rs#L1421) |
+| FR-NC-8 | [`core/dr-catalog/src/rating.rs:204`](../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:900`](../core/dr-catalog/src/rating.rs#L900), [`core/dr-catalog/src/schema.rs:155`](../core/dr-catalog/src/schema.rs#L155), [`core/dr-pipeline/src/sidecar.rs:120`](../core/dr-pipeline/src/sidecar.rs#L120), [`core/dr-pipeline/src/sidecar.rs:2574`](../core/dr-pipeline/src/sidecar.rs#L2574), [`core/dr-pipeline/src/sidecar.rs:619`](../core/dr-pipeline/src/sidecar.rs#L619), [`core/dr-pipeline/src/sidecar.rs:649`](../core/dr-pipeline/src/sidecar.rs#L649), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`ui/dr-ui/src/lib.rs:2263`](../ui/dr-ui/src/lib.rs#L2263), [`ui/dr-ui/src/library.rs:1045`](../ui/dr-ui/src/library.rs#L1045), [`ui/dr-ui/src/library.rs:2310`](../ui/dr-ui/src/library.rs#L2310), [`ui/dr-ui/src/library.rs:500`](../ui/dr-ui/src/library.rs#L500), [`ui/dr-ui/src/library.rs:7312`](../ui/dr-ui/src/library.rs#L7312), [`ui/dr-ui/src/library.rs:755`](../ui/dr-ui/src/library.rs#L755), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/presets.rs:288`](../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:335`](../ui/dr-ui/src/presets.rs#L335) |
| FR-NC-9 | [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:204`](../core/dr-catalog/src/rating.rs#L204), [`core/dr-catalog/src/rating.rs:66`](../core/dr-catalog/src/rating.rs#L66), [`core/dr-catalog/src/rating.rs:900`](../core/dr-catalog/src/rating.rs#L900), [`core/dr-catalog/src/schema.rs:155`](../core/dr-catalog/src/schema.rs#L155), [`core/dr-catalog/src/schema.rs:532`](../core/dr-catalog/src/schema.rs#L532), [`core/dr-catalog/src/schema.rs:728`](../core/dr-catalog/src/schema.rs#L728), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:2340`](../core/dr-pipeline/src/sidecar.rs#L2340), [`core/dr-pipeline/src/sidecar.rs:2574`](../core/dr-pipeline/src/sidecar.rs#L2574), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:452`](../core/dr-pipeline/src/sidecar.rs#L452), [`core/dr-pipeline/src/sidecar.rs:619`](../core/dr-pipeline/src/sidecar.rs#L619), [`core/dr-pipeline/src/sidecar.rs:649`](../core/dr-pipeline/src/sidecar.rs#L649), [`core/dr-pipeline/src/spot.rs:245`](../core/dr-pipeline/src/spot.rs#L245), [`core/dr-pipeline/tests/mask_sidecar.rs:1055`](../core/dr-pipeline/tests/mask_sidecar.rs#L1055), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-sync/src/scan.rs:31`](../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:45`](../core/dr-sync/src/scan.rs#L45), [`core/dr-sync/src/scan.rs:912`](../core/dr-sync/src/scan.rs#L912), [`core/dr-xmp/src/lib.rs:733`](../core/dr-xmp/src/lib.rs#L733), [`core/dr-xmp/src/lib.rs:746`](../core/dr-xmp/src/lib.rs#L746), [`ui/dr-ui/src/derived_sync.rs:585`](../ui/dr-ui/src/derived_sync.rs#L585), [`ui/dr-ui/src/library.rs:1045`](../ui/dr-ui/src/library.rs#L1045), [`ui/dr-ui/src/library.rs:1065`](../ui/dr-ui/src/library.rs#L1065), [`ui/dr-ui/src/library.rs:1376`](../ui/dr-ui/src/library.rs#L1376), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:2310`](../ui/dr-ui/src/library.rs#L2310), [`ui/dr-ui/src/library.rs:7144`](../ui/dr-ui/src/library.rs#L7144), [`ui/dr-ui/src/library.rs:7312`](../ui/dr-ui/src/library.rs#L7312), [`ui/dr-ui/src/library.rs:73`](../ui/dr-ui/src/library.rs#L73), [`ui/dr-ui/src/library.rs:755`](../ui/dr-ui/src/library.rs#L755), [`ui/dr-ui/src/library.rs:899`](../ui/dr-ui/src/library.rs#L899), [`ui/dr-ui/src/library_ui.rs:1265`](../ui/dr-ui/src/library_ui.rs#L1265), [`ui/dr-ui/src/presets.rs:288`](../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:335`](../ui/dr-ui/src/presets.rs#L335) |
| FR-PLAT-AND-2 | [`core/dr-catalog/src/walk.rs:1022`](../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:435`](../core/dr-catalog/src/walk.rs#L435), [`core/dr-sync-folder/src/lib.rs:242`](../core/dr-sync-folder/src/lib.rs#L242), [`core/dr-sync-folder/src/tests.rs:51`](../core/dr-sync-folder/src/tests.rs#L51), [`core/dr-sync/src/error.rs:113`](../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/error.rs:195`](../core/dr-sync/src/error.rs#L195), [`core/dr-sync/src/scan.rs:200`](../core/dr-sync/src/scan.rs#L200), [`core/dr-sync/src/scan.rs:505`](../core/dr-sync/src/scan.rs#L505), [`core/dr-sync/src/scan.rs:531`](../core/dr-sync/src/scan.rs#L531), [`core/dr-sync/src/scan.rs:560`](../core/dr-sync/src/scan.rs#L560), [`ui/dr-ui/src/library.rs:1276`](../ui/dr-ui/src/library.rs#L1276), [`ui/dr-ui/src/library.rs:1329`](../ui/dr-ui/src/library.rs#L1329), [`ui/dr-ui/src/library.rs:1360`](../ui/dr-ui/src/library.rs#L1360), [`ui/dr-ui/src/library.rs:1727`](../ui/dr-ui/src/library.rs#L1727), [`ui/dr-ui/src/library_ui.rs:1241`](../ui/dr-ui/src/library_ui.rs#L1241), [`ui/dr-ui/src/library_ui.rs:1332`](../ui/dr-ui/src/library_ui.rs#L1332), [`ui/dr-ui/src/library_ui.rs:1931`](../ui/dr-ui/src/library_ui.rs#L1931), [`ui/dr-ui/src/library_ui.rs:325`](../ui/dr-ui/src/library_ui.rs#L325), [`ui/dr-ui/src/library_ui.rs:523`](../ui/dr-ui/src/library_ui.rs#L523) |
| FR-PLAT-AND-3 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1), [`core/dr-catalog/src/runner.rs:1`](../core/dr-catalog/src/runner.rs#L1) |
| FR-PLAT-AND-4 | [`core/dr-catalog/src/runner.rs:1`](../core/dr-catalog/src/runner.rs#L1) |
-| FR-PLAT-AND-5 | [`apps/darkroom-android/src/lib.rs:166`](../apps/darkroom-android/src/lib.rs#L166), [`core/dr-gpu/src/adjust.rs:1029`](../core/dr-gpu/src/adjust.rs#L1029), [`core/dr-gpu/src/detail.rs:161`](../core/dr-gpu/src/detail.rs#L161), [`core/dr-gpu/src/detail.rs:547`](../core/dr-gpu/src/detail.rs#L547), [`core/dr-gpu/tests/detail_stage.rs:417`](../core/dr-gpu/tests/detail_stage.rs#L417), [`ui/dr-ui/src/develop.rs:3853`](../ui/dr-ui/src/develop.rs#L3853), [`ui/dr-ui/src/identity_ui.rs:121`](../ui/dr-ui/src/identity_ui.rs#L121), [`ui/dr-ui/src/lib.rs:1198`](../ui/dr-ui/src/lib.rs#L1198), [`ui/dr-ui/src/lib.rs:1647`](../ui/dr-ui/src/lib.rs#L1647), [`ui/dr-ui/src/memory.rs:163`](../ui/dr-ui/src/memory.rs#L163), [`ui/dr-ui/src/memory.rs:1`](../ui/dr-ui/src/memory.rs#L1) |
+| FR-PLAT-AND-5 | [`apps/darkroom-android/src/lib.rs:166`](../apps/darkroom-android/src/lib.rs#L166), [`core/dr-gpu/src/adjust.rs:1029`](../core/dr-gpu/src/adjust.rs#L1029), [`core/dr-gpu/src/detail.rs:161`](../core/dr-gpu/src/detail.rs#L161), [`core/dr-gpu/src/detail.rs:547`](../core/dr-gpu/src/detail.rs#L547), [`core/dr-gpu/tests/detail_stage.rs:417`](../core/dr-gpu/tests/detail_stage.rs#L417), [`ui/dr-ui/src/develop.rs:3853`](../ui/dr-ui/src/develop.rs#L3853), [`ui/dr-ui/src/identity_ui.rs:121`](../ui/dr-ui/src/identity_ui.rs#L121), [`ui/dr-ui/src/lib.rs:1240`](../ui/dr-ui/src/lib.rs#L1240), [`ui/dr-ui/src/lib.rs:1689`](../ui/dr-ui/src/lib.rs#L1689), [`ui/dr-ui/src/memory.rs:163`](../ui/dr-ui/src/memory.rs#L163), [`ui/dr-ui/src/memory.rs:1`](../ui/dr-ui/src/memory.rs#L1) |
| FR-PLAT-AND-6 | [`apps/darkroom-android/src/lib.rs:388`](../apps/darkroom-android/src/lib.rs#L388) |
-| FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1074`](../ui/dr-ui/src/lib.rs#L1074), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) |
+| FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1116`](../ui/dr-ui/src/lib.rs#L1116), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) |
| FR-PLAT-LIN-2 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1) |
| FR-PLG-2 | [`core/dr-pipeline/src/declared/decl.rs:1`](../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/expr.rs:152`](../core/dr-pipeline/src/declared/expr.rs#L152), [`core/dr-pipeline/src/declared/expr.rs:1`](../core/dr-pipeline/src/declared/expr.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:1`](../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:82`](../core/dr-pipeline/src/declared/mod.rs#L82), [`core/dr-pipeline/src/descriptor.rs:15`](../core/dr-pipeline/src/descriptor.rs#L15), [`core/dr-pipeline/src/descriptor.rs:713`](../core/dr-pipeline/src/descriptor.rs#L713), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/tests/declared_parity.rs:1`](../core/dr-pipeline/tests/declared_parity.rs#L1), [`core/dr-pipeline/tests/declared_parity.rs:240`](../core/dr-pipeline/tests/declared_parity.rs#L240), [`core/dr-pipeline/tests/declared_parity.rs:305`](../core/dr-pipeline/tests/declared_parity.rs#L305), [`core/dr-pipeline/tests/declared_parity.rs:358`](../core/dr-pipeline/tests/declared_parity.rs#L358), [`core/dr-pipeline/tests/declared_parity.rs:418`](../core/dr-pipeline/tests/declared_parity.rs#L418) |
| FR-PLG-2d | [`core/dr-pipeline/src/declared/decl.rs:112`](../core/dr-pipeline/src/declared/decl.rs#L112), [`core/dr-pipeline/src/declared/decl.rs:154`](../core/dr-pipeline/src/declared/decl.rs#L154), [`core/dr-pipeline/src/declared/decl.rs:1`](../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/decl.rs:422`](../core/dr-pipeline/src/declared/decl.rs#L422), [`core/dr-pipeline/src/declared/decl.rs:67`](../core/dr-pipeline/src/declared/decl.rs#L67), [`core/dr-pipeline/src/declared/mod.rs:1`](../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:384`](../core/dr-pipeline/src/declared/mod.rs#L384), [`core/dr-pipeline/src/declared/mod.rs:403`](../core/dr-pipeline/src/declared/mod.rs#L403) |
| FR-PLG-8 | [`core/dr-pipeline/src/sidecar.rs:2011`](../core/dr-pipeline/src/sidecar.rs#L2011), [`core/dr-pipeline/src/sidecar.rs:2044`](../core/dr-pipeline/src/sidecar.rs#L2044) |
| FR-RAW-1 | [`core/dr-decode/src/lib.rs:243`](../core/dr-decode/src/lib.rs#L243), [`core/dr-types/src/lib.rs:132`](../core/dr-types/src/lib.rs#L132), [`core/dr-types/src/lib.rs:203`](../core/dr-types/src/lib.rs#L203) |
| FR-RAW-3 | [`core/dr-decode/src/lib.rs:139`](../core/dr-decode/src/lib.rs#L139), [`core/dr-decode/src/lib.rs:506`](../core/dr-decode/src/lib.rs#L506), [`core/dr-decode/src/locate.rs:1366`](../core/dr-decode/src/locate.rs#L1366) |
-| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1), [`ui/dr-ui/src/lib.rs:232`](../ui/dr-ui/src/lib.rs#L232) |
+| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1), [`ui/dr-ui/src/lib.rs:261`](../ui/dr-ui/src/lib.rs#L261) |
| FR-RAW-5 | [`core/dr-decode/src/lib.rs:167`](../core/dr-decode/src/lib.rs#L167), [`core/dr-gpu/src/demosaic.rs:34`](../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:602`](../core/dr-gpu/src/demosaic.rs#L602), [`core/dr-gpu/src/demosaic.rs:681`](../core/dr-gpu/src/demosaic.rs#L681), [`core/dr-gpu/src/demosaic.rs:805`](../core/dr-gpu/src/demosaic.rs#L805) |
-| FR-UI-1 | [`core/dr-types/src/settings.rs:1166`](../core/dr-types/src/settings.rs#L1166), [`core/dr-types/src/settings.rs:321`](../core/dr-types/src/settings.rs#L321), [`core/dr-types/src/settings.rs:341`](../core/dr-types/src/settings.rs#L341), [`ui/dr-ui/src/lib.rs:101`](../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/lib.rs:108`](../ui/dr-ui/src/lib.rs#L108), [`ui/dr-ui/src/lib.rs:2460`](../ui/dr-ui/src/lib.rs#L2460), [`ui/dr-ui/src/lib.rs:3575`](../ui/dr-ui/src/lib.rs#L3575), [`ui/dr-ui/src/lib.rs:3594`](../ui/dr-ui/src/lib.rs#L3594), [`ui/dr-ui/src/lib.rs:3621`](../ui/dr-ui/src/lib.rs#L3621), [`ui/dr-ui/src/lib.rs:3672`](../ui/dr-ui/src/lib.rs#L3672), [`ui/dr-ui/src/masks_ui.rs:951`](../ui/dr-ui/src/masks_ui.rs#L951), [`ui/dr-ui/src/settings_ui.rs:160`](../ui/dr-ui/src/settings_ui.rs#L160), [`ui/dr-ui/ui/app.slint:2661`](../ui/dr-ui/ui/app.slint#L2661), [`ui/dr-ui/ui/app.slint:787`](../ui/dr-ui/ui/app.slint#L787), [`ui/dr-ui/ui/app.slint:956`](../ui/dr-ui/ui/app.slint#L956), [`ui/dr-ui/ui/identity.slint:188`](../ui/dr-ui/ui/identity.slint#L188), [`ui/dr-ui/ui/library.slint:1076`](../ui/dr-ui/ui/library.slint#L1076), [`ui/dr-ui/ui/settings.slint:104`](../ui/dr-ui/ui/settings.slint#L104), [`ui/dr-ui/ui/settings.slint:565`](../ui/dr-ui/ui/settings.slint#L565), [`ui/dr-ui/ui/toolrail.slint:156`](../ui/dr-ui/ui/toolrail.slint#L156), [`ui/dr-ui/ui/toolrail.slint:89`](../ui/dr-ui/ui/toolrail.slint#L89) |
-| FR-UI-2 | [`ui/dr-ui/src/collections_ui.rs:1045`](../ui/dr-ui/src/collections_ui.rs#L1045), [`ui/dr-ui/src/collections_ui.rs:1055`](../ui/dr-ui/src/collections_ui.rs#L1055), [`ui/dr-ui/src/collections_ui.rs:116`](../ui/dr-ui/src/collections_ui.rs#L116), [`ui/dr-ui/src/collections_ui.rs:154`](../ui/dr-ui/src/collections_ui.rs#L154), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1569`](../ui/dr-ui/src/collections_ui.rs#L1569), [`ui/dr-ui/src/collections_ui.rs:1821`](../ui/dr-ui/src/collections_ui.rs#L1821), [`ui/dr-ui/src/collections_ui.rs:2926`](../ui/dr-ui/src/collections_ui.rs#L2926), [`ui/dr-ui/src/gestures.rs:1`](../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:101`](../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/library_ui.rs:360`](../ui/dr-ui/src/library_ui.rs#L360), [`ui/dr-ui/src/library_ui.rs:6457`](../ui/dr-ui/src/library_ui.rs#L6457), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/src/library_ui.rs:7817`](../ui/dr-ui/src/library_ui.rs#L7817), [`ui/dr-ui/ui/app.slint:1038`](../ui/dr-ui/ui/app.slint#L1038), [`ui/dr-ui/ui/app.slint:60`](../ui/dr-ui/ui/app.slint#L60), [`ui/dr-ui/ui/app.slint:652`](../ui/dr-ui/ui/app.slint#L652), [`ui/dr-ui/ui/app.slint:666`](../ui/dr-ui/ui/app.slint#L666), [`ui/dr-ui/ui/controls.slint:605`](../ui/dr-ui/ui/controls.slint#L605), [`ui/dr-ui/ui/gestures.slint:1`](../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1287`](../ui/dr-ui/ui/library.slint#L1287), [`ui/dr-ui/ui/library.slint:1294`](../ui/dr-ui/ui/library.slint#L1294), [`ui/dr-ui/ui/library.slint:1391`](../ui/dr-ui/ui/library.slint#L1391), [`ui/dr-ui/ui/library.slint:2575`](../ui/dr-ui/ui/library.slint#L2575), [`ui/dr-ui/ui/library.slint:4289`](../ui/dr-ui/ui/library.slint#L4289), [`ui/dr-ui/ui/library.slint:965`](../ui/dr-ui/ui/library.slint#L965), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/settings.slint:118`](../ui/dr-ui/ui/settings.slint#L118) |
-| FR-UI-3 | [`ui/dr-ui/src/develop.rs:2525`](../ui/dr-ui/src/develop.rs#L2525), [`ui/dr-ui/src/develop.rs:2634`](../ui/dr-ui/src/develop.rs#L2634), [`ui/dr-ui/src/library_ui.rs:5486`](../ui/dr-ui/src/library_ui.rs#L5486), [`ui/dr-ui/src/masks_ui.rs:1043`](../ui/dr-ui/src/masks_ui.rs#L1043), [`ui/dr-ui/src/masks_ui.rs:1065`](../ui/dr-ui/src/masks_ui.rs#L1065), [`ui/dr-ui/src/masks_ui.rs:263`](../ui/dr-ui/src/masks_ui.rs#L263), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/ui/app.slint:2226`](../ui/dr-ui/ui/app.slint#L2226), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:747`](../ui/dr-ui/ui/collections.slint#L747), [`ui/dr-ui/ui/masks.slint:767`](../ui/dr-ui/ui/masks.slint#L767), [`ui/dr-ui/ui/widgets.slint:71`](../ui/dr-ui/ui/widgets.slint#L71) |
-| FR-UI-4 | [`tools/traceability/src/gestures.rs:1`](../tools/traceability/src/gestures.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1045`](../ui/dr-ui/src/collections_ui.rs#L1045), [`ui/dr-ui/src/collections_ui.rs:1055`](../ui/dr-ui/src/collections_ui.rs#L1055), [`ui/dr-ui/src/collections_ui.rs:116`](../ui/dr-ui/src/collections_ui.rs#L116), [`ui/dr-ui/src/collections_ui.rs:117`](../ui/dr-ui/src/collections_ui.rs#L117), [`ui/dr-ui/src/collections_ui.rs:126`](../ui/dr-ui/src/collections_ui.rs#L126), [`ui/dr-ui/src/collections_ui.rs:154`](../ui/dr-ui/src/collections_ui.rs#L154), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1569`](../ui/dr-ui/src/collections_ui.rs#L1569), [`ui/dr-ui/src/collections_ui.rs:1685`](../ui/dr-ui/src/collections_ui.rs#L1685), [`ui/dr-ui/src/collections_ui.rs:1821`](../ui/dr-ui/src/collections_ui.rs#L1821), [`ui/dr-ui/src/collections_ui.rs:1848`](../ui/dr-ui/src/collections_ui.rs#L1848), [`ui/dr-ui/src/collections_ui.rs:1964`](../ui/dr-ui/src/collections_ui.rs#L1964), [`ui/dr-ui/src/collections_ui.rs:2926`](../ui/dr-ui/src/collections_ui.rs#L2926), [`ui/dr-ui/src/collections_ui.rs:2963`](../ui/dr-ui/src/collections_ui.rs#L2963), [`ui/dr-ui/src/collections_ui.rs:365`](../ui/dr-ui/src/collections_ui.rs#L365), [`ui/dr-ui/src/collections_ui.rs:569`](../ui/dr-ui/src/collections_ui.rs#L569), [`ui/dr-ui/src/collections_ui.rs:589`](../ui/dr-ui/src/collections_ui.rs#L589), [`ui/dr-ui/src/develop.rs:4620`](../ui/dr-ui/src/develop.rs#L4620), [`ui/dr-ui/src/develop.rs:4645`](../ui/dr-ui/src/develop.rs#L4645), [`ui/dr-ui/src/develop.rs:4656`](../ui/dr-ui/src/develop.rs#L4656), [`ui/dr-ui/src/develop.rs:4670`](../ui/dr-ui/src/develop.rs#L4670), [`ui/dr-ui/src/develop.rs:5707`](../ui/dr-ui/src/develop.rs#L5707), [`ui/dr-ui/src/develop.rs:5738`](../ui/dr-ui/src/develop.rs#L5738), [`ui/dr-ui/src/develop.rs:5759`](../ui/dr-ui/src/develop.rs#L5759), [`ui/dr-ui/src/gesture_book.rs:3`](../ui/dr-ui/src/gesture_book.rs#L3), [`ui/dr-ui/src/gestures.rs:1`](../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:1724`](../ui/dr-ui/src/lib.rs#L1724), [`ui/dr-ui/src/lib.rs:2130`](../ui/dr-ui/src/lib.rs#L2130), [`ui/dr-ui/src/lib.rs:2367`](../ui/dr-ui/src/lib.rs#L2367), [`ui/dr-ui/src/lib.rs:2946`](../ui/dr-ui/src/lib.rs#L2946), [`ui/dr-ui/src/lib.rs:3765`](../ui/dr-ui/src/lib.rs#L3765), [`ui/dr-ui/src/lib.rs:414`](../ui/dr-ui/src/lib.rs#L414), [`ui/dr-ui/src/lib.rs:443`](../ui/dr-ui/src/lib.rs#L443), [`ui/dr-ui/src/library_ui.rs:5486`](../ui/dr-ui/src/library_ui.rs#L5486), [`ui/dr-ui/src/library_ui.rs:5498`](../ui/dr-ui/src/library_ui.rs#L5498), [`ui/dr-ui/src/library_ui.rs:5568`](../ui/dr-ui/src/library_ui.rs#L5568), [`ui/dr-ui/src/library_ui.rs:5678`](../ui/dr-ui/src/library_ui.rs#L5678), [`ui/dr-ui/src/library_ui.rs:5706`](../ui/dr-ui/src/library_ui.rs#L5706), [`ui/dr-ui/src/library_ui.rs:6590`](../ui/dr-ui/src/library_ui.rs#L6590), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/ui/app.slint:2000`](../ui/dr-ui/ui/app.slint#L2000), [`ui/dr-ui/ui/app.slint:2184`](../ui/dr-ui/ui/app.slint#L2184), [`ui/dr-ui/ui/app.slint:2450`](../ui/dr-ui/ui/app.slint#L2450), [`ui/dr-ui/ui/app.slint:2561`](../ui/dr-ui/ui/app.slint#L2561), [`ui/dr-ui/ui/app.slint:275`](../ui/dr-ui/ui/app.slint#L275), [`ui/dr-ui/ui/app.slint:628`](../ui/dr-ui/ui/app.slint#L628), [`ui/dr-ui/ui/app.slint:657`](../ui/dr-ui/ui/app.slint#L657), [`ui/dr-ui/ui/app.slint:666`](../ui/dr-ui/ui/app.slint#L666), [`ui/dr-ui/ui/app.slint:754`](../ui/dr-ui/ui/app.slint#L754), [`ui/dr-ui/ui/gestures.slint:1`](../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1053`](../ui/dr-ui/ui/library.slint#L1053), [`ui/dr-ui/ui/library.slint:1262`](../ui/dr-ui/ui/library.slint#L1262), [`ui/dr-ui/ui/library.slint:1287`](../ui/dr-ui/ui/library.slint#L1287), [`ui/dr-ui/ui/library.slint:1294`](../ui/dr-ui/ui/library.slint#L1294), [`ui/dr-ui/ui/library.slint:1327`](../ui/dr-ui/ui/library.slint#L1327), [`ui/dr-ui/ui/library.slint:1384`](../ui/dr-ui/ui/library.slint#L1384), [`ui/dr-ui/ui/library.slint:1391`](../ui/dr-ui/ui/library.slint#L1391), [`ui/dr-ui/ui/library.slint:2575`](../ui/dr-ui/ui/library.slint#L2575), [`ui/dr-ui/ui/library.slint:4173`](../ui/dr-ui/ui/library.slint#L4173), [`ui/dr-ui/ui/library.slint:4289`](../ui/dr-ui/ui/library.slint#L4289), [`ui/dr-ui/ui/library.slint:965`](../ui/dr-ui/ui/library.slint#L965), [`ui/dr-ui/ui/library.slint:992`](../ui/dr-ui/ui/library.slint#L992), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998) |
-| FR-UI-5 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2991`](../ui/dr-ui/src/lib.rs#L2991), [`ui/dr-ui/src/lib.rs:3725`](../ui/dr-ui/src/lib.rs#L3725), [`ui/dr-ui/src/lib.rs:3916`](../ui/dr-ui/src/lib.rs#L3916), [`ui/dr-ui/src/masks_ui.rs:998`](../ui/dr-ui/src/masks_ui.rs#L998), [`ui/dr-ui/ui/app.slint:127`](../ui/dr-ui/ui/app.slint#L127), [`ui/dr-ui/ui/app.slint:2410`](../ui/dr-ui/ui/app.slint#L2410), [`ui/dr-ui/ui/app.slint:2450`](../ui/dr-ui/ui/app.slint#L2450), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4) |
+| FR-UI-1 | [`core/dr-types/src/settings.rs:1166`](../core/dr-types/src/settings.rs#L1166), [`core/dr-types/src/settings.rs:321`](../core/dr-types/src/settings.rs#L321), [`core/dr-types/src/settings.rs:341`](../core/dr-types/src/settings.rs#L341), [`ui/dr-ui/src/lib.rs:101`](../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/lib.rs:116`](../ui/dr-ui/src/lib.rs#L116), [`ui/dr-ui/src/lib.rs:138`](../ui/dr-ui/src/lib.rs#L138), [`ui/dr-ui/src/lib.rs:2508`](../ui/dr-ui/src/lib.rs#L2508), [`ui/dr-ui/src/lib.rs:3654`](../ui/dr-ui/src/lib.rs#L3654), [`ui/dr-ui/src/lib.rs:3673`](../ui/dr-ui/src/lib.rs#L3673), [`ui/dr-ui/src/lib.rs:3700`](../ui/dr-ui/src/lib.rs#L3700), [`ui/dr-ui/src/lib.rs:3751`](../ui/dr-ui/src/lib.rs#L3751), [`ui/dr-ui/src/lib.rs:3784`](../ui/dr-ui/src/lib.rs#L3784), [`ui/dr-ui/src/masks_ui.rs:984`](../ui/dr-ui/src/masks_ui.rs#L984), [`ui/dr-ui/src/settings_ui.rs:160`](../ui/dr-ui/src/settings_ui.rs#L160), [`ui/dr-ui/ui/adjust.slint:953`](../ui/dr-ui/ui/adjust.slint#L953), [`ui/dr-ui/ui/app.slint:2520`](../ui/dr-ui/ui/app.slint#L2520), [`ui/dr-ui/ui/app.slint:786`](../ui/dr-ui/ui/app.slint#L786), [`ui/dr-ui/ui/app.slint:884`](../ui/dr-ui/ui/app.slint#L884), [`ui/dr-ui/ui/identity.slint:188`](../ui/dr-ui/ui/identity.slint#L188), [`ui/dr-ui/ui/library.slint:1076`](../ui/dr-ui/ui/library.slint#L1076), [`ui/dr-ui/ui/settings.slint:104`](../ui/dr-ui/ui/settings.slint#L104), [`ui/dr-ui/ui/settings.slint:565`](../ui/dr-ui/ui/settings.slint#L565), [`ui/dr-ui/ui/toolrail.slint:156`](../ui/dr-ui/ui/toolrail.slint#L156), [`ui/dr-ui/ui/toolrail.slint:89`](../ui/dr-ui/ui/toolrail.slint#L89) |
+| FR-UI-2 | [`ui/dr-ui/src/collections_ui.rs:1045`](../ui/dr-ui/src/collections_ui.rs#L1045), [`ui/dr-ui/src/collections_ui.rs:1055`](../ui/dr-ui/src/collections_ui.rs#L1055), [`ui/dr-ui/src/collections_ui.rs:116`](../ui/dr-ui/src/collections_ui.rs#L116), [`ui/dr-ui/src/collections_ui.rs:154`](../ui/dr-ui/src/collections_ui.rs#L154), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1569`](../ui/dr-ui/src/collections_ui.rs#L1569), [`ui/dr-ui/src/collections_ui.rs:1821`](../ui/dr-ui/src/collections_ui.rs#L1821), [`ui/dr-ui/src/collections_ui.rs:2926`](../ui/dr-ui/src/collections_ui.rs#L2926), [`ui/dr-ui/src/gestures.rs:1`](../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:101`](../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/library_ui.rs:360`](../ui/dr-ui/src/library_ui.rs#L360), [`ui/dr-ui/src/library_ui.rs:6457`](../ui/dr-ui/src/library_ui.rs#L6457), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/src/library_ui.rs:7817`](../ui/dr-ui/src/library_ui.rs#L7817), [`ui/dr-ui/ui/app.slint:536`](../ui/dr-ui/ui/app.slint#L536), [`ui/dr-ui/ui/app.slint:550`](../ui/dr-ui/ui/app.slint#L550), [`ui/dr-ui/ui/app.slint:67`](../ui/dr-ui/ui/app.slint#L67), [`ui/dr-ui/ui/app.slint:868`](../ui/dr-ui/ui/app.slint#L868), [`ui/dr-ui/ui/controls.slint:605`](../ui/dr-ui/ui/controls.slint#L605), [`ui/dr-ui/ui/gestures.slint:1`](../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1287`](../ui/dr-ui/ui/library.slint#L1287), [`ui/dr-ui/ui/library.slint:1294`](../ui/dr-ui/ui/library.slint#L1294), [`ui/dr-ui/ui/library.slint:1391`](../ui/dr-ui/ui/library.slint#L1391), [`ui/dr-ui/ui/library.slint:2575`](../ui/dr-ui/ui/library.slint#L2575), [`ui/dr-ui/ui/library.slint:4289`](../ui/dr-ui/ui/library.slint#L4289), [`ui/dr-ui/ui/library.slint:965`](../ui/dr-ui/ui/library.slint#L965), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/settings.slint:118`](../ui/dr-ui/ui/settings.slint#L118) |
+| FR-UI-3 | [`ui/dr-ui/src/develop.rs:2525`](../ui/dr-ui/src/develop.rs#L2525), [`ui/dr-ui/src/develop.rs:2634`](../ui/dr-ui/src/develop.rs#L2634), [`ui/dr-ui/src/library_ui.rs:5486`](../ui/dr-ui/src/library_ui.rs#L5486), [`ui/dr-ui/src/masks_ui.rs:1076`](../ui/dr-ui/src/masks_ui.rs#L1076), [`ui/dr-ui/src/masks_ui.rs:1098`](../ui/dr-ui/src/masks_ui.rs#L1098), [`ui/dr-ui/src/masks_ui.rs:271`](../ui/dr-ui/src/masks_ui.rs#L271), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/ui/app.slint:2085`](../ui/dr-ui/ui/app.slint#L2085), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:747`](../ui/dr-ui/ui/collections.slint#L747), [`ui/dr-ui/ui/masks.slint:789`](../ui/dr-ui/ui/masks.slint#L789), [`ui/dr-ui/ui/widgets.slint:71`](../ui/dr-ui/ui/widgets.slint#L71) |
+| FR-UI-4 | [`tools/traceability/src/gestures.rs:1`](../tools/traceability/src/gestures.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1045`](../ui/dr-ui/src/collections_ui.rs#L1045), [`ui/dr-ui/src/collections_ui.rs:1055`](../ui/dr-ui/src/collections_ui.rs#L1055), [`ui/dr-ui/src/collections_ui.rs:116`](../ui/dr-ui/src/collections_ui.rs#L116), [`ui/dr-ui/src/collections_ui.rs:117`](../ui/dr-ui/src/collections_ui.rs#L117), [`ui/dr-ui/src/collections_ui.rs:126`](../ui/dr-ui/src/collections_ui.rs#L126), [`ui/dr-ui/src/collections_ui.rs:154`](../ui/dr-ui/src/collections_ui.rs#L154), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1569`](../ui/dr-ui/src/collections_ui.rs#L1569), [`ui/dr-ui/src/collections_ui.rs:1685`](../ui/dr-ui/src/collections_ui.rs#L1685), [`ui/dr-ui/src/collections_ui.rs:1821`](../ui/dr-ui/src/collections_ui.rs#L1821), [`ui/dr-ui/src/collections_ui.rs:1848`](../ui/dr-ui/src/collections_ui.rs#L1848), [`ui/dr-ui/src/collections_ui.rs:1964`](../ui/dr-ui/src/collections_ui.rs#L1964), [`ui/dr-ui/src/collections_ui.rs:2926`](../ui/dr-ui/src/collections_ui.rs#L2926), [`ui/dr-ui/src/collections_ui.rs:2963`](../ui/dr-ui/src/collections_ui.rs#L2963), [`ui/dr-ui/src/collections_ui.rs:365`](../ui/dr-ui/src/collections_ui.rs#L365), [`ui/dr-ui/src/collections_ui.rs:569`](../ui/dr-ui/src/collections_ui.rs#L569), [`ui/dr-ui/src/collections_ui.rs:589`](../ui/dr-ui/src/collections_ui.rs#L589), [`ui/dr-ui/src/develop.rs:4620`](../ui/dr-ui/src/develop.rs#L4620), [`ui/dr-ui/src/develop.rs:4645`](../ui/dr-ui/src/develop.rs#L4645), [`ui/dr-ui/src/develop.rs:4656`](../ui/dr-ui/src/develop.rs#L4656), [`ui/dr-ui/src/develop.rs:4670`](../ui/dr-ui/src/develop.rs#L4670), [`ui/dr-ui/src/develop.rs:5707`](../ui/dr-ui/src/develop.rs#L5707), [`ui/dr-ui/src/develop.rs:5738`](../ui/dr-ui/src/develop.rs#L5738), [`ui/dr-ui/src/develop.rs:5759`](../ui/dr-ui/src/develop.rs#L5759), [`ui/dr-ui/src/gesture_book.rs:3`](../ui/dr-ui/src/gesture_book.rs#L3), [`ui/dr-ui/src/gestures.rs:1`](../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:1766`](../ui/dr-ui/src/lib.rs#L1766), [`ui/dr-ui/src/lib.rs:2175`](../ui/dr-ui/src/lib.rs#L2175), [`ui/dr-ui/src/lib.rs:2415`](../ui/dr-ui/src/lib.rs#L2415), [`ui/dr-ui/src/lib.rs:3004`](../ui/dr-ui/src/lib.rs#L3004), [`ui/dr-ui/src/lib.rs:3888`](../ui/dr-ui/src/lib.rs#L3888), [`ui/dr-ui/src/lib.rs:447`](../ui/dr-ui/src/lib.rs#L447), [`ui/dr-ui/src/lib.rs:476`](../ui/dr-ui/src/lib.rs#L476), [`ui/dr-ui/src/library_ui.rs:5486`](../ui/dr-ui/src/library_ui.rs#L5486), [`ui/dr-ui/src/library_ui.rs:5498`](../ui/dr-ui/src/library_ui.rs#L5498), [`ui/dr-ui/src/library_ui.rs:5568`](../ui/dr-ui/src/library_ui.rs#L5568), [`ui/dr-ui/src/library_ui.rs:5678`](../ui/dr-ui/src/library_ui.rs#L5678), [`ui/dr-ui/src/library_ui.rs:5706`](../ui/dr-ui/src/library_ui.rs#L5706), [`ui/dr-ui/src/library_ui.rs:6590`](../ui/dr-ui/src/library_ui.rs#L6590), [`ui/dr-ui/src/library_ui.rs:6602`](../ui/dr-ui/src/library_ui.rs#L6602), [`ui/dr-ui/ui/app.slint:159`](../ui/dr-ui/ui/app.slint#L159), [`ui/dr-ui/ui/app.slint:1859`](../ui/dr-ui/ui/app.slint#L1859), [`ui/dr-ui/ui/app.slint:2043`](../ui/dr-ui/ui/app.slint#L2043), [`ui/dr-ui/ui/app.slint:2309`](../ui/dr-ui/ui/app.slint#L2309), [`ui/dr-ui/ui/app.slint:2420`](../ui/dr-ui/ui/app.slint#L2420), [`ui/dr-ui/ui/app.slint:512`](../ui/dr-ui/ui/app.slint#L512), [`ui/dr-ui/ui/app.slint:541`](../ui/dr-ui/ui/app.slint#L541), [`ui/dr-ui/ui/app.slint:550`](../ui/dr-ui/ui/app.slint#L550), [`ui/dr-ui/ui/app.slint:638`](../ui/dr-ui/ui/app.slint#L638), [`ui/dr-ui/ui/gestures.slint:1`](../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1053`](../ui/dr-ui/ui/library.slint#L1053), [`ui/dr-ui/ui/library.slint:1262`](../ui/dr-ui/ui/library.slint#L1262), [`ui/dr-ui/ui/library.slint:1287`](../ui/dr-ui/ui/library.slint#L1287), [`ui/dr-ui/ui/library.slint:1294`](../ui/dr-ui/ui/library.slint#L1294), [`ui/dr-ui/ui/library.slint:1327`](../ui/dr-ui/ui/library.slint#L1327), [`ui/dr-ui/ui/library.slint:1384`](../ui/dr-ui/ui/library.slint#L1384), [`ui/dr-ui/ui/library.slint:1391`](../ui/dr-ui/ui/library.slint#L1391), [`ui/dr-ui/ui/library.slint:2575`](../ui/dr-ui/ui/library.slint#L2575), [`ui/dr-ui/ui/library.slint:4173`](../ui/dr-ui/ui/library.slint#L4173), [`ui/dr-ui/ui/library.slint:4289`](../ui/dr-ui/ui/library.slint#L4289), [`ui/dr-ui/ui/library.slint:965`](../ui/dr-ui/ui/library.slint#L965), [`ui/dr-ui/ui/library.slint:992`](../ui/dr-ui/ui/library.slint#L992), [`ui/dr-ui/ui/library.slint:998`](../ui/dr-ui/ui/library.slint#L998) |
+| FR-UI-5 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/lib.rs:3049`](../ui/dr-ui/src/lib.rs#L3049), [`ui/dr-ui/src/lib.rs:3848`](../ui/dr-ui/src/lib.rs#L3848), [`ui/dr-ui/src/lib.rs:4039`](../ui/dr-ui/src/lib.rs#L4039), [`ui/dr-ui/src/masks_ui.rs:1031`](../ui/dr-ui/src/masks_ui.rs#L1031), [`ui/dr-ui/ui/app.slint:2269`](../ui/dr-ui/ui/app.slint#L2269), [`ui/dr-ui/ui/app.slint:2309`](../ui/dr-ui/ui/app.slint#L2309), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/session.slint:75`](../ui/dr-ui/ui/session.slint#L75) |
| FR-UI-6 | [`ui/dr-ui/ui/widgets.slint:1`](../ui/dr-ui/ui/widgets.slint#L1) |
-| FR-UI-7 | [`core/dr-pipeline/src/descriptor.rs:195`](../core/dr-pipeline/src/descriptor.rs#L195), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-types/src/settings.rs:321`](../core/dr-types/src/settings.rs#L321), [`ui/dr-ui/src/develop.rs:1200`](../ui/dr-ui/src/develop.rs#L1200), [`ui/dr-ui/src/lib.rs:3594`](../ui/dr-ui/src/lib.rs#L3594), [`ui/dr-ui/ui/app.slint:2087`](../ui/dr-ui/ui/app.slint#L2087), [`ui/dr-ui/ui/app.slint:787`](../ui/dr-ui/ui/app.slint#L787), [`ui/dr-ui/ui/settings.slint:565`](../ui/dr-ui/ui/settings.slint#L565), [`ui/dr-ui/ui/toolrail.slint:89`](../ui/dr-ui/ui/toolrail.slint#L89) |
+| FR-UI-7 | [`core/dr-pipeline/src/descriptor.rs:195`](../core/dr-pipeline/src/descriptor.rs#L195), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-types/src/settings.rs:321`](../core/dr-types/src/settings.rs#L321), [`ui/dr-ui/src/develop.rs:1200`](../ui/dr-ui/src/develop.rs#L1200), [`ui/dr-ui/src/lib.rs:3673`](../ui/dr-ui/src/lib.rs#L3673), [`ui/dr-ui/ui/adjust.slint:953`](../ui/dr-ui/ui/adjust.slint#L953), [`ui/dr-ui/ui/app.slint:1946`](../ui/dr-ui/ui/app.slint#L1946), [`ui/dr-ui/ui/settings.slint:565`](../ui/dr-ui/ui/settings.slint#L565), [`ui/dr-ui/ui/toolrail.slint:89`](../ui/dr-ui/ui/toolrail.slint#L89) |
| FR-UI-8 | [`core/dr-catalog/src/collections.rs:555`](../core/dr-catalog/src/collections.rs#L555), [`core/dr-catalog/src/collections.rs:576`](../core/dr-catalog/src/collections.rs#L576), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/derived_sync.rs:188`](../ui/dr-ui/src/derived_sync.rs#L188), [`ui/dr-ui/src/derived_sync.rs:657`](../ui/dr-ui/src/derived_sync.rs#L657), [`ui/dr-ui/src/derived_sync.rs:667`](../ui/dr-ui/src/derived_sync.rs#L667), [`ui/dr-ui/src/derived_sync.rs:749`](../ui/dr-ui/src/derived_sync.rs#L749), [`ui/dr-ui/src/derived_sync.rs:74`](../ui/dr-ui/src/derived_sync.rs#L74), [`ui/dr-ui/src/library.rs:1106`](../ui/dr-ui/src/library.rs#L1106), [`ui/dr-ui/src/library.rs:4556`](../ui/dr-ui/src/library.rs#L4556), [`ui/dr-ui/src/library.rs:5274`](../ui/dr-ui/src/library.rs#L5274), [`ui/dr-ui/src/library.rs:5340`](../ui/dr-ui/src/library.rs#L5340), [`ui/dr-ui/src/library_ui.rs:195`](../ui/dr-ui/src/library_ui.rs#L195), [`ui/dr-ui/src/library_ui.rs:2118`](../ui/dr-ui/src/library_ui.rs#L2118), [`ui/dr-ui/src/library_ui.rs:2307`](../ui/dr-ui/src/library_ui.rs#L2307), [`ui/dr-ui/src/library_ui.rs:2324`](../ui/dr-ui/src/library_ui.rs#L2324), [`ui/dr-ui/src/library_ui.rs:2422`](../ui/dr-ui/src/library_ui.rs#L2422), [`ui/dr-ui/src/library_ui.rs:5519`](../ui/dr-ui/src/library_ui.rs#L5519), [`ui/dr-ui/src/library_ui.rs:5559`](../ui/dr-ui/src/library_ui.rs#L5559), [`ui/dr-ui/src/library_ui.rs:5588`](../ui/dr-ui/src/library_ui.rs#L5588), [`ui/dr-ui/src/library_ui.rs:5851`](../ui/dr-ui/src/library_ui.rs#L5851), [`ui/dr-ui/src/library_ui.rs:6074`](../ui/dr-ui/src/library_ui.rs#L6074), [`ui/dr-ui/src/library_ui.rs:6831`](../ui/dr-ui/src/library_ui.rs#L6831), [`ui/dr-ui/src/library_ui.rs:859`](../ui/dr-ui/src/library_ui.rs#L859), [`ui/dr-ui/src/library_ui.rs:892`](../ui/dr-ui/src/library_ui.rs#L892), [`ui/dr-ui/src/library_ui.rs:938`](../ui/dr-ui/src/library_ui.rs#L938), [`ui/dr-ui/src/place.rs:1`](../ui/dr-ui/src/place.rs#L1) |
-| NFR-A11Y-2 | [`ui/dr-ui/tests/ui_controls_are_accessible.rs:1`](../ui/dr-ui/tests/ui_controls_are_accessible.rs#L1), [`ui/dr-ui/ui/adjust.slint:170`](../ui/dr-ui/ui/adjust.slint#L170), [`ui/dr-ui/ui/app.slint:2561`](../ui/dr-ui/ui/app.slint#L2561), [`ui/dr-ui/ui/app.slint:2599`](../ui/dr-ui/ui/app.slint#L2599) |
+| NFR-A11Y-2 | [`ui/dr-ui/tests/ui_controls_are_accessible.rs:1`](../ui/dr-ui/tests/ui_controls_are_accessible.rs#L1), [`ui/dr-ui/ui/adjust.slint:171`](../ui/dr-ui/ui/adjust.slint#L171), [`ui/dr-ui/ui/app.slint:2420`](../ui/dr-ui/ui/app.slint#L2420), [`ui/dr-ui/ui/app.slint:2458`](../ui/dr-ui/ui/app.slint#L2458) |
| NFR-A11Y-3 | [`ui/dr-ui/src/histogram.rs:356`](../ui/dr-ui/src/histogram.rs#L356), [`ui/dr-ui/ui/histogram.slint:137`](../ui/dr-ui/ui/histogram.slint#L137), [`ui/dr-ui/ui/library.slint:761`](../ui/dr-ui/ui/library.slint#L761), [`ui/dr-ui/ui/library.slint:909`](../ui/dr-ui/ui/library.slint#L909), [`ui/dr-ui/ui/peaking.slint:1`](../ui/dr-ui/ui/peaking.slint#L1) |
| NFR-ARCH-2 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/library.rs:3385`](../ui/dr-ui/src/library.rs#L3385) |
-| NFR-ARCH-3 | [`ui/dr-ui/src/export.rs:1809`](../ui/dr-ui/src/export.rs#L1809), [`ui/dr-ui/src/export.rs:1836`](../ui/dr-ui/src/export.rs#L1836), [`ui/dr-ui/src/export.rs:412`](../ui/dr-ui/src/export.rs#L412), [`ui/dr-ui/src/export.rs:438`](../ui/dr-ui/src/export.rs#L438), [`ui/dr-ui/src/lib.rs:2594`](../ui/dr-ui/src/lib.rs#L2594), [`ui/dr-ui/ui/app.slint:1220`](../ui/dr-ui/ui/app.slint#L1220), [`ui/dr-ui/ui/library.slint:4251`](../ui/dr-ui/ui/library.slint#L4251) |
+| NFR-ARCH-3 | [`ui/dr-ui/src/export.rs:1809`](../ui/dr-ui/src/export.rs#L1809), [`ui/dr-ui/src/export.rs:1836`](../ui/dr-ui/src/export.rs#L1836), [`ui/dr-ui/src/export.rs:412`](../ui/dr-ui/src/export.rs#L412), [`ui/dr-ui/src/export.rs:438`](../ui/dr-ui/src/export.rs#L438), [`ui/dr-ui/src/lib.rs:2644`](../ui/dr-ui/src/lib.rs#L2644), [`ui/dr-ui/ui/app.slint:1006`](../ui/dr-ui/ui/app.slint#L1006), [`ui/dr-ui/ui/library.slint:4251`](../ui/dr-ui/ui/library.slint#L4251) |
| NFR-ARCH-4 | [`core/dr-catalog/src/error.rs:1`](../core/dr-catalog/src/error.rs#L1), [`core/dr-export/src/error.rs:1`](../core/dr-export/src/error.rs#L1), [`core/dr-thumbs/src/error.rs:1`](../core/dr-thumbs/src/error.rs#L1), [`core/dr-xmp/src/lib.rs:798`](../core/dr-xmp/src/lib.rs#L798), [`platform/dr-plat/src/storage.rs:148`](../platform/dr-plat/src/storage.rs#L148), [`ui/dr-ui/src/export.rs:514`](../ui/dr-ui/src/export.rs#L514) |
| NFR-OPS-1 | [`platform/dr-plat/src/diagnostics.rs:1`](../platform/dr-plat/src/diagnostics.rs#L1), [`platform/dr-plat/src/state.rs:1`](../platform/dr-plat/src/state.rs#L1) |
| NFR-OPS-2 | [`platform/dr-plat/src/crash.rs:1`](../platform/dr-plat/src/crash.rs#L1) |
| NFR-OPS-3 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) |
| NFR-P1 | [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/scan.rs:1`](../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/walk.rs:162`](../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`tools/bench/src/catalog_open.rs:1`](../tools/bench/src/catalog_open.rs#L1) |
| NFR-P13 | [`core/dr-decode/src/preview.rs:121`](../core/dr-decode/src/preview.rs#L121) |
-| NFR-P14 | [`core/dr-gpu/src/focus.rs:186`](../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`ui/dr-ui/src/develop.rs:3570`](../ui/dr-ui/src/develop.rs#L3570), [`ui/dr-ui/src/lib.rs:1916`](../ui/dr-ui/src/lib.rs#L1916) |
+| NFR-P14 | [`core/dr-gpu/src/focus.rs:186`](../core/dr-gpu/src/focus.rs#L186), [`core/dr-gpu/src/focus.rs:1`](../core/dr-gpu/src/focus.rs#L1), [`core/dr-gpu/src/focus.rs:317`](../core/dr-gpu/src/focus.rs#L317), [`core/dr-gpu/src/shaders/focus_peak.wgsl:1`](../core/dr-gpu/src/shaders/focus_peak.wgsl#L1), [`ui/dr-ui/src/develop.rs:3570`](../ui/dr-ui/src/develop.rs#L3570), [`ui/dr-ui/src/lib.rs:1960`](../ui/dr-ui/src/lib.rs#L1960) |
| NFR-P3 | [`tools/bench/src/thumbnails.rs:1`](../tools/bench/src/thumbnails.rs#L1) |
| NFR-P5 | [`core/dr-catalog/src/schema.rs:356`](../core/dr-catalog/src/schema.rs#L356), [`ui/dr-ui/src/library.rs:4663`](../ui/dr-ui/src/library.rs#L4663), [`ui/dr-ui/src/library.rs:5776`](../ui/dr-ui/src/library.rs#L5776), [`ui/dr-ui/src/library_ui.rs:4726`](../ui/dr-ui/src/library_ui.rs#L4726), [`ui/dr-ui/src/library_ui.rs:64`](../ui/dr-ui/src/library_ui.rs#L64) |
| NFR-P9 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/export.rs:992`](../ui/dr-ui/src/export.rs#L992), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1) |
diff --git a/ui/dr-ui/src/lib.rs b/ui/dr-ui/src/lib.rs
index 05c24ab..8fa2cdb 100644
--- a/ui/dr-ui/src/lib.rs
+++ b/ui/dr-ui/src/lib.rs
@@ -382,23 +382,25 @@ fn is_supported(p: &Path) -> bool {
/// rect chosen for the first — or, since local masking became a mode, would
/// open the next photograph with a mask stack it does not have.
fn reset_view_state(window: &AppWindow) {
- window.set_view_mode(ViewMode::Photo);
+ window.global::().set_view_mode(ViewMode::Photo);
window.set_zoom(1.0);
window.set_zoomed(false);
window.set_crop_x(0.0);
window.set_crop_y(0.0);
window.set_crop_w(1.0);
window.set_crop_h(1.0);
- window.set_max_straighten(dr_pipeline::framing::MAX_STRAIGHTEN);
- window.set_straighten(0.0);
- window.set_flip_h(false);
- window.set_flip_v(false);
- window.set_framing_modified(false);
+ let framing = window.global::();
+ framing.set_max_straighten(dr_pipeline::framing::MAX_STRAIGHTEN);
+ framing.set_angle(0.0);
+ framing.set_flip_h(false);
+ framing.set_flip_v(false);
+ framing.set_modified(false);
// A photograph that failed to decode has no session, so nothing below
// will speak for it — and the buttons would otherwise keep offering the
// previous image's history.
- window.set_can_undo(false);
- window.set_can_redo(false);
+ let steps = window.global::();
+ steps.set_can_undo(false);
+ steps.set_can_redo(false);
// TRACES: FR-DEV-7
// And the comparison goes down with them. Unlike the inspection point
// below it, this is not a way of looking at a folder: it is a question
@@ -411,17 +413,19 @@ fn reset_view_state(window: &AppWindow) {
// And an armed sampler goes down with it: a picker left waiting would make
// the first click on the *next* photograph sample it, which is a click
// nobody meant to spend.
- window.set_sampling_op(-1);
+ window.global::().set_sampling_op(-1);
// TRACES: FR-DSP-7
// Emptied rather than left standing: the previous photograph's histogram
// beside the next one's filename is a confident, precise lie, and the gap
// before the new frame settles is exactly long enough to read it.
- window.set_histogram(histogram::empty());
+ window.global::().set_data(histogram::empty());
// And the raw reading with it. It belongs to one file more completely than
// the display histogram does — nothing about the edit can move it — which
// makes leaving it standing over the next photograph's filename worse
// rather than better: it would look exactly as current as it is wrong.
- window.set_raw_histogram(histogram::raw_empty(histogram::RawAbsence::NoImage));
+ window
+ .global::()
+ .set_raw_data(histogram::raw_empty(histogram::RawAbsence::NoImage));
// TRACES: FR-CULL-3
// The marks go down with it, and for the same reason. What is *not* reset
// is whether peaking is switched on: that is a way of looking at a folder
@@ -521,10 +525,11 @@ fn sync_framing(window: &AppWindow, session: &Rc>
return;
};
let (angle, flip_h, flip_v, modified, crop) = s;
- window.set_straighten(angle);
- window.set_flip_h(flip_h);
- window.set_flip_v(flip_v);
- window.set_framing_modified(modified);
+ let framing = window.global::();
+ framing.set_angle(angle);
+ framing.set_flip_h(flip_h);
+ framing.set_flip_v(flip_v);
+ framing.set_modified(modified);
// The overlay draws from these, and a rotation re-expresses the rect —
// so they have to follow a quarter turn even though no handle moved.
window.set_crop_x(crop.x);
@@ -551,9 +556,10 @@ fn sync_crop_aspect(
.iter()
.position(|a| *a == chosen)
.unwrap_or(0);
- window.set_crop_aspect(index as i32);
- window.set_crop_portrait(portrait.get());
- window.set_crop_aspect_turnable(chosen.has_orientation());
+ let framing = window.global::();
+ framing.set_aspect(index as i32);
+ framing.set_portrait(portrait.get());
+ framing.set_aspect_turnable(chosen.has_orientation());
}
/// TRACES: FR-DEV-3
@@ -582,7 +588,7 @@ fn apply_crop_aspect(
window.set_crop_y(crop.y);
window.set_crop_w(crop.width);
window.set_crop_h(crop.height);
- window.set_framing_modified(modified);
+ window.global::().set_modified(modified);
}
/// TRACES: FR-EXP-6 | FR-EXP-9 | FR-EXP-7
@@ -816,15 +822,16 @@ pub(crate) fn sync_film(window: &AppWindow, session: &Rc();
+ adjustments.set_film_stocks(slint::ModelRc::new(slint::VecModel::from(
choices
.into_iter()
.map(|(_, name)| slint::SharedString::from(name))
.collect::>(),
)));
- window.set_film_selected(selected as i32);
- window.set_film_can_print(can_print);
- window.set_film_print(chosen.map(|(_, print)| print).unwrap_or(false));
+ adjustments.set_film_selected(selected as i32);
+ adjustments.set_film_can_print(can_print);
+ adjustments.set_film_print(chosen.map(|(_, print)| print).unwrap_or(false));
}
pub(crate) fn sync_rows(
@@ -861,8 +868,10 @@ pub(crate) fn sync_rows(
),
None => (Vec::::new(), -1),
};
- window.set_adjust_tabs(slint::ModelRc::new(slint::VecModel::from(tabs)));
- window.set_adjust_active_tab(active_tab);
+ window
+ .global::()
+ .set_tabs(slint::ModelRc::new(slint::VecModel::from(tabs)));
+ window.global::().set_active_tab(active_tab);
let current = match session.borrow().as_ref() {
Some(s) => s.rows(),
@@ -920,7 +929,9 @@ pub(crate) fn sync_rows(
Some(s) => s.curve_channels().into_iter().map(Into::into).collect(),
None => Vec::new(),
};
- window.set_curve_channels(slint::ModelRc::new(slint::VecModel::from(channels)));
+ window
+ .global::()
+ .set_curve_channels(slint::ModelRc::new(slint::VecModel::from(channels)));
}
// Which curve is plotted, on every pass. Picking one that happens to be
@@ -928,7 +939,7 @@ pub(crate) fn sync_rows(
// moves no point, so this cannot ride on the resample below: the chips
// would go on highlighting the curve the user just navigated away from.
let channel = session.borrow().as_ref().map_or(0, |s| s.curve_channel());
- window.set_curve_channel(channel);
+ window.global::().set_curve_channel(channel);
if !curve_moved {
return;
@@ -941,7 +952,9 @@ pub(crate) fn sync_rows(
// The drawn curve follows the points. Replacing this model wholesale is
// safe where replacing `rows` was not: nothing in it is a drag target.
- window.set_curve_samples(slint::ModelRc::new(slint::VecModel::from(samples)));
+ window
+ .global::()
+ .set_curve_samples(slint::ModelRc::new(slint::VecModel::from(samples)));
}
/// Copy `fresh`'s values into `existing`, keeping the model identity.
@@ -1712,7 +1725,7 @@ pub fn run(paths: Vec) -> Result<()> {
// One model for the lifetime of the window. Rows are mutated in place;
// see `sync_rows` for why replacing it breaks dragging.
let rows: Rc> = Rc::new(slint::VecModel::default());
- window.set_adjust_rows(rows.clone().into());
+ window.global::().set_rows(rows.clone().into());
// Viewport size, tracked so a re-render after a slider move matches it.
//
// In *physical* pixels, which is what the render target wants and what
@@ -1799,8 +1812,9 @@ pub fn run(paths: Vec) -> Result<()> {
// edit ends in a redraw and nothing else is on all of their paths:
// the parameter callbacks sync rows, the framing ones sync the
// geometry panel, and a paste arrives through neither.
- window.set_can_undo(s.can_undo());
- window.set_can_redo(s.can_redo());
+ let steps = window.global::();
+ steps.set_can_undo(s.can_undo());
+ steps.set_can_redo(s.can_redo());
// TRACES: FR-DEV-5 | FR-DEV-7
// The list, on the same path and for the same reason — but only
@@ -1811,9 +1825,8 @@ pub fn run(paths: Vec) -> Result<()> {
let revision = s.history_revision();
if drawn_history.get() != Some(revision) {
drawn_history.set(Some(revision));
- window
- .set_history_rows(slint::ModelRc::new(slint::VecModel::from(s.history_rows())));
- window.set_undo_label(s.undo_label().into());
+ steps.set_rows(slint::ModelRc::new(slint::VecModel::from(s.history_rows())));
+ steps.set_undo_label(s.undo_label().into());
}
// TRACES: FR-DEV-3
@@ -1843,7 +1856,9 @@ pub fn run(paths: Vec) -> Result<()> {
if s.peaking() != chosen_peaking.get() {
s.set_peaking(chosen_peaking.get());
}
- window.set_peaking_available(s.peaking_available());
+ window
+ .global::()
+ .set_available(s.peaking_available());
let (mut w, mut h) = *viewport.borrow();
@@ -1872,7 +1887,7 @@ pub fn run(paths: Vec) -> Result<()> {
// Crop mode shows the whole frame, or the area being cropped away
// would not be on screen for the handles to drag across. The
// overlay draws the rect on top of it.
- let rendered = if window.get_view_mode() == ViewMode::Crop {
+ let rendered = if window.global::().get_view_mode() == ViewMode::Crop {
s.render_uncropped(w, h).map(|(image, _, _)| image)
} else if window.get_showing_original() {
s.render_original(w, h)
@@ -1909,7 +1924,7 @@ pub fn run(paths: Vec) -> Result<()> {
// half-resolution frame flickering past under a finger is
// not a reading anyone takes.
if !draft {
- window.set_histogram(
+ window.global::().set_data(
s.histogram()
.as_ref()
.map_or_else(histogram::empty, histogram::view),
@@ -1939,7 +1954,7 @@ pub fn run(paths: Vec) -> Result<()> {
histogram::raw_view,
)
};
- window.set_raw_histogram(raw);
+ window.global::().set_raw_data(raw);
}
// TRACES: FR-CULL-3 | NFR-P14
@@ -1975,7 +1990,7 @@ pub fn run(paths: Vec) -> Result<()> {
window.set_load_error(e.into());
// No frame, so nothing to describe. The stale plot would
// otherwise sit beside the error message looking current.
- window.set_histogram(histogram::empty());
+ window.global::().set_data(histogram::empty());
// **The raw reading is left standing, and that is not an
// oversight.** It describes the sensor data behind the
// session, which a failed *render* says nothing about: the
@@ -2124,16 +2139,17 @@ pub fn run(paths: Vec) -> Result<()> {
match load(gpu.as_ref(), path) {
Ok(l) => {
window.set_load_error("".into());
- window.set_camera(describe_camera(&l.meta).into());
- window.set_exposure(describe_exposure(&l.meta).into());
- window.set_dimensions(format!("{} × {}", l.width, l.height).into());
+ let capture = window.global::();
+ capture.set_camera(describe_camera(&l.meta).into());
+ capture.set_exposure(describe_exposure(&l.meta).into());
+ capture.set_dimensions(format!("{} × {}", l.width, l.height).into());
// Composed by the session rather than here, because only it
// knows whether the lookup found anything — the header can
// name a lens the database has never heard of, which is the
// ordinary case for third-party and adapted glass and must
// read as a fact rather than as a failure.
- window.set_lens(
+ capture.set_lens(
l.session
.as_ref()
.map(|s| s.lens_summary())
@@ -2145,7 +2161,7 @@ pub fn run(paths: Vec) -> Result<()> {
// this code names no operation (FR-DEV-3a).
match l.session {
Some(s) => {
- window.set_adjust_enabled(true);
+ window.global::().set_enabled(true);
*session.borrow_mut() = Some(s);
// A local file stores its edit beside itself. Read
@@ -2178,7 +2194,7 @@ pub fn run(paths: Vec) -> Result<()> {
*session.borrow_mut() = None;
*open_image.borrow_mut() = presets::Stored::Nowhere;
rows.set_vec(Vec::::new());
- window.set_adjust_enabled(false);
+ window.global::().set_enabled(false);
if let Some(image) = l.fallback {
window.set_canvas(image);
}
@@ -2190,12 +2206,13 @@ pub fn run(paths: Vec) -> Result<()> {
// A failure on one image must not stop browsing (FR-RAW-4).
log::warn!("{name}: {e}");
*session.borrow_mut() = None;
- window.set_adjust_enabled(false);
+ window.global::().set_enabled(false);
window.set_load_error(e.into());
- window.set_camera("".into());
- window.set_exposure("".into());
- window.set_dimensions("".into());
- window.set_lens("".into());
+ let capture = window.global::();
+ capture.set_camera("".into());
+ capture.set_exposure("".into());
+ capture.set_dimensions("".into());
+ capture.set_lens("".into());
}
}
})
@@ -2229,9 +2246,10 @@ pub fn run(paths: Vec) -> Result<()> {
reset_view_state(&w);
w.set_filename(name.clone().into());
w.set_load_error("".into());
- w.set_camera("".into());
- w.set_exposure("".into());
- w.set_dimensions("".into());
+ let capture = w.global::();
+ capture.set_camera("".into());
+ capture.set_exposure("".into());
+ capture.set_dimensions("".into());
// The grid is one image at a time, so next/previous have nothing
// to walk. Shown as 1 of 1 rather than left reading 0.
w.set_index(0);
@@ -2345,12 +2363,13 @@ pub fn run(paths: Vec) -> Result<()> {
match load_bytes(gpu.as_ref(), &bytes) {
Ok(l) => {
w.set_load_error("".into());
- w.set_camera(describe_camera(&l.meta).into());
- w.set_exposure(describe_exposure(&l.meta).into());
- w.set_dimensions(format!("{} × {}", l.width, l.height).into());
+ let capture = w.global::();
+ capture.set_camera(describe_camera(&l.meta).into());
+ capture.set_exposure(describe_exposure(&l.meta).into());
+ capture.set_dimensions(format!("{} × {}", l.width, l.height).into());
match l.session {
Some(mut s) => {
- w.set_adjust_enabled(true);
+ w.global::().set_enabled(true);
// TRACES: FR-CULL-10
// Who is in this photograph, so a
// segmentation run can say "Anna" where
@@ -2409,7 +2428,7 @@ pub fn run(paths: Vec) -> Result<()> {
None => {
*session.borrow_mut() = None;
rows.set_vec(Vec::::new());
- w.set_adjust_enabled(false);
+ w.global::().set_enabled(false);
if let Some(image) = l.fallback {
w.set_canvas(image);
}
@@ -2420,7 +2439,7 @@ pub fn run(paths: Vec) -> Result<()> {
Err(e) => {
log::warn!("{name}: {e}");
*session.borrow_mut() = None;
- w.set_adjust_enabled(false);
+ w.global::().set_enabled(false);
w.set_load_error(e.into());
}
}
@@ -2490,7 +2509,9 @@ pub fn run(paths: Vec) -> Result<()> {
// Rendered from the same settings controller and at the same moment,
// so the rail and the strip cannot both be on screen after a change to
// the preference that chooses between them.
- window.set_groups_in_rail(groups_in_rail(&settings));
+ window
+ .global::()
+ .set_groups_in_rail(groups_in_rail(&settings));
presets::render(&window, &clipboard, &settings);
}
@@ -2640,35 +2661,39 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_param_changed(move |op, param, value| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_param(op, param, value);
- // TRACES: FR-DEV-3f
- // The film's own exposures ride *inside* the baked tables
- // rather than arriving as uniforms, because the print balance
- // is solved against them — an enlarger's filtration depends on
- // how the negative was exposed. So moving one has to rebuild
- // the lookup, which no other slider in the panel does.
- s.rebake_film_if_affected(op);
- }
- sync_rows(&w, &rows, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_param_changed(move |op, param, value| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_param(op, param, value);
+ // TRACES: FR-DEV-3f
+ // The film's own exposures ride *inside* the baked tables
+ // rather than arriving as uniforms, because the print balance
+ // is solved against them — an enlarger's filtration depends on
+ // how the negative was exposed. So moving one has to rebuild
+ // the lookup, which no other slider in the panel does.
+ s.rebake_film_if_affected(op);
+ }
+ sync_rows(&w, &rows, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_param_reset(move |op, param| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.reset_param(op, param);
- }
- sync_rows(&w, &rows, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_param_reset(move |op, param| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.reset_param(op, param);
+ }
+ sync_rows(&w, &rows, &session);
+ redraw(&w);
+ });
}
// TRACES: FR-DEV-3
// The local-adjustment panel. Wired as a block rather than inline because
@@ -2680,7 +2705,7 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let rows = rows.clone();
- window.on_adjust_tab_picked(move |index| {
+ window.global::().on_tab_picked(move |index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_active_tab(index);
@@ -2707,7 +2732,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_reset_all(move || {
+ window.global::().on_reset_all(move || {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.reset_all();
@@ -2724,7 +2749,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_curve_reset(move |op| {
+ window.global::().on_curve_reset(move |op| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.reset_curve(op);
@@ -2743,13 +2768,15 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let rows = rows.clone();
- window.on_curve_channel_picked(move |index| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_curve_channel(index);
- }
- sync_rows(&w, &rows, &session);
- });
+ window
+ .global::()
+ .on_curve_channel_picked(move |index| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_curve_channel(index);
+ }
+ sync_rows(&w, &rows, &session);
+ });
}
// ---- the film stock (FR-DEV-3f) -------------------------------------
@@ -2762,7 +2789,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_film_picked(move |index| {
+ window.global::().on_film_picked(move |index| {
let Some(w) = weak.upgrade() else { return };
// Index zero is "None" — see `DevelopSession::film_choices`, which
// puts it first so that the neutral choice needs no sentinel.
@@ -2790,16 +2817,18 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_film_print_toggled(move |print| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- if let Some((stock, _)) = s.film().map(|(a, b)| (a.to_string(), b)) {
- s.pick_film(Some(&stock), print);
+ window
+ .global::()
+ .on_film_print_toggled(move |print| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ if let Some((stock, _)) = s.film().map(|(a, b)| (a.to_string(), b)) {
+ s.pick_film(Some(&stock), print);
+ }
}
- }
- sync_film(&w, &session);
- redraw(&w);
- });
+ sync_film(&w, &session);
+ redraw(&w);
+ });
}
// ---- undo and redo (FR-DEV-5) ---------------------------------------
@@ -2816,7 +2845,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_undo(move || {
+ window.global::().on_undo(move || {
let Some(w) = weak.upgrade() else { return };
let stepped = session.borrow_mut().as_mut().is_some_and(|s| s.undo());
if stepped {
@@ -2830,7 +2859,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_redo(move || {
+ window.global::().on_redo(move || {
let Some(w) = weak.upgrade() else { return };
let stepped = session.borrow_mut().as_mut().is_some_and(|s| s.redo());
if stepped {
@@ -2909,7 +2938,7 @@ pub fn run(paths: Vec) -> Result<()> {
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_history_picked(move |index| {
+ window.global::().on_picked(move |index| {
let Some(w) = weak.upgrade() else { return };
let stepped = session
.borrow_mut()
@@ -2939,7 +2968,7 @@ pub fn run(paths: Vec) -> Result<()> {
// the pipeline needs and the whole of what another application could read.
let crop_aspect = Rc::new(Cell::new(develop::CropAspect::default()));
let crop_portrait = Rc::new(Cell::new(false));
- window.set_crop_aspects(
+ window.global::().set_aspects(
develop::CropAspect::CHOICES
.iter()
.map(|a| slint::SharedString::from(a.label()))
@@ -3073,7 +3102,7 @@ pub fn run(paths: Vec) -> Result<()> {
}
}
}
- w.set_view_mode(mode);
+ w.global::().set_view_mode(mode);
masks_ui::sync(&w, &session);
if let Some(s) = session.borrow().as_ref() {
spots_ui::sync_handles(&w, s);
@@ -3126,7 +3155,7 @@ pub fn run(paths: Vec) -> Result<()> {
w.set_crop_y(c.y);
w.set_crop_w(c.width);
w.set_crop_h(c.height);
- w.set_framing_modified(s.framing_edits_image());
+ w.global::().set_modified(s.framing_edits_image());
}
redraw(&w);
});
@@ -3145,7 +3174,7 @@ pub fn run(paths: Vec) -> Result<()> {
let redraw = redraw.clone();
let crop_aspect = crop_aspect.clone();
let crop_portrait = crop_portrait.clone();
- window.on_crop_aspect_picked(move |index| {
+ window.global::().on_aspect_picked(move |index| {
let Some(w) = weak.upgrade() else { return };
let Some(&aspect) = develop::CropAspect::CHOICES.get(index.max(0) as usize) else {
return;
@@ -3167,7 +3196,7 @@ pub fn run(paths: Vec) -> Result<()> {
let redraw = redraw.clone();
let crop_aspect = crop_aspect.clone();
let crop_portrait = crop_portrait.clone();
- window.on_crop_portrait_toggled(move || {
+ window.global::().on_portrait_toggled(move || {
let Some(w) = weak.upgrade() else { return };
if !crop_aspect.get().has_orientation() {
return;
@@ -3191,7 +3220,7 @@ pub fn run(paths: Vec) -> Result<()> {
let redraw = redraw.clone();
let crop_aspect = crop_aspect.clone();
let crop_portrait = crop_portrait.clone();
- window.on_rotate_quarters(move |turns| {
+ window.global::().on_rotate(move |turns| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.rotate_quarters(turns);
@@ -3214,7 +3243,7 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_flip_h_toggled(move || {
+ window.global::().on_flip_h_toggled(move || {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.toggle_flip_h();
@@ -3227,7 +3256,7 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_flip_v_toggled(move || {
+ window.global::().on_flip_v_toggled(move || {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.toggle_flip_v();
@@ -3240,7 +3269,7 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_straighten_changed(move |degrees| {
+ window.global::().on_angle_changed(move |degrees| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_angle(degrees);
@@ -3270,18 +3299,20 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_straighten_committed(move |_degrees| {
- // The angle itself is already applied: `SliderTrack` emits its
- // last `changed` before it commits, so `on_straighten_changed` has
- // run with this very value. What is left is the correction that
- // has to happen exactly once.
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.auto_crop_to_angle();
- }
- sync_framing(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_angle_committed(move |_degrees| {
+ // The angle itself is already applied: `SliderTrack` emits its
+ // last `changed` before it commits, so `on_straighten_changed` has
+ // run with this very value. What is left is the correction that
+ // has to happen exactly once.
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.auto_crop_to_angle();
+ }
+ sync_framing(&w, &session);
+ redraw(&w);
+ });
}
{
// The geometry section's reset: crop, angle, rotation and flips back
@@ -3290,7 +3321,7 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_framing_reset(move || {
+ window.global::().on_reset(move || {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.reset_framing();
@@ -3383,18 +3414,18 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let chosen = chosen_peaking.clone();
let redraw = redraw.clone();
- window.on_peaking_toggled(move |on| {
+ window.global::().on_toggled(move |on| {
let Some(w) = weak.upgrade() else { return };
// Built from the chips as they currently stand rather than from a
// remembered value: they are what the photographer can see, and an
// overlay that came back in a configuration the panel is not
// showing would be the panel lying about itself.
let next = on.then(|| dr_gpu::FocusPeaking {
- sensitivity: peaking::sensitivity(w.get_peaking_sensitivity()),
- colour: peaking::colour(w.get_peaking_colour()),
+ sensitivity: peaking::sensitivity(w.global::().get_sensitivity()),
+ colour: peaking::colour(w.global::().get_colour()),
});
chosen.set(next);
- w.set_peaking_on(next.is_some());
+ w.global::().set_showing(next.is_some());
redraw(&w);
});
}
@@ -3402,27 +3433,29 @@ pub fn run(paths: Vec) -> Result<()> {
let weak = window.as_weak();
let chosen = chosen_peaking.clone();
let redraw = redraw.clone();
- window.on_peaking_sensitivity_picked(move |index| {
- let Some(w) = weak.upgrade() else { return };
- w.set_peaking_sensitivity(index);
- // Only reachable while peaking is on — the chips are not drawn
- // otherwise — but written as a conditional rather than an
- // `expect`, because a panel is free to change its mind about that
- // and nothing here should fall over when it does.
- if let Some(mut current) = chosen.get() {
- current.sensitivity = peaking::sensitivity(index);
- chosen.set(Some(current));
- redraw(&w);
- }
- });
+ window
+ .global::()
+ .on_sensitivity_picked(move |index| {
+ let Some(w) = weak.upgrade() else { return };
+ w.global::().set_sensitivity(index);
+ // Only reachable while peaking is on — the chips are not drawn
+ // otherwise — but written as a conditional rather than an
+ // `expect`, because a panel is free to change its mind about that
+ // and nothing here should fall over when it does.
+ if let Some(mut current) = chosen.get() {
+ current.sensitivity = peaking::sensitivity(index);
+ chosen.set(Some(current));
+ redraw(&w);
+ }
+ });
}
{
let weak = window.as_weak();
let chosen = chosen_peaking.clone();
let redraw = redraw.clone();
- window.on_peaking_colour_picked(move |index| {
+ window.global::().on_colour_picked(move |index| {
let Some(w) = weak.upgrade() else { return };
- w.set_peaking_colour(index);
+ w.global::().set_colour(index);
if let Some(mut current) = chosen.get() {
current.colour = peaking::colour(index);
chosen.set(Some(current));
@@ -3432,8 +3465,12 @@ pub fn run(paths: Vec) -> Result<()> {
}
// The chips open on whatever the vocabulary calls its default, so the
// panel and the pass agree before anything has been pressed.
- window.set_peaking_sensitivity(peaking::sensitivity_index(Default::default()));
- window.set_peaking_colour(peaking::colour_index(Default::default()));
+ window
+ .global::()
+ .set_sensitivity(peaking::sensitivity_index(Default::default()));
+ window
+ .global::()
+ .set_colour(peaking::colour_index(Default::default()));
// TRACES: FR-DSP-8 | FR-DSP-6
// And which display that canvas is on, from now until the window closes.
@@ -3831,7 +3868,7 @@ fn back_one_step(w: &AppWindow) -> bool {
launch: w.get_show_launch(),
browsing: w.get_launch_browsing(),
library: w.get_show_library(),
- mode: w.get_view_mode(),
+ mode: w.global::().get_view_mode(),
zoomed: w.get_zoomed(),
// Files named on the command line have no grid behind them — the same
// condition the status strip uses to decide whether to offer the way
diff --git a/ui/dr-ui/src/masks_ui.rs b/ui/dr-ui/src/masks_ui.rs
index 9570f42..e699735 100644
--- a/ui/dr-ui/src/masks_ui.rs
+++ b/ui/dr-ui/src/masks_ui.rs
@@ -31,7 +31,8 @@ use slint::{ComponentHandle as _, Model as _, ModelRc, VecModel};
use crate::develop::{Abandon, DevelopSession, RefinedInstance, Segmented, SessionId};
use crate::segmentation;
use crate::{
- sync_rows, AppWindow, CategoryRow, GradientHandle, MaskRow, ParamRow, PartRow, SubjectRow,
+ sync_rows, Adjustments, AppWindow, CategoryRow, GradientHandle, MaskRow, Masking, ParamRow,
+ PartRow, Steps, SubjectRow,
};
/// What the adjust panel's heading says when the controls are global.
@@ -166,12 +167,15 @@ fn category_label(name: &str) -> String {
/// Push every mask-related property from the session into the window.
pub(crate) fn sync(window: &AppWindow, session: &Rc>>) {
let slot = session.borrow();
+ let masking = window.global::();
let Some(s) = slot.as_ref() else {
- window.set_mask_rows(ModelRc::new(VecModel::::default()));
- window.set_subject_rows(ModelRc::new(VecModel::::default()));
- window.set_category_rows(ModelRc::new(VecModel::::default()));
- window.set_segmented(false);
- window.set_adjust_scope(GLOBAL_SCOPE.into());
+ masking.set_masks(ModelRc::new(VecModel::::default()));
+ masking.set_subjects(ModelRc::new(VecModel::::default()));
+ masking.set_categories(ModelRc::new(VecModel::::default()));
+ masking.set_segmented(false);
+ window
+ .global::()
+ .set_scope(GLOBAL_SCOPE.into());
clear_handles(window);
window.set_overlay_on(false);
return;
@@ -213,7 +217,7 @@ pub(crate) fn sync(window: &AppWindow, session: &Rc = s
.detected_subjects()
@@ -225,7 +229,7 @@ pub(crate) fn sync(window: &AppWindow, session: &Rc Vec::new(),
};
- window.set_mask_parts(ModelRc::new(VecModel::from(parts)));
+ masking.set_parts(ModelRc::new(VecModel::from(parts)));
let (radius, hardness, flow) = s.brush();
- window.set_brush_radius(radius);
- window.set_brush_hardness(hardness);
- window.set_brush_flow(flow);
+ masking.set_brush_radius(radius);
+ masking.set_brush_hardness(hardness);
+ masking.set_brush_flow(flow);
- window.set_segmented(s.has_segmentation());
- window.set_adjust_scope(scope_label(s).into());
+ masking.set_segmented(s.has_segmentation());
+ window
+ .global::()
+ .set_scope(scope_label(s).into());
sync_handles(window, s);
// The overlay is regenerated only when there is one to draw. It is a
@@ -382,7 +388,7 @@ pub(crate) fn wire(
let redraw = redraw.clone();
let rows = rows.clone();
let running = running.clone();
- window.on_segment_image(move |fine| {
+ window.global::().on_segment(move |fine| {
let Some(w) = weak.upgrade() else { return };
// Both the photograph and the device come out of the session, so
// no session is nothing to look at and nothing to look with.
@@ -399,7 +405,7 @@ pub(crate) fn wire(
// Set before the thread rather than by it, so there is no moment
// in which the press has been taken and nothing on screen says so.
// The button reads "Looking…" and goes insensitive off this.
- w.set_segmenting(true);
+ w.global::().set_segmenting(true);
let (tx, rx) = std::sync::mpsc::channel();
// The only thing the button decides. Everything else about the
@@ -433,7 +439,7 @@ pub(crate) fn wire(
let redraw = redraw.clone();
let rows = rows.clone();
let running = refining.clone();
- window.on_mask_refined(move |id| {
+ window.global::().on_mask_refined(move |id| {
let Some(w) = weak.upgrade() else { return };
let Some(index) = session
.borrow()
@@ -452,7 +458,7 @@ pub(crate) fn wire(
return;
}
- w.set_refining(true);
+ w.global::().set_refining(true);
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
@@ -515,8 +521,10 @@ pub(crate) fn wire(
s.commit_gradient_drag();
}
if let Some(w) = weak.upgrade() {
- w.set_can_undo(session.borrow().as_ref().is_some_and(|s| s.can_undo()));
- w.set_can_redo(session.borrow().as_ref().is_some_and(|s| s.can_redo()));
+ w.global::()
+ .set_can_undo(session.borrow().as_ref().is_some_and(|s| s.can_undo()));
+ w.global::()
+ .set_can_redo(session.borrow().as_ref().is_some_and(|s| s.can_redo()));
}
});
}
@@ -551,40 +559,42 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let rows = rows.clone();
- window.on_mask_selected(move |id, extend| {
- let Some(w) = weak.upgrade() else { return };
- {
- let mut slot = session.borrow_mut();
- let Some(s) = slot.as_mut() else { return };
- if extend {
- // Control/command-click: add or remove this one layer,
- // keeping whatever else was already selected.
- s.toggle_active_mask(&id);
- } else if s.active_masks() == [id.to_string()] {
- // Clicking the sole selected layer again deselects it,
- // which is how the panel gets back to the whole
- // photograph without a separate "edit globally" control.
- // Only when it is the *only* one selected — a plain click
- // on one row of a multi-selection collapses to just that
- // row rather than clearing everything, which is the more
- // useful reading of "I clicked a specific layer".
- s.set_active_mask(None);
- } else {
- s.set_active_mask(Some(&id));
+ window
+ .global::()
+ .on_mask_selected(move |id, extend| {
+ let Some(w) = weak.upgrade() else { return };
+ {
+ let mut slot = session.borrow_mut();
+ let Some(s) = slot.as_mut() else { return };
+ if extend {
+ // Control/command-click: add or remove this one layer,
+ // keeping whatever else was already selected.
+ s.toggle_active_mask(&id);
+ } else if s.active_masks() == [id.to_string()] {
+ // Clicking the sole selected layer again deselects it,
+ // which is how the panel gets back to the whole
+ // photograph without a separate "edit globally" control.
+ // Only when it is the *only* one selected — a plain click
+ // on one row of a multi-selection collapses to just that
+ // row rather than clearing everything, which is the more
+ // useful reading of "I clicked a specific layer".
+ s.set_active_mask(None);
+ } else {
+ s.set_active_mask(Some(&id));
+ }
}
- }
- sync(&w, &session);
- // The scope changed, so the adjust panel below is now describing a
- // different chain.
- sync_rows(&w, &rows, &session);
- });
+ sync(&w, &session);
+ // The scope changed, so the adjust panel below is now describing a
+ // different chain.
+ sync_rows(&w, &rows, &session);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_mask_removed(move |id| {
+ window.global::().on_mask_removed(move |id| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.remove_mask(&id);
@@ -598,7 +608,7 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_toggled(move |id, on| {
+ window.global::().on_mask_toggled(move |id, on| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_enabled(&id, on);
@@ -611,27 +621,31 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_invert_toggled(move |id, on| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_invert(&id, on);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_invert_toggled(move |id, on| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_invert(&id, on);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_opacity_changed(move |id, value| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_opacity(&id, value);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_opacity_changed(move |id, value| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_opacity(&id, value);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
// --- the edge treatment -------------------------------------------------
@@ -643,14 +657,16 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_feather_changed(move |id, value| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_feather(&id, value);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_feather_changed(move |id, value| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_feather(&id, value);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
// TRACES: FR-DEV-10
// A range mask's band, and a colour range's arc.
@@ -667,27 +683,31 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_band_changed(move |id, lo, hi, softness| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_band(&id, lo, hi, softness);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_band_changed(move |id, lo, hi, softness| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_band(&id, lo, hi, softness);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_hue_changed(move |id, hue, width| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_hue(&id, hue, width);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_hue_changed(move |id, hue, width| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_hue(&id, hue, width);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
// The refine control. Same shape as the feather's handler, and a separate
// one for the same reason every other mask control has its own: the
@@ -700,53 +720,61 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_refine_changed(move |id, value| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_refine(&id, value);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_refine_changed(move |id, value| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_refine(&id, value);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_falloff_picked(move |id, index| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_falloff(&id, index.max(0) as usize);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_falloff_picked(move |id, index| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_falloff(&id, index.max(0) as usize);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_morphology_picked(move |id, index| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_morphology(&id, index.max(0) as usize);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_morphology_picked(move |id, index| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_morphology(&id, index.max(0) as usize);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
{
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_morph_radius_changed(move |id, value| {
- let Some(w) = weak.upgrade() else { return };
- if let Some(s) = session.borrow_mut().as_mut() {
- s.set_mask_morph_radius(&id, value);
- }
- sync(&w, &session);
- redraw(&w);
- });
+ window
+ .global::()
+ .on_mask_morph_radius_changed(move |id, value| {
+ let Some(w) = weak.upgrade() else { return };
+ if let Some(s) = session.borrow_mut().as_mut() {
+ s.set_mask_morph_radius(&id, value);
+ }
+ sync(&w, &session);
+ redraw(&w);
+ });
}
// --- adding layers ------------------------------------------------------
@@ -761,7 +789,7 @@ pub(crate) fn wire(
let redraw = redraw.clone();
window.on_paint_began(move |x, y| {
let Some(w) = weak.upgrade() else { return };
- let erase = w.get_mask_tool() == 2;
+ let erase = w.global::().get_tool() == 2;
if let Some(s) = session.borrow_mut().as_mut() {
s.begin_mask_stroke(x, y, erase);
}
@@ -800,7 +828,7 @@ pub(crate) fn wire(
{
let weak = window.as_weak();
let session = session.clone();
- window.on_brush_changed(move |radius, hardness, flow| {
+ window.global::().on_brush_changed(move |radius, hardness, flow| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_brush(radius, hardness, flow);
@@ -811,7 +839,7 @@ pub(crate) fn wire(
{
let weak = window.as_weak();
let session = session.clone();
- window.on_mask_tool_picked(move |_tool| {
+ window.global::().on_tool_picked(move |_tool| {
// The tool itself lives in the interface — it arms a gesture and
// changes no pixel — so nothing is set here. What this does is
// re-sync, because arming the brush is what makes the parts of a
@@ -826,7 +854,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_mask_part_selected(move |_id, index| {
+ window.global::().on_part_selected(move |_id, index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_active_part(index.max(0) as usize);
@@ -841,7 +869,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_mask_part_added(move |id, join| {
+ window.global::().on_part_added(move |id, join| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.add_mask_part(&id, join.max(0) as usize);
@@ -849,8 +877,8 @@ pub(crate) fn wire(
// Armed, because adding an empty painted part and leaving the
// pointer in "select" would look like the button did nothing —
// the part covers no pixels until something is painted into it.
- if w.get_mask_tool() == 0 {
- w.set_mask_tool(1);
+ if w.global::().get_tool() == 0 {
+ w.global::().set_tool(1);
}
sync(&w, &session);
sync_rows(&w, &rows, &session);
@@ -862,7 +890,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_mask_part_removed(move |id, index| {
+ window.global::().on_part_removed(move |id, index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.remove_mask_part(&id, index.max(0) as usize);
@@ -876,7 +904,7 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_mask_part_join_picked(move |id, index, join| {
+ window.global::().on_part_join_picked(move |id, index, join| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.set_mask_part_join(&id, index.max(0) as usize, join.max(0) as usize);
@@ -890,7 +918,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_add_gradient_mask(move |radial| {
+ window.global::().on_add_gradient(move |radial| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.add_gradient_mask(radial);
@@ -906,7 +934,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_add_range_mask(move |chromatic| {
+ window.global::().on_add_range(move |chromatic| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.add_range_mask(chromatic);
@@ -921,7 +949,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_add_category_mask(move |name| {
+ window.global::().on_add_category(move |name| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.add_category_mask(&name);
@@ -937,7 +965,7 @@ pub(crate) fn wire(
let session = session.clone();
let redraw = redraw.clone();
let rows = rows.clone();
- window.on_add_subject_mask(move |index| {
+ window.global::().on_add_subject(move |index| {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow_mut().as_mut() {
s.add_subject_mask(index.max(0) as usize);
@@ -1012,7 +1040,7 @@ fn watch(
Ok(None) => {}
Err(e) => log::warn!("segmentation failed: {e}"),
}
- w.set_segmenting(false);
+ w.global::().set_segmenting(false);
sync(&w, &session);
sync_rows(&w, &rows, &session);
redraw(&w);
@@ -1069,7 +1097,7 @@ fn watch_refine(
Ok(None) => {}
Err(e) => log::warn!("refine failed: {e}"),
}
- w.set_refining(false);
+ w.global::().set_refining(false);
sync(&w, &session);
sync_rows(&w, &rows, &session);
redraw(&w);
@@ -1087,13 +1115,16 @@ fn watch_refine(
/// follows the view mode, which `reset_view_state` returns to `photo`.
pub(crate) fn reset(window: &AppWindow) {
window.set_overlay_on(false);
- window.set_segmenting(false);
- window.set_refining(false);
- window.set_segmented(false);
- window.set_mask_rows(ModelRc::new(VecModel::::default()));
- window.set_subject_rows(ModelRc::new(VecModel::::default()));
- window.set_category_rows(ModelRc::new(VecModel::::default()));
- window.set_adjust_scope(GLOBAL_SCOPE.into());
+ let masking = window.global::();
+ masking.set_segmenting(false);
+ masking.set_refining(false);
+ masking.set_segmented(false);
+ masking.set_masks(ModelRc::new(VecModel::::default()));
+ masking.set_subjects(ModelRc::new(VecModel::::default()));
+ masking.set_categories(ModelRc::new(VecModel::::default()));
+ window
+ .global::()
+ .set_scope(GLOBAL_SCOPE.into());
clear_handles(window);
}
diff --git a/ui/dr-ui/src/presets.rs b/ui/dr-ui/src/presets.rs
index e29d88a..187cf43 100644
--- a/ui/dr-ui/src/presets.rs
+++ b/ui/dr-ui/src/presets.rs
@@ -40,7 +40,7 @@ use slint::ComponentHandle;
use crate::develop::DevelopSession;
use crate::preset_store::PresetStore;
-use crate::{library, library_ui, settings_ui, AppWindow, ParamRow, ScopeKind};
+use crate::{library, library_ui, settings_ui, AppWindow, ParamRow, ScopeKind, Steps, Transfer};
/// Where the develop view's current edit is stored.
///
@@ -502,8 +502,8 @@ fn refresh_thumbnail_for(
session: &Rc>>,
library: &Rc,
) {
- let worth_it =
- window.get_can_undo() || session.borrow().as_ref().is_some_and(|s| !s.is_neutral());
+ let worth_it = window.global::().get_can_undo()
+ || session.borrow().as_ref().is_some_and(|s| !s.is_neutral());
if !worth_it {
return;
}
@@ -557,12 +557,13 @@ pub fn render(
settings: &Rc,
) {
let scope = scope_for(&settings.snapshot());
- window.set_settings_armed(clipboard.is_armed());
- window.set_settings_summary(clipboard.describe(scope).into());
+ let transfer = window.global::();
+ transfer.set_armed(clipboard.is_armed());
+ transfer.set_summary(clipboard.describe(scope).into());
// Only worth saying when it is actually true of *this* copy: a clipboard
// holding no crop loses nothing to the setting, and saying so anyway would
// train the user to ignore the line.
- window.set_settings_framing_withheld(
+ transfer.set_framing_withheld(
clipboard.holds_framing() && !scope.has(dr_pipeline::Attribute::Compose),
);
}
@@ -603,7 +604,7 @@ pub fn wire(
let clipboard = clipboard.clone();
let session = session.clone();
let settings = settings.clone();
- window.on_copy_settings(move || {
+ window.global::().on_copy(move || {
let Some(w) = weak.upgrade() else { return };
if let Some(s) = session.borrow().as_ref() {
clipboard.copy_from(s);
@@ -622,7 +623,7 @@ pub fn wire(
let redraw = redraw.clone();
let open = open.clone();
let library = library.clone();
- window.on_paste_settings(move || {
+ window.global::().on_paste(move || {
let Some(w) = weak.upgrade() else { return };
let Some(preset) = clipboard.peek() else {
return;
@@ -933,11 +934,22 @@ pub fn wire_named(
});
}
- // --- what saving would capture ----------------------------------------
+ // --- opening the sheet over the open photograph -----------------------
+ //
+ // The develop column's "Presets…" button, and everything opening the sheet
+ // from there means. It used to be four lines inside the panel's
+ // instantiation in `app.slint`, which is exactly the sort of behaviour a
+ // second drawing of that panel would have had to copy; `Transfer` is a
+ // global and a global cannot bind the window's own state, so it lands
+ // here instead — where the summary it also has to compute already lived.
+ //
+ // The grid opens the same sheet with its own count and no capture summary,
+ // still from `app.slint`: nothing there is worth saving, so `can-save` is
+ // false and the summary would describe an edit that is not in hand.
{
let weak = window.as_weak();
let session = session.clone();
- window.on_presets_opened(move || {
+ window.global::().on_open_presets(move || {
let Some(w) = weak.upgrade() else { return };
// At the scope a save would use, which is full: a preset keeps
// the framing it was captured with and drops it at apply time.
@@ -947,6 +959,14 @@ pub fn wire_named(
.map(|s| describe(&s.copy_settings(), Scope::everything()))
.unwrap_or_default();
w.set_preset_capture_summary(summary.into());
+ // Opened with no count, which is what tells the apply handler this
+ // means the open photograph rather than a selection.
+ w.set_preset_apply_count(0);
+ // `crate::Develop` spelled out: this module has a `Develop` of its
+ // own, and it is the bundle of session handles below, not the
+ // interface global.
+ w.set_preset_can_save(w.global::().get_enabled());
+ w.set_presets_open(true);
});
}
diff --git a/ui/dr-ui/src/settings_ui.rs b/ui/dr-ui/src/settings_ui.rs
index 28a694b..8523ffa 100644
--- a/ui/dr-ui/src/settings_ui.rs
+++ b/ui/dr-ui/src/settings_ui.rs
@@ -32,7 +32,7 @@ use dr_types::{
use slint::ComponentHandle;
use crate::settings_store::SettingsStore;
-use crate::AppWindow;
+use crate::{Adjustments, AppWindow};
use dr_sync::Connection;
/// Shared settings state for the running window.
@@ -504,7 +504,8 @@ pub fn wire(
// control to the other, and without it the preference would
// save correctly and change nothing until the next launch.
render(&w, &ctl);
- w.set_groups_in_rail(choice.groups_in_rail(dr_plat::is_touch_first()));
+ w.global::()
+ .set_groups_in_rail(choice.groups_in_rail(dr_plat::is_touch_first()));
});
}
diff --git a/ui/dr-ui/src/spots_ui.rs b/ui/dr-ui/src/spots_ui.rs
index 61bdbd9..2f90b02 100644
--- a/ui/dr-ui/src/spots_ui.rs
+++ b/ui/dr-ui/src/spots_ui.rs
@@ -14,7 +14,7 @@ use std::rc::Rc;
use slint::{ComponentHandle as _, Model as _, ModelRc, VecModel};
use crate::develop::DevelopSession;
-use crate::{AppWindow, SpotHandle};
+use crate::{AppWindow, Repair, SpotHandle, Steps};
/// TRACES: FR-DEV-8 | FR-UI-3
/// Move the circles to where the repairs now are.
@@ -51,7 +51,9 @@ pub(crate) fn sync_handles(window: &AppWindow, session: &DevelopSession) {
}
window.set_spot_handles(ModelRc::from(model));
- window.set_selected_spot(session.selected_spot_id().unwrap_or_default().into());
+ window
+ .global::()
+ .set_selected(session.selected_spot_id().unwrap_or_default().into());
}
/// The circles' model, held for the life of the process — one shared identity,
@@ -73,8 +75,8 @@ pub(crate) fn reset(window: &AppWindow) {
model.remove(model.row_count() - 1);
}
window.set_spot_handles(ModelRc::from(model));
- window.set_selected_spot(Default::default());
- window.set_spot_count(0);
+ window.global::().set_selected(Default::default());
+ window.global::().set_count(0);
}
/// Install the repair tool's callbacks.
@@ -179,7 +181,7 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.$install(move |value| {
+ window.global::().$install(move |value| {
let Some(w) = weak.upgrade() else { return };
let changed = session
.borrow_mut()
@@ -198,18 +200,16 @@ pub(crate) fn wire(
}};
}
- control!(on_spot_radius_changed, |spot: &mut dr_pipeline::Spot, v| {
+ control!(on_radius_changed, |spot: &mut dr_pipeline::Spot, v| {
spot.set_radius(v)
});
- control!(
- on_spot_feather_changed,
- |spot: &mut dr_pipeline::Spot, v| { spot.set_feather(v) }
- );
- control!(
- on_spot_opacity_changed,
- |spot: &mut dr_pipeline::Spot, v| { spot.set_opacity(v) }
- );
- control!(on_spot_mode_picked, |spot: &mut dr_pipeline::Spot, i| {
+ control!(on_feather_changed, |spot: &mut dr_pipeline::Spot, v| {
+ spot.set_feather(v)
+ });
+ control!(on_opacity_changed, |spot: &mut dr_pipeline::Spot, v| {
+ spot.set_opacity(v)
+ });
+ control!(on_mode_picked, |spot: &mut dr_pipeline::Spot, i| {
spot.mode = if i == 1 {
dr_pipeline::SpotMode::Clone
} else {
@@ -243,7 +243,7 @@ pub(crate) fn wire(
let weak = window.as_weak();
let session = session.clone();
let redraw = redraw.clone();
- window.on_spot_removed(move |id| {
+ window.global::().on_removed(move |id| {
let Some(w) = weak.upgrade() else { return };
let removed = session
.borrow_mut()
@@ -269,12 +269,13 @@ pub(crate) fn wire(
/// change at different times: the circles move on every frame of a drag and on
/// every pan, and these move when a repair is selected or a control is used.
pub(crate) fn sync_panel(window: &AppWindow, session: &DevelopSession) {
- window.set_spot_count(session.spot_count() as i32);
+ let repair = window.global::();
+ repair.set_count(session.spot_count() as i32);
if let Some(spot) = session.selected_spot() {
- window.set_spot_radius(spot.radius);
- window.set_spot_feather(spot.feather);
- window.set_spot_opacity(spot.opacity);
- window.set_spot_mode(match spot.mode {
+ repair.set_radius(spot.radius);
+ repair.set_feather(spot.feather);
+ repair.set_opacity(spot.opacity);
+ repair.set_mode(match spot.mode {
dr_pipeline::SpotMode::Heal => 0,
dr_pipeline::SpotMode::Clone => 1,
});
@@ -287,6 +288,10 @@ pub(crate) fn sync_panel(window: &AppWindow, session: &DevelopSession) {
/// disabled undo button after an edit that *is* undoable is the kind of small
/// lie that stops people trusting the button at all.
fn sync_undo(window: &AppWindow, session: &Rc>>) {
- window.set_can_undo(session.borrow().as_ref().is_some_and(|s| s.can_undo()));
- window.set_can_redo(session.borrow().as_ref().is_some_and(|s| s.can_redo()));
+ window
+ .global::()
+ .set_can_undo(session.borrow().as_ref().is_some_and(|s| s.can_undo()));
+ window
+ .global::()
+ .set_can_redo(session.borrow().as_ref().is_some_and(|s| s.can_redo()));
}
diff --git a/ui/dr-ui/ui/adjust.slint b/ui/dr-ui/ui/adjust.slint
index 734cc19..2d03f05 100644
--- a/ui/dr-ui/ui/adjust.slint
+++ b/ui/dr-ui/ui/adjust.slint
@@ -8,6 +8,7 @@
// (FR-DEV-3c).
import { Theme } from "theme.slint";
+import { Develop } from "session.slint";
import { PanelHeading, Label, Value, Caption, Button, IconButton, Swatch } from "widgets.slint";
import { SliderTrack, ControlRow, CurveEditor, Segmented, ChoiceChip, ChipGrid, Check } from "controls.slint";
@@ -620,6 +621,66 @@ component ParamControl inherits Rectangle {
}
}
+/// TRACES: FR-DEV-3
+/// The frame: its shape, its angle, and the two ways of turning it over.
+///
+/// A global rather than nine properties and eight callbacks on the panel — see
+/// `session.slint` for why the develop panels stopped taking their wiring
+/// through the window root.
+///
+/// Everything here is **mirrored from the session rather than held here**, for
+/// the same reason the crop rect is: Rust clamps and wraps these, so the panel
+/// must show what was actually applied and not what the click asked for.
+///
+/// The crop overlay's own state is not here. Whether the overlay is up is
+/// `Develop.cropping`, a reading of the view's mode, and the rect itself is
+/// dragged on the photograph rather than set from this panel.
+export global Framing {
+ in property angle: 0.0;
+ /// The straighten slider's travel either way, from the descriptor.
+ in property max-straighten: 45.0;
+ in property flip-h: false;
+ in property flip-v: false;
+ /// Any of crop, angle, rotation or flips differs from neutral — what
+ /// lights the section's dot and enables its reset. Distinct from the crop
+ /// rect being non-full: a rotation or a flip is an edit with the crop
+ /// still full.
+ in property modified: false;
+
+ /// TRACES: FR-DEV-3
+ /// The ratios the crop may be locked to, and which one is chosen.
+ ///
+ /// Named by Rust rather than listed here: the set is `CropAspect::CHOICES`
+ /// and the labels come off it, so a ratio added there appears without this
+ /// file changing.
+ in property <[string]> aspects;
+ in property aspect: 0;
+ /// Whether the chosen ratio is standing on its short edge.
+ in property portrait: false;
+ /// Whether the chosen ratio has a second orientation at all — `Free` and
+ /// the square do not, and the switch says so rather than vanishing.
+ in property aspect-turnable: false;
+
+ /// Quarter turns, positive clockwise.
+ callback rotate(int);
+ callback flip-h-toggled();
+ callback flip-v-toggled();
+ callback angle-changed(float);
+ /// TRACES: FR-DEV-3
+ /// The straightening gesture is over and this is the angle to keep.
+ ///
+ /// What the auto-crop hangs off — see `DevelopSession::auto_crop_to_angle`
+ /// for why it must be the end of the drag and not every frame of it, and
+ /// `PlainSlider::committed` for why it must not be `drag-changed`.
+ callback angle-committed(float);
+ /// Lock the crop to one of `aspects`, by index.
+ callback aspect-picked(int);
+ /// Stand the chosen ratio on its other edge.
+ callback portrait-toggled();
+ /// Crop, angle, rotation and flips back to neutral, leaving colour alone.
+ callback reset();
+}
+
// Crop, rotation, flips and straightening — the framing controls.
//
// **Why this is hand-built when the rest of the panel is generated.** The
@@ -634,41 +695,6 @@ component ParamControl inherits Rectangle {
// of a descriptor or routes by index. It calls named session actions, which is
// what a bespoke widget for a known stage is entitled to do.
export component ComposePanel inherits Rectangle {
- in property enabled: true;
- in property angle: 0.0;
- in property max-straighten: 45.0;
- in property flip-h: false;
- in property flip-v: false;
- /// Any of crop, angle, rotation or flips differs from neutral.
- in property modified: false;
-
- /// TRACES: FR-DEV-3
- /// The crop overlay is up, so the ratio lock is a control for a gesture
- /// that is currently on screen.
- in property cropping: false;
- /// The ratios on offer, named by Rust — see `CropAspect::CHOICES`.
- in property <[string]> aspects;
- in property aspect: 0;
- in property portrait: false;
- /// Whether the chosen ratio has a second orientation. `Free` and the
- /// square do not.
- in property aspect-turnable: false;
-
- callback rotate(int);
- callback flip-h-toggled();
- callback flip-v-toggled();
- callback angle-changed(float);
- /// The straightening gesture is over and this is the angle to keep.
- ///
- /// What the auto-crop hangs off — see `DevelopSession::auto_crop_to_angle`
- /// for why it must be the end of the drag and not every frame of it, and
- /// `PlainSlider::committed` for why it must not be `drag-changed`.
- callback angle-committed(float);
- callback angle-reset();
- callback aspect-picked(int);
- callback portrait-toggled();
- callback reset();
-
height: layout.preferred-height;
layout := VerticalLayout {
@@ -685,9 +711,9 @@ export component ComposePanel inherits Rectangle {
// reset — without the hiding.
GroupHeading {
title: "COMPOSE";
- modified: root.modified;
- has-reset: root.modified;
- reset => { root.reset(); }
+ modified: Framing.modified;
+ has-reset: Framing.modified;
+ reset => { Framing.reset(); }
}
VerticalLayout {
@@ -717,14 +743,14 @@ export component ComposePanel inherits Rectangle {
IconButton {
icon: "rotate-ccw";
label: "Rotate left";
- enabled: root.enabled;
- clicked => { root.rotate(-1); }
+ enabled: Develop.enabled;
+ clicked => { Framing.rotate(-1); }
}
IconButton {
icon: "rotate-cw";
label: "Rotate right";
- enabled: root.enabled;
- clicked => { root.rotate(1); }
+ enabled: Develop.enabled;
+ clicked => { Framing.rotate(1); }
}
Rectangle { horizontal-stretch: 1; }
@@ -732,33 +758,33 @@ export component ComposePanel inherits Rectangle {
IconButton {
icon: "flip-h";
label: "Flip horizontally";
- active: root.flip-h;
+ active: Framing.flip-h;
accessible-checkable: true;
- accessible-checked: root.flip-h;
- enabled: root.enabled;
- clicked => { root.flip-h-toggled(); }
+ accessible-checked: Framing.flip-h;
+ enabled: Develop.enabled;
+ clicked => { Framing.flip-h-toggled(); }
}
IconButton {
icon: "flip-v";
label: "Flip vertically";
- active: root.flip-v;
+ active: Framing.flip-v;
accessible-checkable: true;
- accessible-checked: root.flip-v;
- enabled: root.enabled;
- clicked => { root.flip-v-toggled(); }
+ accessible-checked: Framing.flip-v;
+ enabled: Develop.enabled;
+ clicked => { Framing.flip-v-toggled(); }
}
}
PlainSlider {
label: "Straighten";
- value: root.angle;
+ value: Framing.angle;
default-value: 0.0;
- minimum: -root.max-straighten;
- maximum: root.max-straighten;
+ minimum: -Framing.max-straighten;
+ maximum: Framing.max-straighten;
unit: "°";
- changed(v) => { root.angle-changed(v); }
- committed(v) => { root.angle-committed(v); }
- reset => { root.angle-reset(); }
+ changed(v) => { Framing.angle-changed(v); }
+ committed(v) => { Framing.angle-committed(v); }
+ reset => { Framing.angle-changed(0); }
}
// TRACES: FR-DEV-3
@@ -780,16 +806,19 @@ export component ComposePanel inherits Rectangle {
// on top of one another — invisible in this file and obvious on
// screen. `app.slint` and `masks.slint` both carry the same note
// for the same reason.
- if root.cropping: Label { text: "Ratio"; body: true; }
+ // **Only while the crop overlay is up.** Shown at all times these
+ // would be a control for a gesture that is not on screen; hidden
+ // behind a lid they would be a feature nobody finds.
+ if Develop.cropping: Label { text: "Ratio"; body: true; }
// The same wrapping grid the generated enum rows use, for the
// same reason: six chips in a row would be 414px of chips setting
// the width of a column that is meant to be 280.
- if root.cropping: ChipGrid {
- options: root.aspects;
- selected: root.aspect;
- enabled: root.enabled;
- picked(i) => { root.aspect-picked(i); }
+ if Develop.cropping: ChipGrid {
+ options: Framing.aspects;
+ selected: Framing.aspect;
+ enabled: Develop.enabled;
+ picked(i) => { Framing.aspect-picked(i); }
}
// One chip, lit when the ratio is standing on its short edge,
@@ -804,7 +833,7 @@ export component ComposePanel inherits Rectangle {
// under the first column: a `ChoiceChip` placed straight into the
// `VerticalLayout` is stretched across the whole panel, which reads
// as a button for the section rather than as one more chip.
- if root.cropping: Rectangle {
+ if Develop.cropping: Rectangle {
height: Theme.control-height;
ChoiceChip {
@@ -812,29 +841,51 @@ export component ComposePanel inherits Rectangle {
width: 88px;
height: 100%;
label: "Portrait";
- selected: root.portrait;
- enabled: root.enabled && root.aspect-turnable;
- clicked => { root.portrait-toggled(); }
+ selected: Framing.portrait;
+ enabled: Develop.enabled && Framing.aspect-turnable;
+ clicked => { Framing.portrait-toggled(); }
}
}
}
}
}
-// The panel: a heading per multi-parameter operation, a control per parameter.
-//
-// **Why the loop is shaped the way it is.** `rows` is flat, and Slint can
-// neither slice a model nor nest a `for` over a run of it. What it *can* do is
-// repeat over an integer — `for n in row.group-len` — so each group's heading
-// row renders its whole group by indexing back into `rows` from `group-head`,
-// and every other row renders nothing.
-//
-// **Nothing here collapses.** Every group was a `Section` with a disclosure
-// triangle until it became clear what that cost on a tablet: five of the
-// pipeline's operations carry one parameter, so the lid was most of the row,
-// and a control behind a lid is one the user does not know the pipeline has.
-// The column is closed as a whole from the status strip instead, which is the
-// control that was actually wanted.
+/// TRACES: FR-DEV-6
+/// The settings clipboard, as the develop column sees it.
+///
+/// A global rather than three properties and three callbacks on the panel —
+/// `session.slint` gives the argument.
+///
+/// The clipboard itself is a **window-lifetime** thing and not a view's: a
+/// copy is taken in develop and may be pasted onto a selection back in the
+/// library grid, and the grid's own paste stays on the window root where the
+/// grid can reach it. What is here is the develop half — the two buttons and
+/// what they would do.
+export global Transfer {
+ /// Whether anything has been copied yet. Distinct from the clipboard
+ /// being *neutral*: a copy of an unedited frame is a real thing to paste,
+ /// since it clears the target.
+ in property armed: false;
+ /// What a paste would apply, at the current scope — "3 adjustments", or
+ /// "Neutral".
+ in property summary;
+ /// Whether the clipboard holds framing the current scope is dropping.
+ /// Only then is it worth saying anything about the crop.
+ in property framing-withheld: false;
+
+ callback copy();
+ callback paste();
+ /// TRACES: FR-DEV-6
+ /// Open the named-preset sheet over the open photograph. Beside copy and
+ /// paste because it is the same thought given a name — this edit, kept.
+ ///
+ /// Handled in Rust rather than by setting the sheet's properties here, as
+ /// the panel's instantiation used to: a global cannot bind the window's
+ /// state, and the handler has to say what saving would capture anyway.
+ /// The grid opens the same sheet with its own count, from `app.slint`.
+ callback open-presets();
+}
+
// TRACES: FR-DEV-6
// Copying this photograph's settings, and pasting settings onto it.
//
@@ -849,24 +900,6 @@ export component ComposePanel inherits Rectangle {
// whether the crop is coming with it — a question the label answers by
// naming the count the *current* scope would apply.
export component TransferPanel inherits VerticalLayout {
- in property enabled: true;
- /// Whether anything has been copied yet. Distinct from the clipboard
- /// being *neutral*: a copy of an unedited frame is a real thing to paste,
- /// since it clears the target.
- in property armed: false;
- /// What a paste would apply — "3 adjustments", or "Neutral".
- in property summary;
- /// Whether the clipboard holds framing the current scope is dropping.
- /// Only then is it worth saying anything about the crop.
- in property framing-withheld: false;
-
- callback copy();
- callback paste();
- /// TRACES: FR-DEV-6
- /// Open the named-preset sheet. Beside copy and paste because it is the
- /// same thought given a name — this edit, kept.
- callback open-presets();
-
padding: Theme.gap;
spacing: Theme.gap-sm;
@@ -880,9 +913,9 @@ export component TransferPanel inherits VerticalLayout {
Button {
text: "Copy";
- enabled: root.enabled;
+ enabled: Develop.enabled;
horizontal-stretch: 1;
- clicked => { root.copy(); }
+ clicked => { Transfer.copy(); }
}
Button {
@@ -890,9 +923,9 @@ export component TransferPanel inherits VerticalLayout {
// Enabled on `armed` rather than on the summary being non-empty,
// so pasting a neutral copy — which clears this image — stays
// available. Still needs an image to paste *onto*.
- enabled: root.enabled && root.armed;
+ enabled: Develop.enabled && Transfer.armed;
horizontal-stretch: 1;
- clicked => { root.paste(); }
+ clicked => { Transfer.paste(); }
}
}
@@ -902,39 +935,117 @@ export component TransferPanel inherits VerticalLayout {
// that does neither sitting between them would read as part of that pair.
Button {
text: "Presets…";
- enabled: root.enabled;
- clicked => { root.open-presets(); }
+ enabled: Develop.enabled;
+ clicked => { Transfer.open-presets(); }
}
- if root.armed: Caption {
- text: root.summary + (root.framing-withheld ? " · crop not included" : "");
+ if Transfer.armed: Caption {
+ text: Transfer.summary + (Transfer.framing-withheld ? " · crop not included" : "");
}
}
-
-/// Which mode the develop view is in.
+/// TRACES: FR-DEV-3
+/// The generated controls: what they show, what they are pointed at, and what
+/// pressing one means.
///
-/// `crop` was a bare `bool` on the window and local masking was a panel with
-/// two toggles, so nothing stopped both being on at once — and nothing on
-/// screen said which of them the canvas and the column were obeying. One value
-/// with three states cannot be in two of them, which is the whole reason this
-/// is an enum rather than a tidier pair of flags.
-export enum ViewMode {
- /// The whole photograph. Sliders are global, the canvas pans and zooms.
- photo,
- /// The crop overlay is up and the canvas shows the uncropped frame.
- crop,
- /// The region map is drawn, a click on the photograph selects, and the
- /// column is the mask stack and the selected layer's adjustments.
- local,
- /// TRACES: FR-DEV-8
- /// The repairs are drawn on the photograph, a click places one, and the
- /// column describes whichever is selected.
+/// A global rather than eleven properties and eight callbacks spread over two
+/// panels — `session.slint` gives the argument. `GroupStrip` and `AdjustPanel`
+/// share it because they are one control between them: the strip says which
+/// slice of `rows` the panel is drawing, and a strip that filtered a different
+/// panel from the one beside it would be a control for nothing.
+///
+/// **This names no operation and no parameter.** Everything here is a model
+/// the core supplied or an index back into it (ARCH §4.3a, FR-DEV-3a).
+export global Adjustments {
+ in property <[ParamRow]> rows;
+ /// What these controls are pointed at — the whole photograph, or one mask
+ /// layer by name.
///
- /// A mode rather than a panel button for the reason the enum exists at
- /// all: arming a click on the canvas is something only one tool may be
- /// doing at a time, and two flags could both be true.
- spots,
+ /// Supplied already resolved: whether a layer is selected and what it is
+ /// called are session facts, and deriving them in the panel would need
+ /// that file to reason about the mask stack.
+ in property scope: "ADJUST";
+
+ /// The groups the strip offers, already resolved, and which is chosen.
+ /// -1 is "everything".
+ in property <[string]> tabs;
+ in property active-tab: -1;
+ callback tab-picked(int);
+ /// TRACES: FR-UI-1 | FR-UI-7
+ /// Whether the groups are chosen from the tool rail instead of from the
+ /// strip above the column.
+ ///
+ /// Owned by Rust, which composes it from the input modality and the
+ /// photographer's override — see `ToolRail::groups-in-rail` for why the
+ /// axis is input rather than platform or width.
+ ///
+ /// The two controls are mutually exclusive by construction: this shows one
+ /// and hides the other, so there is never a moment with two ways to answer
+ /// the same question, and no state to keep in step between them.
+ in property groups-in-rail: false;
+
+ /// The tone curve's sampled shape, evaluated in Rust by the same spline
+ /// the shader runs so the drawn line cannot disagree with the applied one.
+ in property <[float]> curve-samples;
+ /// The curves the tone curve widget can plot, named by the core. Fewer
+ /// than two of them means there is nothing to choose and no selector.
+ in property <[string]> curve-channels;
+ /// Which of them `curve-samples` and the row's points describe.
+ in property curve-channel;
+
+ callback param-changed(int, int, float);
+ callback param-reset(int, int);
+ /// Every parameter of one operation back to its default. A section's reset
+ /// and a curve's reset are the same action, so they share the one callback
+ /// rather than duplicating a handler that would have to be kept in step
+ /// with it.
+ callback curve-reset(int);
+ /// Plot a different one of the curve's curves.
+ callback curve-channel-picked(int);
+ callback reset-all();
+
+ // TRACES: FR-DEV-3
+ // The on-canvas sampler: which group has armed it.
+ //
+ // The op index rather than a bool, because arming is a question about a
+ // *group* — two operations could ask for a sampler and only one of them
+ // can be waiting for the click. -1 is none armed, the sentinel this file
+ // already uses for "no swatch" and "everything" and for the same reason:
+ // a Slint struct or property cannot carry an optional.
+ in-out property sampling-op: -1;
+ /// The heading's picker was pressed for the operation at this index.
+ ///
+ /// A function rather than a callback into Rust, and that is deliberate:
+ /// arming changes what a click on the photograph does and nothing about
+ /// the edit, so there is nothing for the session to hear about until a
+ /// point is actually picked. It lived in `app.slint`'s instantiation of
+ /// the panel before, which is exactly the sort of behaviour a second
+ /// instantiation would have had to copy.
+ public function arm-sampler(op: int) {
+ self.sampling-op = self.sampling-op == op ? -1 : op;
+ }
+
+ // TRACES: FR-DEV-3f
+ // The film stock, which is not a parameter and so is not a `ParamRow`.
+ //
+ // A bespoke control for the same reason the mask panel is one: a stock is
+ // a choice of *material*, named by an id, not a number on a slider. The
+ // generic rows keep their rule — they still name no operation — and the
+ // film's own exposure sliders arrive through them like any other.
+ //
+ // Names are supplied already resolved, and the list is whatever profiles
+ // are installed: this file does not know what a Kodachrome is.
+ in property <[string]> film-stocks;
+ /// Index into `film-stocks`. Zero is the first entry, which Rust makes
+ /// "no film" — so a fresh photograph selects it without a sentinel.
+ in property film-selected: 0;
+ /// Whether the chosen stock is a negative with a paper to print on. False
+ /// for a reversal stock, which is the picture already, and for no film.
+ in property film-can-print: false;
+ /// Print it, rather than view the negative as scanned.
+ in property film-print: false;
+ callback film-picked(int);
+ callback film-print-toggled(bool);
}
/// The group strip: which kind of adjustment the column is showing.
@@ -965,16 +1076,16 @@ export enum ViewMode {
/// joins a group without an edit here (FR-DEV-3a). With the tools gone there is
/// no longer any hand-written word in this row at all, save "All".
export component GroupStrip inherits Rectangle {
- in property <[string]> tabs;
- /// Index into `tabs`, or -1 for "everything".
- in property active-tab: -1;
- in property enabled: true;
-
- callback picked(int);
+ /// Whether the strip has anything to offer and is the control that offers
+ /// it: an open photograph, with the groups not already in the rail.
+ ///
+ /// Derived here rather than bound at the instantiation, so a second
+ /// composition of this column cannot get the rule slightly different.
+ property live: Develop.enabled && !Adjustments.groups-in-rail;
background: Theme.surface;
- height: root.enabled ? layout.preferred-height : 0px;
- visible: root.enabled;
+ height: root.live ? layout.preferred-height : 0px;
+ visible: root.live;
// Scrolls rather than overflowing, exactly as the develop status strip
// does and for the same reason: a `HorizontalLayout` given less width than
@@ -1015,11 +1126,11 @@ export component GroupStrip inherits Rectangle {
width: 34px;
height: Theme.touch-target;
mouse-cursor: pointer;
- clicked => { root.picked(-1); }
+ clicked => { Adjustments.tab-picked(-1); }
Label {
text: "All";
- emphasised: root.active-tab == -1 || all.has-hover;
+ emphasised: Adjustments.active-tab == -1 || all.has-hover;
vertical-alignment: center;
}
@@ -1027,19 +1138,19 @@ export component GroupStrip inherits Rectangle {
y: parent.height - 2px;
height: 2px;
width: parent.width;
- background: root.active-tab == -1 ? Theme.ink : transparent;
+ background: Adjustments.active-tab == -1 ? Theme.ink : transparent;
}
}
- for tab[i] in root.tabs: tab-area := TouchArea {
+ for tab[i] in Adjustments.tabs: tab-area := TouchArea {
width: name.preferred-width + 10px;
height: Theme.touch-target;
mouse-cursor: pointer;
- clicked => { root.picked(i); }
+ clicked => { Adjustments.tab-picked(i); }
name := Label {
text: tab;
- emphasised: root.active-tab == i || tab-area.has-hover;
+ emphasised: Adjustments.active-tab == i || tab-area.has-hover;
vertical-alignment: center;
horizontal-alignment: center;
}
@@ -1050,83 +1161,34 @@ export component GroupStrip inherits Rectangle {
y: parent.height - 2px;
height: 2px;
width: parent.width;
- background: root.active-tab == i ? Theme.ink : transparent;
+ background: Adjustments.active-tab == i ? Theme.ink : transparent;
}
}
}
}
}
+// The panel: a heading per multi-parameter operation, a control per parameter.
+//
+// **Why the loop is shaped the way it is.** `rows` is flat, and Slint can
+// neither slice a model nor nest a `for` over a run of it. What it *can* do is
+// repeat over an integer — `for n in row.group-len` — so each group's heading
+// row renders its whole group by indexing back into `rows` from `group-head`,
+// and every other row renders nothing.
+//
+// **Nothing here collapses.** Every group was a `Section` with a disclosure
+// triangle until it became clear what that cost on a tablet: five of the
+// pipeline's operations carry one parameter, so the lid was most of the row,
+// and a control behind a lid is one the user does not know the pipeline has.
+// The column is closed as a whole from the status strip instead, which is the
+// control that was actually wanted.
export component AdjustPanel inherits Rectangle {
- in property <[ParamRow]> rows;
- in property enabled: true;
- /// What these controls are pointed at — the whole photograph, or one mask
- /// layer by name.
- ///
- /// **The heading, not a caption beside it.** Selecting a layer re-points
- /// every one of these controls at that layer's chain, and until now the
- /// only sign of it was a sentence in the panel above. Putting the answer
- /// in the heading of the thing that changed means the scope cannot be read
- /// without also reading what it applies to.
- ///
- /// Supplied already resolved: whether a layer is selected and what it is
- /// called are session facts, and deriving them here would need this file
- /// to reason about the mask stack.
- in property scope: "ADJUST";
- /// The tone curve's sampled shape, evaluated in Rust by the same spline
- /// the shader runs so the drawn line cannot disagree with the applied one.
- in property <[float]> curve-samples;
- /// The curves the tone curve widget can plot, named by the core. Fewer
- /// than two of them means there is nothing to choose and no selector.
- in property <[string]> curve-channels;
- /// Which of them `curve-samples` and the row's points describe.
- in property curve-channel;
- callback param-changed(int, int, float);
- callback param-reset(int, int);
- callback curve-reset(int);
- /// Plot a different one of the curve's curves.
- callback curve-channel-picked(int);
- /// Return every parameter of one operation to its default — the reset on
- /// a section's own header, beside the panel-wide one.
- callback op-reset(int);
- callback reset-all();
-
- // TRACES: FR-DEV-3
- // The on-canvas sampler: which group has armed it, and the request to arm
- // one.
- //
- // The op index rather than a bool, because arming is a question about a
- // *group* — two operations could ask for a sampler and only one of them
- // can be waiting for the click. -1 is none armed, the sentinel this file
- // already uses for "no swatch" and "everything" and for the same reason:
- // a Slint struct or property cannot carry an optional.
- in property sampling-op: -1;
- /// The heading's picker was pressed, for the operation at this index.
- callback sampler-armed(int);
-
- // TRACES: FR-DEV-3f
- // The film stock, which is not a parameter and so is not a `ParamRow`.
- //
- // A bespoke control for the same reason the mask panel is one: a stock is
- // a choice of *material*, named by an id, not a number on a slider. The
- // generic rows above keep their rule — they still name no operation — and
- // the film's own exposure sliders arrive through them like any other.
- //
- // Names are supplied already resolved, and the list is whatever profiles
- // are installed: this file does not know what a Kodachrome is.
- in property <[string]> film-stocks;
- /// Index into `film-stocks`. Zero is the first entry, which Rust makes
- /// "no film" — so a fresh photograph selects it without a sentinel.
- in property film-selected: 0;
- /// Whether the chosen stock is a negative with a paper to print on. False
- /// for a reversal stock, which is the picture already, and for no film.
- in property film-can-print: false;
- /// Print it, rather than view the negative as scanned.
- in property film-print: false;
- callback film-picked(int);
- callback film-print-toggled(bool);
/// Whether the stock list is open. Pure interface state: it changes no
/// parameter and the core never hears about it.
+ ///
+ /// Private to the panel rather than in `Adjustments`, and deliberately: it
+ /// is a lid, and two drawings of this panel may honestly have their lids
+ /// in different positions.
private property film-expanded: false;
background: Theme.surface;
@@ -1155,7 +1217,7 @@ export component AdjustPanel inherits Rectangle {
HorizontalLayout {
PanelHeading {
- text: root.scope;
+ text: Adjustments.scope;
// Elided rather than wrapped. A layer's name is the user's and
// can be any length; a heading that wrapped would change the
// panel's height as the selection moved, and an unwrapped one
@@ -1169,7 +1231,7 @@ export component AdjustPanel inherits Rectangle {
reset := TouchArea {
width: 44px;
height: 20px;
- clicked => { root.reset-all(); }
+ clicked => { Adjustments.reset-all(); }
Label {
text: "reset";
emphasised: reset.has-hover;
@@ -1178,13 +1240,13 @@ export component AdjustPanel inherits Rectangle {
}
}
- if !root.enabled: Caption { text: "No image"; }
+ if !Develop.enabled: Caption { text: "No image"; }
// TRACES: FR-DEV-3f
// Above the rows, because it decides what they mean: the exposure
// slider below is a slider on *this stock's* characteristic curve, and
// the same number is a different picture on a different film.
- if root.enabled && root.film-stocks.length > 1: VerticalLayout {
+ if Develop.enabled && Adjustments.film-stocks.length > 1: VerticalLayout {
spacing: Theme.gap-sm;
// **Collapsed to one row, and opened only to change it.**
@@ -1224,7 +1286,7 @@ export component AdjustPanel inherits Rectangle {
// The chosen stock's own name, elided rather than
// wrapped: it is a product name of any length and
// this column is 280px.
- text: root.film-stocks[root.film-selected];
+ text: Adjustments.film-stocks[Adjustments.film-selected];
overflow: elide;
horizontal-alignment: right;
horizontal-stretch: 1;
@@ -1241,7 +1303,7 @@ export component AdjustPanel inherits Rectangle {
if root.film-expanded: VerticalLayout {
spacing: 0px;
- for stock[i] in root.film-stocks: film-row := TouchArea {
+ for stock[i] in Adjustments.film-stocks: film-row := TouchArea {
// Shorter than a touch target, which is a deliberate
// exception and the only one here: a list row's neighbours
// are other rows, so growing the hit area the way a chip
@@ -1250,7 +1312,7 @@ export component AdjustPanel inherits Rectangle {
height: 32px;
mouse-cursor: pointer;
clicked => {
- root.film-picked(i);
+ Adjustments.film-picked(i);
// Closed on choosing. The answer is now in the summary
// row, and leaving two dozen entries open after the
// question has been answered is the behaviour this
@@ -1260,7 +1322,7 @@ export component AdjustPanel inherits Rectangle {
Rectangle {
border-radius: Theme.radius;
- background: i == root.film-selected ? Theme.active
+ background: i == Adjustments.film-selected ? Theme.active
: (film-row.pressed ? Theme.pressed
: (film-row.has-hover ? Theme.hover : transparent));
@@ -1281,15 +1343,15 @@ export component AdjustPanel inherits Rectangle {
// Only for a negative. A reversal stock has no paper — it is the
// photograph as it comes — so offering the choice would be
// offering something that cannot happen.
- if root.film-can-print: HorizontalLayout {
+ if Adjustments.film-can-print: HorizontalLayout {
spacing: Theme.gap-sm;
alignment: start;
print-toggle := TouchArea {
width: 120px;
height: Theme.touch-target;
- clicked => { root.film-print-toggled(!root.film-print); }
+ clicked => { Adjustments.film-print-toggled(!Adjustments.film-print); }
Label {
- text: root.film-print ? "Printed" : "Scanned negative";
+ text: Adjustments.film-print ? "Printed" : "Scanned negative";
emphasised: print-toggle.has-hover;
}
}
@@ -1302,7 +1364,7 @@ export component AdjustPanel inherits Rectangle {
// sliders needed and the instrument the sliders are judged against was
// unreachable. The column scrolls as one now, and a scroller inside a
// scroller would give every drag a third thing to be lost to.
- if root.enabled: VerticalLayout {
+ if Develop.enabled: VerticalLayout {
content := VerticalLayout {
spacing: 0px;
alignment: start;
@@ -1336,7 +1398,7 @@ export component AdjustPanel inherits Rectangle {
//
// This used to nest: a group's head row drew the *whole* group
// by repeating over `row.group-len` and indexing back into
- // `root.rows` for each member, and every other row drew
+ // `Adjustments.rows` for each member, and every other row drew
// nothing. It produced the right picture and could not be
// dragged.
//
@@ -1361,7 +1423,7 @@ export component AdjustPanel inherits Rectangle {
// It also drops the old hazard of the head row building every
// control in its group — thirty-six live TouchAreas behind the
// mixer's twelve visible ones.
- for row[i] in root.rows: VerticalLayout {
+ for row[i] in Adjustments.rows: VerticalLayout {
spacing: 0px;
// The group's name, drawn by the row that heads it, above
@@ -1394,11 +1456,11 @@ export component AdjustPanel inherits Rectangle {
// waiting is the panel's business, because only
// the panel can see the others.
has-sampler: row.group-samples;
- sampling: root.sampling-op == row.op-index;
- sample => { root.sampler-armed(row.op-index); }
+ sampling: Adjustments.sampling-op == row.op-index;
+ sample => { Adjustments.arm-sampler(row.op-index); }
// Resetting is what *this* panel's groups do; the
// heading itself has no opinion about it.
- reset => { root.op-reset(row.op-index); }
+ reset => { Adjustments.curve-reset(row.op-index); }
}
}
@@ -1412,16 +1474,16 @@ export component AdjustPanel inherits Rectangle {
ParamControl {
data: row;
- curve-samples: root.curve-samples;
- curve-channels: root.curve-channels;
- curve-channel: root.curve-channel;
+ curve-samples: Adjustments.curve-samples;
+ curve-channels: Adjustments.curve-channels;
+ curve-channel: Adjustments.curve-channel;
drag-changed(on) => { root.slider-dragging = on; }
param-changed(op, param, v) => {
- root.param-changed(op, param, v);
+ Adjustments.param-changed(op, param, v);
}
- param-reset(op, param) => { root.param-reset(op, param); }
- curve-reset(op) => { root.curve-reset(op); }
- curve-channel-picked(i) => { root.curve-channel-picked(i); }
+ param-reset(op, param) => { Adjustments.param-reset(op, param); }
+ curve-reset(op) => { Adjustments.curve-reset(op); }
+ curve-channel-picked(i) => { Adjustments.curve-channel-picked(i); }
}
}
}
diff --git a/ui/dr-ui/ui/app.slint b/ui/dr-ui/ui/app.slint
index b0134c6..c79e136 100644
--- a/ui/dr-ui/ui/app.slint
+++ b/ui/dr-ui/ui/app.slint
@@ -1,9 +1,10 @@
import { Theme } from "theme.slint";
-import { AdjustPanel, ComposePanel, GroupStrip, ParamRow, TransferPanel, ViewMode } from "adjust.slint";
-import { CategoryRow, GradientHandle, GradientHandles, HandleRole, MaskPanel, MaskRow, PartRow, SubjectRow } from "masks.slint";
-import { SpotHandle, SpotHandles, SpotPanel, SpotRole } from "spots.slint";
+import { Develop, ViewMode } from "session.slint";
+import { AdjustPanel, Adjustments, ComposePanel, Framing, GroupStrip, ParamRow, Transfer, TransferPanel } from "adjust.slint";
+import { CategoryRow, GradientHandle, GradientHandles, HandleRole, MaskPanel, MaskRow, Masking, SubjectRow } from "masks.slint";
+import { Repair, SpotHandle, SpotHandles, SpotPanel, SpotRole } from "spots.slint";
import { CropOverlay } from "crop.slint";
-import { HistoryPanel, HistoryRow } from "history.slint";
+import { HistoryPanel, HistoryRow, Steps } from "history.slint";
import { LaunchScreen } from "launch.slint";
import { IdentityScreen, IdentityPerson, IdentityFace } from "identity.slint";
import { LibraryGrid, LibraryCell, TimelineBar, PhotoRoll, KeywordRow, PersonChip } from "library.slint";
@@ -11,19 +12,25 @@ import { GestureRow } from "gestures.slint";
import { Button, PanelHeading, Label, Value, Caption, Panel, EmptyState, ProgressBar, ActivityRow } from "widgets.slint";
import { CollectionsPanel, CollectionRow, OfflinePrompt, CollectionMenu,
MembershipSheet, MembershipRow } from "collections.slint";
-import { HistogramPanel, HistogramView } from "histogram.slint";
+import { HistogramPanel, HistogramView, Levels } from "histogram.slint";
import { RecoveryPrompt } from "recovery.slint";
import { PresetSheet, ScopeChips, ScopeKind } from "presets.slint";
-import { FocusMarks, FocusPanel } from "peaking.slint";
+import { FocusMarks, FocusPanel, Peaking } from "peaking.slint";
import { SettingsPage } from "settings.slint";
import { ImportPage } from "import.slint";
-import { StatusBar, InfoPanel } from "develop.slint";
+import { Capture, StatusBar, InfoPanel } from "develop.slint";
import { ToolRail } from "toolrail.slint";
export { LibraryCell, TimelineBar, CollectionRow, ActivityRow, HistogramView, PersonChip }
export { GestureRow }
export { ViewMode, GradientHandle, HandleRole, SpotHandle, SpotRole }
+// The develop view's globals, re-exported so Rust can reach them: a global is
+// hooked through `window.global::()` and only what this document
+// exports appears in the generated API. `session.slint` says why the develop
+// panels take their wiring this way and why there is one global per family.
+export { Develop, Capture, Levels, Peaking, Adjustments, Framing, Transfer, Masking, Repair, Steps }
+
export component AppWindow inherits Window {
title: "DarkRoom";
// The one raster asset in the UI, and the exception that the header of
@@ -65,49 +72,17 @@ export component AppWindow inherits Window {
// Current image, for the status strip and empty state.
in property filename: "";
- in property camera: "";
- /// TRACES: FR-DEV-3
- /// The lens the file names, and whether a correction profile was found for
- /// it. Composed in Rust because the sentence depends on a database lookup
- /// this file cannot see, and because "not recorded" and "no profile" are
- /// different facts that must not be collapsed into one.
- in property lens: "";
- in property exposure: "";
- in property dimensions: "";
in property index: 0;
in property total: 0;
in property load-error: "";
- /// TRACES: FR-DSP-7
- /// The counted frame. Set only when the render has settled — a histogram
- /// of a draft frame is a histogram of an image nobody is reading.
- in property histogram;
-
- /// The same photograph counted in the raw domain — the demosaiced
- /// scene-linear texture, before white balance, the camera matrix or any
- /// curve, on an axis of stops below sensor saturation.
- ///
- /// Beside the display histogram rather than instead of it: the two answer
- /// different questions and the panel offers both. Unlike the one above it
- /// this is a property of the *file* and not of the render, so it survives
- /// a crop, a zoom and every slider — see `raw_histogram.rs`.
- in property raw-histogram;
-
/// TRACES: FR-CULL-3
- /// Focus peaking: the marks, whether they describe *this* frame, and the
- /// three things the photographer chose. All of them are Rust's, because
- /// the marks come from a compute pass — see `peaking.slint` for why
- /// `focus-overlay-ready` is a separate question from `peaking-on`.
+ /// The focus marks themselves, and whether they describe *this* frame.
+ /// Rust's, because they come from a compute pass — see `peaking.slint` for
+ /// why `focus-overlay-ready` is a separate question from
+ /// `Peaking.showing`, and for the three things the photographer chose.
in property focus-overlay;
in property focus-overlay-ready: false;
- in property peaking-on: false;
- in property peaking-available: true;
- in property peaking-sensitivity: 1;
- in property peaking-colour: 0;
-
- callback peaking-toggled(bool);
- callback peaking-sensitivity-picked(int);
- callback peaking-colour-picked(int);
// --- zoom, pan and crop (FR-DEV-4) ---
//
@@ -125,28 +100,6 @@ export component AppWindow inherits Window {
/// resolution against the viewport's, which Slint does not know.
in property magnified: false;
- /// TRACES: FR-UI-5
- /// What the develop view is currently doing (see `ViewMode`).
- ///
- /// One value rather than a flag per mode, so two modes cannot be on at
- /// once — which, with `crop-mode` a bare bool beside a masking panel that
- /// armed the canvas through two toggles of its own, they could be. Rust
- /// owns it: entering a mode has side effects on the session (crop drops
- /// the zoom, local clears nothing and leaving it clears the selection),
- /// and a property the interface could set directly would let the view
- /// change without them.
- ///
- /// In `crop` the canvas shows the *whole* frame — otherwise the area being
- /// cropped away would not be on screen to drag across — and the surround
- /// is greyed.
- in property view-mode: ViewMode.photo;
- /// Shorthand for the two conditions half this file tests, so a mode
- /// comparison is written once rather than at each of a dozen call sites.
- property cropping: root.view-mode == ViewMode.crop;
- property local-mode: root.view-mode == ViewMode.local;
- /// TRACES: FR-DEV-8
- property repairing: root.view-mode == ViewMode.spots;
-
/// The crop rect in fractions of the frame, mirrored from Rust so the
/// overlay draws exactly what the pipeline holds.
in-out property crop-x: 0.0;
@@ -154,20 +107,6 @@ export component AppWindow inherits Window {
in-out property crop-w: 1.0;
in-out property